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, OpenSslFailed,
OpenVpnExecutableCrashed, OpenVpnExecutableCrashed,
ShadowSocksExecutableCrashed, ShadowSocksExecutableCrashed,
CloakExecutableCrashed CloakExecutableCrashed,
// import and install errors
ImportInvalidConfigError
}; };
} // namespace amnezia } // 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 (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter");
case (AddressPoolError): return QObject::tr("VPN pool error: no available addresses"); 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): case(InternalError):
default: default:
return QObject::tr("Internal error"); 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>images/controls/server.svg</file>
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file> <file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
<file>ui/qml/Pages2/PageSettingsServerServices.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> </qresource>
</RCC> </RCC>

View file

@ -9,21 +9,7 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
} }
bool ConnectionController::onConnectionButtonClicked() void ConnectionController::openConnection()
{
if (!isConnected()) {
openVpnConnection();
} else {
closeVpnConnection();
}
}
bool ConnectionController::isConnected()
{
return m_isConnected;
}
bool ConnectionController::openVpnConnection()
{ {
int serverIndex = m_serversModel->getDefaultServerIndex(); int serverIndex = m_serversModel->getDefaultServerIndex();
QModelIndex serverModelIndex = m_serversModel->index(serverIndex); QModelIndex serverModelIndex = m_serversModel->index(serverIndex);
@ -35,16 +21,6 @@ bool ConnectionController::openVpnConnection()
const QJsonObject &containerConfig = qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, const QJsonObject &containerConfig = qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex,
ContainersModel::Roles::ConfigRole)); 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()) { // if (m_settings->containers(serverIndex).isEmpty()) {
// set_labelErrorText(tr("VPN Protocols is not installed.\n Please install VPN container at first")); // set_labelErrorText(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
// set_pushButtonConnectChecked(false); // set_pushButtonConnectChecked(false);
@ -57,20 +33,23 @@ bool ConnectionController::openVpnConnection()
// return; // return;
// } // }
//todo error handling
// const QJsonObject &containerConfig = m_settings->containerConfig(serverIndex, container); qApp->processEvents();
emit connectToVpn(serverIndex, credentials, container, containerConfig);
// set_labelErrorText("");
// set_pushButtonConnectChecked(true);
// set_pushButtonConnectEnabled(false);
// qApp->processEvents();
// emit connectToVpn(serverIndex, credentials, container, containerConfig);
} }
bool ConnectionController::closeVpnConnection() void ConnectionController::closeConnection()
{ {
emit disconnectFromVpn(); 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 Q_OBJECT
public: public:
Q_PROPERTY(bool isConnected READ isConnected WRITE setIsConnected NOTIFY isConnectedChanged)
explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel, explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, const QSharedPointer<ContainersModel> &containersModel,
QObject *parent = nullptr); QObject *parent = nullptr);
public slots:
bool onConnectionButtonClicked();
bool isConnected(); bool isConnected();
void setIsConnected(bool isConnected);
public slots:
void openConnection();
void closeConnection();
signals: signals:
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig); void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void disconnectFromVpn(); void disconnectFromVpn();
void connectionStateChanged(Vpn::ConnectionState state); void connectionStateChanged(Vpn::ConnectionState state);
void isConnectedChanged();
private: private:
bool openVpnConnection();
bool closeVpnConnection();
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;

View file

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

View file

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

View file

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

View file

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

View file

@ -14,20 +14,6 @@ DrawerType {
width: parent.width width: parent.width
height: parent.height * 0.4375 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 { ColumnLayout {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left

View file

@ -27,44 +27,54 @@ ListView {
delegate: Item { delegate: Item {
implicitWidth: rootWidth implicitWidth: rootWidth
implicitHeight: containerRadioButton.implicitHeight implicitHeight: content.implicitHeight
VerticalRadioButton { ColumnLayout {
id: containerRadioButton id: content
anchors.fill: parent anchors.fill: parent
anchors.rightMargin: 16 anchors.rightMargin: 16
anchors.leftMargin: 16 anchors.leftMargin: 16
text: name VerticalRadioButton {
descriptionText: description id: containerRadioButton
ButtonGroup.group: containersRadioButtonGroup Layout.fillWidth: true
imageSource: "qrc:/images/controls/download.svg" text: name
showImage: !isInstalled descriptionText: description
checkable: isInstalled ButtonGroup.group: containersRadioButtonGroup
checked: isDefault
onClicked: { imageSource: "qrc:/images/controls/download.svg"
if (checked) { showImage: !isInstalled
isDefault = true
menuContent.currentIndex = index checkable: isInstalled
containersDropDown.menuVisible = false checked: isDefault
} else {
ContainersModel.setCurrentlyInstalledContainerIndex(proxyContainersModel.mapToSource(index)) onClicked: {
InstallController.setShouldCreateServer(false) if (checked) {
goToPage(PageEnum.PageSetupWizardProtocolSettings) isDefault = true
containersDropDown.menuVisible = false menuContent.currentIndex = index
menu.visible = false containersDropDown.menuVisible = false
} else {
ContainersModel.setCurrentlyInstalledContainerIndex(proxyContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false)
goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.menuVisible = false
menu.visible = false
}
}
MouseArea {
anchors.fill: containerRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
} }
} }
MouseArea { DividerType {
anchors.fill: containerRadioButton Layout.fillWidth: true
cursorShape: Qt.PointingHandCursor
enabled: false
} }
} }

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 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 width: parent.width
height: parent.height * 0.9 height: parent.height * 0.9
background: Rectangle { ColumnLayout {
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 {
id: header id: header
headerText: root.headerText
backButtonImage: root.headerBackButtonImage
width: parent.width
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@ -146,8 +127,11 @@ Item {
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
backButtonFunction: function() { BackButtonType {
root.menuVisible = false backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
root.menuVisible = false
}
} }
} }
@ -164,6 +148,17 @@ Item {
spacing: 16 spacing: 16
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: root.headerText
width: parent.width
}
Loader { Loader {
id: listViewLoader id: listViewLoader
sourceComponent: root.listView sourceComponent: root.listView

View file

@ -6,10 +6,7 @@ import "TextTypes"
Item { Item {
id: root id: root
property string backButtonImage
property string actionButtonImage property string actionButtonImage
property var backButtonFunction
property var actionButtonFunction property var actionButtonFunction
property string headerText property string headerText
@ -22,25 +19,6 @@ Item {
id: content id: content
anchors.fill: parent 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 { RowLayout {
Header2TextType { Header2TextType {
id: header id: header

View file

@ -6,10 +6,7 @@ import "TextTypes"
Item { Item {
id: root id: root
property string backButtonImage
property string actionButtonImage property string actionButtonImage
property var backButtonFunction
property var actionButtonFunction property var actionButtonFunction
property string headerText property string headerText
@ -22,25 +19,6 @@ Item {
id: content id: content
anchors.fill: parent 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 { RowLayout {
Header1TextType { Header1TextType {
id: header id: header

View file

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

View file

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

View file

@ -6,7 +6,6 @@ Item {
id: root id: root
property string headerText property string headerText
property string textFieldText
property string textFieldPlaceholderText property string textFieldPlaceholderText
property bool textFieldEditable: true property bool textFieldEditable: true
@ -14,6 +13,7 @@ Item {
property var clickedFunc property var clickedFunc
property alias textField: textField property alias textField: textField
property alias textFieldText: textField.text
implicitHeight: 74 implicitHeight: 74
@ -53,7 +53,6 @@ Item {
id: textField id: textField
enabled: root.textFieldEditable enabled: root.textFieldEditable
text: root.textFieldText
color: "#d7d8db" color: "#d7d8db"
placeholderText: textFieldPlaceholderText 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 width: parent.width
height: parent.height * 0.90 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 { ColumnLayout {
id: serversMenuHeader id: serversMenuHeader
anchors.top: parent.top anchors.top: parent.top

View file

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

View file

@ -9,6 +9,7 @@ import ProtocolEnum 1.0
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Components"
PageType { PageType {
id: root id: root
@ -33,7 +34,19 @@ PageType {
descriptionText: "May be needed when changing other settings" descriptionText: "May be needed when changing other settings"
clickedFunction: function() { clickedFunction: function() {
ContainersModel.clearCachedProfiles() 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
} }
} }
@ -46,15 +59,27 @@ PageType {
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
if (ServersModel.isDefaultServerCurrentlyProcessed && ConnectionController.isConnected()) { questionDrawer.headerText = qsTr("Remove server?")
ConnectionController.closeVpnConnection() 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()) {
PageController.replaceStartPage()
} else {
goToStartPage()
}
} }
ServersModel.removeServer() questionDrawer.noButtonFunction = function() {
if (!ServersModel.getServersCount()) { questionDrawer.visible = false
PageController.replaceStartPage()
} else {
goToStartPage()
} }
questionDrawer.visible = true
} }
} }
@ -67,14 +92,32 @@ PageType {
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
if (ServersModel.isDefaultServerCurrentlyProcessed && ConnectionController.isConnected()) { questionDrawer.headerText = qsTr("Clear server from Amnezia software?")
ConnectionController.closeVpnConnection() 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()
} }
ContainersModel.removeAllContainers() questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
} }
} }
DividerType {} DividerType {}
QuestionDrawer {
id: questionDrawer
}
} }
} }
} }

View file

@ -30,8 +30,6 @@ PageType {
} }
ColumnLayout { ColumnLayout {
id: content
anchors.fill: parent anchors.fill: parent
spacing: 16 spacing: 16
@ -40,24 +38,27 @@ PageType {
id: header id: header
model: proxyServersModel model: proxyServersModel
delegate: HeaderType { delegate: ColumnLayout {
Layout.fillWidth: true id: content
Layout.topMargin: 20 Layout.topMargin: 20
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
actionButtonImage: "qrc:/images/controls/edit-3.svg" BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: name
descriptionText: hostName
actionButtonFunction: function() {
connectionTypeSelection.visible = true
} }
backButtonFunction: function() { HeaderType {
closePage() Layout.fillWidth: true
actionButtonImage: "qrc:/images/controls/edit-3.svg"
headerText: name
descriptionText: hostName
actionButtonFunction: function() {
connectionTypeSelection.visible = true
}
} }
} }
} }
@ -74,23 +75,14 @@ PageType {
TabButtonType { TabButtonType {
isSelected: tabBar.currentIndex === 0 isSelected: tabBar.currentIndex === 0
text: qsTr("Protocols") text: qsTr("Protocols")
// onClicked: {
// tabBarStackView.goToTabBarPage(PageEnum.PageSettingsServerProtocols)
// }
} }
TabButtonType { TabButtonType {
isSelected: tabBar.currentIndex === 1 isSelected: tabBar.currentIndex === 1
text: qsTr("Services") text: qsTr("Services")
// onClicked: {
// tabBarStackView.goToTabBarPage(PageEnum.PageSettingsServerServices)
// }
} }
TabButtonType { TabButtonType {
isSelected: tabBar.currentIndex === 2 isSelected: tabBar.currentIndex === 2
text: qsTr("Data") text: qsTr("Data")
// onClicked: {
// tabBarStackView.goToTabBarPage(PageEnum.PageSettingsServerData)
// }
} }
} }
@ -110,25 +102,5 @@ PageType {
stackView: root.stackView 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 { PageType {
id: root id: root
HeaderType { ColumnLayout {
id: header id: header
anchors.top: parent.top anchors.top: parent.top
@ -28,13 +28,19 @@ PageType {
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
actionButtonImage: "qrc:/images/controls/plus.svg" BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg" }
headerText: "Серверы" HeaderType {
Layout.fillWidth: true
actionButtonFunction: function() { actionButtonImage: "qrc:/images/controls/plus.svg"
connectionTypeSelection.visible = true
headerText: "Серверы"
actionButtonFunction: function() {
connectionTypeSelection.visible = true
}
} }
} }

View file

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

View file

@ -11,9 +11,20 @@ import "../Config"
PageType { PageType {
id: root 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 { FlickableType {
id: fl id: fl
anchors.top: root.top anchors.top: backButton.bottom
anchors.bottom: root.bottom anchors.bottom: root.bottom
contentHeight: content.height contentHeight: content.height
@ -30,9 +41,6 @@ PageType {
HeaderType { HeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20
backButtonImage: "qrc:/images/controls/arrow-left.svg"
headerText: "Подключение к серверу" 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 { FlickableType {
id: fl id: fl
anchors.top: root.top anchors.top: backButton.bottom
anchors.bottom: root.bottom anchors.bottom: root.bottom
contentHeight: content.implicitHeight + buttonContinue.anchors.bottomMargin contentHeight: content.implicitHeight + continueButton.anchors.bottomMargin
Column { Column {
id: content id: content
@ -44,7 +55,6 @@ PageType {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16 anchors.rightMargin: 16
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.topMargin: 20
spacing: 16 spacing: 16
@ -53,9 +63,7 @@ PageType {
implicitWidth: parent.width 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 { ListView {
@ -118,11 +126,10 @@ PageType {
} }
BasicButtonType { BasicButtonType {
id: buttonContinue id: continueButton
implicitWidth: parent.width implicitWidth: parent.width
anchors.topMargin: 24 anchors.bottomMargin: 24
anchors.bottomMargin: 32
text: qsTr("Continue") text: qsTr("Continue")

View file

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

View file

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

View file

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

View file

@ -29,23 +29,26 @@ PageType {
spacing: 16 spacing: 16
BackButtonType {
Layout.topMargin: 20
}
HeaderType { HeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20
backButtonImage: "qrc:/images/controls/arrow-left.svg" headerText: qsTr("Connection key")
descriptionText: qsTr("A line that starts with vpn://...")
headerText: "Ключ для подключения"
descriptionText: "Строка, которая начинается с vpn://..."
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: textKey
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
headerText: "Ключ" headerText: qsTr("Key")
textFieldPlaceholderText: "vpn://" textFieldPlaceholderText: "vpn://"
buttonText: "Вставить" buttonText: qsTr("Insert")
clickedFunc: function() { clickedFunc: function() {
textField.text = "" textField.text = ""
@ -63,10 +66,11 @@ PageType {
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.bottomMargin: 32 anchors.bottomMargin: 32
text: qsTr("Подключиться") text: qsTr("Continue")
onClicked: function() { 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: { Component.onCompleted: {
var pagePath = PageController.getPagePath(PageEnum.PageHome) var pagePath = PageController.getPagePath(PageEnum.PageHome)
tabBarStackView.push(pagePath, { "objectName" : pagePath }) tabBarStackView.push(pagePath, { "objectName" : pagePath })
ServersModel.setCurrentlyProcessedServerIndex(ServersModel.getDefaultServerIndex())
ContainersModel.setCurrentlyProcessedServerIndex(ServersModel.getDefaultServerIndex())
} }
} }

View file

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