From 2e4cf7adcbcb0335ba251e014e2b8eb7c1e1468d Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Thu, 30 Sep 2021 23:37:32 +0200 Subject: [ui] size tweaks and new assets plus work on the systray menu --- gui/components/About.qml | 28 ++++--- gui/components/Footer.qml | 37 ++++++---- gui/components/Locations.qml | 13 +++- gui/components/MainView.qml | 29 ++++++-- gui/components/MaterialButton.qml | 1 + gui/components/MaterialRadioButton.qml | 84 +++++++++++++++++++++ gui/components/MaterialRadioIndicator.qml | 63 ++++++++++++++++ gui/components/Spinner.qml | 63 ---------------- gui/components/Splash.qml | 3 +- gui/components/StatusBox.qml | 2 + gui/components/Systray.qml | 7 ++ gui/components/VPNState.qml | 6 +- gui/components/WrappedRadioButton.qml | 10 ++- gui/gui.qrc | 7 +- gui/main.qml | 6 +- gui/resources/birds.svg | 1 - gui/resources/bridge.png | Bin 5543 -> 0 bytes gui/resources/bridge.svg | 118 ++++++++++++++++++++++++++++++ gui/resources/ravens.svg | 62 ++++++++++++++++ gui/themes/themes.js | 20 +++-- 20 files changed, 443 insertions(+), 117 deletions(-) create mode 100644 gui/components/MaterialRadioButton.qml create mode 100644 gui/components/MaterialRadioIndicator.qml delete mode 100644 gui/components/Spinner.qml delete mode 100644 gui/resources/birds.svg delete mode 100644 gui/resources/bridge.png create mode 100644 gui/resources/bridge.svg create mode 100644 gui/resources/ravens.svg diff --git a/gui/components/About.qml b/gui/components/About.qml index 8642578..cceaad4 100644 --- a/gui/components/About.qml +++ b/gui/components/About.qml @@ -27,7 +27,8 @@ ThemedPage { Text { width: parent.width - 40 - font.pixelSize: 11 + color: Theme.fontColor + font.pixelSize: 12 wrapMode: Label.Wrap text: getText() anchors.horizontalCenter: parent.horizontalCenter @@ -36,23 +37,30 @@ ThemedPage { VerticalSpacer { visible: true - height: 20 + height: 10 } Image { - height: 80 + id: aboutIcon + height: 60 source: "../resources/icon-noshield.svg" fillMode: Image.PreserveAspectFit anchors.horizontalCenter: parent.horizontalCenter } - TextEdit { - width: parent.width - 40 - font.pixelSize: 10 - readOnly: true - selectByMouse: true - text: getVersion() + Rectangle { + anchors.top: aboutIcon.bottom + width: 100 anchors.horizontalCenter: parent.horizontalCenter + TextEdit { + width: 100 + font.pixelSize: 10 + readOnly: true + selectByMouse: true + text: getVersion() + //horizontalAlignment: Text.AlignCenter + //anchors.horizontalCenter: parent.horizontalCenter + } } VerticalSpacer { @@ -89,7 +97,7 @@ ThemedPage { var _ver = ctx ? ctx.version : "unknown" //: %1 -> application name //: %2 -> version string - var _txt = qsTr("%1 version: %2").arg(_name).arg(_ver) + var _txt = qsTr("%1 version: \n%2").arg(_name).arg(_ver) return _txt } } diff --git a/gui/components/Footer.qml b/gui/components/Footer.qml index 1b0d8fa..b806807 100644 --- a/gui/components/Footer.qml +++ b/gui/components/Footer.qml @@ -34,18 +34,22 @@ ToolBar { background.implicitHeight: 32 background.implicitWidth: 32 */ - icon.width: 20 - icon.height: 20 - icon.source: stackView.depth > 1 ? "" : "../resources/globe.svg" + icon { + width: 20 + height: 20 + source: stackView.depth > 1 ? "" : "../resources/globe.svg" + } onClicked: stackView.push("Locations.qml") } Label { id: locationLabel - anchors.left: gwButton.right - anchors.leftMargin: -7 - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: 7 + anchors { + left: gwButton.right + leftMargin: -7 + verticalCenter: parent.verticalCenter + verticalCenterOffset: 7 + } text: locationStr() color: getLocationColor() } @@ -57,14 +61,17 @@ ToolBar { Image { id: bridge + smooth: true visible: isBridgeSelected() - height: 24 - width: 24 - source: "../resources/bridge.png" - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: 5 - anchors.right: gwQuality.left - anchors.rightMargin: 10 + width: 40 + source: "../resources/bridge.svg" + fillMode: Image.PreserveAspectFit + anchors { + verticalCenter: parent.verticalCenter + verticalCenterOffset: 5 + right: gwQuality.left + rightMargin: 10 + } } Image { @@ -75,7 +82,7 @@ ToolBar { anchors.right: parent.right anchors.rightMargin: 20 anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: 5 + anchors.verticalCenterOffset: 0 // TODO refactor with SignalIcon ColorOverlay{ anchors.fill: gwQuality diff --git a/gui/components/Locations.qml b/gui/components/Locations.qml index ce510c5..600b504 100644 --- a/gui/components/Locations.qml +++ b/gui/components/Locations.qml @@ -64,10 +64,13 @@ ThemedPage { } WrappedRadioButton { id: autoRadioButton - anchors.top: recommendedLabel.bottom text: getAutoLabel() ButtonGroup.group: locsel checked: false + anchors { + top: recommendedLabel.bottom + leftMargin: -5 + } onClicked: { root.selectedGateway = "auto" console.debug("Selected gateway: auto") @@ -165,10 +168,12 @@ ThemedPage { Layout.fillWidth: true } Image { - height: 16 - width: 16 + height: 30 + width: 30 + smooth: true visible: isBridgeSelected() - source: "../resources/bridge.png" + fillMode: Image.PreserveAspectFit + source: "../resources/bridge.svg" Layout.alignment: Qt.AlignRight Layout.rightMargin: 10 } diff --git a/gui/components/MainView.qml b/gui/components/MainView.qml index bae34fb..95bb212 100644 --- a/gui/components/MainView.qml +++ b/gui/components/MainView.qml @@ -4,6 +4,8 @@ import QtQuick.Dialogs 1.2 import QtQuick.Controls.Material 2.1 import QtQuick.Layouts 1.14 +import "../themes/themes.js" as Theme + Page { StackView { @@ -90,11 +92,20 @@ Page { id: footer } + Keys.onPressed: { + // shortcuts for avid users :) + // bug: doesnt work until the stack is pushed once + if (event.key == Qt.Key_G && stackView.depth == 1) { + console.debug("Open Locations") + stackView.push("Locations.qml") + } + } + Dialog { id: donateDialog - width: 350 + width: root.appWidth title: qsTr("Please donate!") - standardButtons: Dialog.Ok + standardButtons: Dialog.Yes | Dialog.No Text { id: donateText @@ -107,7 +118,7 @@ Page { horizontalCenter: parent.horizontalCenter } font.pixelSize: 12 - text: qsTr("This service is paid for entirely by donations from users like you. The cost of running the VPN is approximately 5 USD per person every month, but every little bit counts.") + text: qsTr("This service is paid for entirely by donations from users like you. The cost of running the VPN is approximately 5 USD per person every month, but every little bit counts. Do you want to donate now?") } Label { @@ -118,26 +129,32 @@ Page { horizontalCenter: parent.horizontalCenter } font.pixelSize: 14 + textFormat: Text.RichText text: getLink(ctx.donateURL) onLinkActivated: Qt.openUrlExternally(ctx.donateURL) } Image { - height: 50 + height: 40 source: "../resources/donate.svg" fillMode: Image.PreserveAspectFit anchors { topMargin: 20 top: donateURL.bottom + bottomMargin: 50 horizontalCenter: parent.horizontalCenter } } - onAccepted: Qt.openUrlExternally(ctx.donateURL) + onYes: Qt.openUrlExternally(ctx.donateURL) } function getLink(url) { - return "" + url + "" + return "" + url + "" + } + + Component.onCompleted: { + root.openDonateDialog.connect(donateDialog.open) } } diff --git a/gui/components/MaterialButton.qml b/gui/components/MaterialButton.qml index 7fe04d9..7d4ff47 100644 --- a/gui/components/MaterialButton.qml +++ b/gui/components/MaterialButton.qml @@ -30,6 +30,7 @@ T.Button { || control.hovered ? 2 : 0 : control.down ? 8 : 2 Material.background: flat ? "transparent" : undefined + contentItem: IconLabel { spacing: control.spacing mirrored: control.mirrored diff --git a/gui/components/MaterialRadioButton.qml b/gui/components/MaterialRadioButton.qml new file mode 100644 index 0000000..31dad12 --- /dev/null +++ b/gui/components/MaterialRadioButton.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Templates 2.12 as T +import QtQuick.Controls.Material 2.12 +import QtQuick.Controls.Material.impl 2.12 + +T.RadioButton { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + spacing: 4 + padding: 4 + verticalPadding: padding + 2 + + indicator: MaterialRadioIndicator { + // XXX modified left offset to align with headers + x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) - 4 : control.leftPadding + (control.availableWidth - width) / 2 + y: control.topPadding + (control.availableHeight - height) / 2 + control: control + + Ripple { + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: 18; height: 18 + + z: -1 + anchor: control + pressed: control.pressed + active: control.down || control.visualFocus || control.hovered + color: control.checked ? control.Material.highlightedRippleColor : control.Material.rippleColor + } + } + + contentItem: Text { + leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0 + rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0 + + text: control.text + font: control.font + color: control.enabled ? control.Material.foreground : control.Material.hintTextColor + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } +} diff --git a/gui/components/MaterialRadioIndicator.qml b/gui/components/MaterialRadioIndicator.qml new file mode 100644 index 0000000..b380f2a --- /dev/null +++ b/gui/components/MaterialRadioIndicator.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Controls.Material 2.12 +import QtQuick.Controls.Material.impl 2.12 + +Rectangle { + id: indicator + implicitWidth: 18 + implicitHeight: 18 + radius: width / 2 + border.width: 2 + border.color: !control.enabled ? control.Material.hintTextColor + : control.checked || control.down ? control.Material.accentColor : control.Material.secondaryTextColor + color: "transparent" + + property Item control + + Rectangle { + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + // XXX overridden size + width: 8 + height: 8 + radius: width / 2 + color: parent.border.color + visible: indicator.control.checked || indicator.control.down + } +} diff --git a/gui/components/Spinner.qml b/gui/components/Spinner.qml deleted file mode 100644 index 9fc535f..0000000 --- a/gui/components/Spinner.qml +++ /dev/null @@ -1,63 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 - -BusyIndicator { - - id: control - - anchors.horizontalCenter: parent.horizontalCenter - - contentItem: Item { - implicitWidth: 64 - implicitHeight: 64 - - Item { - id: item - x: parent.width / 2 - 32 - y: parent.height / 2 - 32 - width: 64 - height: 64 - opacity: control.running ? 1 : 0 - - Behavior on opacity { - OpacityAnimator { - duration: 250 - } - } - - RotationAnimator { - target: item - running: control.visible && control.running - from: 0 - to: 360 - loops: Animation.Infinite - duration: 6200 - } - - Repeater { - id: repeater - model: 6 - - Rectangle { - x: item.width / 2 - width / 2 - y: item.height / 2 - height / 2 - implicitWidth: 10 - implicitHeight: 10 - radius: 5 - color: "#21be2b" - transform: [ - Translate { - y: -Math.min(item.width, item.height) * 0.5 + 5 - }, - Rotation { - angle: index / repeater.count * 360 - origin.x: 5 - origin.y: 5 - } - ] - } - } - } - } -} diff --git a/gui/components/Splash.qml b/gui/components/Splash.qml index 16f1b9d..625ab18 100644 --- a/gui/components/Splash.qml +++ b/gui/components/Splash.qml @@ -32,8 +32,9 @@ Page { ProgressBar { id: splashProgress - anchors.horizontalCenter: parent.horizontalCenter + width: appWidth * 0.8 - 60 indeterminate: true + anchors.horizontalCenter: parent.horizontalCenter } InitErrors { diff --git a/gui/components/StatusBox.qml b/gui/components/StatusBox.qml index c4a4a08..00d0c2d 100644 --- a/gui/components/StatusBox.qml +++ b/gui/components/StatusBox.qml @@ -117,6 +117,8 @@ Item { MaterialButton { id: toggleVPN + // FIXME - this is a workaround. It will BREAK with i18n + width: 100 spacing: 8 anchors.horizontalCenter: parent.horizontalCenter diff --git a/gui/components/Systray.qml b/gui/components/Systray.qml index 6fb1046..9ed52f5 100644 --- a/gui/components/Systray.qml +++ b/gui/components/Systray.qml @@ -19,6 +19,13 @@ Labs.SystemTrayIcon { Labs.MenuSeparator {} + Labs.MenuItem { + text: qsTr("Donate") + onTriggered: root.openDonateDialog() + } + + Labs.MenuSeparator {} + Labs.MenuItem { text: qsTr("Quit") onTriggered: backend.quit() diff --git a/gui/components/VPNState.qml b/gui/components/VPNState.qml index d92065a..d5115f2 100644 --- a/gui/components/VPNState.qml +++ b/gui/components/VPNState.qml @@ -31,7 +31,7 @@ StateGroup { } PropertyChanges { target: connectionImage - source: "../resources/birds.svg" + source: "../resources/ravens.svg" anchors.horizontalCenter: parent.horizontalCenter } PropertyChanges { @@ -128,7 +128,7 @@ StateGroup { } PropertyChanges { target: connectionImage - source: "../resources/birds.svg" + source: "../resources/ravens.svg" anchors.horizontalCenter: parent.horizontalCenter } PropertyChanges { @@ -164,7 +164,7 @@ StateGroup { PropertyChanges { // ?? is this image correct? target: connectionImage - source: "../resources/birds.svg" + source: "../resources/ravens.svg" anchors.horizontalCenter: parent.horizontalCenter } PropertyChanges { diff --git a/gui/components/WrappedRadioButton.qml b/gui/components/WrappedRadioButton.qml index 04643b1..2993bc4 100644 --- a/gui/components/WrappedRadioButton.qml +++ b/gui/components/WrappedRadioButton.qml @@ -5,11 +5,19 @@ import QtQuick.Controls.Material.impl 2.12 import "../themes/themes.js" as Theme -RadioButton { +MaterialRadioButton { id: control width: parent.width property var location + /* this works for the pointer, but breaks the onClick connection + XXX need to dig into RadioButton implementation. + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + } + */ + contentItem: Label { text: control.text font: control.font diff --git a/gui/gui.qrc b/gui/gui.qrc index e4d1cd6..385b476 100644 --- a/gui/gui.qrc +++ b/gui/gui.qrc @@ -13,9 +13,10 @@ components/Header.qml components/Footer.qml components/About.qml + components/MaterialRadioButton.qml + components/MaterialRadioIndicator.qml components/WrappedRadioButton.qml components/StatusBox.qml - components/Spinner.qml components/Systray.qml components/Help.qml components/Locations.qml @@ -42,14 +43,14 @@ resources/tools.svg resources/help.svg resources/about.svg - resources/bridge.png + resources/bridge.svg resources/gear-fill.svg resources/reception-0.svg resources/reception-2.svg resources/reception-4.svg resources/arrow-left.svg resources/globe.svg - resources/birds.svg + resources/ravens.svg resources/riseup-icon.svg resources/spy.gif resources/quit.svg diff --git a/gui/main.qml b/gui/main.qml index 0024670..1c56925 100644 --- a/gui/main.qml +++ b/gui/main.qml @@ -22,7 +22,7 @@ ApplicationWindow { visible: true property int appHeight: 460 - property int appWidth: 260 + property int appWidth: 280 width: appWidth minimumWidth: appWidth @@ -53,6 +53,8 @@ ApplicationWindow { "blocked": "qrc:/assets/icon/png/white/vpn_blocked.png" } + signal openDonateDialog() + FontLoader { id: lightFont source: "qrc:/poppins-light.ttf" @@ -90,7 +92,7 @@ ApplicationWindow { ctx = JSON.parse(j) if (ctx != undefined) { locationsModel = getSortedLocations() - console.debug("Got sorted locations:" + locationsModel) + //console.debug("Got sorted locations: " + locationsModel) } if (ctx.errors) { console.debug("errors, setting root.error") diff --git a/gui/resources/birds.svg b/gui/resources/birds.svg deleted file mode 100644 index cb2a1df..0000000 --- a/gui/resources/birds.svg +++ /dev/null @@ -1 +0,0 @@ -Asset 1 \ No newline at end of file diff --git a/gui/resources/bridge.png b/gui/resources/bridge.png deleted file mode 100644 index d0a2c80..0000000 Binary files a/gui/resources/bridge.png and /dev/null differ diff --git a/gui/resources/bridge.svg b/gui/resources/bridge.svg new file mode 100644 index 0000000..80788d9 --- /dev/null +++ b/gui/resources/bridge.svg @@ -0,0 +1,118 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/resources/ravens.svg b/gui/resources/ravens.svg new file mode 100644 index 0000000..790eb4a --- /dev/null +++ b/gui/resources/ravens.svg @@ -0,0 +1,62 @@ + +image/svg+xml + + diff --git a/gui/themes/themes.js b/gui/themes/themes.js index 1c7a7c8..d35c662 100644 --- a/gui/themes/themes.js +++ b/gui/themes/themes.js @@ -27,11 +27,19 @@ const desktopAppWidth = 360; const darkFocusBorder = fontColor; const lightFocusBorder = "#d5d3e0"; -const accentOff = "#af0909"; -const accentConnecting = "#FFCC33"; -const accentOn = "#669933"; +const red = "#af0909"; +const yellow = "#ffcc33"; +const green = "#669933"; -const blue = "#0060DF"; +const accentOff = red; +const accentConnecting = yellow; +const accentOn = green; + +const signalLow = red; +const signalMedium = yellow; +const signalGood = green; + +const blue = "#007ac6"; const blueHovered = "#0250BB"; const bluePressed = "#054096"; const blueDisabled = "#a3c0f3"; @@ -53,7 +61,3 @@ const buttonColor = "#eeeeee"; const bgColor = "#f3f3f3"; const fgColor = "#ffffff"; - -const signalGood = "green"; -const signalMedium = "orange"; -const signalLow = "red"; -- cgit v1.2.3