From 495e74e2f09edefde97484d909c2c31102bd14fb Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 22 Jan 2022 18:19:38 +0300 Subject: [PATCH 01/20] Sites page fix --- client/ui/pages_logic/SitesLogic.cpp | 38 +++++--- client/ui/pages_logic/SitesLogic.h | 4 +- client/ui/qml/Pages/PageSites.qml | 128 ++++++++++++++++++++++----- 3 files changed, 139 insertions(+), 31 deletions(-) diff --git a/client/ui/pages_logic/SitesLogic.cpp b/client/ui/pages_logic/SitesLogic.cpp index a035e065..13b6f248 100644 --- a/client/ui/pages_logic/SitesLogic.cpp +++ b/client/ui/pages_logic/SitesLogic.cpp @@ -98,27 +98,32 @@ void SitesLogic::onPushButtonAddCustomSitesClicked() } } -void SitesLogic::onPushButtonSitesDeleteClicked(int row) +void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items) { Settings::RouteMode mode = m_settings.routeMode(); auto siteModel = qobject_cast (tableViewSitesModel()); - if (!siteModel) { - return; - } - if (row < 0 || row >= siteModel->rowCount()) { + if (!siteModel || items.isEmpty()) { return; } - { - QStringList sites; + QStringList sites; + QStringList ips; + + for (const QString &s: items) { + bool ok; + int row = s.toInt(&ok); + if (!ok || row < 0 || row >= siteModel->rowCount()) return; sites.append(siteModel->data(row, 0).toString()); - m_settings.removeVpnSites(mode, sites); + + if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) { + ips.append(siteModel->data(row, 1).toString()); + } } + m_settings.removeVpnSites(mode, sites); + if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) { - QStringList ips; - ips.append(siteModel->data(row, 1).toString()); uiLogic()->m_vpnConnection->deleteRoutes(ips); uiLogic()->m_vpnConnection->flushDns(); } @@ -156,3 +161,16 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName) onUpdatePage(); } +void SitesLogic::onPushButtonSitesExportClicked() +{ + Settings::RouteMode mode = m_settings.routeMode(); + + QVariantMap sites = m_settings.vpnSites(mode); + + QString data; + for (auto s : sites.keys()) { + data += s + "\t" + sites.value(s).toString() + "\n"; + } + uiLogic()->saveTextFile("Sites", ".txt", data); +} + diff --git a/client/ui/pages_logic/SitesLogic.h b/client/ui/pages_logic/SitesLogic.h index fdc5ec82..2afb3805 100644 --- a/client/ui/pages_logic/SitesLogic.h +++ b/client/ui/pages_logic/SitesLogic.h @@ -18,8 +18,10 @@ public: Q_INVOKABLE void onUpdatePage() override; Q_INVOKABLE void onPushButtonAddCustomSitesClicked(); - Q_INVOKABLE void onPushButtonSitesDeleteClicked(int row); + Q_INVOKABLE void onPushButtonSitesDeleteClicked(QStringList items); Q_INVOKABLE void onPushButtonSitesImportClicked(const QString &fileName); + Q_INVOKABLE void onPushButtonSitesExportClicked(); + public: explicit SitesLogic(UiLogic *uiLogic, QObject *parent = nullptr); diff --git a/client/ui/qml/Pages/PageSites.qml b/client/ui/qml/Pages/PageSites.qml index 0a90166f..0b2e43e7 100644 --- a/client/ui/qml/Pages/PageSites.qml +++ b/client/ui/qml/Pages/PageSites.qml @@ -1,5 +1,6 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQml.Models 2.15 import Qt.labs.platform 1.0 import QtQuick.Dialogs 1.0 import PageEnum 1.0 @@ -12,6 +13,8 @@ PageBase { page: PageEnum.Sites logic: SitesLogic + property int lastIndex: 0 + BackButton { id: back } @@ -104,20 +107,27 @@ PageBase { } } - ListView { - id: tb - x: 20 - anchors.top: sites_add.bottom - anchors.topMargin: 10 - width: parent.width - 40 - anchors.bottom: sites_delete.top - anchors.bottomMargin: 10 - spacing: 1 - clip: true - property int currentRow: -1 + DelegateModel { + id: visualModel model: SitesLogic.tableViewSitesModel - - delegate: Item { + groups: [ + DelegateModelGroup { + id : delegateModelGroup + name: "multiSelect" + function removeAll(){ + var count = delegateModelGroup.count; + if (count !== 0){ + delegateModelGroup.remove(0,count); + } + } + } + ] + delegate: Rectangle { + id: item + focus: true + height: 25 + width: root.width + color: item.DelegateModel.inMultiSelect ? '#63b4fb' : 'transparent' implicitWidth: 170 * 2 implicitHeight: 30 Item { @@ -171,23 +181,101 @@ PageBase { } MouseArea { anchors.fill: parent - onClicked: { - tb.currentRow = index + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked:{ + tb.focus = true + if(mouse.button === Qt.RightButton){ + //copyPasteMenu.popup() + console.log("RightButton") + } + if(mouse.button === Qt.LeftButton){ + switch(mouse.modifiers){ + case Qt.ControlModifier : + item.DelegateModel.inMultiSelect = !item.DelegateModel.inMultiSelect + break; + case Qt.ShiftModifier : + delegateModelGroup.removeAll(); + var start = lastIndex <= index? lastIndex: index; + var end = lastIndex >= index? lastIndex: index; + for(var i = start;i <= end;i++){ + visualModel.items.get(i).inMultiSelect = true + } + break; + default: + delegateModelGroup.removeAll(); + item.DelegateModel.inMultiSelect = true + lastIndex = index + break; + } + } } } } } + ListView { + id: tb + x: 20 + anchors.top: sites_add.bottom + anchors.topMargin: 10 + width: parent.width - 40 + anchors.bottom: sites_delete.top + anchors.bottomMargin: 10 + spacing: 1 + clip: true + focus: true + activeFocusOnTab: true + keyNavigationEnabled: true + property int currentRow: -1 + //model: SitesLogic.tableViewSitesModel + model: visualModel + + } + BlueButtonType { id: sites_delete - anchors.bottom: parent.bottom - anchors.bottomMargin: 20 + anchors.bottom: select_all.top + anchors.bottomMargin: 10 anchors.horizontalCenter: parent.horizontalCenter height: 31 font.pixelSize: 16 text: qsTr("Delete selected") onClicked: { - SitesLogic.onPushButtonSitesDeleteClicked(tb.currentRow) + var items = [] + for(var i = 0; i < visualModel.count; i++){ + if (visualModel.items.get(i).inMultiSelect) items.push(i) + } + + console.debug(items) + SitesLogic.onPushButtonSitesDeleteClicked(items) + } + } + + BlueButtonType { + id: select_all + anchors.bottom: sites_export.top + anchors.bottomMargin: 10 + anchors.horizontalCenter: parent.horizontalCenter + height: 31 + font.pixelSize: 16 + text: qsTr("Select all") + onClicked: { + for(var i = 0; i < visualModel.count; i++){ + visualModel.items.get(i).inMultiSelect = true + } + } + } + + BlueButtonType { + id: sites_export + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + height: 31 + font.pixelSize: 16 + text: qsTr("Export all") + onClicked: { + SitesLogic.onPushButtonSitesExportClicked() } } } From 8f28964ce2f9c5b4cc896a99433f853445886097 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 22 Jan 2022 18:19:57 +0300 Subject: [PATCH 02/20] Tiny ui fixes --- client/ui/qml/Pages/PageVPN.qml | 4 ++-- client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml | 1 - client/ui/uilogic.cpp | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/ui/qml/Pages/PageVPN.qml b/client/ui/qml/Pages/PageVPN.qml index 6312f416..a4c86714 100644 --- a/client/ui/qml/Pages/PageVPN.qml +++ b/client/ui/qml/Pages/PageVPN.qml @@ -108,7 +108,7 @@ PageBase { Layout.alignment: Qt.AlignLeft height: 21 background: Item {} - text: VpnLogic.labelCurrentServer + text: VpnLogic.labelCurrentServer + " →" font.family: "Lato" font.styleName: "normal" font.pixelSize: 16 @@ -136,7 +136,7 @@ PageBase { Layout.alignment: Qt.AlignLeft height: 21 background: Item {} - text: VpnLogic.labelCurrentService + text: VpnLogic.labelCurrentService + " →" font.family: "Lato" font.styleName: "normal" font.pixelSize: 16 diff --git a/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml b/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml index 88239fb5..be198ec5 100644 --- a/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml +++ b/client/ui/qml/Pages/Protocols/PageProtoShadowSocks.qml @@ -11,7 +11,6 @@ PageProtocolBase { protocol: ProtocolEnum.ShadowSocks logic: UiLogic.protocolLogic(protocol) - enabled: logic.pageEnabled BackButton { id: back } diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index ee2f7c53..9eb208b9 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -650,6 +650,7 @@ void UiLogic::saveTextFile(const QString& desc, const QString& ext, const QStrin QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext); if (fileName.isEmpty()) return; + if (!fileName.endsWith(ext)) fileName.append(ext); QFile save(fileName); save.open(QIODevice::WriteOnly); @@ -666,6 +667,7 @@ void UiLogic::saveBinaryFile(const QString &desc, const QString &ext, const QStr QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext); if (fileName.isEmpty()) return; + if (!fileName.endsWith(ext)) fileName.append(ext); QFile save(fileName); save.open(QIODevice::WriteOnly); From 02acbecef5a128676b558798f2a55f4b697f59c1 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sat, 22 Jan 2022 20:00:06 +0300 Subject: [PATCH 03/20] Re-resolve sites after VPN Connected --- client/vpnconnection.cpp | 51 ++++++++++++++++++++++++++++++++++++++-- client/vpnconnection.h | 1 + 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 23767697..265773f6 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -59,16 +60,19 @@ void VpnConnection::onConnectionStateChanged(VpnProtocol::VpnConnectionState sta if (m_settings.routeMode() == Settings::VpnOnlyForwardSites) { - IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), m_settings.getVpnIps(Settings::VpnOnlyForwardSites)); + QTimer::singleShot(1000, m_vpnProtocol.data(), [this](){ + addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings.routeMode()); + }); } else if (m_settings.routeMode() == Settings::VpnAllExceptSites) { IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0/1"); IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "128.0.0.0/1"); IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), QStringList() << remoteAddress()); - IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), m_settings.getVpnIps(Settings::VpnAllExceptSites)); + addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings.routeMode()); } + } else if (state == VpnProtocol::Error) { IpcClient::Interface()->flushDns(); @@ -87,6 +91,49 @@ const QString &VpnConnection::remoteAddress() const return m_remoteAddress; } +void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode) +{ + QStringList ips; + QStringList sites; + const QVariantMap &m = m_settings.vpnSites(mode); + for (auto i = m.constBegin(); i != m.constEnd(); ++i) { + if (Utils::checkIpSubnetFormat(i.key())) { + ips.append(i.key()); + } + else { + if (Utils::checkIpSubnetFormat(i.value().toString())) { + ips.append(i.value().toString()); + } + sites.append(i.key()); + } + } + ips.removeDuplicates(); + + // add all IPs immediately + IpcClient::Interface()->routeAddList(gw, ips); + + // re-resolve domains + for (const QString &site: sites) { + const auto &cbResolv = [this, site, gw, mode, ips](const QHostInfo &hostInfo){ + const QList &addresses = hostInfo.addresses(); + QString ipv4Addr; + for (const QHostAddress &addr: hostInfo.addresses()) { + if (addr.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) { + const QString &ip = addr.toString(); + //qDebug() << "VpnConnection::addSitesRoutes updating site" << site << ip; + if (!ips.contains(ip)) { + IpcClient::Interface()->routeAddList(gw, QStringList() << ip); + m_settings.addVpnSite(mode, site, ip); + } + flushDns(); + break; + } + } + }; + QHostInfo::lookupHost(site, this, cbResolv); + } +} + QSharedPointer VpnConnection::vpnProtocol() const { return m_vpnProtocol; diff --git a/client/vpnconnection.h b/client/vpnconnection.h index a6f0e13a..7a21e7b0 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -47,6 +47,7 @@ public: void flushDns(); const QString &remoteAddress() const; + void addSitesRoutes(const QString &gw, Settings::RouteMode mode); public slots: void connectToVpn(int serverIndex, From 2b9e615e51a2e13c212d6fc6a2f371e6193151dc Mon Sep 17 00:00:00 2001 From: pokamest Date: Sun, 23 Jan 2022 19:16:40 +0300 Subject: [PATCH 04/20] Various fixes --- client/android/build.gradle | 4 +- client/defines.h | 4 +- client/main.cpp | 13 +++-- client/settings.cpp | 15 ++++++ client/settings.h | 1 + client/ui/pages_logic/SitesLogic.cpp | 45 +++++++++++++++-- client/ui/pages_logic/VpnLogic.cpp | 16 ++++-- client/ui/pages_logic/VpnLogic.h | 2 + client/ui/qml/Controls/RadioButtonType.qml | 2 +- client/ui/qml/Pages/PageSites.qml | 34 +++++++++++-- client/ui/qml/Pages/PageVPN.qml | 2 + client/ui/uilogic.cpp | 58 +++------------------- client/ui/uilogic.h | 14 ------ client/utils.h | 1 + 14 files changed, 122 insertions(+), 89 deletions(-) diff --git a/client/android/build.gradle b/client/android/build.gradle index 318ebd07..fd2afa46 100644 --- a/client/android/build.gradle +++ b/client/android/build.gradle @@ -102,8 +102,8 @@ android { resConfig "en" minSdkVersion = 24 targetSdkVersion = 30 - versionCode 7 // Change to a higher number - versionName "2.0.7" // Change to a higher number + versionCode 8 // Change to a higher number + versionName "2.0.8" // Change to a higher number } buildTypes { diff --git a/client/defines.h b/client/defines.h index fec15e65..89cfa599 100644 --- a/client/defines.h +++ b/client/defines.h @@ -4,7 +4,7 @@ #define APPLICATION_NAME "AmneziaVPN" #define SERVICE_NAME "AmneziaVPN-service" #define ORGANIZATION_NAME "AmneziaVPN.ORG" -#define APP_MAJOR_VERSION "2.0.7" -#define APP_VERSION "2.0.7.0" +#define APP_MAJOR_VERSION "2.0.8" +#define APP_VERSION "2.0.8.0" #endif // DEFINES_H diff --git a/client/main.cpp b/client/main.cpp index 13b1d0ae..db54321a 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -196,13 +196,12 @@ int main(int argc, char *argv[]) uiLogic->setQmlRoot(engine->rootObjects().at(0)); } - // TODO - fix -//#ifdef Q_OS_WIN -// if (parser.isSet("a")) mainWindow.showOnStartup(); -// else mainWindow.show(); -//#else -// mainWindow.showOnStartup(); -//#endif +#ifdef Q_OS_WIN + if (parser.isSet("a")) uiLogic->showOnStartup(); + else emit uiLogic->show(); +#else + uiLogic->showOnStartup(); +#endif // TODO - fix diff --git a/client/settings.cpp b/client/settings.cpp index ef4952dd..317df740 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -228,6 +228,21 @@ void Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip setVpnSites(mode, sites); } +void Settings::addVpnSites(RouteMode mode, const QMap &sites) +{ + QVariantMap allSites = vpnSites(mode); + for (auto i = sites.constBegin(); i != sites.constEnd(); ++i) { + const QString &site = i.key(); + const QString &ip = i.value(); + + if (allSites.contains(site) && allSites.value(site) == ip) continue; + + allSites.insert(site, ip); + } + + setVpnSites(mode, allSites); +} + QStringList Settings::getVpnIps(RouteMode mode) const { QStringList ips; diff --git a/client/settings.h b/client/settings.h index e70ce487..409f4ecd 100644 --- a/client/settings.h +++ b/client/settings.h @@ -82,6 +82,7 @@ public: QVariantMap vpnSites(RouteMode mode) const { return m_settings.value("Conf/" + routeModeString(mode)).toMap(); } void setVpnSites(RouteMode mode, const QVariantMap &sites) { m_settings.setValue("Conf/"+ routeModeString(mode), sites); m_settings.sync(); } void addVpnSite(RouteMode mode, const QString &site, const QString &ip= ""); + void addVpnSites(RouteMode mode, const QMap &sites); // map QStringList getVpnIps(RouteMode mode) const; void removeVpnSite(RouteMode mode, const QString &site); diff --git a/client/ui/pages_logic/SitesLogic.cpp b/client/ui/pages_logic/SitesLogic.cpp index 13b6f248..b61b8a26 100644 --- a/client/ui/pages_logic/SitesLogic.cpp +++ b/client/ui/pages_logic/SitesLogic.cpp @@ -142,18 +142,53 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName) Settings::RouteMode mode = m_settings.routeMode(); QStringList ips; + QMap sites; + while (!file.atEnd()) { QString line = file.readLine(); + QStringList line_ips; + QStringList line_sites; - int pos = 0; - QRegExp rx = Utils::ipAddressWithSubnetRegExp(); - while ((pos = rx.indexIn(line, pos)) != -1) { - ips << rx.cap(0); - pos += rx.matchedLength(); + int posDomain = 0; + QRegExp domainRx = Utils::domainRegExp(); + while ((posDomain = domainRx.indexIn(line, posDomain)) != -1) { + line_sites.append(domainRx.cap(0)); + posDomain += domainRx.matchedLength(); } + + int posIp = 0; + QRegExp ipRx = Utils::ipAddressWithSubnetRegExp(); + while ((posIp = ipRx.indexIn(line, posIp)) != -1) { + line_ips.append(ipRx.cap(0)); + posIp += ipRx.matchedLength(); + } + + // domain regex cover ip regex, so remove ips from sites + for (const QString& ip: line_ips) { + line_sites.removeAll(ip); + } + + if (line_sites.size() == 1 && line_ips.size() == 1) { + sites.insert(line_sites.at(0), line_ips.at(0)); + } + else if (line_sites.size() > 0 && line_ips.size() == 0) { + for (const QString& site: line_sites) { + sites.insert(site, ""); + } + } + else { + for (const QString& site: line_sites) { + sites.insert(site, ""); + } + for (const QString& ip: line_ips) { + ips.append(ip); + } + } + } m_settings.addVpnIps(mode, ips); + m_settings.addVpnSites(mode, sites); uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips); uiLogic()->m_vpnConnection->flushDns(); diff --git a/client/ui/pages_logic/VpnLogic.cpp b/client/ui/pages_logic/VpnLogic.cpp index 65bf3fc2..67e9e37a 100644 --- a/client/ui/pages_logic/VpnLogic.cpp +++ b/client/ui/pages_logic/VpnLogic.cpp @@ -33,15 +33,24 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent): onConnect(); }); } + else { + onConnectionStateChanged(VpnProtocol::Disconnected); + } } void VpnLogic::onUpdatePage() { Settings::RouteMode mode = m_settings.routeMode(); - set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites); - set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites); - set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites); + DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex()); + + set_isCustomRoutesSupported (selectedContainer == DockerContainer::OpenVpn || + selectedContainer == DockerContainer::ShadowSocks|| + selectedContainer == DockerContainer::Cloak); + + set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites || !isCustomRoutesSupported()); + set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites && isCustomRoutesSupported()); + set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites && isCustomRoutesSupported()); const QJsonObject &server = uiLogic()->m_settings.defaultServer(); QString serverString = QString("%2 (%3)") @@ -49,7 +58,6 @@ void VpnLogic::onUpdatePage() .arg(server.value(config_key::hostName).toString()); set_labelCurrentServer(serverString); - DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex()); QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer); set_labelCurrentService(selectedContainerName); diff --git a/client/ui/pages_logic/VpnLogic.h b/client/ui/pages_logic/VpnLogic.h index 811c7f62..e18b49eb 100644 --- a/client/ui/pages_logic/VpnLogic.h +++ b/client/ui/pages_logic/VpnLogic.h @@ -24,6 +24,8 @@ class VpnLogic : public PageLogicBase AUTO_PROPERTY(QString, labelErrorText) AUTO_PROPERTY(QString, labelVersionText) + AUTO_PROPERTY(bool, isCustomRoutesSupported) + AUTO_PROPERTY(bool, radioButtonVpnModeAllSitesChecked) AUTO_PROPERTY(bool, radioButtonVpnModeForwardSitesChecked) AUTO_PROPERTY(bool, radioButtonVpnModeExceptSitesChecked) diff --git a/client/ui/qml/Controls/RadioButtonType.qml b/client/ui/qml/Controls/RadioButtonType.qml index 119cf794..e31525fe 100644 --- a/client/ui/qml/Controls/RadioButtonType.qml +++ b/client/ui/qml/Controls/RadioButtonType.qml @@ -28,7 +28,7 @@ RadioButton { font.family: "Lato" font.styleName: "normal" font.pixelSize: 16 - color: "#181922" + color: enabled ? "#181922" : "#686972" verticalAlignment: Text.AlignVCenter leftPadding: root.indicator.width + root.spacing } diff --git a/client/ui/qml/Pages/PageSites.qml b/client/ui/qml/Pages/PageSites.qml index 0b2e43e7..f5a03ef5 100644 --- a/client/ui/qml/Pages/PageSites.qml +++ b/client/ui/qml/Pages/PageSites.qml @@ -213,6 +213,35 @@ PageBase { } } + Keys.onPressed: { + if (event.key == Qt.Key_PageUp) { + let idx = tb.indexAt(1, tb.contentY) + tb.positionViewAtIndex(idx-20, ListView.Beginning) + event.accepted = true + } + else if (event.key == Qt.Key_PageDown) { + let idx = tb.indexAt(1, tb.contentY) + tb.positionViewAtIndex(idx+20, ListView.Beginning) + event.accepted = true + } + else if (event.key == Qt.Key_Home) { + tb.positionViewAtBeginning() + event.accepted = true + } + else if (event.key == Qt.Key_End) { + tb.positionViewAtEnd() + event.accepted = true + } + else if (event.key == Qt.Key_Delete) { + let items = [] + for(let i = 0; i < visualModel.count; i++){ + if (visualModel.items.get(i).inMultiSelect) items.push(i) + } + SitesLogic.onPushButtonSitesDeleteClicked(items) + event.accepted = true + } + } + ListView { id: tb x: 20 @@ -241,12 +270,11 @@ PageBase { font.pixelSize: 16 text: qsTr("Delete selected") onClicked: { - var items = [] - for(var i = 0; i < visualModel.count; i++){ + let items = [] + for(let i = 0; i < visualModel.count; i++){ if (visualModel.items.get(i).inMultiSelect) items.push(i) } - console.debug(items) SitesLogic.onPushButtonSitesDeleteClicked(items) } } diff --git a/client/ui/qml/Pages/PageVPN.qml b/client/ui/qml/Pages/PageVPN.qml index a4c86714..6158e8ea 100644 --- a/client/ui/qml/Pages/PageVPN.qml +++ b/client/ui/qml/Pages/PageVPN.qml @@ -259,6 +259,7 @@ PageBase { onClicked: VpnLogic.onRadioButtonVpnModeAllSitesClicked(true) } RadioButtonType { + enabled: VpnLogic.isCustomRoutesSupported x: 0 y: 60 width: 341 @@ -268,6 +269,7 @@ PageBase { onClicked: VpnLogic.onRadioButtonVpnModeExceptSitesClicked(true) } RadioButtonType { + enabled: VpnLogic.isCustomRoutesSupported x: 0 y: 30 width: 341 diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 9eb208b9..1f4eb3a8 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -149,24 +149,6 @@ void UiLogic::initalizeUiLogic() connect(m_notificationHandler, &NotificationHandler::connectRequested, vpnLogic(), &VpnLogic::onConnect); connect(m_notificationHandler, &NotificationHandler::disconnectRequested, vpnLogic(), &VpnLogic::onDisconnect); - // if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::Windows7) { - // needToHideCustomTitlebar = true; - // } - - //#if defined Q_OS_MAC - // fixWidget(this); - // needToHideCustomTitlebar = true; - //#endif - - // if (needToHideCustomTitlebar) { - // ui->widget_tittlebar->hide(); - // resize(width(), 640); - // ui->stackedWidget_main->move(0,0); - // } - - // Post initialization - //emit goToPage(Page::Start, true, false); - if (m_settings.serversCount() > 0) { if (m_settings.defaultServerIndex() < 0) m_settings.setDefaultServer(0); emit goToPage(Page::Vpn, true, false); @@ -176,37 +158,9 @@ void UiLogic::initalizeUiLogic() } selectedServerIndex = m_settings.defaultServerIndex(); - //goToPage(Page::ServerContainers, true, false); - //goToPage(Page::NewServerProtocols, true, false); - //onGotoProtocolPage(Proto::OpenVpn); - - - //ui->pushButton_general_settings_exit->hide(); - qInfo().noquote() << QString("Started %1 version %2").arg(APPLICATION_NAME).arg(APP_VERSION); qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName()).arg(QSysInfo::currentCpuArchitecture()); - - - - vpnLogic()->onConnectionStateChanged(VpnProtocol::Disconnected); - - - // m_ipAddressValidator.setRegExp(Utils::ipAddressRegExp()); - // m_ipAddressPortValidator.setRegExp(Utils::ipAddressPortRegExp()); - // m_ipNetwok24Validator.setRegExp(Utils::ipNetwork24RegExp()); - // m_ipPortValidator.setRegExp(Utils::ipPortRegExp()); - - // ui->lineEdit_new_server_ip->setValidator(&m_ipAddressPortValidator); - // ui->lineEdit_network_settings_dns1->setValidator(&m_ipAddressValidator); - // ui->lineEdit_network_settings_dns2->setValidator(&m_ipAddressValidator); - - // ui->lineEdit_proto_openvpn_subnet->setValidator(&m_ipNetwok24Validator); - - // ui->lineEdit_proto_openvpn_port->setValidator(&m_ipPortValidator); - // ui->lineEdit_proto_shadowsocks_port->setValidator(&m_ipPortValidator); - // ui->lineEdit_proto_cloak_port->setValidator(&m_ipPortValidator); - } QString UiLogic::getDialogConnectErrorText() const @@ -225,10 +179,13 @@ void UiLogic::setDialogConnectErrorText(const QString &dialogConnectErrorText) void UiLogic::showOnStartup() { if (! m_settings.isStartMinimized()) { - show(); - } else { -#if defined Q_OS_MACX - setDockIconVisible(false); + emit show(); + } + else { +#ifdef Q_OS_WIN + emit hide(); +#elif defined Q_OS_MACX + // TODO: fix: setDockIconVisible(false); #endif } } @@ -302,7 +259,6 @@ void UiLogic::keyPressEvent(Qt::Key key) // break; // } - //if (! ui->stackedWidget_main->isAnimationRunning() && ui->stackedWidget_main->currentWidget()->isEnabled()) { emit closePage(); //} default: diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 7ff699b2..1363aca9 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -213,20 +213,6 @@ private: NotificationHandler* m_notificationHandler; - - // QRegExpValidator m_ipAddressValidator; - // QRegExpValidator m_ipAddressPortValidator; - // QRegExpValidator m_ipNetwok24Validator; - // QRegExpValidator m_ipPortValidator; - - // QPoint offset; - // bool needToHideCustomTitlebar = false; - - // void showEvent(QShowEvent *event) override; - // void hideEvent(QHideEvent *event) override; - - - // QStack pagesStack; int selectedServerIndex = -1; // server index to use when proto settings page opened DockerContainer selectedDockerContainer; // same ServerCredentials installCredentials; // used to save cred between pages new_server and new_server_protocols and wizard diff --git a/client/utils.h b/client/utils.h index 709a159e..ff5c5e8c 100644 --- a/client/utils.h +++ b/client/utils.h @@ -35,6 +35,7 @@ public: static QRegExp ipPortRegExp() { return QRegExp("^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$"); } + static QRegExp domainRegExp() { return QRegExp("(((?!\\-))(xn\\-\\-)?[a-z0-9\\-_]{0,61}[a-z0-9]{1,1}\\.)*(xn\\-\\-)?([a-z0-9\\-]{1,61}|[a-z0-9\\-]{1,30})\\.[a-z]{2,}"); } static bool processIsRunning(const QString& fileName); static void killProcessByName(const QString &name); From daf53226c3efdaea1eea125204dbdbaa9116d200 Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 24 Jan 2022 02:01:56 +0300 Subject: [PATCH 05/20] SFTP fixes --- .../protocols/OtherProtocolsLogic.cpp | 2 +- client/ui/qml/Pages/PageSites.qml | 72 ++++++++++--------- .../ui/qml/Pages/Protocols/PageProtoSftp.qml | 16 ++++- 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp index 98354ec6..6c5a4315 100644 --- a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp +++ b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp @@ -85,7 +85,7 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked() } }); -// QString cmd = QString("net use \\\\sshfs\\%1@51.77.32.168!%2 /USER:%1 %3") +// QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3") // .arg(labelTftpUserNameText()) // .arg(labelTftpPortText()) // .arg(labelTftpPasswordText()); diff --git a/client/ui/qml/Pages/PageSites.qml b/client/ui/qml/Pages/PageSites.qml index f5a03ef5..f558586b 100644 --- a/client/ui/qml/Pages/PageSites.qml +++ b/client/ui/qml/Pages/PageSites.qml @@ -120,6 +120,11 @@ PageBase { delegateModelGroup.remove(0,count); } } + function selectAll(){ + for(var i = 0; i < visualModel.count; i++){ + visualModel.items.get(i).inMultiSelect = true + } + } } ] delegate: Rectangle { @@ -213,35 +218,6 @@ PageBase { } } - Keys.onPressed: { - if (event.key == Qt.Key_PageUp) { - let idx = tb.indexAt(1, tb.contentY) - tb.positionViewAtIndex(idx-20, ListView.Beginning) - event.accepted = true - } - else if (event.key == Qt.Key_PageDown) { - let idx = tb.indexAt(1, tb.contentY) - tb.positionViewAtIndex(idx+20, ListView.Beginning) - event.accepted = true - } - else if (event.key == Qt.Key_Home) { - tb.positionViewAtBeginning() - event.accepted = true - } - else if (event.key == Qt.Key_End) { - tb.positionViewAtEnd() - event.accepted = true - } - else if (event.key == Qt.Key_Delete) { - let items = [] - for(let i = 0; i < visualModel.count; i++){ - if (visualModel.items.get(i).inMultiSelect) items.push(i) - } - SitesLogic.onPushButtonSitesDeleteClicked(items) - event.accepted = true - } - } - ListView { id: tb x: 20 @@ -256,9 +232,41 @@ PageBase { activeFocusOnTab: true keyNavigationEnabled: true property int currentRow: -1 - //model: SitesLogic.tableViewSitesModel model: visualModel + Keys.onPressed: { + if (event.key === Qt.Key_PageUp) { + let idx = tb.indexAt(1, tb.contentY) + tb.positionViewAtIndex(idx-20, ListView.Beginning) + event.accepted = true + } + else if (event.key === Qt.Key_PageDown) { + let idx = tb.indexAt(1, tb.contentY) + tb.positionViewAtIndex(idx+20, ListView.Beginning) + event.accepted = true + } + else if (event.key === Qt.Key_Home) { + tb.positionViewAtBeginning() + event.accepted = true + } + else if (event.key === Qt.Key_End) { + tb.positionViewAtEnd() + event.accepted = true + } + else if (event.key === Qt.Key_Delete) { + let items = [] + for(let i = 0; i < visualModel.count; i++){ + if (visualModel.items.get(i).inMultiSelect) items.push(i) + } + SitesLogic.onPushButtonSitesDeleteClicked(items) + event.accepted = true + } + else if (event.key === Qt.Key_A) { + delegateModelGroup.selectAll() + event.accepted = true + } + } + } BlueButtonType { @@ -288,9 +296,7 @@ PageBase { font.pixelSize: 16 text: qsTr("Select all") onClicked: { - for(var i = 0; i < visualModel.count; i++){ - visualModel.items.get(i).inMultiSelect = true - } + delegateModelGroup.selectAll() } } diff --git a/client/ui/qml/Pages/Protocols/PageProtoSftp.qml b/client/ui/qml/Pages/Protocols/PageProtoSftp.qml index 04b60e26..b8b7fedc 100644 --- a/client/ui/qml/Pages/Protocols/PageProtoSftp.qml +++ b/client/ui/qml/Pages/Protocols/PageProtoSftp.qml @@ -96,11 +96,23 @@ PageProtocolBase { //- Install the latest version of SSHFS-Win. Choose the x64 or x86 installer according to your computer's architecture [https://github.com/billziss-gh/sshfs-win/releases]" onLinkActivated: Qt.openUrlExternally(link) - text:"In order to mount remote SFTP folder as local drive, perform following steps: + readonly property string windows_text: "In order to mount remote SFTP folder as local drive, perform following steps:
  • Install the latest version of WinFsp.
  • Install the latest version of SSHFS-Win. Choose the x64 or x86 installer according to your computer's architecture.
" + + readonly property string macos_text: "In order to mount remote SFTP folder as local folder, perform following steps: +
    +
  • Install the latest version of macFUSE.
  • +
" + + text: { + if (Qt.platform.os == "windows") return windows_text + else if (Qt.platform.os == "osx") return macos_text + else if (Qt.platform.os == "linux") return "" + else return "" + } } CheckBoxType { @@ -110,7 +122,7 @@ PageProtocolBase { x: 30 width: parent.width height: 21 - text: qsTr("Restore drive after restart") + text: qsTr("Restore drive when client starts") checked: logic.checkBoxSftpRestoreChecked onCheckedChanged: { logic.checkBoxSftpRestoreChecked = checked From 8e26da17593fd705fe02310a08dddb92584a4888 Mon Sep 17 00:00:00 2001 From: pokamest Date: Sun, 23 Jan 2022 15:25:53 -0800 Subject: [PATCH 06/20] Macos build fixes --- client/containers/containers_defs.cpp | 6 +++++- client/protocols/vpnprotocol.cpp | 4 +++- deploy/build_macos_notarized.sh | 2 +- service/service.pro | 6 +++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp index 63a00e0b..38d1ae68 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -148,7 +148,11 @@ bool ContainerProps::isWorkingOnPlatform(DockerContainer c) default: return false; } #elif defined (Q_OS_MAC) - return false; + switch (c) { + case DockerContainer::WireGuard: return false; + case DockerContainer::Ipsec: return false; + default: return true; + } #elif defined (Q_OS_ANDROID) switch (c) { diff --git a/client/protocols/vpnprotocol.cpp b/client/protocols/vpnprotocol.cpp index c64cff90..2d304cdf 100644 --- a/client/protocols/vpnprotocol.cpp +++ b/client/protocols/vpnprotocol.cpp @@ -103,12 +103,14 @@ QString VpnProtocol::vpnGateway() const VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject& configuration) { switch (container) { +#if defined(Q_OS_WINDOWS) + case DockerContainer::Ipsec: return new Ikev2Protocol(configuration); +#endif #if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration); case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration); case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration); case DockerContainer::WireGuard: return new WireguardProtocol(configuration); - case DockerContainer::Ipsec: return new Ikev2Protocol(configuration); #endif default: return nullptr; } diff --git a/deploy/build_macos_notarized.sh b/deploy/build_macos_notarized.sh index 7c7a9490..2133286b 100755 --- a/deploy/build_macos_notarized.sh +++ b/deploy/build_macos_notarized.sh @@ -64,7 +64,7 @@ echo "Packaging ..." #cd $DEPLOY_DIR -$QT_BIN_DIR/macdeployqt $OUT_APP_DIR/$APP_FILENAME -always-overwrite +$QT_BIN_DIR/macdeployqt $OUT_APP_DIR/$APP_FILENAME -always-overwrite -qmldir=$PROJECT_DIR cp -av $BUILD_DIR/service/server/$APP_NAME-service.app/Contents/macOS/$APP_NAME-service $BUNDLE_DIR/Contents/macOS cp -Rv $PROJECT_DIR/deploy/data/macos/* $BUNDLE_DIR/Contents/macOS rm -f $BUNDLE_DIR/Contents/macOS/post_install.sh $BUNDLE_DIR/Contents/macOS/post_uninstall.sh diff --git a/service/service.pro b/service/service.pro index e89166db..4c9a0536 100644 --- a/service/service.pro +++ b/service/service.pro @@ -4,7 +4,7 @@ include(common.pri) qtservice-uselib:SUBDIRS=buildlib SUBDIRS+=server - win32 { - SUBDIRS+=wireguard-service - } +} +win32 { + SUBDIRS+=wireguard-service } From 1a144da36da2728ed889177a3169c644e17f3073 Mon Sep 17 00:00:00 2001 From: pokamest Date: Mon, 24 Jan 2022 14:29:37 -0800 Subject: [PATCH 07/20] SFTP fixes for Macos --- client/client.pro | 1 + .../protocols/OtherProtocolsLogic.cpp | 87 +++++++++++++------ .../protocols/OtherProtocolsLogic.h | 6 +- .../ui/qml/Pages/Protocols/PageProtoSftp.qml | 5 +- 4 files changed, 71 insertions(+), 28 deletions(-) diff --git a/client/client.pro b/client/client.pro index cc88f4e8..28f11c42 100644 --- a/client/client.pro +++ b/client/client.pro @@ -200,6 +200,7 @@ linux:!android { } win32|macx|linux:!android { + DEFINES += AMNEZIA_DESKTOP HEADERS += \ ui/systemtray_notificationhandler.h \ diff --git a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp index 6c5a4315..a94391d5 100644 --- a/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp +++ b/client/ui/pages_logic/protocols/OtherProtocolsLogic.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "OtherProtocolsLogic.h" #include "core/servercontroller.h" @@ -41,17 +42,12 @@ void OtherProtocolsLogic::updateProtocolPage(const QJsonObject &config, DockerCo set_labelTftpPortText(config.value(config_key::port).toString()); set_labelTorWebSiteAddressText(config.value(config_key::site).toString()); + set_pushButtonSftpMountEnabled(true); } -//QJsonObject OtherProtocolsLogic::getProtocolConfigFromPage(QJsonObject oldConfig) -//{ - -//} - - -void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked() -{ #ifdef Q_OS_WINDOWS +QString OtherProtocolsLogic::getNextDriverLetter() const +{ QProcess drivesProc; drivesProc.start("wmic logicaldisk get caption"); drivesProc.waitForFinished(); @@ -68,53 +64,93 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked() if (letter == "C:") { // set err info qDebug() << "Can't find free drive letter"; - return; + return ""; + } + return letter; +} +#endif + +//QJsonObject OtherProtocolsLogic::getProtocolConfigFromPage(QJsonObject oldConfig) +//{ + +//} + + +void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked() +{ + QString mountPath; + QString cmd; + QString host = m_settings.serverCredentials(uiLogic()->selectedServerIndex).hostName; + + +#ifdef Q_OS_WINDOWS + mountPath = getNextDriverLetter() + ":"; + // QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3") + // .arg(labelTftpUserNameText()) + // .arg(labelTftpPortText()) + // .arg(labelTftpPasswordText()); + + cmd = "C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe"; +#elif defined AMNEZIA_DESKTOP + mountPath = QString("%1/sftp:%2:%3") + .arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)) + .arg(host) + .arg(labelTftpPortText()); + QDir dir(mountPath); + if (!dir.exists()){ + dir.mkpath(mountPath); } + cmd = "/usr/local/bin/sshfs"; +#endif +#ifdef AMNEZIA_DESKTOP set_pushButtonSftpMountEnabled(false); QProcess *p = new QProcess; m_sftpMountProcesses.append(p); p->setProcessChannelMode(QProcess::MergedChannels); - connect(p, &QProcess::readyRead, this, [this, p, letter](){ + connect(p, &QProcess::readyRead, this, [this, p, mountPath](){ QString s = p->readAll(); if (s.contains("The service sshfs has been started")) { - QDesktopServices::openUrl(QUrl("file:///" + letter + ":")); + QDesktopServices::openUrl(QUrl("file:///" + mountPath)); set_pushButtonSftpMountEnabled(true); } + qDebug() << s; }); -// QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3") -// .arg(labelTftpUserNameText()) -// .arg(labelTftpPortText()) -// .arg(labelTftpPasswordText()); - p->setProgram("C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe"); - QString host = m_settings.serverCredentials(uiLogic()->selectedServerIndex).hostName; + p->setProgram(cmd); + QString args = QString( - "%1@%2:/ %3: " + "%1@%2:/ %3 " "-o port=%4 " "-f " - "-o reconnect" - "-orellinks " - "-ofstypename=SSHFS " + "-o reconnect " + "-o rellinks " + "-o fstypename=SSHFS " "-o ssh_command=/usr/bin/ssh.exe " - "-oUserKnownHostsFile=/dev/null " - "-oStrictHostKeyChecking=no " + "-o UserKnownHostsFile=/dev/null " + "-o StrictHostKeyChecking=no " "-o password_stdin") .arg(labelTftpUserNameText()) .arg(host) - .arg(letter) + .arg(mountPath) .arg(labelTftpPortText()); - p->setNativeArguments(args); +// args.replace("\n", " "); +// args.replace("\r", " "); +//#ifndef Q_OS_WIN +// args.replace("reconnect-orellinks", ""); +//#endif + p->setArguments(args.split(" ", QString::SkipEmptyParts)); p->start(); p->waitForStarted(50); if (p->state() != QProcess::Running) { qDebug() << "onPushButtonSftpMountDriveClicked process not started"; + qDebug() << args; } else { p->write((labelTftpPasswordText() + "\n").toUtf8()); @@ -123,7 +159,6 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked() //qDebug().noquote() << "onPushButtonSftpMountDriveClicked" << args; set_pushButtonSftpMountEnabled(true); - #endif } diff --git a/client/ui/pages_logic/protocols/OtherProtocolsLogic.h b/client/ui/pages_logic/protocols/OtherProtocolsLogic.h index dc099186..8639ba54 100644 --- a/client/ui/pages_logic/protocols/OtherProtocolsLogic.h +++ b/client/ui/pages_logic/protocols/OtherProtocolsLogic.h @@ -34,9 +34,13 @@ private: Settings m_settings; UiLogic *m_uiLogic; -#ifdef Q_OS_WINDOWS +#ifdef AMNEZIA_DESKTOP QList m_sftpMountProcesses; #endif +#ifdef Q_OS_WINDOWS + QString getNextDriverLetter() const; +#endif + }; #endif // OTHER_PROTOCOLS_LOGIC_H diff --git a/client/ui/qml/Pages/Protocols/PageProtoSftp.qml b/client/ui/qml/Pages/Protocols/PageProtoSftp.qml index b8b7fedc..45d10de5 100644 --- a/client/ui/qml/Pages/Protocols/PageProtoSftp.qml +++ b/client/ui/qml/Pages/Protocols/PageProtoSftp.qml @@ -16,7 +16,7 @@ PageProtocolBase { Caption { id: caption - text: qsTr("SFTF settings") + text: qsTr("SFTP settings") } Rectangle { @@ -105,6 +105,7 @@ PageProtocolBase { readonly property string macos_text: "In order to mount remote SFTP folder as local folder, perform following steps:
  • Install the latest version of macFUSE.
  • +
  • Install the latest version of SSHFS.
" text: { @@ -117,6 +118,7 @@ PageProtocolBase { CheckBoxType { id: check_persist + visible: false anchors.bottom: pb_mount.top anchors.bottomMargin: 10 x: 30 @@ -134,6 +136,7 @@ PageProtocolBase { BlueButtonType { id: pb_mount + visible: GC.isDesktop() enabled: logic.pushButtonSftpMountEnabled anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom From 95fe09489cd2c187849f4ed80f47aa7d480238a6 Mon Sep 17 00:00:00 2001 From: pokamest Date: Fri, 28 Jan 2022 16:03:21 +0300 Subject: [PATCH 08/20] Vpn and wizard pages fixes --- client/resources.qrc | 2 + client/ui/pages.h | 2 +- .../ui/pages_logic/ServerContainersLogic.cpp | 12 ++ client/ui/qml/Controls/RichLabelType.qml | 17 ++ client/ui/qml/Pages/PageAbout.qml | 80 +++++++++ client/ui/qml/Pages/PageAppSetting.qml | 149 ++++++++------- client/ui/qml/Pages/PageServerSettings.qml | 14 +- client/ui/qml/Pages/PageSetupWizard.qml | 169 +++++++++--------- .../ui/qml/Pages/PageSetupWizardHighLevel.qml | 138 ++++++++------ .../ui/qml/Pages/PageSetupWizardLowLevel.qml | 79 ++++---- .../qml/Pages/PageSetupWizardMediumLevel.qml | 74 ++++---- .../ui/qml/Pages/PageSetupWizardVPNMode.qml | 80 +++++---- client/ui/qml/Pages/PageVPN.qml | 29 ++- .../ui/qml/Pages/Protocols/PageProtoSftp.qml | 14 +- 14 files changed, 550 insertions(+), 309 deletions(-) create mode 100644 client/ui/qml/Controls/RichLabelType.qml create mode 100644 client/ui/qml/Pages/PageAbout.qml diff --git a/client/resources.qrc b/client/resources.qrc index b7e499fe..407fe227 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -142,5 +142,7 @@ images/connected.png images/disconnected.png ui/qml/Pages/PageQrDecoder.qml + ui/qml/Pages/PageAbout.qml + ui/qml/Controls/RichLabelType.qml diff --git a/client/ui/pages.h b/client/ui/pages.h index 69067e7f..b111679a 100644 --- a/client/ui/pages.h +++ b/client/ui/pages.h @@ -24,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn, Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress, GeneralSettings, AppSettings, NetworkSettings, ServerSettings, ServerContainers, ServersList, ShareConnection, Sites, - ProtocolSettings, ProtocolShare, QrDecoder}; + ProtocolSettings, ProtocolShare, QrDecoder, About}; Q_ENUM_NS(Page) static void declareQmlPageEnum() { diff --git a/client/ui/pages_logic/ServerContainersLogic.cpp b/client/ui/pages_logic/ServerContainersLogic.cpp index dbcc3b61..e01e1bac 100644 --- a/client/ui/pages_logic/ServerContainersLogic.cpp +++ b/client/ui/pages_logic/ServerContainersLogic.cpp @@ -12,6 +12,9 @@ #include #include "../uilogic.h" +#include "../pages_logic/VpnLogic.h" +#include "vpnconnection.h" + ServerContainersLogic::ServerContainersLogic(UiLogic *logic, QObject *parent): PageLogicBase(logic, parent) @@ -42,8 +45,17 @@ void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c, void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c) { + if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == c) return; + m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c); uiLogic()->onUpdateAllPages(); + + if (uiLogic()->selectedServerIndex != m_settings.defaultServerIndex()) return; + if (!uiLogic()->m_vpnConnection) return; + if (!uiLogic()->m_vpnConnection->isConnected()) return; + + uiLogic()->vpnLogic()->onDisconnect(); + uiLogic()->vpnLogic()->onConnect(); } void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c) diff --git a/client/ui/qml/Controls/RichLabelType.qml b/client/ui/qml/Controls/RichLabelType.qml new file mode 100644 index 00000000..f7dfdeed --- /dev/null +++ b/client/ui/qml/Controls/RichLabelType.qml @@ -0,0 +1,17 @@ +import QtQuick 2.12 + +LabelType { + id: label_connection_code + width: parent.width - 60 + x: 30 + font.pixelSize: 14 + textFormat: Text.RichText + onLinkActivated: Qt.openUrlExternally(link) + + MouseArea { + anchors.fill: parent + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + acceptedButtons: Qt.NoButton + } +} + diff --git a/client/ui/qml/Pages/PageAbout.qml b/client/ui/qml/Pages/PageAbout.qml new file mode 100644 index 00000000..7bf406d3 --- /dev/null +++ b/client/ui/qml/Pages/PageAbout.qml @@ -0,0 +1,80 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import PageEnum 1.0 +import "./" +import "../Controls" +import "../Config" + +PageBase { + id: root + page: PageEnum.About + + BackButton { + id: back_from_start + } + + Caption { + id: caption + font.pixelSize: 22 + text: qsTr("About Amnezia") + } + + RichLabelType { + id: label_about + anchors.top: caption.bottom + + text: qsTr("AmneziaVPN is opensource software, it's free forever. Our goal is to make the best VPN client in the world. + +") + } + + Caption { + id: caption2 + anchors.topMargin: 20 + font.pixelSize: 22 + text: qsTr("Support") + anchors.top: label_about.bottom + } + + RichLabelType { + id: label_support + anchors.top: caption2.bottom + + text: qsTr("Have questions? You can get support by: +") + } + + Caption { + id: caption3 + anchors.topMargin: 20 + font.pixelSize: 22 + text: qsTr("Donate") + anchors.top: label_support.bottom + } + + RichLabelType { + id: label_donate + anchors.top: caption3.bottom + + text: qsTr("Please support Amnezia project by donation, we really need it now more than ever. + +") + } + + Logo { + id: logo + anchors.bottom: parent.bottom + } +} diff --git a/client/ui/qml/Pages/PageAppSetting.qml b/client/ui/qml/Pages/PageAppSetting.qml index 8be9274c..497471b4 100644 --- a/client/ui/qml/Pages/PageAppSetting.qml +++ b/client/ui/qml/Pages/PageAppSetting.qml @@ -1,5 +1,6 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.15 import PageEnum 1.0 import "./" import "../Controls" @@ -14,75 +15,97 @@ PageBase { id: back } Caption { + id: caption text: qsTr("Application Settings") } - CheckBoxType { - x: 30 - y: 140 - width: 211 - height: 31 - text: qsTr("Auto connect") - checked: AppSettingsLogic.checkBoxAutoConnectChecked - onCheckedChanged: { - AppSettingsLogic.checkBoxAutoConnectChecked = checked - AppSettingsLogic.onCheckBoxAutoconnectToggled(checked) - } - } - CheckBoxType { - x: 30 - y: 100 - width: 211 - height: 31 - text: qsTr("Auto start") - checked: AppSettingsLogic.checkBoxAutostartChecked - onCheckedChanged: { - AppSettingsLogic.checkBoxAutostartChecked = checked - AppSettingsLogic.onCheckBoxAutostartToggled(checked) - } - } - CheckBoxType { - x: 30 - y: 180 - width: 211 - height: 31 - text: qsTr("Start minimized") - checked: AppSettingsLogic.checkBoxStartMinimizedChecked - onCheckedChanged: { - AppSettingsLogic.checkBoxStartMinimizedChecked = checked - AppSettingsLogic.onCheckBoxStartMinimizedToggled(checked) - } - } - LabelType { - x: 30 - y: 240 - width: 281 - height: 21 - text: AppSettingsLogic.labelVersionText - } - BlueButtonType { - x: 30 - y: 280 - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - 40 - height: 41 - text: qsTr("Check for updates") - onClicked: { - Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") - } - } - BlueButtonType { - x: 30 - y: 340 - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - 40 - height: 41 - text: qsTr("Open logs folder") - onClicked: { - AppSettingsLogic.onPushButtonOpenLogsClicked() + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: logo.top + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + CheckBoxType { + Layout.fillWidth: true + text: qsTr("Auto connect") + checked: AppSettingsLogic.checkBoxAutoConnectChecked + onCheckedChanged: { + AppSettingsLogic.checkBoxAutoConnectChecked = checked + AppSettingsLogic.onCheckBoxAutoconnectToggled(checked) + } + } + CheckBoxType { + Layout.fillWidth: true + text: qsTr("Auto start") + checked: AppSettingsLogic.checkBoxAutostartChecked + onCheckedChanged: { + AppSettingsLogic.checkBoxAutostartChecked = checked + AppSettingsLogic.onCheckBoxAutostartToggled(checked) + } + } + CheckBoxType { + Layout.fillWidth: true + text: qsTr("Start minimized") + checked: AppSettingsLogic.checkBoxStartMinimizedChecked + onCheckedChanged: { + AppSettingsLogic.checkBoxStartMinimizedChecked = checked + AppSettingsLogic.onCheckBoxStartMinimizedToggled(checked) + } + } + LabelType { + Layout.fillWidth: true + Layout.topMargin: 15 + text: AppSettingsLogic.labelVersionText + } + BlueButtonType { + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: qsTr("Check for updates") + onClicked: { + Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") + } + } + BlueButtonType { + Layout.fillWidth: true + Layout.topMargin: 15 + Layout.preferredHeight: 41 + text: qsTr("Open logs folder") + onClicked: { + AppSettingsLogic.onPushButtonOpenLogsClicked() + } + } + + BlueButtonType { + Layout.fillWidth: true + Layout.topMargin: 15 + Layout.preferredHeight: 41 + text: qsTr("Export logs") + onClicked: { + AppSettingsLogic.onPushButtonOpenLogsClicked() + } + } + } } Logo { + id: logo anchors.bottom: parent.bottom } } diff --git a/client/ui/qml/Pages/PageServerSettings.qml b/client/ui/qml/Pages/PageServerSettings.qml index 465d1348..143f5374 100644 --- a/client/ui/qml/Pages/PageServerSettings.qml +++ b/client/ui/qml/Pages/PageServerSettings.qml @@ -28,7 +28,16 @@ PageBase { horizontalAlignment: Text.AlignHCenter text: ServerSettingsLogic.labelCurrentVpnProtocolText } - LabelType { +// LabelType { +// anchors.horizontalCenter: parent.horizontalCenter +// y: 120 +// width: 341 +// height: 31 +// font.pixelSize: 20 +// horizontalAlignment: Text.AlignHCenter +// text: ServerSettingsLogic.labelServerText +// } + TextFieldType { anchors.horizontalCenter: parent.horizontalCenter y: 120 width: 341 @@ -36,7 +45,10 @@ PageBase { font.pixelSize: 20 horizontalAlignment: Text.AlignHCenter text: ServerSettingsLogic.labelServerText + readOnly: true + background: Item {} } + LabelType { anchors.horizontalCenter: parent.horizontalCenter y: 530 diff --git a/client/ui/qml/Pages/PageSetupWizard.qml b/client/ui/qml/Pages/PageSetupWizard.qml index 00144386..8a13d667 100644 --- a/client/ui/qml/Pages/PageSetupWizard.qml +++ b/client/ui/qml/Pages/PageSetupWizard.qml @@ -1,5 +1,6 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.15 import PageEnum 1.0 import "./" import "../Controls" @@ -14,93 +15,99 @@ PageBase { id: back_from_setup_wizard } Caption { + id: caption text: qsTr("Setup your server to use VPN") } - Item { - x: 10 - y: 70 - width: 361 - height: 561 - LabelType { - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignTop - text: qsTr("I'm living in country with high censorship level. Many of foreign web sites and VPNs blocked by my government. I want to setup reliable VPN, which is invisible for government.") - wrapMode: Text.Wrap - x: 30 - y: 40 - width: 321 - height: 121 - } - LabelType { - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignTop - text: qsTr("I'm living in country with medium censorship level. Some web sites blocked by my government, but VPNs are not blocked at all. I want to setup flexible solution.") - wrapMode: Text.Wrap - x: 30 - y: 210 - width: 321 - height: 121 - } - LabelType { - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignTop - text: qsTr("I just want to improve my privacy in internet.") - wrapMode: Text.Wrap - x: 30 - y: 360 - width: 321 - height: 121 - } - BlueButtonType { - anchors.horizontalCenter: parent.horizontalCenter - y: 490 - width: 321 - height: 40 - text: qsTr("Next") - onClicked: { - if (radioButton_setup_wizard_high.checked) { - UiLogic.goToPage(PageEnum.WizardHigh); - } else if (radioButton_setup_wizard_medium.checked) { - UiLogic.goToPage(PageEnum.WizardMedium); - } else if (radioButton_setup_wizard_low.checked) { - UiLogic.goToPage(PageEnum.WizardLow); + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + RadioButtonType { + id: radioButton_setup_wizard_high + Layout.fillWidth: true + text: qsTr("High censorship level") + checked: WizardLogic.radioButtonHighChecked + onCheckedChanged: { + WizardLogic.radioButtonHighChecked = checked } } - } - RadioButtonType { - id: radioButton_setup_wizard_high - x: 10 - y: 10 - width: 331 - height: 25 - text: qsTr("High censorship level") - checked: WizardLogic.radioButtonHighChecked - onCheckedChanged: { - WizardLogic.radioButtonHighChecked = checked + LabelType { + Layout.fillWidth: true + Layout.leftMargin: 25 + verticalAlignment: Text.AlignTop + text: qsTr("I'm living in a country with a high censorship level. Many of the foreign websites and VPNs are blocked by my government. I want to setup a reliable VPN, which can not be detected by my internet provider and my government. +OpenVPN and ShadowSocks over Cloak (VPN obfuscation) profiles will be installed.\n") } - } - RadioButtonType { - id: radioButton_setup_wizard_medium - x: 10 - y: 330 - width: 331 - height: 25 - text: qsTr("Low censorship level") - checked: WizardLogic.radioButtonLowChecked - onCheckedChanged: { - WizardLogic.radioButtonLowChecked = checked + + + RadioButtonType { + id: radioButton_setup_wizard_medium + Layout.fillWidth: true + text: qsTr("Medium censorship level") + checked: WizardLogic.radioButtonMediumChecked + onCheckedChanged: { + WizardLogic.radioButtonMediumChecked = checked + } } - } - RadioButtonType { - id: radioButton_setup_wizard_low - x: 10 - y: 180 - width: 331 - height: 25 - text: qsTr("Medium censorship level") - checked: WizardLogic.radioButtonMediumChecked - onCheckedChanged: { - WizardLogic.radioButtonMediumChecked = checked + LabelType { + Layout.fillWidth: true + Layout.leftMargin: 25 + verticalAlignment: Text.AlignTop + text: qsTr("I'm living in a country with a medium censorship level. Some websites are blocked by my government, but VPNs are not blocked at all. I want to setup a flexible solution. +OpenVPN over ShadowSocks profile will be installed.\n") + } + + + RadioButtonType { + id: radioButton_setup_wizard_low + Layout.fillWidth: true + text: qsTr("Low censorship level") + checked: WizardLogic.radioButtonLowChecked + onCheckedChanged: { + WizardLogic.radioButtonLowChecked = checked + } + } + LabelType { + Layout.fillWidth: true + Layout.leftMargin: 25 + verticalAlignment: Text.AlignTop + text: qsTr("I want to improve my privacy on the internet. +OpenVPN profile will be installed.\n") + } + + + BlueButtonType { + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: qsTr("Next") + onClicked: { + if (radioButton_setup_wizard_high.checked) { + UiLogic.goToPage(PageEnum.WizardHigh, false); + } else if (radioButton_setup_wizard_medium.checked) { + UiLogic.goToPage(PageEnum.WizardMedium, false); + } else if (radioButton_setup_wizard_low.checked) { + UiLogic.goToPage(PageEnum.WizardLow, false); + } + } } } } diff --git a/client/ui/qml/Pages/PageSetupWizardHighLevel.qml b/client/ui/qml/Pages/PageSetupWizardHighLevel.qml index 47a13e5b..1729aff0 100644 --- a/client/ui/qml/Pages/PageSetupWizardHighLevel.qml +++ b/client/ui/qml/Pages/PageSetupWizardHighLevel.qml @@ -1,5 +1,6 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.15 import PageEnum 1.0 import "./" import "../Controls" @@ -14,69 +15,90 @@ PageBase { id: back_from_setup_wizard } Caption { + id: caption text: qsTr("Setup Wizard") } - Item { - x: 10 - y: 70 - width: 361 - height: 561 - LabelType { - x: 30 - y: 10 - width: 321 - height: 321 - text: qsTr("AmneziaVPN will install VPN protocol which is not visible for your internet provider and government firewall. Your VPN connection will be detected by your provider as regular web traffic to particular web site.\n\nYou SHOULD set this web site address to some foreign web site which is updatesnot blocked by your internet provider. Other words you need to type below some foreign web site address which is accessible without VPN.\n\nPlease note, this protocol still does not support export connection profile to mobile devices. Keep for updates.") - } - LabelType { - x: 30 - y: 400 - width: 321 - height: 71 - text: qsTr("OpenVPN over Cloak (VPN obfuscation) profile will be installed") - } - LabelType { - x: 30 - y: 330 - width: 291 - height: 21 - text: qsTr("Type web site address for mask") - } - TextFieldType { - id: website_masking - x: 30 - y: 360 - width: 301 - height: 41 - text: WizardLogic.lineEditHighWebsiteMaskingText - onEditingFinished: { - let _text = website_masking.text - _text.replace("http://", ""); - _text.replace("https://", ""); - if (!_text) { - return + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + LabelType { + Layout.fillWidth: true + verticalAlignment: Text.AlignTop + text: qsTr("AmneziaVPN will install a VPN protocol which is not visible to your internet provider and government firewall. Your VPN connection will be seen by your internet provider as regular web traffic to a particular website. + +You SHOULD set this website address to some foreign website which is not blocked by your internet provider. In other words, you need to type some foreign website address which is accessible to you without a VPN.") + } + + LabelType { + Layout.fillWidth: true + Layout.topMargin: 15 + verticalAlignment: Text.AlignTop + text: qsTr("Type another web site address for masking or keep it by default. Your internet provider will think you working on this web site when you connected to VPN.") + } + + TextFieldType { + id: website_masking + Layout.fillWidth: true + text: WizardLogic.lineEditHighWebsiteMaskingText + onEditingFinished: { + let _text = website_masking.text + _text.replace("http://", ""); + _text.replace("https://", ""); + if (!_text) { + return + } + _text = _text.split("/").first(); + WizardLogic.lineEditHighWebsiteMaskingText = _text } - _text = _text.split("/").first(); - WizardLogic.lineEditHighWebsiteMaskingText = _text - } - onAccepted: { - next_button.clicked() - } - } - BlueButtonType { - id: next_button - x: 30 - y: 490 - width: 301 - height: 40 - text: qsTr("Next") - onClicked: { - let domain = website_masking.text; - if (!domain || !domain.includes(".")) { - return + onAccepted: { + next_button.clicked() } - UiLogic.goToPage(PageEnum.WizardVpnMode) } + + LabelType { + Layout.fillWidth: true + Layout.topMargin: 15 + verticalAlignment: Text.AlignTop + text: qsTr("OpenVPN and ShadowSocks over Cloak (VPN obfuscation) profiles will be installed. + +This protocol support exporting connection profiles to mobile devices by exporting ShadowSocks and Cloak configs (you should launch the 3rd party open source VPN client - ShadowSocks VPN and install Cloak plugin).") + } + BlueButtonType { + id: next_button + Layout.fillWidth: true + Layout.topMargin: 15 + Layout.preferredHeight: 41 + text: qsTr("Next") + onClicked: { + let domain = website_masking.text; + if (!domain || !domain.includes(".")) { + return + } + UiLogic.goToPage(PageEnum.WizardVpnMode, false) + } + } + } + } } diff --git a/client/ui/qml/Pages/PageSetupWizardLowLevel.qml b/client/ui/qml/Pages/PageSetupWizardLowLevel.qml index 21ed6686..8b7ee744 100644 --- a/client/ui/qml/Pages/PageSetupWizardLowLevel.qml +++ b/client/ui/qml/Pages/PageSetupWizardLowLevel.qml @@ -1,5 +1,6 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.15 import PageEnum 1.0 import "./" import "../Controls" @@ -14,38 +15,56 @@ PageBase { id: back_from_setup_wizard } Caption { + id: caption text: qsTr("Setup Wizard") } - Item { - x: 10 - y: 70 - width: 361 - height: 561 - LabelType { - x: 30 - y: 10 - width: 321 - height: 341 - verticalAlignment: Text.AlignTop - text: qsTr('AmneziaVPN will install OpenVPN protocol with public/private key pairs generated on server and client sides. You can also configure connection on your mobile device by copying exported ".ovpn" file to your device and setting up official OpenVPN client. We recommend do not use messengers for sending connection profile - it contains VPN private keys.') - } - LabelType { - x: 30 - y: 400 - width: 321 - height: 71 - text: qsTr('OpenVPN profile will be installed') - verticalAlignment: Text.AlignBottom - } - BlueButtonType { - id: next_button - x: 30 - y: 490 - width: 301 - height: 40 - text: qsTr("Start configuring") - onClicked: { - WizardLogic.onPushButtonLowFinishClicked() + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + LabelType { + Layout.fillWidth: true + verticalAlignment: Text.AlignTop + text: qsTr('AmneziaVPN will install the OpenVPN protocol with public/private key pairs generated on both server and client sides. + +You can also configure the connection on your mobile device by copying the exported ".ovpn" file to your device, and setting up the official OpenVPN client. + +We recommend not to use messaging applications for sending the connection profile - it contains VPN private keys.') + } + LabelType { + Layout.fillWidth: true + Layout.topMargin: 15 + text: qsTr('OpenVPN profile will be installed') + verticalAlignment: Text.AlignBottom + } + BlueButtonType { + id: next_button + Layout.fillWidth: true + Layout.topMargin: 15 + Layout.preferredHeight: 41 + text: qsTr("Start configuring") + onClicked: { + WizardLogic.onPushButtonLowFinishClicked() + } } } } diff --git a/client/ui/qml/Pages/PageSetupWizardMediumLevel.qml b/client/ui/qml/Pages/PageSetupWizardMediumLevel.qml index 0765aa5e..01721cdc 100644 --- a/client/ui/qml/Pages/PageSetupWizardMediumLevel.qml +++ b/client/ui/qml/Pages/PageSetupWizardMediumLevel.qml @@ -1,5 +1,6 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.15 import PageEnum 1.0 import "./" import "../Controls" @@ -14,38 +15,51 @@ PageBase { id: back_from_setup_wizard } Caption { + id: caption text: qsTr("Setup Wizard") } - Item { - x: 10 - y: 70 - width: 361 - height: 561 - LabelType { - x: 30 - y: 10 - width: 321 - height: 341 - verticalAlignment: Text.AlignTop - text: qsTr('AmneziaVPN will install VPN protocol which is difficult to detect by your internet provider and government firewall (but possible). In most cases, this is the most suitable protocol. This protocol is faster compared to the VPN protocols with "web traffic masking".\n\nThis protocol support export connection profile to mobile devices using QR code (you should launch 3rd party opensource VPN client - ShadowSocks VPN).') - } - LabelType { - x: 30 - y: 400 - width: 321 - height: 71 - text: qsTr('OpenVPN over ShadowSocks profile will be installed') - verticalAlignment: Text.AlignBottom - } - BlueButtonType { - id: next_button - x: 30 - y: 490 - width: 301 - height: 40 - text: qsTr("Next") - onClicked: { - UiLogic.goToPage(PageEnum.WizardVpnMode) + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + LabelType { + Layout.fillWidth: true + verticalAlignment: Text.AlignTop + text: qsTr('AmneziaVPN will install a VPN protocol which is difficult to detect by your internet provider and government firewall (but possible). In most cases, this is the most suitable protocol. This protocol is faster compared to the VPN protocols with "VPN masking".\n\nThis protocol supports exporting connection profiles to mobile devices by using QR codes (you should launch the 3rd party open source VPN client - ShadowSocks VPN).') + } + LabelType { + Layout.fillWidth: true + Layout.topMargin: 15 + text: qsTr('OpenVPN over ShadowSocks profile will be installed') + } + BlueButtonType { + id: next_button + Layout.fillWidth: true + Layout.topMargin: 15 + Layout.preferredHeight: 41 + text: qsTr("Next") + onClicked: { + UiLogic.goToPage(PageEnum.WizardVpnMode, false) + } } } } diff --git a/client/ui/qml/Pages/PageSetupWizardVPNMode.qml b/client/ui/qml/Pages/PageSetupWizardVPNMode.qml index 37aca119..2445819e 100644 --- a/client/ui/qml/Pages/PageSetupWizardVPNMode.qml +++ b/client/ui/qml/Pages/PageSetupWizardVPNMode.qml @@ -1,5 +1,6 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.15 import PageEnum 1.0 import "./" import "../Controls" @@ -14,40 +15,57 @@ PageBase { id: back_from_setup_wizard } Caption { + id: caption text: qsTr("Setup Wizard") } - Item { - x: 10 - y: 70 - width: 361 - height: 561 - CheckBoxType { - x: 30 - y: 350 - width: 301 - height: 71 - text: qsTr('Turn on mode "VPN for selected sites"') - checked: WizardLogic.checkBoxVpnModeChecked - onCheckedChanged: { - WizardLogic.checkBoxVpnModeChecked = checked + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + LabelType { + Layout.fillWidth: true + verticalAlignment: Text.AlignTop + text: qsTr('Optional.\n +You can enable VPN mode "For selected sites" and add blocked sites you need to visit manually. If you will choose this option, you will need add every bloked site you want to visit to the access list. You may switch between modes later.\n\nPlease note, you should add addresses to the list after VPN connection established. You may add any domain, URL or IP address, it will be resolved to IP address.') } - } - LabelType { - x: 30 - y: 10 - width: 321 - height: 341 - text: qsTr('Optional.\n\nWe recommend to enable VPN mode "For selected sites" and add blocked sites you need to visit manually. If you will choose this option, you will need add every bloked site you want to visit to the access list. You may switch between modes later.\n\nPlease note, you should add addresses to the list after VPN connection established. You may add any domain, URL or IP address, it will be resolved to IP address.') - } - BlueButtonType { - id: vpn_mode_finish - x: 30 - y: 490 - width: 301 - height: 40 - text: qsTr("Start configuring") - onClicked: { - WizardLogic.onPushButtonVpnModeFinishClicked() + + CheckBoxType { + Layout.fillWidth: true + text: qsTr('Turn on mode "VPN for selected sites"') + checked: WizardLogic.checkBoxVpnModeChecked + onCheckedChanged: { + WizardLogic.checkBoxVpnModeChecked = checked + } + } + + BlueButtonType { + id: vpn_mode_finish + Layout.fillWidth: true + Layout.topMargin: 15 + Layout.preferredHeight: 41 + text: qsTr("Start configuring") + onClicked: { + WizardLogic.onPushButtonVpnModeFinishClicked() + } } } } diff --git a/client/ui/qml/Pages/PageVPN.qml b/client/ui/qml/Pages/PageVPN.qml index 6158e8ea..e4bbaecb 100644 --- a/client/ui/qml/Pages/PageVPN.qml +++ b/client/ui/qml/Pages/PageVPN.qml @@ -22,7 +22,7 @@ PageBase { LabelType { x: 10 - y: 5 + y: 10 width: 100 height: 21 text: VpnLogic.labelVersionText @@ -30,6 +30,33 @@ PageBase { font.pixelSize: 12 } + BasicButtonType { + y: 10 + anchors.horizontalCenter: parent.horizontalCenter + height: 21 + background: Item {} + + + contentItem: Text { + anchors.fill: parent + font.family: "Lato" + font.styleName: "normal" + font.pixelSize: 18 + font.underline: true + + text: qsTr("Donate") + color: "#D4D4D4" + + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + onClicked: { + UiLogic.goToPage(PageEnum.About) + } + } + ImageButtonType { x: parent.width - 40 y: 10 diff --git a/client/ui/qml/Pages/Protocols/PageProtoSftp.qml b/client/ui/qml/Pages/Protocols/PageProtoSftp.qml index 45d10de5..2ad5436b 100644 --- a/client/ui/qml/Pages/Protocols/PageProtoSftp.qml +++ b/client/ui/qml/Pages/Protocols/PageProtoSftp.qml @@ -77,24 +77,12 @@ PageProtocolBase { } } - LabelType { + RichLabelType { anchors.bottom: check_persist.top anchors.bottomMargin: 10 width: parent.width - 60 x: 30 font.pixelSize: 14 - textFormat: Text.RichText - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - } - -// text: "In order to mount remote SFTP folder as local drive, perform following steps: -//- Install the latest version of WinFsp [https://github.com/billziss-gh/winfsp/releases/latest]. -//- Install the latest version of SSHFS-Win. Choose the x64 or x86 installer according to your computer's architecture [https://github.com/billziss-gh/sshfs-win/releases]" - onLinkActivated: Qt.openUrlExternally(link) readonly property string windows_text: "In order to mount remote SFTP folder as local drive, perform following steps: