Merge pull request #1 from amnezia-vpn/feature/default-vpn-ui

feature: added ui for DefaultVPN
This commit is contained in:
Nethius 2025-03-19 09:57:36 +07:00 committed by GitHub
commit db71889cc2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1442 additions and 4 deletions

View file

@ -61,7 +61,7 @@ void AmneziaApplication::init()
{ {
m_engine = new QQmlApplicationEngine; m_engine = new QQmlApplicationEngine;
const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml")); const QUrl url(QStringLiteral("qrc:/ui/qml/DefaultVpn/main.qml"));
QObject::connect( QObject::connect(
m_engine, &QQmlApplicationEngine::objectCreated, this, m_engine, &QQmlApplicationEngine::objectCreated, this,
[url](QObject *obj, const QUrl &objUrl) { [url](QObject *obj, const QUrl &objUrl) {
@ -78,7 +78,7 @@ void AmneziaApplication::init()
m_coreController.reset(new CoreController(m_vpnConnection, m_settings, m_engine)); m_coreController.reset(new CoreController(m_vpnConnection, m_settings, m_engine));
m_engine->addImportPath("qrc:/ui/qml/Modules/"); m_engine->addImportPath("qrc:/ui/qml/DefaultVpn");
m_engine->load(url); m_engine->load(url);
m_coreController->setQmlRoot(); m_coreController->setQmlRoot();
@ -153,7 +153,7 @@ void AmneziaApplication::loadFonts()
{ {
QQuickStyle::setStyle("Basic"); QQuickStyle::setStyle("Basic");
QFontDatabase::addApplicationFont(":/fonts/pt-root-ui_vf.ttf"); QFontDatabase::addApplicationFont(":/fonts/VelaSans-GX.ttf");
} }
bool AmneziaApplication::parseCommands() bool AmneziaApplication::parseCommands()

Binary file not shown.

View file

@ -0,0 +1,4 @@
<svg width="82" height="85" viewBox="0 0 82 85" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M61.5 14.4031C70.8668 20.9031 77 31.7353 77 44.0001C77 63.8823 60.8823 80.0001 41 80.0001C21.1177 80.0001 5 63.8823 5 44.0001C5 31.7353 11.1332 20.9031 20.5 14.4031" stroke="white" stroke-width="7" stroke-linecap="round"/>
<path d="M41 4V29" stroke="white" stroke-width="7" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 411 B

View file

@ -231,6 +231,28 @@
<file>ui/qml/Pages2/PageSettingsApiNativeConfigs.qml</file> <file>ui/qml/Pages2/PageSettingsApiNativeConfigs.qml</file>
<file>ui/qml/Pages2/PageSettingsApiDevices.qml</file> <file>ui/qml/Pages2/PageSettingsApiDevices.qml</file>
<file>images/controls/monitor.svg</file> <file>images/controls/monitor.svg</file>
<file>ui/qml/DefaultVpn/Controls/DropDownType.qml</file>
<file>ui/qml/DefaultVpn/main.qml</file>
<file>ui/qml/DefaultVpn/Pages/PageHome.qml</file>
<file>ui/qml/DefaultVpn/Controls/TextTypes/MediumTextType.qml</file>
<file>ui/qml/DefaultVpn/Config/DeviceInfo.qml</file>
<file>ui/qml/DefaultVpn/Config/qmldir</file>
<file>ui/qml/DefaultVpn/Controls/TextTypes/XSmallTextType.qml</file>
<file>ui/qml/DefaultVpn/Controls/ButtonType.qml</file>
<file>ui/qml/DefaultVpn/Pages/PageSettingsServersList.qml</file>
<file>ui/qml/DefaultVpn/Controls/TextTypes/Header1TextType.qml</file>
<file>ui/qml/DefaultVpn/Controls/TextTypes/Header3TextType.qml</file>
<file>ui/qml/DefaultVpn/Config/Style.qml</file>
<file>ui/qml/DefaultVpn/Components/WhiteButtonWithBorder.qml</file>
<file>ui/qml/DefaultVpn/Components/WhiteButtonNoBorder.qml</file>
<file>ui/qml/DefaultVpn/Pages/PageSetupWizardConfigSource.qml</file>
<file>ui/qml/DefaultVpn/Components/BlueButtonNoBorder.qml</file>
<file>ui/qml/DefaultVpn/Controls/InputType.qml</file>
<file>ui/qml/DefaultVpn/Controls/PopupType.qml</file>
<file>ui/qml/DefaultVpn/Pages/PageSettingsServerInfo.qml</file>
<file>ui/qml/DefaultVpn/Controls/BusyIndicatorType.qml</file>
<file>images/controls/connect-button.svg</file>
<file>fonts/VelaSans-GX.ttf</file>
</qresource> </qresource>
<qresource prefix="/countriesFlags"> <qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file> <file>images/flagKit/ZW.svg</file>

View file

@ -51,7 +51,7 @@ QString PageController::getPagePath(PageLoader::PageEnum page)
{ {
QMetaEnum metaEnum = QMetaEnum::fromType<PageLoader::PageEnum>(); QMetaEnum metaEnum = QMetaEnum::fromType<PageLoader::PageEnum>();
QString pageName = metaEnum.valueToKey(static_cast<int>(page)); QString pageName = metaEnum.valueToKey(static_cast<int>(page));
return "qrc:/ui/qml/Pages2/" + pageName + ".qml"; return "qrc:/ui/qml/DefaultVpn/Pages/" + pageName + ".qml";
} }
void PageController::closeWindow() void PageController::closeWindow()

View file

@ -0,0 +1,36 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Config 1.0
import "../Controls/TextTypes"
import "../Controls"
ButtonType {
defaultBackgroundColor: Style.color.accent1
defaultBorderColor: Style.color.gray3
defaultTextColor: Style.color.white
defaultImageColor: Style.color.white
hoveredBackgroundColor: Style.color.accent2
hoveredBorderColor: Style.color.gray3
hoveredTextColor: Style.color.white
hoveredImageColor: Style.color.white
pressedBackgroundColor: Style.color.accent3
pressedBorderColor: Style.color.gray3
pressedTextColor: Style.color.white
pressedImageColor: Style.color.white
disabledBackgroundColor: Style.color.gray6
disabledBorderColor: Style.color.gray3
disabledTextColor: Style.color.gray2
disabledImageColor: Style.color.gray2
defaultBorderWidth: 0
disabledBorderWidth: 0
}

View file

@ -0,0 +1,36 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Config 1.0
import "../Controls/TextTypes"
import "../Controls"
ButtonType {
defaultBackgroundColor: Style.color.white
defaultBorderColor: Style.color.gray3
defaultTextColor: Style.color.accent1
defaultImageColor: Style.color.accent1
hoveredBackgroundColor: Style.color.gray1
hoveredBorderColor: Style.color.gray3
hoveredTextColor: Style.color.accent2
hoveredImageColor: Style.color.accent2
pressedBackgroundColor: Style.color.gray2
pressedBorderColor: Style.color.gray3
pressedTextColor: Style.color.accent3
pressedImageColor: Style.color.accent3
disabledBackgroundColor: Style.color.white
disabledBorderColor: Style.color.gray3
disabledTextColor: Style.color.gray8
disabledImageColor: Style.color.gray8
defaultBorderWidth: 0
disabledBorderWidth: 0
}

View file

@ -0,0 +1,37 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Config 1.0
import "../Controls/TextTypes"
import "../Controls"
ButtonType {
defaultBackgroundColor: Style.color.white
defaultBorderColor: Style.color.gray3
defaultTextColor: Style.color.black
defaultImageColor: Style.color.black
hoveredBackgroundColor: Style.color.white
hoveredBorderColor: Style.color.gray6
hoveredTextColor: Style.color.black
hoveredImageColor: Style.color.black
pressedBackgroundColor: Style.color.gray1
pressedBorderColor: Style.color.gray6
pressedTextColor: Style.color.black
pressedImageColor: Style.color.black
disabledBackgroundColor: Style.color.gray3
disabledBorderColor: Style.color.gray2
disabledTextColor: Style.color.gray9
disabledImageColor: Style.color.gray9
defaultBorderWidth: 1
disabledBorderWidth: 1
hoveredBorderWidth: 1
}

View file

@ -0,0 +1,37 @@
pragma Singleton
import QtQuick
Item {
readonly property int screenWidth: 380
readonly property int screenHeight: 680
function isMobile() {
if (Qt.platform.os === "android" ||
Qt.platform.os === "ios") {
return true
}
return false
}
function isDesktop() {
if (Qt.platform.os === "windows" ||
Qt.platform.os === "linux" ||
Qt.platform.os === "osx") {
return true
}
return false
}
TextEdit {
id: clipboard
visible: false
}
function copyToClipBoard(text) {
clipboard.text = text
clipboard.selectAll()
clipboard.copy()
clipboard.select(0, 0)
}
}

View file

@ -0,0 +1,30 @@
pragma Singleton
import QtQuick
QtObject {
property QtObject color: QtObject {
readonly property color transparent: 'transparent'
readonly property color gray1: '#F2F2F7'
readonly property color gray2: '#E5E5EA'
readonly property color gray3: '#D1D1D6'
readonly property color gray4: '#C7C7CC'
readonly property color gray5: '#AEAEB2'
readonly property color gray6: '#8E8E93'
readonly property color gray7: '#7C7C83'
readonly property color gray8: '#707075'
readonly property color gray9: '#57575B'
readonly property color accent1: '#007AFF'
readonly property color accent2: '#0B6EDA'
readonly property color accent3: '#1256A1'
readonly property color error: '#FF3B30'
readonly property color warning: '#FF9500'
readonly property color success: '#34C759'
readonly property color black: '#000000'
readonly property color white: '#FFFFFF'
readonly property color transparentBlack: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
readonly property string font: "Vela Sans GX"
}

View file

@ -0,0 +1,4 @@
module Config
singleton DeviceInfo 1.0 DeviceInfo.qml
singleton Style 1.0 Style.qml

View file

@ -0,0 +1,70 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Shapes
import Config 1.0
Popup {
id: root
anchors.centerIn: parent
modal: true
closePolicy: Popup.NoAutoClose
visible: false
Overlay.modal: Rectangle {
color: Style.color.transparentBlack
}
background: Rectangle {
color: Style.color.transparent
}
BusyIndicator {
id: busyIndicator
visible: true
running: true
contentItem: Item {
implicitWidth: 46
implicitHeight: 46
transformOrigin: Item.Center
Shape {
id: shape
width: parent.implicitWidth
height: parent.implicitHeight
anchors.bottom: parent.bottom
anchors.right: parent.right
layer.enabled: true
layer.samples: 4
ShapePath {
fillColor: Style.color.transparent
strokeColor: Style.color.gray3
strokeWidth: 3
capStyle: ShapePath.RoundCap
PathAngleArc {
centerX: shape.width / 2
centerY: shape.height / 2
radiusX: 18
radiusY: 18
startAngle: 225
sweepAngle: -90
}
}
RotationAnimator {
target: shape
running: busyIndicator.visible && busyIndicator.running
from: 0
to: 360
loops: Animation.Infinite
duration: 1250
}
}
}
}
}

View file

@ -0,0 +1,154 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Config 1.0
import "TextTypes"
Button {
id: root
property string defaultBackgroundColor: Style.color.white
property string defaultBorderColor: Style.color.gray3
property string defaultTextColor: Style.color.accent1
property string defaultImageColor: Style.color.accent1
property string hoveredBackgroundColor: Style.color.gray1
property string hoveredBorderColor: Style.color.gray3
property string hoveredTextColor: Style.color.accent2
property string hoveredImageColor: Style.color.accent2
property string pressedBackgroundColor: Style.color.gray2
property string pressedBorderColor: Style.color.gray3
property string pressedTextColor: Style.color.accent3
property string pressedImageColor: Style.color.accent3
property string disabledBackgroundColor: Style.color.white
property string disabledBorderColor: Style.color.gray3
property string disabledTextColor: Style.color.gray8
property string disabledImageColor: Style.color.gray8
property int defaultBorderWidth: 0
property int disabledBorderWidth: 0
property int hoveredBorderWidth: 0
property string imageSource: ""
readonly property bool isImageOnly: root.text !== ""
background: Rectangle {
id: background
anchors.fill: parent
radius: 6
color: root.enabled ? root.defaultBackgroundColor : root.disabledBackgroundColor
border.color: root.enabled ? root.defaultBorderColor : root.disabledBorderColor
border.width: root.enabled ? root.defaultBorderWidth : root.disabledBorderWidth
}
MouseArea {
id: mouseArea
anchors.fill: background
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
enabled: root.enabled
onEntered: {
background.color = root.hoveredBackgroundColor
background.border.color = root.hoveredBorderColor
background.border.width = root.hoveredBorderWidth
image.imageColor = root.hoveredImageColor
buttonText.color = root.hoveredTextColor
}
onExited: {
background.color = root.defaultBackgroundColor
background.border.color = root.defaultBorderColor
background.border.width = root.defaultBorderWidth
image.imageColor = root.defaultImageColor
buttonText.color = root.defaultTextColor
}
onPressedChanged: {
if (pressed) {
background.color = root.pressedBackgroundColor
background.border.color = root.pressedBorderColor
image.imageColor = root.pressedImageColor
buttonText.color = root.pressedTextColor
} else if (entered) {
background.color = root.hoveredBackgroundColor
background.border.color = root.hoveredBorderColor
image.imageColor = root.hoveredImageColor
buttonText.color = root.hoveredTextColor
} else {
background.color = root.defaultBackgroundColor
background.border.color = root.defaultBorderColor
image.imageColor = root.defaultImageColor
buttonText.color = root.defaultTextColor
}
}
onClicked: {
root.clicked()
}
}
contentItem: Item {
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.fill: parent
MediumTextType {
id: buttonText
Layout.fillWidth: true
Layout.topMargin: 12
Layout.bottomMargin: 12
Layout.leftMargin: 12
Layout.rightMargin: 12
visible: root.isImageOnly
color: root.defaultTextColor
text: root.text
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
}
Image {
id: image
property color imageColor: root.enabled ? root.defaultImageColor : root.disabledImageColor
Layout.preferredHeight: 22
Layout.preferredWidth: 22
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 12
Layout.bottomMargin: 12
Layout.leftMargin: 12
Layout.rightMargin: 12
source: root.imageSource
visible: root.imageSource === "" ? false : true
layer {
enabled: true
effect: ColorOverlay {
color: image.imageColor
}
}
}
}
}
}

View file

@ -0,0 +1,99 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Config 1.0
import "TextTypes"
Button {
id: root
property string defaultBackgroundColor: "#FFFFFF"
property string defaultBorderColor: "#D1D1D6"
property string defaultTextColor: "#000000"
property string defaultImageColor: "#000000"
property string hoveredBackgroundColor: "#FFFFFF"
property string hoveredBorderColor: "#D1D1D6"
property string hoveredTextColor: "#D1D1D6"
property string hoveredImageColor: "#D1D1D6"
property string pressedBackgroundColor: "#FFFFFF"
property string pressedBorderColor: "#D1D1D6"
property string pressedTextColor: "#D1D1D6"
property string pressedImageColor: "#D1D1D6"
property string disabledBackgroundColor: "#FFFFFF"
property string disabledBorderColor: "#D1D1D6"
property string disabledTextColor: "#D1D1D6"
property string disabledImageColor: "#D1D1D6"
property string imageSource: "qrc:/images/controls/chevron-down.svg"
hoverEnabled: true
background: Rectangle {
id: focusBorder
color: root.defaultBackgroundColor
border.color: root.defaultBorderColor
border.width: 1
anchors.fill: parent
radius: 6
}
MouseArea {
anchors.fill: focusBorder
enabled: false
cursorShape: Qt.PointingHandCursor
}
contentItem: Item {
anchors.fill: focusBorder
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.fill: parent
anchors.leftMargin: 16
anchors.rightMargin: 16
MediumTextType {
id: buttonText
Layout.fillWidth: true
Layout.topMargin: 12
Layout.bottomMargin: 12
color: root.defaultTextColor
text: root.text
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
}
Image {
Layout.preferredHeight: 22
Layout.preferredWidth: 22
source: root.imageSource
visible: root.imageSource === "" ? false : true
layer {
enabled: true
effect: ColorOverlay {
color: root.defaultImageColor
}
}
}
}
}
}

View file

@ -0,0 +1,56 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Config 1.0
import "TextTypes"
TextField {
id: root
property string defaultBackgroundColor: Style.color.white
property string defaultBorderColor: Style.color.gray3
property string defaultTextColor: Style.color.gray6
property string hoveredBackgroundColor: Style.color.white
property string hoveredBorderColor: Style.color.gray6
property string hoveredTextColor: Style.color.black
property string disabledBackgroundColor: Style.color.gray2
property string disabledBorderColor: Style.color.gray3
property string disabledTextColor: Style.color.gray9
color: root.enabled ? root.defaultTextColor : (root.hovered || root.pressed) ? root.hoveredTextColor : root.disabledTextColor
background: Rectangle {
anchors.fill: parent
color: root.enabled ? root.defaultBackgroundColor : (root.hovered || root.pressed) ? root.hoveredBackgroundColor : root.disabledBackgroundColor
border.color: root.enabled ? root.defaultBorderColor : (root.hovered || root.pressed) ? root.hoveredBorderColor : root.disabledBorderColor
border.width: 1
radius: 6
}
topPadding: 12
bottomPadding: 12
leftPadding: 16
rightPadding: 16
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
selectionColor: Style.color.accent1
selectedTextColor: Style.color.white
font.pixelSize: 17
font.weight: 400
font.family: Style.font
wrapMode: TextEdit.Wrap
verticalAlignment: Text.AlignTop
}

View file

@ -0,0 +1,96 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Config 1.0
import "TextTypes"
import "../Components"
Popup {
id: root
property string text
property bool closeButtonVisible: true
leftMargin: 25
rightMargin: 25
bottomMargin: 70
width: parent.width - leftMargin - rightMargin
anchors.centerIn: parent
modal: root.closeButtonVisible
closePolicy: Popup.CloseOnEscape
Overlay.modal: Rectangle {
visible: root.closeButtonVisible
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
background: Rectangle {
anchors.fill: parent
color: Style.color.white
radius: 8
layer.enabled: true
layer.effect: DropShadow {
color: Style.color.gray3
horizontalOffset: 0
verticalOffset: 1
radius: 10
samples: 25
}
}
contentItem: Item {
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
anchors.fill: parent
RowLayout {
id: content
anchors.fill: parent
anchors.leftMargin: 16
anchors.rightMargin: 16
XSmallTextType {
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
text: root.text
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
Item {
id: focusItem
KeyNavigation.tab: closeButton
}
WhiteButtonNoBorder {
id: closeButton
visible: closeButtonVisible
imageSource: "qrc:/images/controls/x-circle.svg"
onClicked: function() {
root.close()
}
}
}
}
}

View file

@ -0,0 +1,15 @@
import QtQuick
import Config 1.0
Text {
lineHeight: 34
lineHeightMode: Text.FixedHeight
color: Style.color.black
font.pixelSize: 28
font.weight: 700
font.family: Style.font
wrapMode: Text.WordWrap
}

View file

@ -0,0 +1,15 @@
import QtQuick
import Config 1.0
Text {
lineHeight: 24
lineHeightMode: Text.FixedHeight
color: Style.color.black
font.pixelSize: 20
font.weight: 700
font.family: Style.font
wrapMode: Text.WordWrap
}

View file

@ -0,0 +1,15 @@
import QtQuick
import Config 1.0
Text {
lineHeight: 22
lineHeightMode: Text.FixedHeight
color: Style.color.black
font.pixelSize: 17
font.weight: 400
font.family: Style.font
wrapMode: Text.WordWrap
}

View file

@ -0,0 +1,15 @@
import QtQuick
import Config 1.0
Text {
lineHeight: 18
lineHeightMode: Text.FixedHeight
color: Style.color.black
font.pixelSize: 13
font.weight: 400
font.family: Style.font
wrapMode: Text.WordWrap
}

View file

@ -0,0 +1,122 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Config 1.0
import "../Components"
import "../Controls"
import "../Controls/TextTypes"
Page {
id: root
ColumnLayout {
anchors.fill: parent
anchors.topMargin: 8
anchors.bottomMargin: 36
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
Text {
lineHeight: 68
lineHeightMode: Text.FixedHeight
color: Style.color.gray2
font.pixelSize: 56
font.weight: 700
font.family: Style.font
horizontalAlignment: Qt.AlignLeft
text: ConnectionController.isConnected ? qsTr("Online") : qsTr("Offline")
}
Item {
Layout.fillHeight: true
}
XSmallTextType {
text: qsTr("Connection to")
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
}
RowLayout {
DropDownType {
Layout.fillWidth: true
text: ServersModel.defaultServerName
onClicked: function() {
PageController.goToPage(PageEnum.PageSettingsServersList)
}
}
WhiteButtonWithBorder {
imageSource: "qrc:/images/controls/plus.svg"
onClicked: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
}
}
}
Button {
id: connectButton
Layout.fillWidth: true
implicitHeight: 358
Layout.topMargin: 16
background: Rectangle {
anchors.fill: parent
radius: 16
color: {
if (ConnectionController.isConnectionInProgress) {
return Style.color.accent3
} else if (ConnectionController.isConnected) {
return Style.color.accent1
} else {
return Style.color.black
}
}
ColumnLayout {
anchors.centerIn: parent
Image {
Layout.alignment: Qt.AlignCenter
source: "qrc:/images/controls/connect-button.svg"
}
Header3TextType {
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 24
text: ConnectionController.connectionStateText
color: Style.color.white
}
Item {
Layout.fillWidth: true
}
}
}
onClicked: function() {
ServersModel.setProcessedServerIndex(ServersModel.defaultIndex)
ConnectionController.connectButtonClicked()
}
}
}
}

View file

@ -0,0 +1,103 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Config 1.0
import "../Components"
import "../Controls"
import "../Controls/TextTypes"
Page {
id: root
Connections {
target: InstallController
function onRemoveProcessedServerFinished(finishedMessage) {
if (!ServersModel.getServersCount()) {
PageController.goToStartPage()
} else {
PageController.closePage()
}
PageController.showNotificationMessage(finishedMessage)
}
}
ColumnLayout {
anchors.fill: parent
spacing: 0
RowLayout {
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.topMargin: 8
WhiteButtonNoBorder {
id: backButton
imageSource: "qrc:/images/controls/arrow-left.svg"
onClicked: PageController.closePage()
}
Item {
Layout.fillWidth: true
}
}
Header1TextType {
id: header
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
Layout.fillWidth: true
text: qsTr("Server settings")
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
}
XSmallTextType {
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 8
Layout.fillWidth: true
text: qsTr("Name")
}
InputType {
id: textKey
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.fillWidth: true
}
WhiteButtonWithBorder {
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 24
Layout.fillWidth: true
text: qsTr("Remove server")
onClicked: function() {
PageController.showBusyIndicator(true)
InstallController.removeProcessedServer()
PageController.showBusyIndicator(false)
}
}
Item {
Layout.fillHeight: true
}
}
}

View file

@ -0,0 +1,165 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Config 1.0
import "../Components"
import "../Controls"
import "../Controls/TextTypes"
Page {
id: root
ColumnLayout {
anchors.fill: parent
RowLayout {
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.topMargin: 8
WhiteButtonNoBorder {
id: backButton
imageSource: "qrc:/images/controls/arrow-left.svg"
onClicked: PageController.closePage()
}
Item {
Layout.fillWidth: true
}
WhiteButtonNoBorder {
imageSource: "qrc:/images/controls/plus.svg"
onClicked: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
}
}
}
Header1TextType {
id: header
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.fillWidth: true
text: qsTr("Connect to")
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
}
ButtonGroup {
id: serversRadioButtonGroup
}
ListView {
id: serversListView
Layout.topMargin: 16
Layout.fillHeight: true
Layout.fillWidth: true
model: ServersModel
currentIndex: ServersModel.defaultIndex
ScrollBar.vertical: ScrollBar {}
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversListView.currentIndex = serverIndex
serversListView.positionViewAtIndex(serversListView.currentIndex, ListView.Contain)
}
}
Component.onCompleted: positionViewAtIndex(currentIndex, ListView.Center)
delegate: Item {
id: menuContentDelegate
required property string name
required property int index
implicitWidth: serversListView.width
implicitHeight: serverItem.implicitHeight
RadioButton {
id: serverItem
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
ButtonGroup.group: serversRadioButtonGroup
checked: index === serversListView.currentIndex
indicator: Item { }
contentItem: Item {
id: contentContainer
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: content.implicitHeight
Rectangle {
anchors.fill: parent
radius: 8
color: serverItem.checked ? Style.color.gray1 : Style.color.transparent
}
RowLayout {
id: content
anchors.fill: parent
Header3TextType {
Layout.fillWidth: true
Layout.leftMargin: 8
Layout.topMargin: 19
Layout.bottomMargin: 19
text: name
color: serverItem.hovered ? Style.color.gray9 : Style.color.black
}
ButtonType {
Layout.rightMargin: 8
imageSource: "qrc:/images/controls/edit-3.svg"
hoveredBorderColor: Style.color.gray2
hoveredBorderWidth: 1
onClicked: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
}
}
}
}
onClicked: function() {
ServersModel.defaultIndex = index
}
MouseArea {
anchors.fill: serverItem
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
}
}
}
}

View file

@ -0,0 +1,112 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Config 1.0
import "../Components"
import "../Controls"
import "../Controls/TextTypes"
Page {
id: root
Connections {
target: ImportController
function onImportErrorOccurred(error, goToPageHome) {
PageController.showErrorMessage(error)
}
function onImportFinished() {
if (!ConnectionController.isConnected) {
ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1);
ServersModel.processedIndex = ServersModel.defaultIndex
}
PageController.goToStartPage()
}
}
ColumnLayout {
anchors.fill: parent
spacing: 0
RowLayout {
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.topMargin: 8
WhiteButtonNoBorder {
id: backButton
imageSource: "qrc:/images/controls/arrow-left.svg"
onClicked: PageController.closePage()
}
Item {
Layout.fillWidth: true
}
}
Header1TextType {
id: header
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
Layout.fillWidth: true
text: qsTr("Adding a server to connect to")
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
}
XSmallTextType {
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 8
Layout.fillWidth: true
text: qsTr("Key")
}
InputType {
id: textKey
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.fillWidth: true
Layout.preferredHeight: 308
placeholderText: qsTr("VPN://")
}
BlueButtonNoBorder {
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.fillWidth: true
text: qsTr("Add")
onClicked: function() {
if (ImportController.extractConfigFromData(textKey.text)) {
ImportController.importConfig()
} else {
PageController.showErrorMessage(qsTr("Unsupported config file"))
}
}
}
Item {
Layout.fillHeight: true
}
}
}

View file

@ -0,0 +1,195 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import Config 1.0
import PageEnum 1.0
import "Controls"
import "Pages"
ApplicationWindow {
id: root
objectName: "mainWindow"
visible: true
width: DeviceInfo.screenWidth
height: DeviceInfo.screenHeight
minimumWidth: DeviceInfo.isDesktop() ? 360 : 0
minimumHeight: DeviceInfo.isDesktop() ? 640 : 0
maximumWidth: 600
maximumHeight: 800
color: Style.color.white
onClosing: function() {
console.debug("QML onClosing signal")
PageController.closeWindow()
}
title: "DefaultVPN"
Connections {
target: PageController
function onRaiseMainWindow() {
root.show()
root.raise()
root.requestActivate()
}
function onHideMainWindow() {
root.hide()
}
function onShowErrorMessage(errorMessage) {
popupErrorMessage.text = errorMessage
popupErrorMessage.open()
}
function onShowNotificationMessage(message) {
popupNotificationMessage.text = message
popupNotificationMessage.closeButtonVisible = false
popupNotificationMessage.open()
popupNotificationTimer.start()
}
function onShowBusyIndicator(visible) {
busyIndicator.visible = visible
PageController.disableControls(visible)
}
function onClosePage() {
if (stackview.depth <= 1) {
PageController.hideWindow()
return
}
stackview.pop()
}
function onGoToPage(page, slide) {
var pagePath = PageController.getPagePath(page)
if (slide) {
stackview.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
} else {
stackview.push(pagePath, { "objectName" : pagePath }, StackView.Immediate)
}
}
function onGoToStartPage() {
while (stackview.depth > 1) {
stackview.pop()
}
}
}
Connections {
target: SettingsController
function onChangeSettingsFinished(finishedMessage) {
PageController.showNotificationMessage(finishedMessage)
}
}
StackView {
id: stackview
anchors.fill: parent
Component.onCompleted: {
var pagePath = PageController.getPagePath(PageEnum.PageHome)
ServersModel.processedIndex = ServersModel.defaultIndex
stackview.push(pagePath, { "objectName" : pagePath })
}
}
Item {
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
implicitHeight: popupNotificationMessage.height
PopupType {
id: popupNotificationMessage
}
Timer {
id: popupNotificationTimer
interval: 3000
repeat: false
running: false
onTriggered: {
popupNotificationMessage.close()
}
}
}
Item {
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
implicitHeight: popupErrorMessage.height
PopupType {
id: popupErrorMessage
}
}
// Item {
// anchors.fill: parent
// QuestionDrawer {
// id: questionDrawer
// anchors.fill: parent
// }
// }
Item {
anchors.fill: parent
BusyIndicatorType {
id: busyIndicator
anchors.centerIn: parent
z: 1
}
}
// function showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) {
// questionDrawer.headerText = headerText
// questionDrawer.descriptionText = descriptionText
// questionDrawer.yesButtonText = yesButtonText
// questionDrawer.noButtonText = noButtonText
// questionDrawer.yesButtonFunction = function() {
// questionDrawer.close()
// if (yesButtonFunction && typeof yesButtonFunction === "function") {
// yesButtonFunction()
// }
// }
// questionDrawer.noButtonFunction = function() {
// questionDrawer.close()
// if (noButtonFunction && typeof noButtonFunction === "function") {
// noButtonFunction()
// }
// }
// questionDrawer.open()
// }
FileDialog {
id: mainFileDialog
property bool isSaveMode: false
objectName: "mainFileDialog"
fileMode: isSaveMode ? FileDialog.SaveFile : FileDialog.OpenFile
onAccepted: SystemController.fileDialogClosed(true)
onRejected: SystemController.fileDialogClosed(false)
}
}