added PageSetupWizardViewConfig

- added a popup with a question when deleting containers/servers
- added import from code and import error handling
This commit is contained in:
vladimir.kuznetsov 2023-06-05 15:49:10 +08:00
parent de0cd976de
commit 420c33d3ba
37 changed files with 701 additions and 312 deletions

View file

@ -68,7 +68,10 @@ enum ErrorCode
OpenSslFailed,
OpenVpnExecutableCrashed,
ShadowSocksExecutableCrashed,
CloakExecutableCrashed
CloakExecutableCrashed,
// import and install errors
ImportInvalidConfigError
};
} // namespace amnezia

View file

@ -57,6 +57,8 @@ QString errorString(ErrorCode code){
case (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter");
case (AddressPoolError): return QObject::tr("VPN pool error: no available addresses");
case (ImportInvalidConfigError): return QObject::tr("The config does not contain any containers and credentiaks for connecting to the server");
case(InternalError):
default:
return QObject::tr("Internal error");

View file

@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V7.5L14.5 2Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 2V8H20" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 17C13.1046 17 14 16.1046 14 15C14 13.8954 13.1046 13 12 13C10.8954 13 10 13.8954 10 15C10 16.1046 10.8954 17 12 17Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 12V13" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 17V18" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.6 13.5L13.73 14" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.27 16L9.40002 16.5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.6 16.5L13.73 16" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.27 14L9.40002 13.5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -249,5 +249,10 @@
<file>images/controls/server.svg</file>
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
<file>ui/qml/Pages2/PageSettingsServerServices.qml</file>
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
<file>images/controls/file-cog-2.svg</file>
<file>ui/qml/Components/QuestionDrawer.qml</file>
<file>ui/qml/Pages2/PageDeinstalling.qml</file>
<file>ui/qml/Controls2/BackButtonType.qml</file>
</qresource>
</RCC>

View file

@ -9,21 +9,7 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
}
bool ConnectionController::onConnectionButtonClicked()
{
if (!isConnected()) {
openVpnConnection();
} else {
closeVpnConnection();
}
}
bool ConnectionController::isConnected()
{
return m_isConnected;
}
bool ConnectionController::openVpnConnection()
void ConnectionController::openConnection()
{
int serverIndex = m_serversModel->getDefaultServerIndex();
QModelIndex serverModelIndex = m_serversModel->index(serverIndex);
@ -35,16 +21,6 @@ bool ConnectionController::openVpnConnection()
const QJsonObject &containerConfig = qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex,
ContainersModel::Roles::ConfigRole));
//todo error handling
qApp->processEvents();
emit connectToVpn(serverIndex, credentials, container, containerConfig);
m_isConnected = true;
// int serverIndex = m_settings->defaultServerIndex();
// ServerCredentials credentials = m_settings->serverCredentials(serverIndex);
// DockerContainer container = m_settings->defaultContainer(serverIndex);
// if (m_settings->containers(serverIndex).isEmpty()) {
// set_labelErrorText(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
// set_pushButtonConnectChecked(false);
@ -57,20 +33,23 @@ bool ConnectionController::openVpnConnection()
// return;
// }
// const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container);
// set_labelErrorText("");
// set_pushButtonConnectChecked(true);
// set_pushButtonConnectEnabled(false);
// qApp->processEvents();
// emit connectToVpn(serverIndex, credentials, container, containerConfig);
//todo error handling
qApp->processEvents();
emit connectToVpn(serverIndex, credentials, container, containerConfig);
}
bool ConnectionController::closeVpnConnection()
void ConnectionController::closeConnection()
{
emit disconnectFromVpn();
m_isConnected = false;
}
bool ConnectionController::isConnected()
{
return m_isConnected;
}
void ConnectionController::setIsConnected(bool isConnected)
{
m_isConnected = isConnected;
emit isConnectedChanged();
}

View file

@ -10,24 +10,26 @@ class ConnectionController : public QObject
Q_OBJECT
public:
Q_PROPERTY(bool isConnected READ isConnected WRITE setIsConnected NOTIFY isConnectedChanged)
explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
QObject *parent = nullptr);
public slots:
bool onConnectionButtonClicked();
bool isConnected();
void setIsConnected(bool isConnected);
public slots:
void openConnection();
void closeConnection();
signals:
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void disconnectFromVpn();
void connectionStateChanged(Vpn::ConnectionState state);
void isConnectedChanged();
private:
bool openVpnConnection();
bool closeVpnConnection();
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;

View file

@ -1,6 +1,9 @@
#include "importController.h"
#include <QFile>
#include <QFileInfo>
#include "core/errorstrings.h"
namespace {
enum class ConfigTypes {
@ -39,50 +42,68 @@ ImportController::ImportController(const QSharedPointer<ServersModel> &serversMo
}
bool ImportController::importFromFile(const QUrl &fileUrl)
void ImportController::extractConfigFromFile(const QUrl &fileUrl)
{
QFile file(fileUrl.toLocalFile());
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readAll();
QString data = file.readAll();
auto configFormat = checkConfigFormat(data);
if (configFormat == ConfigTypes::OpenVpn) {
return importOpenVpnConfig(data);
m_config = extractOpenVpnConfig(data);
} else if (configFormat == ConfigTypes::WireGuard) {
return importWireGuardConfig(data);
m_config = extractWireGuardConfig(data);
} else {
return importAmneziaConfig(data);
m_config = extractAmneziaConfig(data);
}
m_configFileName = QFileInfo(file.fileName()).fileName();
}
return false;
}
bool ImportController::import(const QJsonObject &config)
void ImportController::extractConfigFromCode(QString code)
{
m_config = extractAmneziaConfig(code);
}
QString ImportController::getConfig()
{
return QJsonDocument(m_config).toJson(QJsonDocument::Indented);
}
QString ImportController::getConfigFileName()
{
return m_configFileName;
}
void ImportController::importConfig()
{
ServerCredentials credentials;
credentials.hostName = config.value(config_key::hostName).toString();
credentials.port = config.value(config_key::port).toInt();
credentials.userName = config.value(config_key::userName).toString();
credentials.secretData = config.value(config_key::password).toString();
credentials.hostName = m_config.value(config_key::hostName).toString();
credentials.port = m_config.value(config_key::port).toInt();
credentials.userName = m_config.value(config_key::userName).toString();
credentials.secretData = m_config.value(config_key::password).toString();
if (credentials.isValid() || config.contains(config_key::containers)) {
m_settings->addServer(config);
if (credentials.isValid() || m_config.contains(config_key::containers)) {
m_serversModel->addServer(m_config);
if (config.value(config_key::containers).toArray().isEmpty()) {
m_settings->setDefaultServer(m_settings->serversCount() - 1);
if (!m_config.value(config_key::containers).toArray().isEmpty()) {
auto newServerIndex = m_serversModel->index(m_serversModel->getServersCount() - 1);
m_serversModel->setData(newServerIndex, true, ServersModel::ServersModelRoles::IsDefaultRole);
}
emit importFinished();
} else {
qDebug() << "Failed to import profile";
qDebug().noquote() << QJsonDocument(config).toJson();
return false;
qDebug().noquote() << QJsonDocument(m_config).toJson();
emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError));
}
return true;
m_config = {};
m_configFileName.clear();
}
bool ImportController::importAmneziaConfig(QString data)
QJsonObject ImportController::extractAmneziaConfig(QString &data)
{
data.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
@ -92,13 +113,7 @@ bool ImportController::importAmneziaConfig(QString data)
ba = ba_uncompressed;
}
QJsonObject config;
config = QJsonDocument::fromJson(ba).object();
if (!config.isEmpty()) {
return import(config);
}
return false;
return QJsonDocument::fromJson(ba).object();
}
//bool ImportController::importConnectionFromQr(const QByteArray &data)
@ -116,7 +131,7 @@ bool ImportController::importAmneziaConfig(QString data)
// return false;
//}
bool ImportController::importOpenVpnConfig(const QString &data)
QJsonObject ImportController::extractOpenVpnConfig(const QString &data)
{
QJsonObject openVpnConfig;
openVpnConfig[config_key::config] = data;
@ -156,10 +171,10 @@ bool ImportController::importOpenVpnConfig(const QString &data)
config[config_key::hostName] = hostName;
return import(config);
return config;
}
bool ImportController::importWireGuardConfig(const QString &data)
QJsonObject ImportController::extractWireGuardConfig(const QString &data)
{
QJsonObject lastConfig;
lastConfig[config_key::config] = data;
@ -200,5 +215,5 @@ bool ImportController::importWireGuardConfig(const QString &data)
config[config_key::hostName] = hostName;
return import(config);
return config;
}

View file

@ -18,20 +18,27 @@ public:
QObject *parent = nullptr);
public slots:
bool importFromFile(const QUrl &fileUrl);
void importConfig();
void extractConfigFromFile(const QUrl &fileUrl);
void extractConfigFromCode(QString code);
QString getConfig();
QString getConfigFileName();
signals:
void importFinished();
void importErrorOccurred(QString errorMessage);
private:
bool import(const QJsonObject &config);
bool importAmneziaConfig(QString data);
bool importOpenVpnConfig(const QString &data);
bool importWireGuardConfig(const QString &data);
QJsonObject extractAmneziaConfig(QString &data);
QJsonObject extractOpenVpnConfig(const QString &data);
QJsonObject extractWireGuardConfig(const QString &data);
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
std::shared_ptr<Settings> m_settings;
QJsonObject m_config;
QString m_configFileName;
};
#endif // IMPORTCONTROLLER_H

View file

@ -9,14 +9,14 @@
namespace PageLoader
{
Q_NAMESPACE
enum class PageEnum { PageStart = 0, PageHome, PageShare,
enum class PageEnum { PageStart = 0, PageHome, PageShare, PageDeinstalling,
PageSettingsServersList, PageSettings, PageSettingsServerData, PageSettingsServerInfo,
PageSettingsServerProtocols, PageSettingsServerServices,
PageSetupWizardStart, PageTest, PageSetupWizardCredentials, PageSetupWizardProtocols, PageSetupWizardEasy,
PageSetupWizardProtocolSettings, PageSetupWizardInstalling, PageSetupWizardConfigSource,
PageSetupWizardTextKey
PageSetupWizardTextKey, PageSetupWizardViewConfig
};
Q_ENUM_NS(PageEnum)

View file

@ -13,7 +13,7 @@ Button {
id: border
source: connectionProccess.running ? "/images/connectionProgress.svg" :
ConnectionController.isConnected() ? "/images/connectionOff.svg" : "/images/connectionOn.svg"
ConnectionController.isConnected ? "/images/connectionOff.svg" : "/images/connectionOn.svg"
RotationAnimator {
id: connectionProccess
@ -46,7 +46,7 @@ Button {
}
onClicked: {
ConnectionController.onConnectionButtonClicked()
ConnectionController.isConnected ? ConnectionController.closeConnection() : ConnectionController.openConnection()
}
Connections {
@ -61,6 +61,7 @@ Button {
console.log("Disconnected")
connectionProccess.running = false
root.text = qsTr("Connect")
ConnectionController.isConnected = false
break
}
case ConnectionState.Preparing: {
@ -78,7 +79,8 @@ Button {
case ConnectionState.Connected: {
console.log("Connected")
connectionProccess.running = false
root.text = qsTr("Connected")
root.text = qsTr("Disconnect")
ConnectionController.isConnected = true
break
}
case ConnectionState.Disconnecting: {

View file

@ -14,20 +14,6 @@ DrawerType {
width: parent.width
height: parent.height * 0.4375
background: Rectangle {
anchors.fill: parent
anchors.bottomMargin: -radius
radius: 16
color: "#1C1D21"
border.color: "#2C2D30"
border.width: 1
}
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left

View file

@ -27,15 +27,20 @@ ListView {
delegate: Item {
implicitWidth: rootWidth
implicitHeight: containerRadioButton.implicitHeight
implicitHeight: content.implicitHeight
VerticalRadioButton {
id: containerRadioButton
ColumnLayout {
id: content
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
VerticalRadioButton {
id: containerRadioButton
Layout.fillWidth: true
text: name
descriptionText: description
@ -68,6 +73,11 @@ ListView {
}
}
DividerType {
Layout.fillWidth: true
}
}
Component.onCompleted: {
if (isDefault) {
root.currentContainerName = name

View file

@ -0,0 +1,77 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType {
id: root
property string headerText
property string descriptionText
property string yesButtonText
property string noButtonText
property var yesButtonFunction
property var noButtonFunction
width: parent.width
height: parent.height * 0.5
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 8
Header2TextType {
Layout.fillWidth: true
text: headerText
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
text: descriptionText
}
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
text: yesButtonText
onClicked: {
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
}
}
BasicButtonType {
Layout.fillWidth: true
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
disabledColor: "#878B91"
textColor: "#D7D8DB"
borderWidth: 1
text: noButtonText
onClicked: {
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
}
}
}
}

View file

@ -0,0 +1,55 @@
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
Item {
id: root
property string backButtonImage: "qrc:/images/controls/arrow-left.svg"
property var backButtonFunction
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.fill: parent
ImageButtonType {
image: backButtonImage
imageColor: "#D7D8DB"
onClicked: {
if (backButtonFunction && typeof backButtonFunction === "function") {
backButtonFunction()
} else {
closePage()
}
}
}
Rectangle {
id: background
Layout.fillWidth: true
color: "transparent"
ShaderEffectSource {
id: effectSource
sourceItem: background
anchors.fill: background
sourceRect: Qt.rect(x,y, width, height)
}
FastBlur {
id: blur
anchors.fill: effectSource
source: effectSource
radius: 100
}
}
}
}

View file

@ -17,4 +17,18 @@ Drawer {
velocity: 4
}
}
background: Rectangle {
anchors.fill: parent
anchors.bottomMargin: -radius
radius: 16
color: "#1C1D21"
border.color: "#2C2D30"
border.width: 1
}
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
}

View file

@ -117,28 +117,9 @@ Item {
width: parent.width
height: parent.height * 0.9
background: Rectangle {
anchors.fill: parent
anchors.bottomMargin: -radius
radius: 16
color: "#1C1D21"
border.color: "#494B50"
border.width: 1
}
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
Header2Type {
ColumnLayout {
id: header
headerText: root.headerText
backButtonImage: root.headerBackButtonImage
width: parent.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@ -146,10 +127,13 @@ Item {
anchors.leftMargin: 16
anchors.rightMargin: 16
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
root.menuVisible = false
}
}
}
FlickableType {
anchors.top: header.bottom
@ -164,6 +148,17 @@ Item {
spacing: 16
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: root.headerText
width: parent.width
}
Loader {
id: listViewLoader
sourceComponent: root.listView

View file

@ -6,10 +6,7 @@ import "TextTypes"
Item {
id: root
property string backButtonImage
property string actionButtonImage
property var backButtonFunction
property var actionButtonFunction
property string headerText
@ -22,25 +19,6 @@ Item {
id: content
anchors.fill: parent
ImageButtonType {
id: backButton
Layout.leftMargin: -6
image: root.backButtonImage
imageColor: "#D7D8DB"
visible: image ? true : false
onClicked: {
if (backButtonFunction && typeof backButtonFunction === "function") {
backButtonFunction()
} else {
closePage()
}
}
}
RowLayout {
Header2TextType {
id: header

View file

@ -6,10 +6,7 @@ import "TextTypes"
Item {
id: root
property string backButtonImage
property string actionButtonImage
property var backButtonFunction
property var actionButtonFunction
property string headerText
@ -22,25 +19,6 @@ Item {
id: content
anchors.fill: parent
ImageButtonType {
id: backButton
Layout.leftMargin: -6
image: root.backButtonImage
imageColor: "#D7D8DB"
visible: image ? true : false
onClicked: {
if (backButtonFunction && typeof backButtonFunction === "function") {
backButtonFunction()
} else {
closePage()
}
}
}
RowLayout {
Header1TextType {
id: header

View file

@ -11,9 +11,11 @@ ProgressBar {
color: "#412102"
}
contentItem: Rectangle {
width: root.visualPosition * root.width
height: root.height
contentItem: Item {
Rectangle {
width: root.visualPosition * parent.width
height: parent.height
color: "#FBB26A"
}
}
}

View file

@ -59,7 +59,6 @@ Switch {
}
}
contentItem: ColumnLayout {
contentItem: ColumnLayout {
id: content

View file

@ -6,7 +6,6 @@ Item {
id: root
property string headerText
property string textFieldText
property string textFieldPlaceholderText
property bool textFieldEditable: true
@ -14,6 +13,7 @@ Item {
property var clickedFunc
property alias textField: textField
property alias textFieldText: textField.text
implicitHeight: 74
@ -53,7 +53,6 @@ Item {
id: textField
enabled: root.textFieldEditable
text: root.textFieldText
color: "#d7d8db"
placeholderText: textFieldPlaceholderText

View file

@ -0,0 +1,91 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
PageType {
id: root
SortFilterProxyModel {
id: proxyServersModel
sourceModel: ServersModel
filters: [
ValueFilter {
roleName: "isCurrentlyProcessed"
value: true
}
]
}
FlickableType {
id: fl
anchors.fill: parent
contentHeight: content.height
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 16
Repeater {
model: proxyServersModel
delegate: Item {
implicitWidth: parent.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 20
headerText: qsTr("Removing services from ") + name
}
ProgressBarType {
id: progressBar
Layout.fillWidth: true
Layout.topMargin: 32
Timer {
id: timer
interval: 300
repeat: true
running: true
onTriggered: {
progressBar.value += 0.001
}
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
text: "Обычно это занимает не больше 5 минут"
}
}
}
}
}
}
}

View file

@ -113,20 +113,6 @@ PageType {
width: parent.width
height: parent.height * 0.90
background: Rectangle {
anchors.fill: parent
anchors.bottomMargin: -radius
radius: 16
color: "#1C1D21"
border.color: root.borderColor
border.width: 1
}
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
ColumnLayout {
id: serversMenuHeader
anchors.top: parent.top

View file

@ -71,7 +71,6 @@ PageType {
iconImage: "qrc:/images/controls/app.svg"
clickedFunction: function() {
goToPage(PageEnum.PageSetupWizardTextKey)
}
}
@ -85,7 +84,6 @@ PageType {
iconImage: "qrc:/images/controls/save.svg"
clickedFunction: function() {
goToPage(PageEnum.PageSetupWizardTextKey)
}
}
@ -99,7 +97,6 @@ PageType {
iconImage: "qrc:/images/controls/amnezia.svg"
clickedFunction: function() {
goToPage(PageEnum.PageSetupWizardTextKey)
}
}

View file

@ -9,6 +9,7 @@ import ProtocolEnum 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Components"
PageType {
id: root
@ -33,8 +34,20 @@ PageType {
descriptionText: "May be needed when changing other settings"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Clear cached profiles?")
questionDrawer.descriptionText = qsTr("some description")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
ContainersModel.clearCachedProfiles()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
DividerType {}
@ -46,8 +59,15 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
if (ServersModel.isDefaultServerCurrentlyProcessed && ConnectionController.isConnected()) {
ConnectionController.closeVpnConnection()
questionDrawer.headerText = qsTr("Remove server?")
questionDrawer.descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
if (ServersModel.isDefaultServerCurrentlyProcessed && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
ServersModel.removeServer()
if (!ServersModel.getServersCount()) {
@ -56,6 +76,11 @@ PageType {
goToStartPage()
}
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
DividerType {}
@ -67,14 +92,32 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
if (ServersModel.isDefaultServerCurrentlyProcessed && ConnectionController.isConnected()) {
questionDrawer.headerText = qsTr("Clear server from Amnezia software?")
questionDrawer.descriptionText = qsTr(" All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed && ConnectionController.isConnected) {
ConnectionController.closeVpnConnection()
}
ContainersModel.removeAllContainers()
closePage()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
}

View file

@ -30,8 +30,6 @@ PageType {
}
ColumnLayout {
id: content
anchors.fill: parent
spacing: 16
@ -40,14 +38,20 @@ PageType {
id: header
model: proxyServersModel
delegate: HeaderType {
Layout.fillWidth: true
delegate: ColumnLayout {
id: content
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
BackButtonType {
}
HeaderType {
Layout.fillWidth: true
actionButtonImage: "qrc:/images/controls/edit-3.svg"
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: name
descriptionText: hostName
@ -55,9 +59,6 @@ PageType {
actionButtonFunction: function() {
connectionTypeSelection.visible = true
}
backButtonFunction: function() {
closePage()
}
}
}
@ -74,23 +75,14 @@ PageType {
TabButtonType {
isSelected: tabBar.currentIndex === 0
text: qsTr("Protocols")
// onClicked: {
// tabBarStackView.goToTabBarPage(PageEnum.PageSettingsServerProtocols)
// }
}
TabButtonType {
isSelected: tabBar.currentIndex === 1
text: qsTr("Services")
// onClicked: {
// tabBarStackView.goToTabBarPage(PageEnum.PageSettingsServerServices)
// }
}
TabButtonType {
isSelected: tabBar.currentIndex === 2
text: qsTr("Data")
// onClicked: {
// tabBarStackView.goToTabBarPage(PageEnum.PageSettingsServerData)
// }
}
}
@ -110,25 +102,5 @@ PageType {
stackView: root.stackView
}
}
// StackViewType {
// id: tabBarStackView
// Layout.preferredWidth: root.width
// Layout.preferredHeight: root.height - tabBar.implicitHeight - header.implicitHeight
// function goToTabBarPage(page) {
// var pagePath = PageController.getPagePath(page)
// while (tabBarStackView.depth > 1) {
// tabBarStackView.pop()
// }
// tabBarStackView.replace(pagePath, { "objectName" : pagePath })
// }
// Component.onCompleted: {
// var pagePath = PageController.getPagePath(PageEnum.PageSettingsServerProtocols)
// tabBarStackView.push(pagePath, { "objectName" : pagePath })
// }
// }
}
}

View file

@ -17,7 +17,7 @@ import "../Components"
PageType {
id: root
HeaderType {
ColumnLayout {
id: header
anchors.top: parent.top
@ -28,8 +28,13 @@ PageType {
anchors.leftMargin: 16
anchors.rightMargin: 16
BackButtonType {
}
HeaderType {
Layout.fillWidth: true
actionButtonImage: "qrc:/images/controls/plus.svg"
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Серверы"
@ -37,6 +42,7 @@ PageType {
connectionTypeSelection.visible = true
}
}
}
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection

View file

@ -13,14 +13,6 @@ import "../Config"
PageType {
id: root
Connections {
target: ImportController
function onImportFinished() {
}
}
FlickableType {
id: fl
anchors.top: root.top
@ -34,13 +26,18 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
BackButtonType {
Layout.topMargin: 20
Layout.rightMargin: 16
Layout.leftMargin: 16
}
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.rightMargin: 16
Layout.leftMargin: 16
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Подключение к серверу"
descriptionText: "Не используйте код подключения из публичных источников. Его могли создать, чтобы перехватывать ваши данные.\n
@ -71,7 +68,8 @@ PageType {
FileDialog {
id: fileDialog
onAccepted: {
ImportController.importFromFile(selectedFile)
ImportController.extractConfigFromFile(selectedFile)
goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
}

View file

@ -11,9 +11,20 @@ import "../Config"
PageType {
id: root
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20
}
FlickableType {
id: fl
anchors.top: root.top
anchors.top: backButton.bottom
anchors.bottom: root.bottom
contentHeight: content.height
@ -30,9 +41,6 @@ PageType {
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 20
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Подключение к серверу"
}

View file

@ -30,11 +30,22 @@ PageType {
}
}
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20
}
FlickableType {
id: fl
anchors.top: root.top
anchors.top: backButton.bottom
anchors.bottom: root.bottom
contentHeight: content.implicitHeight + buttonContinue.anchors.bottomMargin
contentHeight: content.implicitHeight + continueButton.anchors.bottomMargin
Column {
id: content
@ -44,7 +55,6 @@ PageType {
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20
spacing: 16
@ -53,9 +63,7 @@ PageType {
implicitWidth: parent.width
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: qsTr("What is the level of Internet control in your region?")
headerText: qsTr("What is the level of internet control in your region?")
}
ListView {
@ -118,11 +126,10 @@ PageType {
}
BasicButtonType {
id: buttonContinue
id: continueButton
implicitWidth: parent.width
anchors.topMargin: 24
anchors.bottomMargin: 32
anchors.bottomMargin: 24
text: qsTr("Continue")

View file

@ -109,7 +109,7 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 32
value: progressBarValue
// value: progressBarValue
Timer {
id: timer
@ -118,7 +118,7 @@ PageType {
repeat: true
running: true
onTriggered: {
progressBarValue += 0.001
progressBar.value += 0.001
}
}
}

View file

@ -62,13 +62,14 @@ PageType {
anchors.rightMargin: 16
anchors.leftMargin: 16
BackButtonType {
Layout.topMargin: 20
}
HeaderType {
id: header
Layout.fillWidth: true
Layout.topMargin: 20
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Установка " + name
descriptionText: "Эти настройки можно будет изменить позже"

View file

@ -48,9 +48,12 @@ PageType {
spacing: 16
BackButtonType {
width: parent.width
}
HeaderType {
width: parent.width
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Протокол подключения"
descriptionText: "Выберите более приоритетный для вас. Позже можно будет установить остальные протоколы и доп сервисы, вроде DNS-прокси и SFTP."

View file

@ -29,23 +29,26 @@ PageType {
spacing: 16
BackButtonType {
Layout.topMargin: 20
}
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 20
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Ключ для подключения"
descriptionText: "Строка, которая начинается с vpn://..."
headerText: qsTr("Connection key")
descriptionText: qsTr("A line that starts with vpn://...")
}
TextFieldWithHeaderType {
id: textKey
Layout.fillWidth: true
Layout.topMargin: 32
headerText: "Ключ"
headerText: qsTr("Key")
textFieldPlaceholderText: "vpn://"
buttonText: "Вставить"
buttonText: qsTr("Insert")
clickedFunc: function() {
textField.text = ""
@ -63,10 +66,11 @@ PageType {
anchors.leftMargin: 16
anchors.bottomMargin: 32
text: qsTr("Подключиться")
text: qsTr("Continue")
onClicked: function() {
// goToPage(PageEnum.PageSetupWizardInstalling)
ImportController.extractConfigFromCode(textKey.textFieldText)
goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
}

View file

@ -0,0 +1,152 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import PageEnum 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
PageType {
id: root
property bool showContent: false
Connections {
target: ImportController
function onImportErrorOccurred(errorMessage) {
closePage()
PageController.showErrorMessage(errorMessage)
}
function onImportFinished() {
goToStartPage()
if (stackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageHome)) {
PageController.restorePageHomeState()
} else if (stackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageSettings)) {
goToPage(PageEnum.PageSettingsServersList, false)
} else {
var pagePath = PageController.getPagePath(PageEnum.PageStart)
stackView.replace(pagePath, { "objectName" : pagePath })
}
}
}
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 20
}
FlickableType {
id: fl
anchors.top: backButton.bottom
anchors.bottom: root.bottom
contentHeight: content.implicitHeight + connectButton.implicitHeight
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
HeaderType {
headerText: qsTr("New connection")
}
RowLayout {
Layout.topMargin: 32
spacing: 8
visible: fileName.text !== ""
Image {
source: "qrc:/images/controls/file-cog-2.svg"
}
Header2TextType {
id: fileName
Layout.fillWidth: true
text: ImportController.getConfigFileName()
}
}
CaptionTextType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Do not use connection code from public sources. It could be created to intercept your data.")
color: "#878B91"
}
BasicButtonType {
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
disabledColor: "#878B91"
textColor: "#D7D8DB"
text: showContent ? qsTr("Collapse content") : qsTr("Show content")
onClicked: {
showContent = !showContent
}
}
Rectangle {
Layout.fillWidth: true
Layout.bottomMargin: 16
implicitHeight: configContent.implicitHeight
radius: 10
color: "#1C1D21"
visible: showContent
ParagraphTextType {
id: configContent
anchors.fill: parent
anchors.margins: 16
text: ImportController.getConfig()
}
}
}
}
ColumnLayout {
id: connectButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
BasicButtonType {
Layout.fillWidth: true
Layout.bottomMargin: 32
text: qsTr("Connect")
onClicked: {
ImportController.importConfig()
}
}
}
}

View file

@ -46,6 +46,8 @@ PageType {
Component.onCompleted: {
var pagePath = PageController.getPagePath(PageEnum.PageHome)
tabBarStackView.push(pagePath, { "objectName" : pagePath })
ServersModel.setCurrentlyProcessedServerIndex(ServersModel.getDefaultServerIndex())
ContainersModel.setCurrentlyProcessedServerIndex(ServersModel.getDefaultServerIndex())
}
}

View file

@ -36,7 +36,7 @@ Window {
focus: true
Component.onCompleted: {
var pagePath = PageController.getPagePath(PageEnum.PageStart)
var pagePath = PageController.getInitialPage()
rootStackView.push(pagePath, { "objectName" : pagePath })
}
}