From e9abb6f1e202653a8ccfef3b4ae83e760c21b1bd Mon Sep 17 00:00:00 2001 From: MrMirDan <58086007+MrMirDan@users.noreply.github.com> Date: Fri, 1 Aug 2025 06:36:30 +0300 Subject: [PATCH 01/40] fix: mirror links (#1760) * Instructions links * amnezia free feature link * trying fix api instructions page issue * androidTV link fix * tv link fix 2 --- client/ui/models/api/apiServicesModel.cpp | 2 +- client/ui/models/languageModel.cpp | 10 ++++++++++ client/ui/models/languageModel.h | 1 + .../qml/Pages2/PageSettingsApiInstructions.qml | 16 ++++++++-------- .../qml/Pages2/PageSetupWizardApiServiceInfo.qml | 2 +- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/client/ui/models/api/apiServicesModel.cpp b/client/ui/models/api/apiServicesModel.cpp index b893096a..d3155292 100644 --- a/client/ui/models/api/apiServicesModel.cpp +++ b/client/ui/models/api/apiServicesModel.cpp @@ -112,7 +112,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const } else { return tr("VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. " "Other sites will be opened from your real IP address, " - "more details on the website."); + "more details on the website."); } } case PriceRole: { diff --git a/client/ui/models/languageModel.cpp b/client/ui/models/languageModel.cpp index 09755e06..1f9fa678 100644 --- a/client/ui/models/languageModel.cpp +++ b/client/ui/models/languageModel.cpp @@ -110,3 +110,13 @@ QString LanguageModel::getCurrentSiteUrl(const QString &path) default: return QString("https://amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path))); } } + +QString LanguageModel::getCurrentDocsUrl(const QString &path) +{ + auto language = static_cast(getCurrentLanguageIndex()); + switch (language) { + case LanguageSettings::AvailableLanguageEnum::Russian: + return "https://storage.googleapis.com/amnezia/docs" + (path.isEmpty() ? "" : (QString("?m-path=/%1").arg(path))); + default: return QString("https://docs.amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path))); + } +} diff --git a/client/ui/models/languageModel.h b/client/ui/models/languageModel.h index d1a2e7d5..4cd68ca6 100644 --- a/client/ui/models/languageModel.h +++ b/client/ui/models/languageModel.h @@ -60,6 +60,7 @@ public slots: int getLineHeightAppend(); QString getCurrentLanguageName(); QString getCurrentSiteUrl(const QString &path = ""); + QString getCurrentDocsUrl(const QString &path = ""); signals: void updateTranslations(const QLocale &locale); diff --git a/client/ui/qml/Pages2/PageSettingsApiInstructions.qml b/client/ui/qml/Pages2/PageSettingsApiInstructions.qml index 9b325b82..49802100 100644 --- a/client/ui/qml/Pages2/PageSettingsApiInstructions.qml +++ b/client/ui/qml/Pages2/PageSettingsApiInstructions.qml @@ -20,49 +20,49 @@ PageType { id: windows readonly property string title: qsTr("Windows") - readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#windows") + readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#windows") } QtObject { id: macos readonly property string title: qsTr("macOS") - readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#macos") + readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#macos") } QtObject { id: android readonly property string title: qsTr("Android") - readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#android") + readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#android") } QtObject { id: androidTv readonly property string title: qsTr("AndroidTV") - readonly property string link: qsTr("https://docs.amnezia.org/ru/documentation/instructions/android_tv_connect/") + readonly property string link: qsTr("documentation/instructions/android_tv_connect/") } QtObject { id: ios readonly property string title: qsTr("iOS") - readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#ios") + readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#ios") } QtObject { id: linux readonly property string title: qsTr("Linux") - readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#linux") + readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#linux") } QtObject { id: routers readonly property string title: qsTr("Routers") - readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#routers") + readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#routers") } property list instructionsModel: [ @@ -114,7 +114,7 @@ PageType { rightImageSource: "qrc:/images/controls/external-link.svg" clickedFunction: function() { - Qt.openUrlExternally(link) + Qt.openUrlExternally(LanguageModel.getCurrentDocsUrl(link)) } } diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml index 30128de6..cfc07fd1 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml @@ -104,7 +104,7 @@ PageType { textFormat: Text.RichText text: { var text = ApiServicesModel.getSelectedServiceData("features") - return text.replace("%1", LanguageModel.getCurrentSiteUrl()) + return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")) } MouseArea { From 174e85a20a1464a813ce2b0359f91f1c5c12fb6d Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 07:36:52 +0400 Subject: [PATCH 02/40] fix: not restoring parameters for open vpn after scanning server (#1759) * added lines for restoring settings when scanning server for OpenVPN, OpenVPN over Cloak and OpenVPN over SS protocols * minor fix * added functionality to restore config for multiprotocol configsCloak and Shadowsocks --- client/ui/controllers/installController.cpp | 97 ++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp index d7f9dfbc..04b06eaf 100755 --- a/client/ui/controllers/installController.cpp +++ b/client/ui/controllers/installController.cpp @@ -403,9 +403,19 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia QJsonObject config; Proto mainProto = ContainerProps::defaultProtocol(container); const auto &protocols = ContainerProps::protocolsForContainer(container); + for (const auto &protocol : protocols) { QJsonObject containerConfig; - if (protocol == mainProto) { + + // for Multiprotocols (OpenVPN over SS, OpenVPN over Cloak) + bool shouldProcessProtocol = false; + if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) { + shouldProcessProtocol = true; + } else { + shouldProcessProtocol = (protocol == mainProto); + } + + if (shouldProcessProtocol) { containerConfig.insert(config_key::port, port); containerConfig.insert(config_key::transport_proto, transportProto); @@ -550,14 +560,97 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia qDebug() << siteName; containerConfig.insert(config_key::site, siteName); + } else if (protocol == Proto::OpenVpn) { + QString serverConfig = serverController->getTextFileFromContainer(container, credentials, + protocols::openvpn::serverConfigPath, errorCode); + + QMap serverConfigMap; + auto serverConfigLines = serverConfig.split("\n"); + for (auto &line : serverConfigLines) { + auto trimmedLine = line.trimmed(); + if (trimmedLine.startsWith("#") || trimmedLine.isEmpty()) { + continue; + } else { + QStringList parts = trimmedLine.split(" "); + if (parts.count() >= 2) { + QString key = parts[0]; + QString value = parts.mid(1).join(" "); + serverConfigMap.insert(key, value); + } + } + } + + QString serverValue = serverConfigMap.value("server"); + + if (!serverValue.isEmpty()) { + QStringList serverParts = serverValue.split(" "); + if (serverParts.count() >= 1) { + containerConfig[config_key::subnet_address] = serverParts[0]; + } + } + + bool ncpDisable = serverConfig.contains("ncp-disable"); + containerConfig[config_key::ncp_disable] = ncpDisable; + + bool tlsAuth = serverConfig.contains("tls-auth"); + containerConfig[config_key::tls_auth] = tlsAuth; + + bool blockOutsideDns = serverConfig.contains("block-outside-dns"); + + containerConfig[config_key::block_outside_dns] = blockOutsideDns; + + QString cipher = serverConfigMap.value("cipher"); + if (!cipher.isEmpty()) { + containerConfig[config_key::cipher] = cipher; + } + + QString hash = serverConfigMap.value("auth"); + if (!hash.isEmpty()) { + containerConfig[config_key::hash] = hash; + } + } else if (protocol == Proto::Cloak) { + QString cloakConfig = serverController->getTextFileFromContainer(container, credentials, + "/opt/amnezia/cloak/ck-config.json", errorCode); + + QJsonDocument doc = QJsonDocument::fromJson(cloakConfig.toUtf8()); + + if (!doc.isNull() && doc.isObject()) { + QJsonObject cloakConfigObj = doc.object(); + + QString site = cloakConfigObj.value("RedirAddr").toString(); + if (!site.isEmpty()) { + containerConfig[config_key::site] = site; + } + } else { + qDebug() << "Failed to parse main loop Cloak JSON config"; + } + + } else if (protocol == Proto::ShadowSocks) { + QString shadowsocksConfig = serverController->getTextFileFromContainer(container, credentials, + "/opt/amnezia/shadowsocks/ss-config.json", errorCode); + + QJsonDocument doc = QJsonDocument::fromJson(shadowsocksConfig.toUtf8()); + + if (!doc.isNull() && doc.isObject()) { + QJsonObject ssConfigObj = doc.object(); + QString cipher = ssConfigObj.value("method").toString(); + if (!cipher.isEmpty()) { + containerConfig[config_key::cipher] = cipher; + } + } else { + qDebug() << "Failed to parse main loop Shadowsocks JSON config"; + } } config.insert(config_key::container, ContainerProps::containerToString(container)); } - config.insert(ProtocolProps::protoToString(protocol), containerConfig); + if (shouldProcessProtocol) { + config.insert(ProtocolProps::protoToString(protocol), containerConfig); + } } installedContainers.insert(container, config); } + const static QRegularExpression torOrDnsRegExp("(amnezia-(?:torwebsite|dns)).*?([0-9]*)/(udp|tcp).*"); QRegularExpressionMatch torOrDnsRegMatch = torOrDnsRegExp.match(containerInfo); if (torOrDnsRegMatch.hasMatch()) { From 0531508a75610fbcd69dd09b14b8836dc141f1fa Mon Sep 17 00:00:00 2001 From: Nethius Date: Fri, 1 Aug 2025 11:37:56 +0800 Subject: [PATCH 03/40] feat: added 'clear site list' button (#1747) (#1753) * feat: added 'clear site list' button (#1747) * chore: rename 'Export/Import Sites' to 'Additional options' --------- Co-authored-by: MrMirDan <58086007+MrMirDan@users.noreply.github.com> --- client/ui/controllers/sitesController.cpp | 7 +++++ client/ui/controllers/sitesController.h | 1 + client/ui/models/sites_model.cpp | 10 +++++++ client/ui/models/sites_model.h | 1 + .../qml/Pages2/PageSettingsSplitTunneling.qml | 30 ++++++++++++++++++- 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/client/ui/controllers/sitesController.cpp b/client/ui/controllers/sitesController.cpp index d40be458..08c74a93 100644 --- a/client/ui/controllers/sitesController.cpp +++ b/client/ui/controllers/sitesController.cpp @@ -78,6 +78,13 @@ void SitesController::removeSite(int index) emit finished(tr("Site removed: %1").arg(hostname)); } +void SitesController::removeSites() +{ + m_sitesModel->removeSites(); + + emit finished(tr("Site list cleared!")); +} + void SitesController::importSites(const QString &fileName, bool replaceExisting) { QByteArray jsonData; diff --git a/client/ui/controllers/sitesController.h b/client/ui/controllers/sitesController.h index e66478da..8cfe3b39 100644 --- a/client/ui/controllers/sitesController.h +++ b/client/ui/controllers/sitesController.h @@ -19,6 +19,7 @@ public slots: void addSite(QString hostname); void removeSite(int index); + void removeSites(); void importSites(const QString &fileName, bool replaceExisting); void exportSites(const QString &fileName); diff --git a/client/ui/models/sites_model.cpp b/client/ui/models/sites_model.cpp index 99d93618..a3bc0009 100644 --- a/client/ui/models/sites_model.cpp +++ b/client/ui/models/sites_model.cpp @@ -83,6 +83,16 @@ void SitesModel::removeSite(QModelIndex index) endRemoveRows(); } +void SitesModel::removeSites() +{ + beginResetModel(); + + m_settings->removeAllVpnSites(m_currentRouteMode); + fillSites(); + + endResetModel(); +} + int SitesModel::getRouteMode() { return m_currentRouteMode; diff --git a/client/ui/models/sites_model.h b/client/ui/models/sites_model.h index 803b7fd1..fc062887 100644 --- a/client/ui/models/sites_model.h +++ b/client/ui/models/sites_model.h @@ -28,6 +28,7 @@ public slots: bool addSite(const QString &hostname, const QString &ip); void addSites(const QMap &sites, bool replaceExisting); void removeSite(QModelIndex index); + void removeSites(); int getRouteMode(); void setRouteMode(int routeMode); diff --git a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml index 292f903a..17de5494 100644 --- a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml @@ -308,7 +308,7 @@ PageType { Layout.fillWidth: true Layout.margins: 16 - headerText: qsTr("Import / Export Sites") + headerText: qsTr("Additional options") } LabelWithButtonType { @@ -351,6 +351,34 @@ PageType { } DividerType {} + + LabelWithButtonType { + id: clearSitesButton + Layout.fillWidth: true + + text: qsTr("Clear site list") + rightImageSource: "qrc:/images/controls/trash.svg" + + clickedFunction: function() { + var headerText = qsTr("Clear site list?") + var descriptionText = qsTr("All sites will be removed from list.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + PageController.showBusyIndicator(true) + SitesController.removeSites() + PageController.showBusyIndicator(false) + } + var noButtonFunction = function() { + + } + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } + + DividerType {} } } From f9002b4f43e02d691931ec101c3f345527c71a47 Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 07:38:36 +0400 Subject: [PATCH 04/40] refactoring: made start-minimized-option available only when autostart-option is truned on (#1740) --- client/ui/qml/Pages2/PageSettingsApplication.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/ui/qml/Pages2/PageSettingsApplication.qml b/client/ui/qml/Pages2/PageSettingsApplication.qml index cbc04075..5f4ada82 100644 --- a/client/ui/qml/Pages2/PageSettingsApplication.qml +++ b/client/ui/qml/Pages2/PageSettingsApplication.qml @@ -147,7 +147,10 @@ PageType { Layout.margins: 16 text: qsTr("Start minimized") - descriptionText: qsTr("Launch application minimized") + descriptionText: qsTr("Launch application minimized (works with autostart option turned on)") + + enabled: switcherAutoStart.checked + opacity: enabled ? 1.0 : 0.5 parentFlickable: fl From e5dcb25a4a461d641a0cbc5aaa3fbbf7abd7cad5 Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 07:45:19 +0400 Subject: [PATCH 05/40] fix: removed the ability to change location while making connection (#1736) --- client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml b/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml index ce57e97e..e4c57b5b 100644 --- a/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml +++ b/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml @@ -119,6 +119,10 @@ PageType { checkable: !ConnectionController.isConnected onClicked: { + if (ConnectionController.isConnectionInProgress) { + PageController.showNotificationMessage(qsTr("Unable change server location while trying to make an active connection")) + return + } if (ConnectionController.isConnected) { PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection")) return From d53c7949362987ce6c62e5fe4f02ba00bad100f3 Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 07:47:43 +0400 Subject: [PATCH 06/40] fix: fixed language load after settings reset (#1735) --- client/ui/controllers/settingsController.cpp | 3 +-- client/ui/models/languageModel.cpp | 17 +++++++++++++++++ client/ui/models/languageModel.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index f8e97a1f..1d69315a 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -185,8 +185,7 @@ void SettingsController::clearSettings() { m_settings->clearSettings(); m_serversModel->resetModel(); - m_languageModel->changeLanguage( - static_cast(m_languageModel->getCurrentLanguageIndex())); + m_languageModel->changeLanguage(m_languageModel->getSystemLanguageEnum()); m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites); m_sitesModel->toggleSplitTunneling(false); diff --git a/client/ui/models/languageModel.cpp b/client/ui/models/languageModel.cpp index 1f9fa678..f1c9ebc2 100644 --- a/client/ui/models/languageModel.cpp +++ b/client/ui/models/languageModel.cpp @@ -101,6 +101,23 @@ QString LanguageModel::getCurrentLanguageName() return m_availableLanguages[getCurrentLanguageIndex()].name; } +LanguageSettings::AvailableLanguageEnum LanguageModel::getSystemLanguageEnum() +{ + QLocale locale = QLocale::system(); + switch (locale.language()) { + case QLocale::Russian: return LanguageSettings::AvailableLanguageEnum::Russian; + case QLocale::Chinese: return LanguageSettings::AvailableLanguageEnum::China_cn; + case QLocale::Ukrainian: return LanguageSettings::AvailableLanguageEnum::Ukrainian; + case QLocale::Persian: return LanguageSettings::AvailableLanguageEnum::Persian; + case QLocale::Arabic: return LanguageSettings::AvailableLanguageEnum::Arabic; + case QLocale::Burmese: return LanguageSettings::AvailableLanguageEnum::Burmese; + case QLocale::Urdu: return LanguageSettings::AvailableLanguageEnum::Urdu; + case QLocale::Hindi: return LanguageSettings::AvailableLanguageEnum::Hindi; + case QLocale::English: return LanguageSettings::AvailableLanguageEnum::English; + default: return LanguageSettings::AvailableLanguageEnum::English; + } +} + QString LanguageModel::getCurrentSiteUrl(const QString &path) { auto language = static_cast(getCurrentLanguageIndex()); diff --git a/client/ui/models/languageModel.h b/client/ui/models/languageModel.h index 4cd68ca6..6c3241d8 100644 --- a/client/ui/models/languageModel.h +++ b/client/ui/models/languageModel.h @@ -46,6 +46,7 @@ public: }; LanguageModel(std::shared_ptr settings, QObject *parent = nullptr); + LanguageSettings::AvailableLanguageEnum getSystemLanguageEnum(); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; From d15c0bd9621f6b203f6e7debd08772caefb35e00 Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 07:50:31 +0400 Subject: [PATCH 07/40] fix: fixed system tray open site link (#1686) * added signal-slot connection between corecontroller and systemtraynofificationhandler updating websiteurl * cleared up the commented lines --- client/core/controllers/coreController.cpp | 4 ++++ client/core/controllers/coreController.h | 3 +++ client/ui/systemtray_notificationhandler.cpp | 7 ++++++- client/ui/systemtray_notificationhandler.h | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/client/core/controllers/coreController.cpp b/client/core/controllers/coreController.cpp index a4dbc6d6..c8a5d9a3 100644 --- a/client/core/controllers/coreController.cpp +++ b/client/core/controllers/coreController.cpp @@ -243,6 +243,9 @@ void CoreController::initNotificationHandler() &ConnectionController::closeConnection); connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated); #endif + + auto* trayHandler = qobject_cast(m_notificationHandler.get()); + connect(this, &CoreController::websiteUrlChanged, trayHandler, &SystemTrayNotificationHandler::updateWebsiteUrl); } void CoreController::updateTranslator(const QLocale &locale) @@ -279,6 +282,7 @@ void CoreController::updateTranslator(const QLocale &locale) m_engine->retranslate(); emit translationsUpdated(); + emit websiteUrlChanged(m_languageModel->getCurrentSiteUrl()); } void CoreController::initErrorMessagesHandler() diff --git a/client/core/controllers/coreController.h b/client/core/controllers/coreController.h index 9ae53562..2b18dca1 100644 --- a/client/core/controllers/coreController.h +++ b/client/core/controllers/coreController.h @@ -5,6 +5,8 @@ #include #include +#include "ui/systemtray_notificationhandler.h" + #include "ui/controllers/api/apiConfigsController.h" #include "ui/controllers/api/apiSettingsController.h" #include "ui/controllers/api/apiPremV1MigrationController.h" @@ -61,6 +63,7 @@ public: signals: void translationsUpdated(); + void websiteUrlChanged(const QString &newUrl); private: void initModels(); diff --git a/client/ui/systemtray_notificationhandler.cpp b/client/ui/systemtray_notificationhandler.cpp index e1361302..edb65530 100644 --- a/client/ui/systemtray_notificationhandler.cpp +++ b/client/ui/systemtray_notificationhandler.cpp @@ -35,7 +35,7 @@ SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) : m_menu.addSeparator(); m_trayActionVisitWebSite = m_menu.addAction(QIcon(":/images/tray/link.png"), tr("Visit Website"), [&](){ - QDesktopServices::openUrl(QUrl("https://amnezia.org")); + QDesktopServices::openUrl(QUrl(websiteUrl)); }); m_trayActionQuit = m_menu.addAction(QIcon(":/images/tray/cancel.png"), tr("Quit") + " " + APPLICATION_NAME, this, [&](){ @@ -64,6 +64,11 @@ void SystemTrayNotificationHandler::onTranslationsUpdated() m_trayActionQuit->setText(tr("Quit")+ " " + APPLICATION_NAME); } +void SystemTrayNotificationHandler::updateWebsiteUrl(const QString &newWebsiteUrl) { + qDebug() << "Updated website URL:" << newWebsiteUrl; + websiteUrl = newWebsiteUrl; +} + void SystemTrayNotificationHandler::setTrayIcon(const QString &iconPath) { QIcon trayIconMask(QPixmap(iconPath).scaled(128,128)); diff --git a/client/ui/systemtray_notificationhandler.h b/client/ui/systemtray_notificationhandler.h index 60bf0b35..d1458021 100644 --- a/client/ui/systemtray_notificationhandler.h +++ b/client/ui/systemtray_notificationhandler.h @@ -21,6 +21,9 @@ public: void onTranslationsUpdated() override; +public slots: + void updateWebsiteUrl(const QString &newWebsiteUrl); + protected: virtual void notify(Message type, const QString& title, const QString& message, int timerMsec) override; @@ -48,6 +51,7 @@ private: const QString ConnectedTrayIconName = "active.png"; const QString DisconnectedTrayIconName = "default.png"; const QString ErrorTrayIconName = "error.png"; + QString websiteUrl = "https://amnezia.org"; }; #endif // SYSTEMTRAY_NOTIFICATIONHANDLER_H From d328739192eda591348bfa375e2af7d9fa474f9f Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 07:52:11 +0400 Subject: [PATCH 08/40] fix: add update model after clear profile (#1674) * fixed issue when ui was not getting update about clearing profile cache right after it * fixed the problem of not clearing the profile * refactored reload function in protolocolsModel * refactored the issue with signal connect in corecontroller --- client/core/controllers/coreController.cpp | 3 +++ client/ui/controllers/installController.cpp | 2 ++ client/ui/controllers/installController.h | 2 ++ 3 files changed, 7 insertions(+) diff --git a/client/core/controllers/coreController.cpp b/client/core/controllers/coreController.cpp index c8a5d9a3..de14d0c9 100644 --- a/client/core/controllers/coreController.cpp +++ b/client/core/controllers/coreController.cpp @@ -120,6 +120,9 @@ void CoreController::initControllers() connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(), &ConnectionController::onCurrentContainerUpdated); // TODO remove this + connect(m_installController.get(), &InstallController::profileCleared, + m_protocolsModel.get(), &ProtocolsModel::updateModel); + m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings)); m_engine->rootContext()->setContextProperty("ImportController", m_importController.get()); diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp index 04b06eaf..ec22fc12 100755 --- a/client/ui/controllers/installController.cpp +++ b/client/ui/controllers/installController.cpp @@ -814,6 +814,8 @@ void InstallController::clearCachedProfile(QSharedPointer serv m_clientManagementModel->revokeClient(containerConfig, container, serverCredentials, serverIndex, serverController); emit cachedProfileCleared(tr("%1 cached profile cleared").arg(ContainerProps::containerHumanNames().value(container))); + QJsonObject updatedConfig = m_settings->containerConfig(serverIndex, container); + emit profileCleared(updatedConfig); } QRegularExpression InstallController::ipAddressPortRegExp() diff --git a/client/ui/controllers/installController.h b/client/ui/controllers/installController.h index 8e42b5b2..d18ba946 100644 --- a/client/ui/controllers/installController.h +++ b/client/ui/controllers/installController.h @@ -83,6 +83,8 @@ signals: void noInstalledContainers(); + void profileCleared(const QJsonObject &config); + private: void installServer(const DockerContainer container, const QMap &installedContainers, const ServerCredentials &serverCredentials, const QSharedPointer &serverController, From 6cede712f5e2e70e26bb482309b73ce40994e8bb Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 07:54:58 +0400 Subject: [PATCH 09/40] fix: backup contains platform specific variables (#1646) * fixed issue with restoring wrong platform specific variables in backup * fixed wrong line * fixed issue when restong app split tunneling mode not intended for windows platform * added field containing application platform to backup file, added feature to clear appsSplitTunneling list from backup file if backup was made on other platform --- client/ui/controllers/settingsController.cpp | 44 +++++++++++++++++++- client/ui/controllers/settingsController.h | 2 + client/ui/models/appSplitTunnelingModel.cpp | 19 ++++++--- client/ui/models/appSplitTunnelingModel.h | 1 + 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index 1d69315a..25de134e 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -35,6 +35,23 @@ SettingsController::SettingsController(const QSharedPointer &serve #endif } +QString getPlatformName() +{ +#if defined(Q_OS_WINDOWS) + return "Windows"; +#elif defined(Q_OS_ANDROID) + return "Android"; +#elif defined(Q_OS_LINUX) + return "Linux"; +#elif defined(Q_OS_MACX) + return "MacOS"; +#elif defined(Q_OS_IOS) + return "iOS"; +#else + return "Unknown"; +#endif +} + void SettingsController::toggleAmneziaDns(bool enable) { m_settings->setUseAmneziaDns(enable); @@ -130,7 +147,10 @@ void SettingsController::backupAppConfig(const QString &fileName) QJsonDocument doc = QJsonDocument::fromJson(data); QJsonObject config = doc.object(); + config["AppPlatform"] = getPlatformName(); config["Conf/autoStart"] = Autostart::isAutostart(); + config["Conf/killSwitchEnabled"] = isKillSwitchEnabled(); + config["Conf/strictKillSwitchEnabled"] = isStrictKillSwitchEnabled(); SystemController::saveFile(fileName, QJsonDocument(config).toJson()); } @@ -155,21 +175,41 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data) } toggleAutoStart(autoStart); #endif + m_serversModel->resetModel(); m_languageModel->changeLanguage( static_cast(m_languageModel->getCurrentLanguageIndex())); #if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID) int appSplitTunnelingRouteMode = newConfigData.value("Conf/appsRouteMode").toInt(); - bool appSplittunnelingEnabled = newConfigData.value("Conf/appsSplitTunnelingEnabled").toBool(); + bool appSplittunnelingEnabled = newConfigData.value("Conf/appsSplitTunnelingEnabled").toString().toLower() == "true"; m_appSplitTunnelingModel->setRouteMode(appSplitTunnelingRouteMode); + + #if defined(Q_OS_WINDOWS) + m_appSplitTunnelingModel->setRouteMode(static_cast(Settings::AppsRouteMode::VpnAllExceptApps)); + #endif + + if (newConfigData.contains("AppPlatform")) { //if backup is from a new version + if (newConfigData.value("AppPlatform").toString() != getPlatformName()) { + m_appSplitTunnelingModel->clearAppsList(); + } + } + m_appSplitTunnelingModel->toggleSplitTunneling(appSplittunnelingEnabled); #endif + int siteSplitTunnelingRouteMode = newConfigData.value("Conf/routeMode").toInt(); - bool siteSplittunnelingEnabled = newConfigData.value("Conf/sitesSplitTunnelingEnabled").toBool(); + bool siteSplittunnelingEnabled = newConfigData.value("Conf/sitesSplitTunnelingEnabled").toString().toLower() == "true"; m_sitesModel->setRouteMode(siteSplitTunnelingRouteMode); m_sitesModel->toggleSplitTunneling(siteSplittunnelingEnabled); +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + m_settings->setAutoConnect(false); + m_settings->setStartMinimized(false); + m_settings->setKillSwitchEnabled(false); + m_settings->setStrictKillSwitchEnabled(false); +#endif + emit restoreBackupFinished(); } else { emit changeSettingsErrorOccurred(tr("Backup file is corrupted")); diff --git a/client/ui/controllers/settingsController.h b/client/ui/controllers/settingsController.h index 1485e1a0..a9e686e6 100644 --- a/client/ui/controllers/settingsController.h +++ b/client/ui/controllers/settingsController.h @@ -136,6 +136,8 @@ private: QString m_appVersion; + QString getPlatform(); + QDateTime m_loggingDisableDate; bool m_isDevModeEnabled = false; diff --git a/client/ui/models/appSplitTunnelingModel.cpp b/client/ui/models/appSplitTunnelingModel.cpp index 2fb2d084..77660c96 100644 --- a/client/ui/models/appSplitTunnelingModel.cpp +++ b/client/ui/models/appSplitTunnelingModel.cpp @@ -26,12 +26,12 @@ QVariant AppSplitTunnelingModel::data(const QModelIndex &index, int role) const return QVariant(); switch (role) { - case AppPathRole: { - return m_apps.at(index.row()).appName; - } - default: { - return true; - } + case AppPathRole: { + return m_apps.at(index.row()).appName; + } + default: { + return true; + } } return QVariant(); @@ -59,6 +59,13 @@ void AppSplitTunnelingModel::removeApp(QModelIndex index) endRemoveRows(); } +void AppSplitTunnelingModel::clearAppsList() { + beginResetModel(); + m_apps.clear(); + m_settings->setVpnApps(m_currentRouteMode, m_apps); + endResetModel(); +} + int AppSplitTunnelingModel::getRouteMode() { return m_currentRouteMode; diff --git a/client/ui/models/appSplitTunnelingModel.h b/client/ui/models/appSplitTunnelingModel.h index b96c0472..998ced49 100644 --- a/client/ui/models/appSplitTunnelingModel.h +++ b/client/ui/models/appSplitTunnelingModel.h @@ -29,6 +29,7 @@ public: public slots: bool addApp(const InstalledAppInfo &appInfo); void removeApp(QModelIndex index); + void clearAppsList(); int getRouteMode(); void setRouteMode(int routeMode); From dbeb7edd7a8bdd14422253fb48549cb919cc8b09 Mon Sep 17 00:00:00 2001 From: Cyril Anisimov Date: Fri, 1 Aug 2025 05:56:02 +0200 Subject: [PATCH 10/40] refactor: update ScrollBar policy to use AsNeeded for better usability (#1579) * refactor: update `ScrollBarType` policy to use `AsNeeded` for better usability * add selecting of location settings with Enter * add handlers to enter push --- .../qml/Components/SettingsContainersListView.qml | 2 +- client/ui/qml/Controls2/FlickableType.qml | 1 - client/ui/qml/Controls2/ScrollBarType.qml | 2 +- client/ui/qml/Pages2/PageHome.qml | 15 +++++++++------ .../qml/Pages2/PageProtocolWireGuardSettings.qml | 4 ++-- client/ui/qml/Pages2/PageSettingsKillSwitch.qml | 6 ++++++ .../Pages2/PageSettingsKillSwitchExceptions.qml | 2 +- .../ui/qml/Pages2/PageSettingsSplitTunneling.qml | 4 ++-- .../qml/Pages2/PageSetupWizardApiServicesList.qml | 4 ++-- .../ui/qml/Pages2/PageSetupWizardConfigSource.qml | 3 +++ .../ui/qml/Pages2/PageSetupWizardCredentials.qml | 3 +++ client/ui/qml/Pages2/PageSetupWizardEasy.qml | 6 ++++++ client/ui/qml/Pages2/PageShare.qml | 6 ++++++ 13 files changed, 42 insertions(+), 16 deletions(-) diff --git a/client/ui/qml/Components/SettingsContainersListView.qml b/client/ui/qml/Components/SettingsContainersListView.qml index 9e672130..4b551cbb 100644 --- a/client/ui/qml/Components/SettingsContainersListView.qml +++ b/client/ui/qml/Components/SettingsContainersListView.qml @@ -13,7 +13,7 @@ import "../Controls2" import "../Controls2/TextTypes" -ListView { +ListViewType { id: root width: parent.width diff --git a/client/ui/qml/Controls2/FlickableType.qml b/client/ui/qml/Controls2/FlickableType.qml index b3e5cabf..a6f38ac9 100644 --- a/client/ui/qml/Controls2/FlickableType.qml +++ b/client/ui/qml/Controls2/FlickableType.qml @@ -27,6 +27,5 @@ Flickable { ScrollBar.vertical: ScrollBarType { id: scrollBar - policy: fl.height >= fl.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn } } diff --git a/client/ui/qml/Controls2/ScrollBarType.qml b/client/ui/qml/Controls2/ScrollBarType.qml index 26e8edb6..d91431ab 100644 --- a/client/ui/qml/Controls2/ScrollBarType.qml +++ b/client/ui/qml/Controls2/ScrollBarType.qml @@ -7,5 +7,5 @@ import "../Controls2" ScrollBar { id: root - policy: parent.height >= parent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn + policy: ScrollBar.AsNeeded } diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml index 7934e5fb..43a9df32 100644 --- a/client/ui/qml/Pages2/PageHome.qml +++ b/client/ui/qml/Pages2/PageHome.qml @@ -101,8 +101,8 @@ PageType { visible: isLoggingEnabled ? true : false text: qsTr("Logging enabled") - Keys.onEnterPressed: loggingButton.clicked() - Keys.onReturnPressed: loggingButton.clicked() + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() onClicked: { PageController.goToPage(PageEnum.PageSettingsLogging) @@ -147,8 +147,8 @@ PageType { leftImageColor: "" rightImageSource: "qrc:/images/controls/chevron-down.svg" - Keys.onEnterPressed: splitTunnelingButton.clicked() - Keys.onReturnPressed: splitTunnelingButton.clicked() + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() onClicked: { homeSplitTunnelingDrawer.openTriggered() @@ -276,8 +276,8 @@ PageType { topPadding: 4 bottomPadding: 3 - Keys.onEnterPressed: collapsedButtonChevron.clicked() - Keys.onReturnPressed: collapsedButtonChevron.clicked() + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() onClicked: { if (drawer.isCollapsedStateActive()) { @@ -320,6 +320,9 @@ PageType { rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : "" + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() + onClicked: { ServersModel.processedIndex = ServersModel.defaultIndex diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index 21b35bc1..3122267f 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -158,8 +158,8 @@ PageType { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } } } diff --git a/client/ui/qml/Pages2/PageSettingsKillSwitch.qml b/client/ui/qml/Pages2/PageSettingsKillSwitch.qml index d6d73b20..4894a89a 100644 --- a/client/ui/qml/Pages2/PageSettingsKillSwitch.qml +++ b/client/ui/qml/Pages2/PageSettingsKillSwitch.qml @@ -71,6 +71,9 @@ PageType { onClicked: function() { SettingsController.strictKillSwitchEnabled = false } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } DividerType {} @@ -103,6 +106,9 @@ PageType { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } DividerType { diff --git a/client/ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml b/client/ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml index 31d1721b..e1af4245 100644 --- a/client/ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml +++ b/client/ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml @@ -64,7 +64,7 @@ PageType { displayMarginBeginning: 40 displayMarginEnd: 40 - ScrollBar.vertical: ScrollBarType { } + ScrollBar.vertical: ScrollBarType {} footer: Item { width: listView.width diff --git a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml index 17de5494..0cbed7c8 100644 --- a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml @@ -286,8 +286,8 @@ PageType { moreActionsDrawer.openTriggered() } - Keys.onReturnPressed: addSiteButtonImage.clicked() - Keys.onEnterPressed: addSiteButtonImage.clicked() + Keys.onReturnPressed: this.clicked() + Keys.onEnterPressed: this.clicked() } } diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml index 549eb381..207c305e 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml @@ -91,8 +91,8 @@ PageType { } } - Keys.onEnterPressed: clicked() - Keys.onReturnPressed: clicked() + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 7159ab59..520dc5d3 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -234,6 +234,9 @@ PageType { leftImageSource: imageSource onClicked: { handler() } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } } diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index 63d4d5f6..fd9404e0 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -177,6 +177,9 @@ PageType { onClicked: { Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("starter-guide")) } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardEasy.qml b/client/ui/qml/Pages2/PageSetupWizardEasy.qml index 096406e9..599464cf 100644 --- a/client/ui/qml/Pages2/PageSetupWizardEasy.qml +++ b/client/ui/qml/Pages2/PageSetupWizardEasy.qml @@ -118,6 +118,9 @@ PageType { containers.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto) containers.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto) } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } } } @@ -147,6 +150,9 @@ PageType { onClicked: function() { isEasySetup = false } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } BasicButtonType { diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 0f0976bc..21a5771c 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -256,6 +256,9 @@ PageType { onClicked: { accessTypeSelector.currentIndex = 0 } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } HorizontalRadioButton { @@ -272,6 +275,9 @@ PageType { ServersModel.getProcessedServerCredentials()) PageController.showBusyIndicator(false) } + + Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: this.clicked() } } } From 47f917de0b2fe29a11d5c01b787d1682ea835dfb Mon Sep 17 00:00:00 2001 From: Cyril Anisimov Date: Fri, 1 Aug 2025 05:56:16 +0200 Subject: [PATCH 11/40] refactoring: change logs time to UTC (#1578) * update logger to show utc * add logger to `FocusController` * add utc timestamps to android logs --- client/android/utils/src/main/kotlin/Log.kt | 6 +- client/ui/controllers/focusController.cpp | 16 +- common/logger/logger.cpp | 109 ++++++---- common/logger/logger.h | 230 ++++++++++---------- 4 files changed, 198 insertions(+), 163 deletions(-) diff --git a/client/android/utils/src/main/kotlin/Log.kt b/client/android/utils/src/main/kotlin/Log.kt index da11c200..8fda91c8 100644 --- a/client/android/utils/src/main/kotlin/Log.kt +++ b/client/android/utils/src/main/kotlin/Log.kt @@ -10,6 +10,8 @@ import java.nio.channels.FileChannel import java.nio.channels.FileLock import java.time.LocalDateTime import java.time.format.DateTimeFormatter +import java.time.ZonedDateTime +import java.time.ZoneOffset import java.util.concurrent.locks.ReentrantLock import org.amnezia.vpn.util.Log.Priority.D import org.amnezia.vpn.util.Log.Priority.E @@ -135,8 +137,8 @@ object Log { } private fun formatLogMsg(tag: String, msg: String, priority: Priority): String { - val date = LocalDateTime.now().format(dateTimeFormat) - return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " + + val utcDate = ZonedDateTime.now(ZoneOffset.UTC).format(dateTimeFormat) + return "${utcDate}Z ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " + "$tag: $msg\n" } diff --git a/client/ui/controllers/focusController.cpp b/client/ui/controllers/focusController.cpp index 54bdc7d8..65ae3b8b 100644 --- a/client/ui/controllers/focusController.cpp +++ b/client/ui/controllers/focusController.cpp @@ -4,6 +4,12 @@ #include #include +#include "logger.h" + +namespace { + Logger logger("FocusController"); +} + FocusController::FocusController(QQmlApplicationEngine *engine, QObject *parent) : QObject { parent }, m_engine { engine }, @@ -85,7 +91,7 @@ void FocusController::dropRootObject(QObject *object) dropListView(); setFocusOnDefaultItem(); } else { - qWarning() << "===>> TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object; + logger.warning() << "TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object; } } @@ -101,7 +107,7 @@ void FocusController::reload(Direction direction) QObject *rootObject = (m_rootObjects.empty() ? m_engine->rootObjects().value(0) : m_rootObjects.top()); if (!rootObject) { - qCritical() << "No ROOT OBJECT found!"; + logger.error() << "No ROOT OBJECT found!"; resetRootObject(); dropListView(); return; @@ -113,7 +119,7 @@ void FocusController::reload(Direction direction) direction == Direction::Forward ? FocusControl::isLess : FocusControl::isMore); if (m_focusChain.empty()) { - qWarning() << "Focus chain is empty!"; + logger.warning() << "Focus chain is empty!"; resetRootObject(); dropListView(); return; @@ -131,7 +137,7 @@ void FocusController::nextItem(Direction direction) } if (m_focusChain.empty()) { - qWarning() << "There are no items to navigate"; + logger.warning() << "There are no items to navigate"; setFocusOnDefaultItem(); return; } @@ -149,7 +155,7 @@ void FocusController::nextItem(Direction direction) const auto focusedItem = qobject_cast(m_focusChain.at(focusedItemIndex)); if (focusedItem == nullptr) { - qWarning() << "Failed to get item to focus on. Setting focus on default"; + logger.warning() << "Failed to get item to focus on. Setting focus on default"; setFocusOnDefaultItem(); return; } diff --git a/common/logger/logger.cpp b/common/logger/logger.cpp index 747590b9..f1d40f47 100644 --- a/common/logger/logger.cpp +++ b/common/logger/logger.cpp @@ -9,8 +9,6 @@ #include #include -#include - #include "utilities.h" #include "version.h" @@ -27,7 +25,7 @@ QTextStream Logger::m_textStream; QString Logger::m_logFileName = QString("%1.log").arg(APPLICATION_NAME); QString Logger::m_serviceLogFileName = QString("%1.log").arg(SERVICE_NAME); -void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (msg.simplified().isEmpty()) { return; @@ -38,14 +36,21 @@ void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, cons return; } - if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap") || msg.startsWith("Populating font") - || msg.startsWith("stale focus object")) { + if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap") + || msg.startsWith("Populating font") || msg.startsWith("stale focus object")) { return; } - Logger::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush; - - std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush; + switch (type) { + case QtDebugMsg: Logger::Instance().debug() << msg; break; + case QtInfoMsg: Logger::Instance().info() << msg; break; + case QtWarningMsg: Logger::Instance().warning() << msg; break; + case QtCriticalMsg: Logger::Instance().error() << msg; break; + case QtFatalMsg: { + Logger::Instance().error() << msg; + } // Brackets are needed to ensure the destructor of LogStreamer is called before abort() + abort(); + } } Logger &Logger::Instance() @@ -57,7 +62,7 @@ Logger &Logger::Instance() bool Logger::init(bool isServiceLogger) { QString path = isServiceLogger ? systemLogDir() : userLogsDir(); - QString logFileName = isServiceLogger ? m_serviceLogFileName : m_logFileName ; + QString logFileName = isServiceLogger ? m_serviceLogFileName : m_logFileName; QDir appDir(path); if (!appDir.mkpath(path)) { return false; @@ -71,19 +76,14 @@ bool Logger::init(bool isServiceLogger) m_file.setTextModeEnabled(true); m_textStream.setDevice(&m_file); - qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}"); -#if !defined(QT_DEBUG) || defined(Q_OS_IOS) - qInstallMessageHandler(debugMessageHandler); -#endif + qInstallMessageHandler(messageHandler); return true; } void Logger::deInit() { - qInstallMessageHandler(nullptr); - qSetMessagePattern("%{message}"); m_textStream.setDevice(nullptr); m_file.close(); } @@ -234,76 +234,101 @@ void Logger::cleanUp() clearLogs(true); } -Logger::Log::Log(Logger *logger, LogLevel logLevel) : m_logger(logger), m_logLevel(logLevel), m_data(new Data()) +Logger::LogStreamer::LogStreamer(Logger *logger, LogLevel logLevel) + : m_logger(logger), m_logLevel(logLevel), m_data(new Data()) { } -Logger::Log::~Log() +Logger::LogStreamer::~LogStreamer() { - qDebug() << "Amnezia" << m_logger->className() << m_data->m_buffer.trimmed(); + QString logLevelString; + switch (m_logLevel) { + case LogLevel::Trace: logLevelString = "[TRACE]"; break; + case LogLevel::Debug: logLevelString = "[DEBUG]"; break; + case LogLevel::Info: logLevelString = "[INFO]"; break; + case LogLevel::Warning: logLevelString = "[WARNING]"; break; + case LogLevel::Error: logLevelString = "[ERROR]"; break; + } + + const QString message = QString("%1 %2 Amnezia %3 : %4") + .arg(QDateTime::currentDateTimeUtc().toString("[yyyy-MM-dd hh:mm:ss.zzzZ]"), + logLevelString, m_logger->className(), m_data->m_buffer.trimmed()); + + if (m_file.isOpen()) { + QTextStream logToFile(&m_file); + logToFile << message << Qt::endl << Qt::flush; + } + + QTextStream logToOutput((m_logLevel == LogLevel::Error) ? stderr : stdout); + logToOutput << message << Qt::endl << Qt::flush; + delete m_data; } -Logger::Log Logger::error() +Logger::LogStreamer Logger::error() { - return Log(this, LogLevel::Error); + return { this, LogLevel::Error }; } -Logger::Log Logger::warning() + +Logger::LogStreamer Logger::warning() { - return Log(this, LogLevel::Warning); + return { this, LogLevel::Warning }; } -Logger::Log Logger::info() + +Logger::LogStreamer Logger::info() { - return Log(this, LogLevel::Info); + return { this, LogLevel::Info }; } -Logger::Log Logger::debug() + +Logger::LogStreamer Logger::debug() { - return Log(this, LogLevel::Debug); + return { this, LogLevel::Debug }; } + QString Logger::sensitive(const QString &input) { #ifdef Q_DEBUG return input; #else Q_UNUSED(input); - return QString(8, 'X'); + return { 8, 'X' }; #endif } -#define CREATE_LOG_OP_REF(x) \ - Logger::Log &Logger::Log::operator<<(x t) \ - { \ - m_data->m_ts << t << ' '; \ - return *this; \ +#define CREATE_LOGSTREAMER_OP_REF(x) \ + Logger::LogStreamer &Logger::LogStreamer::operator<<(x t) \ + { \ + m_data->m_ts << t << ' '; \ + return *this; \ } -CREATE_LOG_OP_REF(uint64_t); -CREATE_LOG_OP_REF(const char *); -CREATE_LOG_OP_REF(const QString &); -CREATE_LOG_OP_REF(const QByteArray &); -CREATE_LOG_OP_REF(const void *); +CREATE_LOGSTREAMER_OP_REF(uint64_t); +CREATE_LOGSTREAMER_OP_REF(const char *); +CREATE_LOGSTREAMER_OP_REF(const QString &); +CREATE_LOGSTREAMER_OP_REF(const QByteArray &); +CREATE_LOGSTREAMER_OP_REF(const void *); -#undef CREATE_LOG_OP_REF +#undef CREATE_LOGSTREAMER_OP_REF -Logger::Log &Logger::Log::operator<<(const QStringList &t) +Logger::LogStreamer &Logger::LogStreamer::operator<<(const QStringList &t) { m_data->m_ts << '[' << t.join(",") << ']' << ' '; return *this; } -Logger::Log &Logger::Log::operator<<(const QJsonObject &t) +Logger::LogStreamer &Logger::LogStreamer::operator<<(const QJsonObject &t) { m_data->m_ts << QJsonDocument(t).toJson(QJsonDocument::Indented) << ' '; return *this; } -Logger::Log &Logger::Log::operator<<(QTextStreamFunction t) +Logger::LogStreamer &Logger::LogStreamer::operator<<(QTextStreamFunction t) { m_data->m_ts << t; return *this; } -void Logger::Log::addMetaEnum(quint64 value, const QMetaObject *meta, const char *name) +void Logger::LogStreamer::addMetaEnum(quint64 value, const QMetaObject *meta, const char *name) { QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name)); diff --git a/common/logger/logger.h b/common/logger/logger.h index 7dff7ede..1fd7a523 100644 --- a/common/logger/logger.h +++ b/common/logger/logger.h @@ -1,114 +1,116 @@ -#ifndef LOGGER_H -#define LOGGER_H - -#include -#include -#include -#include -#include - -#include "mozilla/shared/loglevel.h" - -class Logger : public QObject -{ - Q_OBJECT - -public: - static Logger &Instance(); - - static bool init(bool isServiceLogger); - static void deInit(); - - static bool setServiceLogsEnabled(bool enabled); - - static bool openLogsFolder(bool isServiceLogger); - - static void clearLogs(bool isServiceLogger); - static void clearServiceLogs(); - static void cleanUp(); - - static QString userLogsFilePath(); - static QString serviceLogsFilePath(); - static QString systemLogDir(); - - static QString getLogFile(); - static QString getServiceLogFile(); - - // compat with Mozilla logger - Logger(const QString &className) - { - m_className = className; - } - const QString &className() const - { - return m_className; - } - - class Log - { - public: - Log(Logger *logger, LogLevel level); - ~Log(); - - Log &operator<<(uint64_t t); - Log &operator<<(const char *t); - Log &operator<<(const QString &t); - Log &operator<<(const QStringList &t); - Log &operator<<(const QByteArray &t); - Log &operator<<(const QJsonObject &t); - Log &operator<<(QTextStreamFunction t); - Log &operator<<(const void *t); - - // Q_ENUM - template typename std::enable_if::Value, Log &>::type operator<<(T t) - { - const QMetaObject *meta = qt_getEnumMetaObject(t); - const char *name = qt_getEnumName(t); - addMetaEnum(typename QFlags::Int(t), meta, name); - return *this; - } - - private: - void addMetaEnum(quint64 value, const QMetaObject *meta, const char *name); - - Logger *m_logger; - LogLevel m_logLevel; - - struct Data - { - Data() : m_ts(&m_buffer, QIODevice::WriteOnly) - { - } - - QString m_buffer; - QTextStream m_ts; - }; - - Data *m_data; - }; - - Log error(); - Log warning(); - Log info(); - Log debug(); - QString sensitive(const QString &input); - -private: - Logger() {}; - Logger(Logger const &) = delete; - Logger &operator=(Logger const &) = delete; - - static QString userLogsDir(); - - static QFile m_file; - static QTextStream m_textStream; - static QString m_logFileName; - static QString m_serviceLogFileName; - - friend void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); - - // compat with Mozilla logger - QString m_className; -}; - -#endif // LOGGER_H +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include +#include +#include + +#include "mozilla/shared/loglevel.h" + +class Logger : public QObject +{ + Q_OBJECT + +public: + static Logger &Instance(); + + static bool init(bool isServiceLogger); + static void deInit(); + + static bool setServiceLogsEnabled(bool enabled); + + static bool openLogsFolder(bool isServiceLogger); + + static void clearLogs(bool isServiceLogger); + static void clearServiceLogs(); + static void cleanUp(); + + static QString userLogsFilePath(); + static QString serviceLogsFilePath(); + static QString systemLogDir(); + + static QString getLogFile(); + static QString getServiceLogFile(); + + // compat with Mozilla logger + Logger(const QString &className) + { + m_className = className; + } + + Logger(Logger const &) = delete; + Logger &operator=(Logger const &) = delete; + + const QString &className() const + { + return m_className; + } + + class LogStreamer + { + public: + LogStreamer(Logger *logger, LogLevel level); + ~LogStreamer(); + + LogStreamer &operator<<(uint64_t t); + LogStreamer &operator<<(const char *t); + LogStreamer &operator<<(const QString &t); + LogStreamer &operator<<(const QStringList &t); + LogStreamer &operator<<(const QByteArray &t); + LogStreamer &operator<<(const QJsonObject &t); + LogStreamer &operator<<(QTextStreamFunction t); + LogStreamer &operator<<(const void *t); + + // Q_ENUM + template typename std::enable_if::Value, LogStreamer &>::type operator<<(T t) + { + const QMetaObject *meta = qt_getEnumMetaObject(t); + const char *name = qt_getEnumName(t); + addMetaEnum(typename QFlags::Int(t), meta, name); + return *this; + } + + private: + void addMetaEnum(quint64 value, const QMetaObject *meta, const char *name); + + Logger *m_logger; + LogLevel m_logLevel; + + struct Data + { + Data() : m_ts(&m_buffer, QIODevice::WriteOnly) + { + } + + QString m_buffer; + QTextStream m_ts; + }; + + Data *m_data; + }; + + LogStreamer error(); + LogStreamer warning(); + LogStreamer info(); + LogStreamer debug(); + QString sensitive(const QString &input); + +private: + Logger() = default; + + static QString userLogsDir(); + + static QFile m_file; + static QTextStream m_textStream; + static QString m_logFileName; + static QString m_serviceLogFileName; + + friend void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); + + // compat with Mozilla logger + QString m_className; +}; + +#endif // LOGGER_H From a43f7a6926ad03eb88d8dcfd79e5933b63ef21d2 Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Fri, 1 Aug 2025 17:02:12 +0400 Subject: [PATCH 12/40] feat: added vpn key to subscription settings page (#1717) * added subscription key display element to subscription management page * refactrored KeySubscription item to a new page * minor fix * changed PageShareDrawer into PageShareConnection * added back button * Removed deprecated ShareConnectionDrawer and migrated to PageShareConnection * fixed issue when show-connection settings button was not working * deleted empty lines * minor fix --- client/resources.qrc | 4 +- client/ui/controllers/pageController.h | 2 + .../qml/Components/ShareConnectionDrawer.qml | 375 ------------------ .../qml/Pages2/PageSettingsApiServerInfo.qml | 35 +- .../Pages2/PageSettingsApiSubscriptionKey.qml | 204 ++++++++++ client/ui/qml/Pages2/PageShare.qml | 35 +- client/ui/qml/Pages2/PageShareConnection.qml | 329 +++++++++++++++ client/ui/qml/Pages2/PageShareFullAccess.qml | 18 +- 8 files changed, 558 insertions(+), 444 deletions(-) delete mode 100644 client/ui/qml/Components/ShareConnectionDrawer.qml create mode 100644 client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml create mode 100644 client/ui/qml/Pages2/PageShareConnection.qml diff --git a/client/resources.qrc b/client/resources.qrc index 54b5846c..4c15c6bb 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -127,7 +127,7 @@ ui/qml/Components/SelectLanguageDrawer.qml ui/qml/Components/ServersListView.qml ui/qml/Components/SettingsContainersListView.qml - ui/qml/Components/ShareConnectionDrawer.qml + ui/qml/Components/TransportProtoSelector.qml ui/qml/Components/AddSitePanel.qml ui/qml/Config/GlobalConfig.qml @@ -228,6 +228,7 @@ ui/qml/Pages2/PageSetupWizardViewConfig.qml ui/qml/Pages2/PageShare.qml ui/qml/Pages2/PageShareFullAccess.qml + ui/qml/Pages2/PageShareConnection.qml ui/qml/Pages2/PageStart.qml ui/qml/Components/RenameServerDrawer.qml ui/qml/Controls2/ListViewType.qml @@ -240,6 +241,7 @@ ui/qml/Components/ApiPremV1SubListDrawer.qml ui/qml/Components/OtpCodeDrawer.qml ui/qml/Components/AwgTextField.qml + ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml images/flagKit/ZW.svg diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h index fc981091..1aee1ed7 100644 --- a/client/ui/controllers/pageController.h +++ b/client/ui/controllers/pageController.h @@ -38,6 +38,7 @@ namespace PageLoader PageSettingsApiInstructions, PageSettingsApiNativeConfigs, PageSettingsApiDevices, + PageSettingsApiSubscriptionKey, PageSettingsKillSwitchExceptions, PageServiceSftpSettings, @@ -71,6 +72,7 @@ namespace PageLoader PageProtocolAwgClientSettings, PageShareFullAccess, + PageShareConnection, PageDevMenu }; diff --git a/client/ui/qml/Components/ShareConnectionDrawer.qml b/client/ui/qml/Components/ShareConnectionDrawer.qml deleted file mode 100644 index dd59180b..00000000 --- a/client/ui/qml/Components/ShareConnectionDrawer.qml +++ /dev/null @@ -1,375 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import QtCore - -import SortFilterProxyModel 0.2 - -import PageEnum 1.0 -import ContainerProps 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" -import "../Components" - -DrawerType2 { - id: root - - property string headerText - property string configContentHeaderText - property string shareButtonText: qsTr("Share") - property string copyButtonText: qsTr("Copy") - property bool isSelfHostedConfig: true - - property string configExtension: ".vpn" - property string configCaption: qsTr("Save AmneziaVPN config") - property string configFileName: "amnezia_config" - - expandedHeight: parent.height * 0.9 - - onClosed: { - configExtension = ".vpn" - configCaption = qsTr("Save AmneziaVPN config") - configFileName = "amnezia_config" - } - - expandedStateContent: Item { - implicitHeight: root.expandedHeight - - Header2Type { - id: header - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 20 - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - headerText: root.headerText - } - - ListView { - id: listView - - anchors.top: header.bottom - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - - model: 1 - - clip: true - reuseItems: true - - header: ColumnLayout { - width: listView.width - - BasicButtonType { - id: shareButton - Layout.fillWidth: true - Layout.topMargin: 16 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - text: root.shareButtonText - leftImageSource: "qrc:/images/controls/share-2.svg" - - clickedFunc: function() { - var fileName = "" - if (GC.isMobile()) { - fileName = configFileName + configExtension - } else { - fileName = SystemController.getFileName(configCaption, - qsTr("Config files (*" + configExtension + ")"), - StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + configFileName, - true, - configExtension) - } - if (fileName !== "") { - PageController.showBusyIndicator(true) - ExportController.exportConfig(fileName) - PageController.showBusyIndicator(false) - } - } - } - - BasicButtonType { - id: copyConfigTextButton - Layout.fillWidth: true - Layout.topMargin: 8 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - text: root.copyButtonText - leftImageSource: "qrc:/images/controls/copy.svg" - - Keys.onReturnPressed: { copyConfigTextButton.clicked() } - Keys.onEnterPressed: { copyConfigTextButton.clicked() } - } - - BasicButtonType { - id: copyNativeConfigStringButton - Layout.fillWidth: true - Layout.topMargin: 8 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: false - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - text: qsTr("Copy config string") - leftImageSource: "qrc:/images/controls/copy.svg" - - KeyNavigation.tab: showSettingsButton - } - - BasicButtonType { - id: showSettingsButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: root.isSelfHostedConfig - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - text: qsTr("Show connection settings") - - clickedFunc: function() { - configContentDrawer.openTriggered() - } - } - - DrawerType2 { - id: configContentDrawer - - parent: root.parent - - anchors.fill: parent - expandedHeight: parent.height * 0.9 - - expandedStateContent: Item { - id: configContentContainer - - implicitHeight: configContentDrawer.expandedHeight - - Connections { - target: copyNativeConfigStringButton - function onClicked() { - nativeConfigString.selectAll() - nativeConfigString.copy() - nativeConfigString.select(0, 0) - PageController.showNotificationMessage(qsTr("Copied")) - } - } - - Connections { - target: copyConfigTextButton - function onClicked() { - configText.selectAll() - configText.copy() - configText.select(0, 0) - PageController.showNotificationMessage(qsTr("Copied")) - header.forceActiveFocus() - } - } - - BackButtonType { - id: backButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 - - backButtonFunction: function() { configContentDrawer.closeTriggered() } - } - - FlickableType { - anchors.top: backButton.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin - - ColumnLayout { - id: configContent - - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 - - Header2Type { - id: configContentHeader - Layout.fillWidth: true - Layout.topMargin: 16 - - headerText: root.configContentHeaderText - } - - TextField { - id: nativeConfigString - visible: false - text: ExportController.nativeConfigString - - onTextChanged: { - copyNativeConfigStringButton.visible = nativeConfigString.text !== "" - } - } - - TextArea { - id: configText - - Layout.fillWidth: true - Layout.topMargin: 16 - Layout.bottomMargin: 16 - - padding: 0 - leftPadding: 0 - height: 24 - - readOnly: true - activeFocusOnTab: false - - color: AmneziaStyle.color.paleGray - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - - font.pixelSize: 16 - font.weight: Font.Medium - font.family: "PT Root UI VF" - - text: ExportController.config - - wrapMode: Text.Wrap - - background: Rectangle { - color: AmneziaStyle.color.transparent - } - } - } - } - } - } - } - - delegate: ColumnLayout { - width: listView.width - - property bool isQrCodeVisible: root.isSelfHostedConfig ? ExportController.qrCodesCount > 0 : ApiConfigsController.qrCodesCount > 0 - - Rectangle { - id: qrCodeContainer - - Layout.fillWidth: true - Layout.preferredHeight: width - Layout.topMargin: 20 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: isQrCodeVisible - - color: "white" - - Image { - anchors.fill: parent - smooth: false - - source: root.isSelfHostedConfig ? (isQrCodeVisible ? ExportController.qrCodes[0] : "") : - (isQrCodeVisible ? ApiConfigsController.qrCodes[0] : "") - - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - Timer { - property int index: 0 - interval: 1000 - running: isQrCodeVisible - repeat: true - onTriggered: { - if (isQrCodeVisible) { - index++ - let qrCodesCount = root.isSelfHostedConfig ? ExportController.qrCodesCount : ApiConfigsController.qrCodesCount - if (index >= qrCodesCount) { - index = 0 - } - - parent.source = root.isSelfHostedConfig ? ExportController.qrCodes[index] : ApiConfigsController.qrCodes[index] - } - } - } - - Behavior on source { - PropertyAnimation { duration: 200 } - } - } - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 32 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: isQrCodeVisible - - horizontalAlignment: Text.AlignHCenter - text: qsTr("To read the QR code in the Amnezia app, select \"Add server\" → \"I have data to connect\" → \"QR code, key or settings file\"") - } - } - } - } -} diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index 75832fa6..48fcfa11 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -111,17 +111,6 @@ PageType { serverNameEditDrawer.openTriggered() } } - - RenameServerDrawer { - id: serverNameEditDrawer - - parent: root - - anchors.fill: parent - expandedHeight: root.height * 0.35 - - serverNameText: root.processedServer.name - } } delegate: ColumnLayout { @@ -207,35 +196,30 @@ PageType { Layout.fillWidth: true Layout.topMargin: warning.visible ? 16 : 32 - visible: false //footer.isVisibleForAmneziaFree + visible: footer.isVisibleForAmneziaFree text: qsTr("Subscription Key") rightImageSource: "qrc:/images/controls/chevron-right.svg" clickedFunction: function() { - shareConnectionDrawer.headerText = qsTr("Amnezia Premium subscription key") - - shareConnectionDrawer.openTriggered() - shareConnectionDrawer.isSelfHostedConfig = false; - shareConnectionDrawer.shareButtonText = qsTr("Save VPN key as a file") - shareConnectionDrawer.copyButtonText = qsTr("Copy VPN key") - - + PageController.goToPage(PageEnum.PageSettingsApiSubscriptionKey) PageController.showBusyIndicator(true) ApiConfigsController.prepareVpnKeyExport() PageController.showBusyIndicator(false) + + // Navigate to PageShareConnection page + //PageController.goToPage(PageEnum.PageShareConnection) } } DividerType { - visible: false //footer.isVisibleForAmneziaFree + visible: footer.isVisibleForAmneziaFree } LabelWithButtonType { Layout.fillWidth: true - Layout.topMargin: warning.visible ? 16 : 32 visible: footer.isVisibleForAmneziaFree @@ -420,9 +404,12 @@ PageType { } } - ShareConnectionDrawer { - id: shareConnectionDrawer + RenameServerDrawer { + id: serverNameEditDrawer anchors.fill: parent + expandedHeight: parent.height * 0.35 + + serverNameText: root.processedServer.name } } diff --git a/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml b/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml new file mode 100644 index 00000000..eace92ed --- /dev/null +++ b/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml @@ -0,0 +1,204 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import Qt.labs.platform 1.1 + +import QtCore + +import PageEnum 1.0 +import Style 1.0 + +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + Component.onCompleted: { + PageController.showBusyIndicator(true) + ApiConfigsController.prepareVpnKeyExport() + PageController.showBusyIndicator(false) + } + + FlickableType { + anchors.fill: parent + contentHeight: layout.implicitHeight + + ColumnLayout { + id: layout + width: root.width + + BackButtonType { + Layout.topMargin: 20 + } + + Label { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 16 + text: qsTr("Amnezia Premium\nsubscription key") + font.pixelSize: 32 + font.bold: true + color: AmneziaStyle.color.paleGray + wrapMode: Text.Wrap + } + + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: AmneziaStyle.color.paleGray + hoveredColor: AmneziaStyle.color.sheerWhite + pressedColor: AmneziaStyle.color.translucentWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.black + leftImageColor: "black" + borderWidth: 1 + + text: qsTr("Copy key") + leftImageSource: "qrc:/images/controls/copy.svg" + + onClicked: { + ApiConfigsController.copyVpnKeyToClipboard() + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 4 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: "transparent" + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: qsTr("Save key as a file") + leftImageSource: "qrc:/images/controls/share-2.svg" + + onClicked: { + var fileName = GC.isMobile() + ? "amnezia_vpn_key.vpn" + : SystemController.getFileName( + qsTr("Save AmneziaVPN config"), + qsTr("Config files (*.vpn)"), + StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_vpn_key", + true, + ".vpn" + ) + + if (fileName !== "") { + PageController.showBusyIndicator(true) + ExportController.exportConfig(fileName) + PageController.showBusyIndicator(false) + } + } + } + + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + defaultColor: "transparent" + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: qsTr("Show key text") + leftImageSource: "qrc:/images/controls/eye.svg" + + onClicked: { + PageController.showBusyIndicator(true) + ApiConfigsController.prepareVpnKeyExport() + PageController.showBusyIndicator(false) + vpnKeyDrawer.openTriggered() + } + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: width + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: ApiConfigsController.qrCodesCount > 0 + color: "white" + radius: 12 + + Image { + anchors.fill: parent + smooth: false + source: ApiConfigsController.qrCodesCount > 0 && ApiConfigsController.qrCodes[0] ? ApiConfigsController.qrCodes[0] : "" + } + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: ApiConfigsController.qrCodesCount > 0 + horizontalAlignment: Text.AlignHCenter + text: qsTr("To read the QR code in the Amnezia app, tap + in the main menu → 'QR code'") + } + } + } + + DrawerType2 { + id: vpnKeyDrawer + + anchors.fill: root + expandedHeight: root.height * 0.9 + + expandedStateContent: Item { + BackButtonType { + anchors.top: parent.top + anchors.left: parent.left + anchors.topMargin: 16 + backButtonFunction: function() { vpnKeyDrawer.closeTriggered() } + } + + ColumnLayout { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 56 + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + Header2Type { + Layout.fillWidth: true + headerText: qsTr("Amnezia Premium Subscription key") + } + + TextArea { + Layout.fillWidth: true + Layout.topMargin: 16 + readOnly: true + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + text: ApiConfigsController.vpnKey //|| "" + wrapMode: Text.Wrap + background: Rectangle { color: AmneziaStyle.color.transparent } + } + } + } + } +} diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 21a5771c..327b59b6 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -15,6 +15,7 @@ import "../Controls2/TextTypes" import "../Components" import "../Config" + PageType { id: root @@ -42,10 +43,6 @@ PageType { target: ExportController function onGenerateConfig(type) { - shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text - - shareConnectionDrawer.openTriggered() PageController.showBusyIndicator(true) switch (type) { @@ -55,54 +52,36 @@ PageType { } case PageShare.ConfigType.OpenVpn: { ExportController.generateOpenVpnConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config") - shareConnectionDrawer.configExtension = ".ovpn" - shareConnectionDrawer.configFileName = "amnezia_for_openvpn" break } case PageShare.ConfigType.WireGuard: { ExportController.generateWireGuardConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save WireGuard config") - shareConnectionDrawer.configExtension = ".conf" - shareConnectionDrawer.configFileName = "amnezia_for_wireguard" break } case PageShare.ConfigType.Awg: { ExportController.generateAwgConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save AmneziaWG config") - shareConnectionDrawer.configExtension = ".conf" - shareConnectionDrawer.configFileName = "amnezia_for_awg" break } case PageShare.ConfigType.ShadowSocks: { ExportController.generateShadowSocksConfig() - shareConnectionDrawer.configCaption = qsTr("Save Shadowsocks config") - shareConnectionDrawer.configExtension = ".json" - shareConnectionDrawer.configFileName = "amnezia_for_shadowsocks" break } case PageShare.ConfigType.Cloak: { ExportController.generateCloakConfig() - shareConnectionDrawer.configCaption = qsTr("Save Cloak config") - shareConnectionDrawer.configExtension = ".json" - shareConnectionDrawer.configFileName = "amnezia_for_cloak" break } case PageShare.ConfigType.Xray: { ExportController.generateXrayConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save XRay config") - shareConnectionDrawer.configExtension = ".json" - shareConnectionDrawer.configFileName = "amnezia_for_xray" break } } PageController.showBusyIndicator(false) + + PageController.goToPage(PageEnum.PageShareConnection) } function onExportErrorOccurred(error) { - shareConnectionDrawer.closeTriggered() - PageController.showErrorMessage(error) } } @@ -832,9 +811,6 @@ PageType { root.revokeConfig(index) } var noButtonFunction = function() { - if (!GC.isMobile()) { - // focusItem1.forceActiveFocus() - } } showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) @@ -848,9 +824,4 @@ PageType { } } - ShareConnectionDrawer { - id: shareConnectionDrawer - - anchors.fill: parent - } } diff --git a/client/ui/qml/Pages2/PageShareConnection.qml b/client/ui/qml/Pages2/PageShareConnection.qml new file mode 100644 index 00000000..9bc81ca3 --- /dev/null +++ b/client/ui/qml/Pages2/PageShareConnection.qml @@ -0,0 +1,329 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import QtCore + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import ContainerProps 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: pageShareConnection + + property string headerText + + Component.onCompleted: { + var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server" + headerText = qsTr("Connection to ") + serverName + configContentHeaderText = qsTr("File with connection settings to ") + serverName + } + property string configContentHeaderText + property string shareButtonText: qsTr("Share") + property string copyButtonText: qsTr("Copy") + property bool isSelfHostedConfig: true + + property string configExtension: ".vpn" + property string configCaption: qsTr("Save AmneziaVPN config") + property string configFileName: "amnezia_config" + + onVisibleChanged: { + configExtension = ".vpn" + configCaption = qsTr("Save AmneziaVPN config") + configFileName = "amnezia_config" + + if (visible) { + var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server" + headerText = qsTr("Connection to ") + serverName + configContentHeaderText = qsTr("File with connection settings to ") + serverName + } + } + + BackButtonType { + id: backButton + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + } + + Text { + id: shareHeader + anchors.top: backButton.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + text: pageShareConnection.headerText + color: AmneziaStyle.color.paleGray + font.pixelSize: 32 + font.weight: 700 + font.family: "PT Root UI VF" + wrapMode: Text.WordWrap + } + + ListView { + id: listView + + anchors.top: shareHeader.bottom + anchors.topMargin: 16 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + property bool isFocusable: true + + ScrollBar.vertical: ScrollBarType {} + model: 1 + clip: true + reuseItems: true + + header: ColumnLayout { + width: listView.width + + BasicButtonType { + id: shareButton + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + text: pageShareConnection.shareButtonText + leftImageSource: "qrc:/images/controls/share-2.svg" + clickedFunc: function() { + var fileName = "" + if (GC.isMobile()) { + fileName = configFileName + configExtension + } else { + fileName = SystemController.getFileName(configCaption, + qsTr("Config files (*" + configExtension + ")"), + StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + configFileName, + true, + configExtension) + } + if (fileName !== "") { + PageController.showBusyIndicator(true) + ExportController.exportConfig(fileName) + PageController.showBusyIndicator(false) + } + } + } + + BasicButtonType { + id: copyConfigTextButton + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: pageShareConnection.copyButtonText + leftImageSource: "qrc:/images/controls/copy.svg" + + Keys.onReturnPressed: copyConfigTextButton.clicked() + Keys.onEnterPressed: copyConfigTextButton.clicked() + } + + BasicButtonType { + id: copyNativeConfigStringButton + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: false + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + text: qsTr("Copy config string") + leftImageSource: "qrc:/images/controls/copy.svg" + KeyNavigation.tab: showSettingsButton + } + + BasicButtonType { + id: showSettingsButton + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: pageShareConnection.isSelfHostedConfig + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + text: qsTr("Show connection settings") + clickedFunc: function() { + configContentDrawer.openTriggered() + } + } + + DrawerType2 { + id: configContentDrawer + parent: pageShareConnection.parent + anchors.fill: parent + expandedHeight: parent.height * 0.9 + expandedStateContent: Item { + id: configContentContainer + implicitHeight: configContentDrawer.expandedHeight + + Connections { + target: copyNativeConfigStringButton + function onClicked() { + nativeConfigString.selectAll() + nativeConfigString.copy() + nativeConfigString.select(0, 0) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + Connections { + target: copyConfigTextButton + function onClicked() { + configText.selectAll() + configText.copy() + configText.select(0, 0) + PageController.showNotificationMessage(qsTr("Copied")) + header.forceActiveFocus() + } + } + + BackButtonType { + id: configBackButton + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 + backButtonFunction: function() { configContentDrawer.closeTriggered() } + } + + FlickableType { + anchors.top: configBackButton.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin + + ColumnLayout { + id: configContent + anchors.fill: parent + anchors.rightMargin: 16 + anchors.leftMargin: 16 + + Header2Type { + id: configContentHeader + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: pageShareConnection.configContentHeaderText + } + + TextField { + id: nativeConfigString + visible: false + text: ExportController.nativeConfigString + onTextChanged: copyNativeConfigStringButton.visible = nativeConfigString.text !== "" + } + + TextArea { + id: configText + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.bottomMargin: 16 + padding: 0 + leftPadding: 0 + height: 24 + readOnly: true + activeFocusOnTab: false + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + text: ExportController.config + wrapMode: Text.Wrap + background: Rectangle { color: AmneziaStyle.color.transparent } + } + } + } + } + } + } + + delegate: ColumnLayout { + width: listView.width + property bool isQrCodeVisible: pageShareConnection.isSelfHostedConfig ? ExportController.qrCodesCount > 0 : ApiConfigsController.qrCodesCount > 0 + + Rectangle { + id: qrCodeContainer + Layout.fillWidth: true + Layout.preferredHeight: width + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: isQrCodeVisible + color: "white" + + Image { + anchors.fill: parent + smooth: false + source: pageShareConnection.isSelfHostedConfig ? (isQrCodeVisible ? ExportController.qrCodes[0] : "") : (isQrCodeVisible ? ApiConfigsController.qrCodes[0] : "") + property bool isFocusable: true + Keys.onTabPressed: FocusController.nextKeyTabItem() + Keys.onBacktabPressed: FocusController.previousKeyTabItem() + Keys.onUpPressed: FocusController.nextKeyUpItem() + Keys.onDownPressed: FocusController.nextKeyDownItem() + Keys.onLeftPressed: FocusController.nextKeyLeftItem() + Keys.onRightPressed: FocusController.nextKeyRightItem() + + Timer { + property int index: 0 + interval: 1000 + running: isQrCodeVisible + repeat: true + onTriggered: { + if (isQrCodeVisible) { + index++ + let qrCodesCount = pageShareConnection.isSelfHostedConfig ? ExportController.qrCodesCount : ApiConfigsController.qrCodesCount + if (index >= qrCodesCount) index = 0 + parent.source = pageShareConnection.isSelfHostedConfig ? ExportController.qrCodes[index] : ApiConfigsController.qrCodes[index] + } + } + } + + Behavior on source { PropertyAnimation { duration: 200 } } + } + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: isQrCodeVisible + horizontalAlignment: Text.AlignHCenter + text: qsTr("To read the QR code in the Amnezia app, select \"Add server\" → \"I have data to connect\" → \"QR code, key or settings file\"") + } + } + } +} diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 82effb57..062d0d1b 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -15,6 +15,7 @@ import "../Controls2/TextTypes" import "../Components" import "../Config" + PageType { id: root @@ -100,8 +101,8 @@ PageType { serverSelector.currentIndex = serverSelectorListView.currentIndex } - shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text + shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text + shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text serverSelector.closeTriggered() } @@ -137,20 +138,13 @@ PageType { ExportController.generateFullAccessConfig() } - shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text - - shareConnectionDrawer.openTriggered() - PageController.showBusyIndicator(false) + + PageController.goToPage(PageEnum.PageShareConnection) } } } } - ShareConnectionDrawer { - id: shareConnectionDrawer - - anchors.fill: parent - } } + From 5472347969f44f72499495ccd99b40bb878ae354 Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Mon, 4 Aug 2025 10:13:22 +0400 Subject: [PATCH 13/40] feature: added warning label when config files have changed in premium configuration files menu (#1718) * added warning label when config files have changed in premium configuration files display * moved warning display from PageSettingsApiNativeConfigs.qml to PageSettingsApiServerInfo.qml --- client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml | 5 +++-- client/ui/qml/Pages2/PageSettingsApiServerInfo.qml | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml index d2042a76..8fa85a33 100644 --- a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml +++ b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml @@ -58,8 +58,9 @@ PageType { Layout.topMargin: 6 text: countryName - descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : "" - descriptionColor: AmneziaStyle.color.vibrantRed + descriptionText: isWorkerExpired ? qsTr("Download the update") : "" + hideDescription: false + descriptionColor: AmneziaStyle.color.mutedGray leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg" rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg" diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index 48fcfa11..1e947bd2 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -187,7 +187,13 @@ PageType { iconPath: "qrc:/images/controls/alert-circle.svg" - visible: ApiAccountInfoModel.data("hasExpiredWorker") + visible: { + for (let i = 0; i < ApiCountryModel.count; ++i) { + if (ApiCountryModel.get(i).isWorkerExpired) + return true; + } + return false; + } } LabelWithButtonType { From da8ad1f6ba657e36c9720b9854cc165b7a52d56e Mon Sep 17 00:00:00 2001 From: KsZnak Date: Mon, 4 Aug 2025 21:34:12 +0300 Subject: [PATCH 14/40] UTM added.md [no ci] Update README_RU.md --- README_RU.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README_RU.md b/README_RU.md index 44681875..a9d6740c 100644 --- a/README_RU.md +++ b/README_RU.md @@ -6,16 +6,16 @@ [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client) ### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский -[AmneziaVPN](https://amnezia.org) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере. +[AmneziaVPN](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере. [![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org) -### [Сайт](https://amnezia.org) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting) +### [Сайт](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting) > [!TIP] -> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org). +> Если [сайт Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror). - + [Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases) From eae2936449de782120b27588f2c6eb18188bf6cb Mon Sep 17 00:00:00 2001 From: KsZnak Date: Mon, 4 Aug 2025 21:35:45 +0300 Subject: [PATCH 15/40] Update README links.md [no ci] Update README links.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 992c3ad0..f2327b33 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,17 @@ ### [English]([https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md](https://github.com/amnezia-vpn/amnezia-client/tree/dev?tab=readme-ov-file#)) | [Русский](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md) -[Amnezia](https://amnezia.org) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server. +[Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server. [![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org) -### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting) +### [Website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting) > [!TIP] -> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org ). +> If the [Amnezia website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror). - - + + [All releases](https://github.com/amnezia-vpn/amnezia-client/releases) From d20ed4ad01dc9a4562ca0ff72879decbe4377b57 Mon Sep 17 00:00:00 2001 From: Cyril Anisimov Date: Wed, 6 Aug 2025 04:35:51 +0200 Subject: [PATCH 16/40] refactoring: improved stability of focus controller (#1464) * change position view mode * remove `parentFlickable` from `PageShare` * replace `FlickableType` with `ListViewType` in `PageSettings` * reorganize `PageSettingsAbout` for improved structure * replace `Flickable` with `ListViewType` in drawer in `PageSettingsApiNativeConfigs` * replace `FlickableType` with `ListViewType` in `PageSettingsApplication` and update layout structure * replace `FlickableType` with `ListViewType` in `PageSettingsAppSplitTunneling` and adjust layout for better structure * replace `FlickableType` with `ListViewType` in `PageSettingsBackup` * replace `FlickableType` with `ListViewType` in `PageSettingsConnection` * replace `FlickableType` with `ListViewType` in `PageSettingsDns` * replace `FlickableType` with `ListViewType` in `PageSettingsLogging` * replace `FlickableType` with `ListViewType` in `PageSettingsServerData` * update structure of `PageSettingsServerProtocol` * update `PageSettingsServersList` * replace `ListView` with `ListViewType` in `PageSettingsSplitTunneling` * replace `FlickableType` with `ListViewType` in `PageServiceDnsSettings` * update `PageServiceSftpSettings` * update `PageServiceSocksProxySettings` * replace `FlickableType` with `ListViewType` in `PageServiceTorWebsiteSettings` * replace `FlickableType` with `ListViewType` in `PageSetupWizardApiServiceInfo` * update `PageSetupWizardApiServicesList` * replace `ListView` with `ListViewType` in `PageSetupWizardConfigSource` * replace `ListView` with `ListViewType` in `PageSetupWizardCredentials` * replace `FlickableType` with `ListViewType` in `PageSetupWizardEasy` * replace `FlickableType` with `ListViewType` in `PageSetupWizardInstalling` * replace `ListView` with `ListViewType` in `PageSetupWizardProtocols` * replace `FlickableType` with `ListViewType` in `PageSetupWizardProtocolSettings` * replace `FlickableType` with `ListViewType` in `PageSetupWizardTextKey` * replace `FlickableType` with `ListViewType` in `PageSetupWizardViewConfig` * update `PageProtocolAwgClientSettings` * update `PageProtocolAwgSettings` * replace `FlickableType` with `ListViewType` in `PageProtocolCloakSettings` * replace `FlickableType` with `ListViewType` in `PageProtocolRaw` * replace `FlickableType` with `ListViewType` in `PageProtocolShadowSocksSettings` * replace `FlickableType` with `ListViewType` in `PageProtocolWireGuardClientSettings` * replace `FlickableType` with `ListViewType` in `PageProtocolWireGuardSettings` * replace `FlickableType` with `ListViewType` in `PageProtocolXraySettings` * replace `FlickableType` with `ListViewType` in `PageShareFullAccess` * replace `FlickableType` with `ListViewType` in `PageDeinstalling` * update `PageDevMenu` * remove `Flickable` references in `LabelWithButtonType` * remove useless key navigation handlers from `ListViewType` * replace `ListView` with `ListViewType` in `ListViewWithRadioButtonType.qml` and remove unnecessary properties * remove references to `Flickable` in `TextAreaType.qml` * remove references to `Flickable` in `TextAreaWithFooterType` * remove references to `FlickableType` in `TextFieldWithHeaderType` * remove references to `FlickableType` in `SwitcherType` * remove references to `FlickableType` in `CheckBoxType` * remove references to `FlickableType` in `CardWithIconsType.qml` * remove references to `FlickableType` in `BasicButtonType.qml` * update `ServersListView` * update `SettingsContainersListView` * update `InstalledAppsDrawer` * update `SelectLanguageDrawer` * update `HomeContainersListView` * update `HomeSplitTunnelingDrawer` * fix `PageSetupWizardApiServicesList` --------- Co-authored-by: vladimir.kuznetsov --- .../controllers/listViewFocusController.cpp | 2 +- .../qml/Components/HomeContainersListView.qml | 10 +- .../Components/HomeSplitTunnelingDrawer.qml | 194 +++--- .../ui/qml/Components/InstalledAppsDrawer.qml | 54 +- .../qml/Components/SelectLanguageDrawer.qml | 8 +- client/ui/qml/Components/ServersListView.qml | 9 +- .../Components/SettingsContainersListView.qml | 98 ++- client/ui/qml/Controls2/BasicButtonType.qml | 430 ++++++------ client/ui/qml/Controls2/CardWithIconsType.qml | 388 +++++------ client/ui/qml/Controls2/CheckBoxType.qml | 357 +++++----- .../ui/qml/Controls2/LabelWithButtonType.qml | 637 +++++++++--------- client/ui/qml/Controls2/ListViewType.qml | 33 +- .../Controls2/ListViewWithRadioButtonType.qml | 9 +- client/ui/qml/Controls2/SwitcherType.qml | 334 +++++---- client/ui/qml/Controls2/TextAreaType.qml | 253 +++---- .../qml/Controls2/TextAreaWithFooterType.qml | 351 +++++----- .../qml/Controls2/TextFieldWithHeaderType.qml | 453 ++++++------- client/ui/qml/Pages2/PageDeinstalling.qml | 86 ++- client/ui/qml/Pages2/PageDevMenu.qml | 16 +- .../Pages2/PageProtocolAwgClientSettings.qml | 567 +++++++++------- .../ui/qml/Pages2/PageProtocolAwgSettings.qml | 571 ++++++++-------- .../qml/Pages2/PageProtocolCloakSettings.qml | 320 +++++---- client/ui/qml/Pages2/PageProtocolRaw.qml | 230 +++---- .../PageProtocolShadowSocksSettings.qml | 255 ++++--- .../PageProtocolWireGuardClientSettings.qml | 208 +++--- .../Pages2/PageProtocolWireGuardSettings.qml | 227 +++---- .../qml/Pages2/PageProtocolXraySettings.qml | 276 ++++---- .../ui/qml/Pages2/PageServiceDnsSettings.qml | 58 +- .../ui/qml/Pages2/PageServiceSftpSettings.qml | 411 +++++------ .../Pages2/PageServiceSocksProxySettings.qml | 463 ++++++------- .../Pages2/PageServiceTorWebsiteSettings.qml | 50 +- client/ui/qml/Pages2/PageSettings.qml | 323 ++++----- client/ui/qml/Pages2/PageSettingsAbout.qml | 139 ++-- .../Pages2/PageSettingsApiNativeConfigs.qml | 464 +++++++------ .../Pages2/PageSettingsAppSplitTunneling.qml | 106 ++- .../ui/qml/Pages2/PageSettingsApplication.qml | 65 +- client/ui/qml/Pages2/PageSettingsBackup.qml | 50 +- .../ui/qml/Pages2/PageSettingsConnection.qml | 46 +- client/ui/qml/Pages2/PageSettingsDns.qml | 307 +++++---- client/ui/qml/Pages2/PageSettingsLogging.qml | 15 +- .../ui/qml/Pages2/PageSettingsServerData.qml | 316 ++++----- .../qml/Pages2/PageSettingsServerProtocol.qml | 422 ++++++------ .../ui/qml/Pages2/PageSettingsServersList.qml | 9 +- .../qml/Pages2/PageSettingsSplitTunneling.qml | 117 ++-- .../Pages2/PageSetupWizardApiServiceInfo.qml | 323 +++++---- .../Pages2/PageSetupWizardApiServicesList.qml | 97 ++- .../Pages2/PageSetupWizardConfigSource.qml | 14 +- .../qml/Pages2/PageSetupWizardCredentials.qml | 33 +- client/ui/qml/Pages2/PageSetupWizardEasy.qml | 166 ++--- .../qml/Pages2/PageSetupWizardInstalling.qml | 130 ++-- .../PageSetupWizardProtocolSettings.qml | 411 ++++++----- .../qml/Pages2/PageSetupWizardProtocols.qml | 21 +- .../ui/qml/Pages2/PageSetupWizardTextKey.qml | 74 +- .../qml/Pages2/PageSetupWizardViewConfig.qml | 107 +-- client/ui/qml/Pages2/PageShare.qml | 3 - client/ui/qml/Pages2/PageShareFullAccess.qml | 320 ++++----- 56 files changed, 5574 insertions(+), 5862 deletions(-) diff --git a/client/ui/controllers/listViewFocusController.cpp b/client/ui/controllers/listViewFocusController.cpp index 9fa232ca..6e91b78a 100644 --- a/client/ui/controllers/listViewFocusController.cpp +++ b/client/ui/controllers/listViewFocusController.cpp @@ -37,7 +37,7 @@ void ListViewFocusController::viewAtCurrentIndex() const } case Section::Delegate: { QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index - Q_ARG(int, 2)); // PositionMode (0 = Visible) + Q_ARG(int, 6)); // PositionMode (0 = Beginning; 1 = Center; 2 = End; 3 = Visible; 4 = Contain; 5 = SnapPosition) break; } case Section::Footer: { diff --git a/client/ui/qml/Components/HomeContainersListView.qml b/client/ui/qml/Components/HomeContainersListView.qml index 1cbdd82d..54cb27e2 100644 --- a/client/ui/qml/Components/HomeContainersListView.qml +++ b/client/ui/qml/Components/HomeContainersListView.qml @@ -10,8 +10,7 @@ import ProtocolEnum 1.0 import "../Controls2" import "../Controls2/TextTypes" - -ListView { +ListViewType { id: menuContent property var rootWidth @@ -21,13 +20,6 @@ ListView { anchors.top: parent.top anchors.bottom: parent.bottom - clip: true - snapMode: ListView.SnapToItem - - ScrollBar.vertical: ScrollBarType {} - - property bool isFocusable: true - ButtonGroup { id: containersRadioButtonGroup } diff --git a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml index 097274a4..6fdb6852 100644 --- a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml +++ b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml @@ -1,97 +1,97 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import PageEnum 1.0 - -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" - -DrawerType2 { - id: root - - property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android" - - anchors.fill: parent - expandedHeight: parent.height * 0.9 - - expandedStateContent: ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - spacing: 0 - - Header2Type { - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: 16 - - headerText: qsTr("Split tunneling") - descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others") - } - - LabelWithButtonType { - id: splitTunnelingSwitch - Layout.fillWidth: true - Layout.topMargin: 16 - - visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling - - text: qsTr("Split tunneling on the server") - descriptionText: qsTr("Enabled \nCan't be disabled for current server") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsSplitTunneling) - root.closeTriggered() - } - } - - DividerType { - visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling - } - - LabelWithButtonType { - id: siteBasedSplitTunnelingSwitch - Layout.fillWidth: true - Layout.topMargin: 16 - - text: qsTr("Site-based split tunneling") - descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsSplitTunneling) - root.closeTriggered() - } - } - - DividerType { - } - - LabelWithButtonType { - id: appSplitTunnelingSwitch - visible: isAppSplitTinnelingEnabled - - Layout.fillWidth: true - - text: qsTr("App-based split tunneling") - descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) - root.closeTriggered() - } - } - - DividerType { - visible: isAppSplitTinnelingEnabled - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import PageEnum 1.0 + +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" + +DrawerType2 { + id: root + + property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android" + + anchors.fill: parent + expandedHeight: parent.height * 0.9 + + expandedStateContent: ColumnLayout { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + spacing: 0 + + Header2Type { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + headerText: qsTr("Split tunneling") + descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others") + } + + LabelWithButtonType { + id: splitTunnelingSwitch + Layout.fillWidth: true + Layout.topMargin: 16 + + visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling + + text: qsTr("Split tunneling on the server") + descriptionText: qsTr("Enabled \nCan't be disabled for current server") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + clickedFunction: function() { + PageController.goToPage(PageEnum.PageSettingsSplitTunneling) + root.closeTriggered() + } + } + + DividerType { + visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling + } + + LabelWithButtonType { + id: siteBasedSplitTunnelingSwitch + Layout.fillWidth: true + Layout.topMargin: 16 + + text: qsTr("Site-based split tunneling") + descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + clickedFunction: function() { + PageController.goToPage(PageEnum.PageSettingsSplitTunneling) + root.closeTriggered() + } + } + + DividerType { + } + + LabelWithButtonType { + id: appSplitTunnelingSwitch + visible: isAppSplitTinnelingEnabled + + Layout.fillWidth: true + + text: qsTr("App-based split tunneling") + descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + clickedFunction: function() { + PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) + root.closeTriggered() + } + } + + DividerType { + visible: isAppSplitTinnelingEnabled + } + } +} diff --git a/client/ui/qml/Components/InstalledAppsDrawer.qml b/client/ui/qml/Components/InstalledAppsDrawer.qml index ce8ef837..ccf8951e 100644 --- a/client/ui/qml/Components/InstalledAppsDrawer.qml +++ b/client/ui/qml/Components/InstalledAppsDrawer.qml @@ -57,7 +57,7 @@ DrawerType2 { headerText: qsTr("Choose application") } - ListView { + ListViewType { id: listView Layout.fillWidth: true @@ -66,11 +66,6 @@ DrawerType2 { Layout.rightMargin: 16 Layout.leftMargin: 16 - clip: true - interactive: true - - property bool isFocusable: true - model: SortFilterProxyModel { id: proxyInstalledAppsModel sourceModel: installedAppsModel @@ -81,44 +76,35 @@ DrawerType2 { } } - ScrollBar.vertical: ScrollBarType {} - ButtonGroup { id: buttonGroup } - delegate: Item { - implicitWidth: root.width - implicitHeight: delegateContent.implicitHeight + delegate: ColumnLayout { + width: listView.width - ColumnLayout { - id: delegateContent + RowLayout { + CheckBoxType { + Layout.fillWidth: true - anchors.fill: parent - - RowLayout { - CheckBoxType { - Layout.fillWidth: true - - text: appName - checked: isAppSelected - onCheckedChanged: { - installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked) - } - } - - Image { - source: "image://installedAppImage/" + appIcon - - sourceSize.width: 24 - sourceSize.height: 24 - - Layout.rightMargin: 48 + text: appName + checked: isAppSelected + onCheckedChanged: { + installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked) } } - DividerType {} + Image { + source: "image://installedAppImage/" + appIcon + + sourceSize.width: 24 + sourceSize.height: 24 + + Layout.rightMargin: 48 + } } + + DividerType {} } } } diff --git a/client/ui/qml/Components/SelectLanguageDrawer.qml b/client/ui/qml/Components/SelectLanguageDrawer.qml index 2c026848..09829fa7 100644 --- a/client/ui/qml/Components/SelectLanguageDrawer.qml +++ b/client/ui/qml/Components/SelectLanguageDrawer.qml @@ -49,7 +49,7 @@ DrawerType2 { } } - ListView { + ListViewType { id: listView anchors.top: backButtonLayout.bottom @@ -57,14 +57,8 @@ DrawerType2 { anchors.right: parent.right anchors.bottom: parent.bottom - property bool isFocusable: true property int selectedIndex: LanguageModel.currentLanguageIndex - clip: true - reuseItems: true - - ScrollBar.vertical: ScrollBarType {} - model: LanguageModel ButtonGroup { diff --git a/client/ui/qml/Components/ServersListView.qml b/client/ui/qml/Components/ServersListView.qml index d0567a8c..4417e0b2 100644 --- a/client/ui/qml/Components/ServersListView.qml +++ b/client/ui/qml/Components/ServersListView.qml @@ -15,7 +15,7 @@ import "../Controls2" import "../Controls2/TextTypes" import "../Config" -ListView { +ListViewType { id: root property int selectedIndex: ServersModel.defaultIndex @@ -28,10 +28,6 @@ ListView { model: ServersModel - ScrollBar.vertical: ScrollBarType {} - - property bool isFocusable: true - Connections { target: ServersModel function onDefaultServerIndexChanged(serverIndex) { @@ -39,9 +35,6 @@ ListView { } } - clip: true - reuseItems: true - delegate: Item { id: menuContentDelegate objectName: "menuContentDelegate" diff --git a/client/ui/qml/Components/SettingsContainersListView.qml b/client/ui/qml/Components/SettingsContainersListView.qml index 4b551cbb..ccf60917 100644 --- a/client/ui/qml/Components/SettingsContainersListView.qml +++ b/client/ui/qml/Components/SettingsContainersListView.qml @@ -16,75 +16,61 @@ import "../Controls2/TextTypes" ListViewType { id: root - width: parent.width - height: root.contentItem.height + anchors.fill: parent - clip: true - reuseItems: true + delegate: ColumnLayout { + width: root.width - property bool isFocusable: false + LabelWithButtonType { + Layout.fillWidth: true - delegate: Item { - implicitWidth: root.width - implicitHeight: delegateContent.implicitHeight + text: name + descriptionText: description + rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg" - ColumnLayout { - id: delegateContent + clickedFunction: function() { + if (isInstalled) { + var containerIndex = root.model.mapToSource(index) + ContainersModel.setProcessedContainerIndex(containerIndex) - anchors.fill: parent - - LabelWithButtonType { - id: containerRadioButton - implicitWidth: parent.width - - text: name - descriptionText: description - rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg" - - clickedFunction: function() { - if (isInstalled) { - var containerIndex = root.model.mapToSource(index) - ContainersModel.setProcessedContainerIndex(containerIndex) - - if (serviceType !== ProtocolEnum.Other) { - if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) { - ProtocolsModel.updateModel(config) - PageController.goToPage(PageEnum.PageProtocolRaw) - return - } - } - - switch (containerIndex) { - case ContainerEnum.Ipsec: { + if (serviceType !== ProtocolEnum.Other) { + if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) { ProtocolsModel.updateModel(config) PageController.goToPage(PageEnum.PageProtocolRaw) - break + return } - case ContainerEnum.Dns: { - PageController.goToPage(PageEnum.PageServiceDnsSettings) - break - } - default: { - ProtocolsModel.updateModel(config) - PageController.goToPage(PageEnum.PageSettingsServerProtocol) - } - } - - } else { - ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index)) - InstallController.setShouldCreateServer(false) - PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) } - } - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - enabled: false + switch (containerIndex) { + case ContainerEnum.Ipsec: { + ProtocolsModel.updateModel(config) + PageController.goToPage(PageEnum.PageProtocolRaw) + break + } + case ContainerEnum.Dns: { + PageController.goToPage(PageEnum.PageServiceDnsSettings) + break + } + default: { + ProtocolsModel.updateModel(config) + PageController.goToPage(PageEnum.PageSettingsServerProtocol) + } + } + + } else { + ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index)) + InstallController.setShouldCreateServer(false) + PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) } } - DividerType {} + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + enabled: false + } } + + DividerType {} } } diff --git a/client/ui/qml/Controls2/BasicButtonType.qml b/client/ui/qml/Controls2/BasicButtonType.qml index b60e96cf..914fc267 100644 --- a/client/ui/qml/Controls2/BasicButtonType.qml +++ b/client/ui/qml/Controls2/BasicButtonType.qml @@ -1,220 +1,210 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - -import Style 1.0 - -import "TextTypes" - -Button { - id: root - - property string hoveredColor: AmneziaStyle.color.lightGray - property string defaultColor: AmneziaStyle.color.paleGray - property string disabledColor: AmneziaStyle.color.charcoalGray - property string pressedColor: AmneziaStyle.color.mutedGray - - property string textColor: AmneziaStyle.color.midnightBlack - - property string borderColor: AmneziaStyle.color.paleGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - property int borderWidth: 0 - property int borderFocusedWidth: 1 - - property string leftImageSource - property string rightImageSource - property string leftImageColor: textColor - property bool changeLeftImageSize: true - - property bool squareLeftSide: false - - property FlickableType parentFlickable - - property var clickedFunc - - property alias buttonTextLabel: buttonText - - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - implicitHeight: 56 - - hoverEnabled: true - - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(this) - } - } - } - - background: Rectangle { - id: focusBorder - - color: AmneziaStyle.color.transparent - border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent - border.width: root.activeFocus ? root.borderFocusedWidth : 0 - - anchors.fill: parent - - radius: 16 - - Rectangle { - id: background - - anchors.fill: focusBorder - anchors.margins: root.activeFocus ? 2 : 0 - - radius: root.activeFocus ? 14 : 16 - color: { - if (root.enabled) { - if (root.pressed) { - return pressedColor - } - return root.hovered ? hoveredColor : defaultColor - } else { - return disabledColor - } - } - border.color: borderColor - border.width: borderWidth - - Behavior on color { - PropertyAnimation { duration: 200 } - } - - Rectangle { - visible: root.squareLeftSide - - z: 1 - - width: parent.radius - height: parent.radius - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - color: { - if (root.enabled) { - if (root.pressed) { - return pressedColor - } - return root.hovered ? hoveredColor : defaultColor - } else { - return disabledColor - } - } - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - } - } - - MouseArea { - anchors.fill: focusBorder - enabled: false - cursorShape: Qt.PointingHandCursor - } - - contentItem: Item { - anchors.fill: focusBorder - - implicitWidth: content.implicitWidth - implicitHeight: content.implicitHeight - - RowLayout { - id: content - anchors.centerIn: parent - - Image { - id: leftImage - source: root.leftImageSource - visible: root.leftImageSource === "" ? false : true - - layer { - enabled: leftImageColor !== "" ? true : false - effect: ColorOverlay { - color: leftImageColor - } - } - - Component.onCompleted: { - if (root.changeLeftImageSize) { - leftImage.Layout.preferredHeight = 20 - leftImage.Layout.preferredWidth = 20 - } - } - } - - ButtonTextType { - id: buttonText - - color: root.textColor - text: root.text - visible: root.text === "" ? false : true - - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - } - - Image { - Layout.preferredHeight: 20 - Layout.preferredWidth: 20 - - source: root.rightImageSource - visible: root.rightImageSource === "" ? false : true - - layer { - enabled: true - effect: ColorOverlay { - color: textColor - } - } - } - } - } - - Keys.onEnterPressed: { - if (root.clickedFunc && typeof root.clickedFunc === "function") { - root.clickedFunc() - } - } - - Keys.onReturnPressed: { - if (root.clickedFunc && typeof root.clickedFunc === "function") { - root.clickedFunc() - } - } - - onClicked: { - if (root.clickedFunc && typeof root.clickedFunc === "function") { - root.clickedFunc() - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects + +import Style 1.0 + +import "TextTypes" + +Button { + id: root + + property string hoveredColor: AmneziaStyle.color.lightGray + property string defaultColor: AmneziaStyle.color.paleGray + property string disabledColor: AmneziaStyle.color.charcoalGray + property string pressedColor: AmneziaStyle.color.mutedGray + + property string textColor: AmneziaStyle.color.midnightBlack + + property string borderColor: AmneziaStyle.color.paleGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + property int borderWidth: 0 + property int borderFocusedWidth: 1 + + property string leftImageSource + property string rightImageSource + property string leftImageColor: textColor + property bool changeLeftImageSize: true + + property bool squareLeftSide: false + + property var clickedFunc + + property alias buttonTextLabel: buttonText + + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + Keys.onUpPressed: { + FocusController.nextKeyUpItem() + } + + Keys.onDownPressed: { + FocusController.nextKeyDownItem() + } + + Keys.onLeftPressed: { + FocusController.nextKeyLeftItem() + } + + Keys.onRightPressed: { + FocusController.nextKeyRightItem() + } + + implicitHeight: 56 + + hoverEnabled: true + + background: Rectangle { + id: focusBorder + + color: AmneziaStyle.color.transparent + border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent + border.width: root.activeFocus ? root.borderFocusedWidth : 0 + + anchors.fill: parent + + radius: 16 + + Rectangle { + id: background + + anchors.fill: focusBorder + anchors.margins: root.activeFocus ? 2 : 0 + + radius: root.activeFocus ? 14 : 16 + color: { + if (root.enabled) { + if (root.pressed) { + return pressedColor + } + return root.hovered ? hoveredColor : defaultColor + } else { + return disabledColor + } + } + border.color: borderColor + border.width: borderWidth + + Behavior on color { + PropertyAnimation { duration: 200 } + } + + Rectangle { + visible: root.squareLeftSide + + z: 1 + + width: parent.radius + height: parent.radius + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + color: { + if (root.enabled) { + if (root.pressed) { + return pressedColor + } + return root.hovered ? hoveredColor : defaultColor + } else { + return disabledColor + } + } + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + } + } + + MouseArea { + anchors.fill: focusBorder + enabled: false + cursorShape: Qt.PointingHandCursor + } + + contentItem: Item { + anchors.fill: focusBorder + + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight + + RowLayout { + id: content + anchors.centerIn: parent + + Image { + id: leftImage + source: root.leftImageSource + visible: root.leftImageSource === "" ? false : true + + layer { + enabled: leftImageColor !== "" ? true : false + effect: ColorOverlay { + color: leftImageColor + } + } + + Component.onCompleted: { + if (root.changeLeftImageSize) { + leftImage.Layout.preferredHeight = 20 + leftImage.Layout.preferredWidth = 20 + } + } + } + + ButtonTextType { + id: buttonText + + color: root.textColor + text: root.text + visible: root.text === "" ? false : true + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + + Image { + Layout.preferredHeight: 20 + Layout.preferredWidth: 20 + + source: root.rightImageSource + visible: root.rightImageSource === "" ? false : true + + layer { + enabled: true + effect: ColorOverlay { + color: textColor + } + } + } + } + } + + Keys.onEnterPressed: { + if (root.clickedFunc && typeof root.clickedFunc === "function") { + root.clickedFunc() + } + } + + Keys.onReturnPressed: { + if (root.clickedFunc && typeof root.clickedFunc === "function") { + root.clickedFunc() + } + } + + onClicked: { + if (root.clickedFunc && typeof root.clickedFunc === "function") { + root.clickedFunc() + } + } +} diff --git a/client/ui/qml/Controls2/CardWithIconsType.qml b/client/ui/qml/Controls2/CardWithIconsType.qml index 4277d735..02d033d2 100644 --- a/client/ui/qml/Controls2/CardWithIconsType.qml +++ b/client/ui/qml/Controls2/CardWithIconsType.qml @@ -1,203 +1,185 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Button { - id: root - - property string headerText - property string bodyText - property string footerText - - property string hoveredColor: AmneziaStyle.color.slateGray - property string defaultColor: AmneziaStyle.color.onyxBlack - - property string textColor: AmneziaStyle.color.midnightBlack - - property string rightImageSource - property string rightImageColor: AmneziaStyle.color.paleGray - - property string leftImageSource - - property real textOpacity: 1.0 - - property alias focusItem: rightImage - - property FlickableType parentFlickable - - hoverEnabled: true - - background: Rectangle { - id: backgroundRect - - anchors.fill: parent - radius: 16 - - color: defaultColor - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - - function ensureVisible(item) { - if (item.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - onFocusChanged: { - ensureVisible(root) - } - - focusItem.onFocusChanged: { - root.ensureVisible(focusItem) - } - - contentItem: Item { - anchors.left: parent.left - anchors.right: parent.right - - implicitHeight: content.implicitHeight - - RowLayout { - id: content - - anchors.fill: parent - - Image { - id: leftImage - source: leftImageSource - - visible: leftImageSource !== "" - - Layout.alignment: Qt.AlignLeft | Qt.AlignTop - Layout.topMargin: 24 - Layout.bottomMargin: 24 - Layout.leftMargin: 24 - } - - ColumnLayout { - - ListItemTitleType { - text: root.headerText - visible: text !== "" - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.topMargin: 16 - Layout.bottomMargin: root.bodyText !== "" ? 0 : 16 - - opacity: root.textOpacity - } - - CaptionTextType { - text: root.bodyText - visible: text !== "" - - color: AmneziaStyle.color.mutedGray - textFormat: Text.RichText - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: root.footerText !== "" ? 0 : 16 - - opacity: root.textOpacity - } - - ButtonTextType { - text: root.footerText - visible: text !== "" - - color: AmneziaStyle.color.mutedGray - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.topMargin: 16 - Layout.bottomMargin: 16 - - opacity: root.textOpacity - } - } - - ImageButtonType { - id: rightImage - - implicitWidth: 40 - implicitHeight: 40 - - hoverEnabled: false - image: rightImageSource - imageColor: rightImageColor - visible: rightImageSource ? true : false - - Layout.alignment: Qt.AlignRight | Qt.AlignTop - Layout.topMargin: 16 - Layout.bottomMargin: 16 - Layout.rightMargin: 16 - - Rectangle { - id: rightImageBackground - - anchors.fill: parent - radius: 12 - color: "transparent" - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - - onClicked: { - root.clicked() - } - } - } - } - - MouseArea { - anchors.fill: parent - - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - enabled: root.enabled - - onEntered: { - backgroundRect.color = root.hoveredColor - - if (rightImageSource) { - rightImageBackground.color = rightImage.hoveredColor - } - root.textOpacity = 0.8 - } - - onExited: { - backgroundRect.color = root.defaultColor - - if (rightImageSource) { - rightImageBackground.color = rightImage.defaultColor - } - root.textOpacity = 1 - } - - onPressedChanged: { - if (rightImageSource) { - rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor - } - root.textOpacity = 0.7 - } - - onClicked: { - root.clicked() - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Button { + id: root + + property string headerText + property string bodyText + property string footerText + + property string hoveredColor: AmneziaStyle.color.slateGray + property string defaultColor: AmneziaStyle.color.onyxBlack + + property string textColor: AmneziaStyle.color.midnightBlack + + property string rightImageSource + property string rightImageColor: AmneziaStyle.color.paleGray + + property string leftImageSource + + property real textOpacity: 1.0 + + property alias focusItem: rightImage + + hoverEnabled: true + + background: Rectangle { + id: backgroundRect + + anchors.fill: parent + radius: 16 + + color: defaultColor + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + contentItem: Item { + anchors.left: parent.left + anchors.right: parent.right + + implicitHeight: content.implicitHeight + + RowLayout { + id: content + + anchors.fill: parent + + Image { + id: leftImage + source: leftImageSource + + visible: leftImageSource !== "" + + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 24 + } + + ColumnLayout { + + ListItemTitleType { + text: root.headerText + visible: text !== "" + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: root.bodyText !== "" ? 0 : 16 + + opacity: root.textOpacity + } + + CaptionTextType { + text: root.bodyText + visible: text !== "" + + color: AmneziaStyle.color.mutedGray + textFormat: Text.RichText + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: root.footerText !== "" ? 0 : 16 + + opacity: root.textOpacity + } + + ButtonTextType { + text: root.footerText + visible: text !== "" + + color: AmneziaStyle.color.mutedGray + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: 16 + + opacity: root.textOpacity + } + } + + ImageButtonType { + id: rightImage + + implicitWidth: 40 + implicitHeight: 40 + + hoverEnabled: false + image: rightImageSource + imageColor: rightImageColor + visible: rightImageSource ? true : false + + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.topMargin: 16 + Layout.bottomMargin: 16 + Layout.rightMargin: 16 + + Rectangle { + id: rightImageBackground + + anchors.fill: parent + radius: 12 + color: "transparent" + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + onClicked: { + root.clicked() + } + } + } + } + + MouseArea { + anchors.fill: parent + + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + enabled: root.enabled + + onEntered: { + backgroundRect.color = root.hoveredColor + + if (rightImageSource) { + rightImageBackground.color = rightImage.hoveredColor + } + root.textOpacity = 0.8 + } + + onExited: { + backgroundRect.color = root.defaultColor + + if (rightImageSource) { + rightImageBackground.color = rightImage.defaultColor + } + root.textOpacity = 1 + } + + onPressedChanged: { + if (rightImageSource) { + rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor + } + root.textOpacity = 0.7 + } + + onClicked: { + root.clicked() + } + } +} diff --git a/client/ui/qml/Controls2/CheckBoxType.qml b/client/ui/qml/Controls2/CheckBoxType.qml index a26a68f1..451fe01d 100644 --- a/client/ui/qml/Controls2/CheckBoxType.qml +++ b/client/ui/qml/Controls2/CheckBoxType.qml @@ -1,170 +1,187 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - -import Style 1.0 - -import "TextTypes" - -CheckBox { - id: root - - property string descriptionText - property string descriptionTextColor: AmneziaStyle.color.mutedGray - property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray - - property string textColor: AmneziaStyle.color.paleGray - property string textDisabledColor: AmneziaStyle.color.mutedGray - - property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite - property string defaultColor: AmneziaStyle.color.transparent - property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite - - property string defaultBorderColor: AmneziaStyle.color.paleGray - property string checkedBorderColor: AmneziaStyle.color.goldenApricot - property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown - - property string borderFocusedColor: AmneziaStyle.color.paleGray - - property string checkedImageColor: AmneziaStyle.color.goldenApricot - property string pressedImageColor: AmneziaStyle.color.burntOrange - property string defaultImageColor: AmneziaStyle.color.transparent - property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown - - property string imageSource: "qrc:/images/controls/check.svg" - - property var parentFlickable - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - hoverEnabled: enabled ? true : false - focusPolicy: Qt.NoFocus - - background: Rectangle { - color: AmneziaStyle.color.transparent - border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent - border.width: 1 - radius: 16 - } - - indicator: Rectangle { - id: background - - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: 56 - implicitHeight: 56 - radius: 16 - - color: { - if (root.hovered) { - return hoveredColor - } - return defaultColor - } - - Behavior on color { - PropertyAnimation { duration: 200 } - } - - Rectangle { - id: imageBorder - - anchors.centerIn: parent - width: 24 - height: 24 - color: AmneziaStyle.color.transparent - border.color: root.checked ? - (root.enabled ? - checkedBorderColor : - checkedBorderDisabledColor) : - defaultBorderColor - border.width: 1 - radius: 4 - - Image { - anchors.centerIn: parent - - source: root.pressed ? imageSource : root.checked ? imageSource : "" - layer { - enabled: true - effect: ColorOverlay { - color: { - if (root.pressed) { - return root.pressedImageColor - } else if (root.checked) { - if (root.enabled) { - return root.checkedImageColor - } else { - return root.checkedDisabledImageColor - } - } else { - return root.defaultImageColor - } - } - } - } - } - } - } - - contentItem: Item { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 8 + background.width - - implicitHeight: content.implicitHeight - - ColumnLayout { - id: content - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - spacing: 4 - - ListItemTitleType { - Layout.fillWidth: true - - text: root.text - color: root.enabled ? root.textColor : root.textDisabledColor - } - - CaptionTextType { - id: description - - Layout.fillWidth: true - - text: root.descriptionText - color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor - - visible: root.descriptionText !== "" - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - enabled: false - } - - - Keys.onEnterPressed: { - root.checked = !root.checked - } - - Keys.onReturnPressed: { - root.checked = !root.checked - } - -} - - +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects + +import Style 1.0 + +import "TextTypes" + +CheckBox { + id: root + + property string descriptionText + property string descriptionTextColor: AmneziaStyle.color.mutedGray + property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray + + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray + + property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite + property string defaultColor: AmneziaStyle.color.transparent + property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite + + property string defaultBorderColor: AmneziaStyle.color.paleGray + property string checkedBorderColor: AmneziaStyle.color.goldenApricot + property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown + + property string borderFocusedColor: AmneziaStyle.color.paleGray + + property string checkedImageColor: AmneziaStyle.color.goldenApricot + property string pressedImageColor: AmneziaStyle.color.burntOrange + property string defaultImageColor: AmneziaStyle.color.transparent + property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown + + property string imageSource: "qrc:/images/controls/check.svg" + + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + Keys.onUpPressed: { + FocusController.nextKeyUpItem() + } + + Keys.onDownPressed: { + FocusController.nextKeyDownItem() + } + + Keys.onLeftPressed: { + FocusController.nextKeyLeftItem() + } + + Keys.onRightPressed: { + FocusController.nextKeyRightItem() + } + + hoverEnabled: enabled ? true : false + focusPolicy: Qt.NoFocus + + background: Rectangle { + color: AmneziaStyle.color.transparent + border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent + border.width: 1 + radius: 16 + } + + indicator: Rectangle { + id: background + + anchors.verticalCenter: parent.verticalCenter + + implicitWidth: 56 + implicitHeight: 56 + radius: 16 + + color: { + if (root.hovered) { + return hoveredColor + } + return defaultColor + } + + Behavior on color { + PropertyAnimation { duration: 200 } + } + + Rectangle { + id: imageBorder + + anchors.centerIn: parent + width: 24 + height: 24 + color: AmneziaStyle.color.transparent + border.color: root.checked ? + (root.enabled ? + checkedBorderColor : + checkedBorderDisabledColor) : + defaultBorderColor + border.width: 1 + radius: 4 + + Image { + anchors.centerIn: parent + + source: root.pressed ? imageSource : root.checked ? imageSource : "" + layer { + enabled: true + effect: ColorOverlay { + color: { + if (root.pressed) { + return root.pressedImageColor + } else if (root.checked) { + if (root.enabled) { + return root.checkedImageColor + } else { + return root.checkedDisabledImageColor + } + } else { + return root.defaultImageColor + } + } + } + } + } + } + } + + contentItem: Item { + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 8 + background.width + + implicitHeight: content.implicitHeight + + ColumnLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + spacing: 4 + + ListItemTitleType { + Layout.fillWidth: true + + text: root.text + color: root.enabled ? root.textColor : root.textDisabledColor + } + + CaptionTextType { + id: description + + Layout.fillWidth: true + + text: root.descriptionText + color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor + + visible: root.descriptionText !== "" + } + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + enabled: false + } + + + Keys.onEnterPressed: { + root.checked = !root.checked + } + + Keys.onReturnPressed: { + root.checked = !root.checked + } + +} + + diff --git a/client/ui/qml/Controls2/LabelWithButtonType.qml b/client/ui/qml/Controls2/LabelWithButtonType.qml index 087415f7..56d721b9 100644 --- a/client/ui/qml/Controls2/LabelWithButtonType.qml +++ b/client/ui/qml/Controls2/LabelWithButtonType.qml @@ -1,328 +1,309 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Item { - id: root - - property string text - property int textMaximumLineCount: 2 - property int textElide: Qt.ElideRight - - property string descriptionText - - property var clickedFunction - - property string buttonImageSource - property string rightImageSource - property string leftImageSource - property bool isLeftImageHoverEnabled: true - property bool isSmallLeftImage: false - - property alias rightButton: rightImage - property alias eyeButton: eyeImage - property FlickableType parentFlickable - - property string textColor: AmneziaStyle.color.paleGray - property string textDisabledColor: AmneziaStyle.color.mutedGray - property string descriptionColor: AmneziaStyle.color.mutedGray - property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray - property real textOpacity: 1.0 - - property string borderFocusedColor: AmneziaStyle.color.paleGray - property int borderFocusedWidth: 1 - - property string rightImageColor: AmneziaStyle.color.paleGray - - property bool descriptionOnTop: false - property bool hideDescription: true - - property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin - implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin - - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - Connections { - target: rightImage - function onFocusChanged() { - if (rightImage.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: root.enabled - - onEntered: { - if (rightImageSource) { - rightImageBackground.color = rightImage.hoveredColor - } else if (leftImageSource) { - leftImageBackground.color = rightImage.hoveredColor - } - root.textOpacity = 0.8 - } - - onExited: { - if (rightImageSource) { - rightImageBackground.color = rightImage.defaultColor - } else if (leftImageSource) { - leftImageBackground.color = rightImage.defaultColor - } - root.textOpacity = 1 - } - - onPressedChanged: { - if (rightImageSource) { - rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor - } else if (leftImageSource) { - leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor - } - root.textOpacity = 0.7 - } - - onClicked: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } - } - - RowLayout { - id: content - anchors.fill: parent - anchors.leftMargin: 16 - anchors.rightMargin: 16 - anchors.topMargin: 16 - anchors.bottomMargin: 16 - - Rectangle { - id: leftImageBackground - - visible: leftImageSource ? true : false - - Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56 - Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56 - Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0 - - radius: 12 - color: AmneziaStyle.color.transparent - - Behavior on color { - PropertyAnimation { duration: 200 } - } - - Image { - id: leftImage - - anchors.centerIn: parent - source: leftImageSource - } - } - - ColumnLayout { - property real textLineHeight: 21.6 - property real descriptionTextLineHeight: 16 - - property int textPixelSize: 18 - property int descriptionTextSize: 13 - - ListItemTitleType { - text: root.text - color: { - if (root.enabled) { - return root.descriptionOnTop ? root.descriptionColor : root.textColor - } else { - return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor - } - } - - maximumLineCount: root.textMaximumLineCount - elide: root.textElide - - opacity: root.textOpacity - - Layout.fillWidth: true - - lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight - font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize - font.letterSpacing: root.descriptionOnTop ? 0.02 : 0 - - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - - Behavior on opacity { - PropertyAnimation { duration: 200 } - } - } - - - CaptionTextType { - id: description - - text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText - color: { - if (root.enabled) { - return root.descriptionOnTop ? root.textColor : root.descriptionColor - } else { - return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor - } - } - - opacity: root.textOpacity - - visible: root.descriptionText !== "" - - Layout.fillWidth: true - - lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight - font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize - font.letterSpacing: root.descriptionOnTop ? 0 : 0.02 - - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - - Behavior on opacity { - PropertyAnimation { duration: 200 } - } - - function replaceWithAsterisks(input) { - return '*'.repeat(input.length) - } - } - } - - ImageButtonType { - id: eyeImage - visible: buttonImageSource !== "" - - implicitWidth: 40 - implicitHeight: 40 - - hoverEnabled: true - image: buttonImageSource - imageColor: rightImageColor - - Layout.alignment: Qt.AlignRight - - Rectangle { - id: eyeImageBackground - anchors.fill: parent - radius: 12 - color: AmneziaStyle.color.transparent - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - - onClicked: { - hideDescription = !hideDescription - } - - Keys.onEnterPressed: { - clicked() - } - - Keys.onReturnPressed: { - clicked() - } - } - - ImageButtonType { - id: rightImage - - implicitWidth: 40 - implicitHeight: 40 - - hoverEnabled: false - image: rightImageSource - imageColor: rightImageColor - visible: rightImageSource ? true : false - - Layout.alignment: Qt.AlignRight - - Rectangle { - id: rightImageBackground - anchors.fill: parent - radius: 12 - color: AmneziaStyle.color.transparent - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - onClicked: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } - } - } - - Rectangle { - id: background - anchors.fill: root - color: AmneziaStyle.color.transparent - - border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent - border.width: root.activeFocus ? root.borderFocusedWidth : 0 - - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - - Keys.onEnterPressed: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } - - Keys.onReturnPressed: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Item { + id: root + + // property alias focusObjectName: eyeImage.objectName + property string text + property int textMaximumLineCount: 2 + property int textElide: Qt.ElideRight + + property string descriptionText + + property var clickedFunction + + property string buttonImageSource + property string rightImageSource + property string leftImageSource + property bool isLeftImageHoverEnabled: true + property bool isSmallLeftImage: false + + property alias rightButton: rightImage + property alias eyeButton: eyeImage + + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray + property string descriptionColor: AmneziaStyle.color.mutedGray + property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray + property real textOpacity: 1.0 + + property string borderFocusedColor: AmneziaStyle.color.paleGray + property int borderFocusedWidth: 1 + + property string rightImageColor: AmneziaStyle.color.paleGray + + property bool descriptionOnTop: false + property bool hideDescription: true + + property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + Keys.onUpPressed: { + FocusController.nextKeyUpItem() + } + + Keys.onDownPressed: { + FocusController.nextKeyDownItem() + } + + Keys.onLeftPressed: { + FocusController.nextKeyLeftItem() + } + + Keys.onRightPressed: { + FocusController.nextKeyRightItem() + } + + implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin + implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: root.enabled + + onEntered: { + if (rightImageSource) { + rightImageBackground.color = rightImage.hoveredColor + } else if (leftImageSource) { + leftImageBackground.color = rightImage.hoveredColor + } + root.textOpacity = 0.8 + } + + onExited: { + if (rightImageSource) { + rightImageBackground.color = rightImage.defaultColor + } else if (leftImageSource) { + leftImageBackground.color = rightImage.defaultColor + } + root.textOpacity = 1 + } + + onPressedChanged: { + if (rightImageSource) { + rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor + } else if (leftImageSource) { + leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor + } + root.textOpacity = 0.7 + } + + onClicked: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } + } + + RowLayout { + id: content + anchors.fill: parent + anchors.leftMargin: 16 + anchors.rightMargin: 16 + anchors.topMargin: 16 + anchors.bottomMargin: 16 + + Rectangle { + id: leftImageBackground + + visible: leftImageSource ? true : false + + Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56 + Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56 + Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0 + + radius: 12 + color: AmneziaStyle.color.transparent + + Behavior on color { + PropertyAnimation { duration: 200 } + } + + Image { + id: leftImage + + anchors.centerIn: parent + source: leftImageSource + } + } + + ColumnLayout { + property real textLineHeight: 21.6 + property real descriptionTextLineHeight: 16 + + property int textPixelSize: 18 + property int descriptionTextSize: 13 + + ListItemTitleType { + text: root.text + color: { + if (root.enabled) { + return root.descriptionOnTop ? root.descriptionColor : root.textColor + } else { + return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor + } + } + + maximumLineCount: root.textMaximumLineCount + elide: root.textElide + + opacity: root.textOpacity + + Layout.fillWidth: true + + lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight + font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize + font.letterSpacing: root.descriptionOnTop ? 0.02 : 0 + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + Behavior on opacity { + PropertyAnimation { duration: 200 } + } + } + + + CaptionTextType { + id: description + + text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText + color: { + if (root.enabled) { + return root.descriptionOnTop ? root.textColor : root.descriptionColor + } else { + return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor + } + } + + opacity: root.textOpacity + + visible: root.descriptionText !== "" + + Layout.fillWidth: true + + lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight + font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize + font.letterSpacing: root.descriptionOnTop ? 0 : 0.02 + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + Behavior on opacity { + PropertyAnimation { duration: 200 } + } + + function replaceWithAsterisks(input) { + return '*'.repeat(input.length) + } + } + } + + ImageButtonType { + id: eyeImage + visible: buttonImageSource !== "" + + implicitWidth: 40 + implicitHeight: 40 + + hoverEnabled: true + image: buttonImageSource + imageColor: rightImageColor + + Layout.alignment: Qt.AlignRight + + Rectangle { + id: eyeImageBackground + anchors.fill: parent + radius: 12 + color: AmneziaStyle.color.transparent + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + onClicked: { + hideDescription = !hideDescription + } + + Keys.onEnterPressed: { + clicked() + } + + Keys.onReturnPressed: { + clicked() + } + } + + ImageButtonType { + id: rightImage + + implicitWidth: 40 + implicitHeight: 40 + + hoverEnabled: false + image: rightImageSource + imageColor: rightImageColor + visible: rightImageSource ? true : false + + Layout.alignment: Qt.AlignRight + + Rectangle { + id: rightImageBackground + anchors.fill: parent + radius: 12 + color: AmneziaStyle.color.transparent + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + onClicked: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } + } + } + + Rectangle { + id: background + anchors.fill: root + color: AmneziaStyle.color.transparent + + border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent + border.width: root.activeFocus ? root.borderFocusedWidth : 0 + + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + Keys.onEnterPressed: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } + + Keys.onReturnPressed: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } +} diff --git a/client/ui/qml/Controls2/ListViewType.qml b/client/ui/qml/Controls2/ListViewType.qml index 0de43d77..8d067537 100644 --- a/client/ui/qml/Controls2/ListViewType.qml +++ b/client/ui/qml/Controls2/ListViewType.qml @@ -6,33 +6,16 @@ ListView { property bool isFocusable: true - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - ScrollBar.vertical: ScrollBarType {} clip: true reuseItems: true - snapMode: ListView.SnapToItem + + function findChildWithObjectName(items, name) { + for (var i = 0; i < items.length; ++i) { + if (items[i].objectName === name) + return items[i]; + } + return null; + } } diff --git a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml index bd7ca32e..abd4da3e 100644 --- a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml +++ b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml @@ -6,7 +6,7 @@ import Style 1.0 import "TextTypes" -ListView { +ListViewType { id: root property var rootWidth @@ -25,13 +25,6 @@ ListView { width: rootWidth height: root.contentItem.height - clip: true - reuseItems: true - - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - ButtonGroup { id: buttonGroup } diff --git a/client/ui/qml/Controls2/SwitcherType.qml b/client/ui/qml/Controls2/SwitcherType.qml index 0651390f..db9ef755 100644 --- a/client/ui/qml/Controls2/SwitcherType.qml +++ b/client/ui/qml/Controls2/SwitcherType.qml @@ -1,172 +1,162 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Switch { - id: root - - property alias descriptionText: description.text - property string descriptionTextColor: AmneziaStyle.color.mutedGray - property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray - - property string textColor: AmneziaStyle.color.paleGray - property string textDisabledColor: AmneziaStyle.color.mutedGray - - property string checkedIndicatorColor: AmneziaStyle.color.richBrown - property string defaultIndicatorColor: AmneziaStyle.color.transparent - property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown - - property string borderFocusedColor: AmneziaStyle.color.paleGray - property int borderFocusedWidth: 1 - - property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown - property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray - property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown - - property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot - property string defaultInnerCircleColor: AmneziaStyle.color.paleGray - property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown - property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray - - property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite - property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent - - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - hoverEnabled: enabled ? true : false - focusPolicy: Qt.TabFocus - - property FlickableType parentFlickable: null - - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - indicator: Rectangle { - id: switcher - - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: 52 - implicitHeight: 32 - - radius: 16 - color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor) - : root.defaultIndicatorColor - - border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor) - : root.defaultIndicatorBorderColor) - - Behavior on color { - PropertyAnimation { duration: 200 } - } - Behavior on border.color { - PropertyAnimation { duration: 200 } - } - - Rectangle { - id: innerCircle - - anchors.verticalCenter: parent.verticalCenter - x: root.checked ? parent.width - width - 4 : 8 - width: root.checked ? 24 : 16 - height: root.checked ? 24 : 16 - radius: 23 - color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor) - : (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor) - - Behavior on x { - PropertyAnimation { duration: 200 } - } - } - - Rectangle { - anchors.centerIn: innerCircle - width: 40 - height: 40 - radius: 23 - color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - } - - contentItem: ColumnLayout { - id: content - - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - - ListItemTitleType { - Layout.fillWidth: true - rightPadding: indicator.width - - text: root.text - color: root.enabled ? root.textColor : root.textDisabledColor - } - - CaptionTextType { - id: description - - Layout.fillWidth: true - rightPadding: indicator.width - - color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor - - visible: text !== "" - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - enabled: false - } - - Keys.onEnterPressed: event => handleSwitch(event) - Keys.onReturnPressed: event => handleSwitch(event) - Keys.onSpacePressed: event => handleSwitch(event) - - function handleSwitch(event) { - if (!event.isAutoRepeat) { - root.checked = !root.checked - root.checkedChanged() - } - event.accepted = true - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Switch { + id: root + + property alias descriptionText: description.text + property string descriptionTextColor: AmneziaStyle.color.mutedGray + property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray + + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray + + property string checkedIndicatorColor: AmneziaStyle.color.richBrown + property string defaultIndicatorColor: AmneziaStyle.color.transparent + property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown + + property string borderFocusedColor: AmneziaStyle.color.paleGray + property int borderFocusedWidth: 1 + + property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown + property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray + property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown + + property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot + property string defaultInnerCircleColor: AmneziaStyle.color.paleGray + property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown + property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray + + property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite + property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent + + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + Keys.onUpPressed: { + FocusController.nextKeyUpItem() + } + + Keys.onDownPressed: { + FocusController.nextKeyDownItem() + } + + Keys.onLeftPressed: { + FocusController.nextKeyLeftItem() + } + + Keys.onRightPressed: { + FocusController.nextKeyRightItem() + } + + hoverEnabled: enabled ? true : false + focusPolicy: Qt.TabFocus + + indicator: Rectangle { + id: switcher + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + implicitWidth: 52 + implicitHeight: 32 + + radius: 16 + color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor) + : root.defaultIndicatorColor + + border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor) + : root.defaultIndicatorBorderColor) + + Behavior on color { + PropertyAnimation { duration: 200 } + } + Behavior on border.color { + PropertyAnimation { duration: 200 } + } + + Rectangle { + id: innerCircle + + anchors.verticalCenter: parent.verticalCenter + x: root.checked ? parent.width - width - 4 : 8 + width: root.checked ? 24 : 16 + height: root.checked ? 24 : 16 + radius: 23 + color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor) + : (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor) + + Behavior on x { + PropertyAnimation { duration: 200 } + } + } + + Rectangle { + anchors.centerIn: innerCircle + width: 40 + height: 40 + radius: 23 + color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + } + + contentItem: ColumnLayout { + id: content + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + ListItemTitleType { + Layout.fillWidth: true + rightPadding: indicator.width + + text: root.text + color: root.enabled ? root.textColor : root.textDisabledColor + } + + CaptionTextType { + id: description + + Layout.fillWidth: true + rightPadding: indicator.width + + color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor + + visible: text !== "" + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + enabled: false + } + + Keys.onEnterPressed: event => handleSwitch(event) + Keys.onReturnPressed: event => handleSwitch(event) + Keys.onSpacePressed: event => handleSwitch(event) + + function handleSwitch(event) { + if (!event.isAutoRepeat) { + root.checked = !root.checked + root.checkedChanged() + } + event.accepted = true + } +} diff --git a/client/ui/qml/Controls2/TextAreaType.qml b/client/ui/qml/Controls2/TextAreaType.qml index 9359fa16..7b6721dd 100644 --- a/client/ui/qml/Controls2/TextAreaType.qml +++ b/client/ui/qml/Controls2/TextAreaType.qml @@ -1,118 +1,135 @@ -import QtQuick -import QtQuick.Controls - -import Style 1.0 - -Rectangle { - id: root - - property string placeholderText - property string text - property alias textArea: textArea - property alias textAreaText: textArea.text - - property string borderHoveredColor: AmneziaStyle.color.charcoalGray - property string borderNormalColor: AmneziaStyle.color.slateGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - - height: 148 - color: AmneziaStyle.color.onyxBlack - border.width: 1 - border.color: getBorderColor(borderNormalColor) - radius: 16 - - property FlickableType parentFlickable: null - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - MouseArea { - id: parentMouse - anchors.fill: parent - cursorShape: Qt.IBeamCursor - onClicked: textArea.forceActiveFocus() - hoverEnabled: true - - FlickableType { - id: fl - interactive: false - - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: textArea.implicitHeight - TextArea { - id: textArea - - width: parent.width - - topPadding: 16 - leftPadding: 16 - anchors.topMargin: 16 - anchors.bottomMargin: 16 - - color: AmneziaStyle.color.paleGray - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - placeholderTextColor: AmneziaStyle.color.mutedGray - - font.pixelSize: 16 - font.weight: Font.Medium - font.family: "PT Root UI VF" - - placeholderText: root.placeholderText - text: root.text - - onCursorVisibleChanged: { - if (textArea.cursorVisible) { - fl.interactive = true - } else { - fl.interactive = false - } - } - - wrapMode: Text.Wrap - - MouseArea { - id: textAreaMouse - anchors.fill: parent - acceptedButtons: Qt.RightButton - hoverEnabled: true - onClicked: { - fl.interactive = true - contextMenu.open() - } - } - - onFocusChanged: { - root.border.color = getBorderColor(borderNormalColor) - } - - ContextMenuType { - id: contextMenu - textObj: textArea - } - } - } - - onPressed: { - root.border.color = getBorderColor(borderFocusedColor) - } - - onExited: { - root.border.color = getBorderColor(borderNormalColor) - } - - onEntered: { - root.border.color = getBorderColor(borderHoveredColor) - } - } - - - function getBorderColor(noneFocusedColor) { - return textArea.focus ? root.borderFocusedColor : noneFocusedColor - } -} +import QtQuick +import QtQuick.Controls + +import Style 1.0 + +Rectangle { + id: root + + property string placeholderText + property string text + property alias textArea: textArea + property alias textAreaText: textArea.text + + property string borderHoveredColor: AmneziaStyle.color.charcoalGray + property string borderNormalColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + + height: 148 + color: AmneziaStyle.color.onyxBlack + border.width: 1 + border.color: getBorderColor(borderNormalColor) + radius: 16 + + MouseArea { + id: parentMouse + anchors.fill: parent + cursorShape: Qt.IBeamCursor + onClicked: textArea.forceActiveFocus() + hoverEnabled: true + + FlickableType { + id: fl + interactive: false + + anchors.top: parent.top + anchors.bottom: parent.bottom + contentHeight: textArea.implicitHeight + TextArea { + id: textArea + + width: parent.width + + topPadding: 16 + leftPadding: 16 + anchors.topMargin: 16 + anchors.bottomMargin: 16 + + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + Keys.onUpPressed: { + FocusController.nextKeyUpItem() + } + + Keys.onDownPressed: { + FocusController.nextKeyDownItem() + } + + Keys.onLeftPressed: { + FocusController.nextKeyLeftItem() + } + + Keys.onRightPressed: { + FocusController.nextKeyRightItem() + } + + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + placeholderTextColor: AmneziaStyle.color.mutedGray + + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + + placeholderText: root.placeholderText + text: root.text + + onCursorVisibleChanged: { + if (textArea.cursorVisible) { + fl.interactive = true + } else { + fl.interactive = false + } + } + + wrapMode: Text.Wrap + + MouseArea { + id: textAreaMouse + anchors.fill: parent + acceptedButtons: Qt.RightButton + hoverEnabled: true + onClicked: { + fl.interactive = true + contextMenu.open() + } + } + + onFocusChanged: { + root.border.color = getBorderColor(borderNormalColor) + } + + ContextMenuType { + id: contextMenu + textObj: textArea + } + } + } + + onPressed: { + root.border.color = getBorderColor(borderFocusedColor) + } + + onExited: { + root.border.color = getBorderColor(borderNormalColor) + } + + onEntered: { + root.border.color = getBorderColor(borderHoveredColor) + } + } + + + function getBorderColor(noneFocusedColor) { + return textArea.focus ? root.borderFocusedColor : noneFocusedColor + } +} diff --git a/client/ui/qml/Controls2/TextAreaWithFooterType.qml b/client/ui/qml/Controls2/TextAreaWithFooterType.qml index cf7b9146..2cb6a69c 100644 --- a/client/ui/qml/Controls2/TextAreaWithFooterType.qml +++ b/client/ui/qml/Controls2/TextAreaWithFooterType.qml @@ -1,180 +1,171 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Rectangle { - id: root - - property string placeholderText - property string text - property string headerText - property alias textArea: textArea - property alias textAreaText: textArea.text - - property string borderHoveredColor: AmneziaStyle.color.charcoalGray - property string borderNormalColor: AmneziaStyle.color.slateGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - - property string firstButtonImage - property string secondButtonImage - - property var firstButtonClickedFunc - property var secondButtonClickedFunc - - height: 148 - color: AmneziaStyle.color.onyxBlack - border.width: 1 - border.color: getBorderColor(borderNormalColor) - radius: 16 - - property FlickableType parentFlickable: null - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - MouseArea { - id: parentMouse - anchors.fill: parent - cursorShape: Qt.IBeamCursor - onClicked: textArea.forceActiveFocus() - hoverEnabled: true - - ColumnLayout { - anchors.fill: parent - anchors.margins: 16 - spacing: 0 - - LabelTextType { - Layout.fillWidth: true - text: root.headerText - } - - TextArea { - id: textArea - - Layout.fillWidth: true - Layout.fillHeight: true - - leftPadding: 0 - Layout.bottomMargin: 16 - - color: AmneziaStyle.color.paleGray - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - placeholderTextColor: AmneziaStyle.color.mutedGray - - font.pixelSize: 16 - font.weight: Font.Medium - font.family: "PT Root UI VF" - - placeholderText: root.placeholderText - text: root.text - - onCursorVisibleChanged: { - if (textArea.cursorVisible) { - fl.interactive = true - } else { - fl.interactive = false - } - } - - wrapMode: Text.Wrap - - MouseArea { - id: textAreaMouse - anchors.fill: parent - acceptedButtons: Qt.RightButton - hoverEnabled: true - onClicked: { - fl.interactive = true - contextMenu.open() - } - } - - onFocusChanged: { - root.border.color = getBorderColor(borderNormalColor) - } - - ContextMenuType { - id: contextMenu - textObj: textArea - } - } - - RowLayout { - Layout.fillWidth: true - Layout.leftMargin: -8 - spacing: 0 - ImageButtonType { - id: firstButton - visible: root.firstButtonImage !== "" - - imageColor: AmneziaStyle.color.paleGray - - image: root.firstButtonImage - onClicked: function() { - if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") { - root.firstButtonClickedFunc() - } - } - } - - ImageButtonType { - id: secondButton - visible: root.secondButtonImage !== "" - - imageColor: AmneziaStyle.color.paleGray - - image: root.secondButtonImage - onClicked: function() { - if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") { - root.secondButtonClickedFunc() - } - } - } - - Item { - Layout.fillWidth: true - } - - ImageButtonType { - id: resetButton - imageColor: AmneziaStyle.color.paleGray - - visible: root.textAreaText !== "" - image: "qrc:/images/controls/close.svg" - - onClicked: function() { - root.textAreaText = "" - textArea.focus = true - } - } - } - } - - onPressed: { - root.border.color = getBorderColor(borderFocusedColor) - } - - onExited: { - root.border.color = getBorderColor(borderNormalColor) - } - - onEntered: { - root.border.color = getBorderColor(borderHoveredColor) - } - } - - - function getBorderColor(noneFocusedColor) { - return textArea.focus ? root.borderFocusedColor : noneFocusedColor - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Rectangle { + id: root + + property string placeholderText + property string text + property string headerText + property alias textArea: textArea + property alias textAreaText: textArea.text + + property string borderHoveredColor: AmneziaStyle.color.charcoalGray + property string borderNormalColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + + property string firstButtonImage + property string secondButtonImage + + property var firstButtonClickedFunc + property var secondButtonClickedFunc + + height: 148 + color: AmneziaStyle.color.onyxBlack + border.width: 1 + border.color: getBorderColor(borderNormalColor) + radius: 16 + + MouseArea { + id: parentMouse + anchors.fill: parent + cursorShape: Qt.IBeamCursor + onClicked: textArea.forceActiveFocus() + hoverEnabled: true + + ColumnLayout { + anchors.fill: parent + anchors.margins: 16 + spacing: 0 + + LabelTextType { + Layout.fillWidth: true + text: root.headerText + } + + TextArea { + id: textArea + + Layout.fillWidth: true + Layout.fillHeight: true + + leftPadding: 0 + Layout.bottomMargin: 16 + + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + placeholderTextColor: AmneziaStyle.color.mutedGray + + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + + placeholderText: root.placeholderText + text: root.text + + onCursorVisibleChanged: { + if (textArea.cursorVisible) { + fl.interactive = true + } else { + fl.interactive = false + } + } + + wrapMode: Text.Wrap + + MouseArea { + id: textAreaMouse + anchors.fill: parent + acceptedButtons: Qt.RightButton + hoverEnabled: true + onClicked: { + fl.interactive = true + contextMenu.open() + } + } + + onFocusChanged: { + root.border.color = getBorderColor(borderNormalColor) + } + + ContextMenuType { + id: contextMenu + textObj: textArea + } + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: -8 + spacing: 0 + ImageButtonType { + id: firstButton + visible: root.firstButtonImage !== "" + + imageColor: AmneziaStyle.color.paleGray + + image: root.firstButtonImage + onClicked: function() { + if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") { + root.firstButtonClickedFunc() + } + } + } + + ImageButtonType { + id: secondButton + visible: root.secondButtonImage !== "" + + imageColor: AmneziaStyle.color.paleGray + + image: root.secondButtonImage + onClicked: function() { + if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") { + root.secondButtonClickedFunc() + } + } + } + + Item { + Layout.fillWidth: true + } + + ImageButtonType { + id: resetButton + imageColor: AmneziaStyle.color.paleGray + + visible: root.textAreaText !== "" + image: "qrc:/images/controls/close.svg" + + onClicked: function() { + root.textAreaText = "" + textArea.focus = true + } + } + } + } + + onPressed: { + root.border.color = getBorderColor(borderFocusedColor) + } + + onExited: { + root.border.color = getBorderColor(borderNormalColor) + } + + onEntered: { + root.border.color = getBorderColor(borderHoveredColor) + } + } + + + function getBorderColor(noneFocusedColor) { + return textArea.focus ? root.borderFocusedColor : noneFocusedColor + } +} diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml index c4ed91b3..d7697867 100644 --- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml +++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml @@ -1,233 +1,220 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Item { - id: root - - property string headerText - property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray - property string headerTextColor: AmneziaStyle.color.mutedGray - - property alias errorText: errorField.text - property bool checkEmptyText: false - property bool rightButtonClickedOnEnter: false - - property string buttonText - property string buttonImageSource - property var clickedFunc - - property alias textField: textField - property string textFieldTextColor: AmneziaStyle.color.paleGray - property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray - - property bool textFieldEditable: true - - property string borderColor: AmneziaStyle.color.slateGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - - property string backgroundColor: AmneziaStyle.color.onyxBlack - property string backgroundDisabledColor: AmneziaStyle.color.transparent - property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray - - implicitWidth: content.implicitWidth - implicitHeight: content.implicitHeight - - property FlickableType parentFlickable - - Connections { - target: textField - function onFocusChanged() { - if (textField.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - } - - ColumnLayout { - id: content - anchors.fill: parent - - Rectangle { - id: backgroud - Layout.fillWidth: true - Layout.preferredHeight: input.implicitHeight - color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor - radius: 16 - border.color: getBackgroundBorderColor(root.borderColor) - border.width: 1 - - Behavior on border.color { - PropertyAnimation { duration: 200 } - } - - RowLayout { - id: input - anchors.fill: backgroud - ColumnLayout { - Layout.margins: 16 - LabelTextType { - text: root.headerText - color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor - - visible: text !== "" - - Layout.fillWidth: true - } - - TextField { - id: textField - - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - enabled: root.textFieldEditable - color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor - - inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText - - placeholderTextColor: AmneziaStyle.color.charcoalGray - - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - - font.pixelSize: 16 - font.weight: 400 - font.family: "PT Root UI VF" - - height: 24 - Layout.fillWidth: true - - topPadding: 0 - rightPadding: 0 - leftPadding: 0 - bottomPadding: 0 - - background: Rectangle { - anchors.fill: parent - color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor - } - - onTextChanged: { - root.errorText = "" - } - - onActiveFocusChanged: { - if (root.checkEmptyText && text === "") { - root.errorText = qsTr("The field can't be empty") - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: contextMenu.open() - enabled: true - } - - ContextMenuType { - id: contextMenu - textObj: textField - } - - onFocusChanged: { - backgroud.border.color = getBackgroundBorderColor(root.borderColor) - } - } - } - } - } - - SmallTextType { - id: errorField - - text: root.errorText - visible: root.errorText !== "" - color: AmneziaStyle.color.vibrantRed - - Layout.fillWidth: true - } - } - - MouseArea { - anchors.fill: root - cursorShape: Qt.IBeamCursor - - hoverEnabled: true - - onPressed: function(mouse) { - textField.forceActiveFocus() - mouse.accepted = false - - backgroud.border.color = getBackgroundBorderColor(root.borderColor) - } - - onEntered: { - backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor) - } - - - onExited: { - backgroud.border.color = getBackgroundBorderColor(root.borderColor) - } - } - - BasicButtonType { - visible: (root.buttonText !== "") || (root.buttonImageSource !== "") - - focusPolicy: Qt.NoFocus - text: root.buttonText - leftImageSource: root.buttonImageSource - - anchors.top: content.top - anchors.bottom: content.bottom - anchors.right: content.right - - height: content.implicitHeight - width: content.implicitHeight - squareLeftSide: true - - clickedFunc: function() { - if (root.clickedFunc && typeof root.clickedFunc === "function") { - root.clickedFunc() - } - } - } - - function getBackgroundBorderColor(noneFocusedColor) { - return textField.focus ? root.borderFocusedColor : noneFocusedColor - } - - Keys.onEnterPressed: { - if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") { - clickedFunc() - } - - // if (KeyNavigation.tab) { - // KeyNavigation.tab.forceActiveFocus(); - // } - } - - Keys.onReturnPressed: { - if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") { - clickedFunc() - } - - // if (KeyNavigation.tab) { - // KeyNavigation.tab.forceActiveFocus(); - // } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Item { + id: root + + property string headerText + property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray + property string headerTextColor: AmneziaStyle.color.mutedGray + + property alias errorText: errorField.text + property bool checkEmptyText: false + property bool rightButtonClickedOnEnter: false + + property string buttonText + property string buttonImageSource + property var clickedFunc + + property alias textField: textField + property string textFieldTextColor: AmneziaStyle.color.paleGray + property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray + + property bool textFieldEditable: true + + property string borderColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + + property string backgroundColor: AmneziaStyle.color.onyxBlack + property string backgroundDisabledColor: AmneziaStyle.color.transparent + property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray + + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight + + ColumnLayout { + id: content + anchors.fill: parent + + Rectangle { + id: backgroud + Layout.fillWidth: true + Layout.preferredHeight: input.implicitHeight + color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor + radius: 16 + border.color: getBackgroundBorderColor(root.borderColor) + border.width: 1 + + Behavior on border.color { + PropertyAnimation { duration: 200 } + } + + RowLayout { + id: input + anchors.fill: backgroud + ColumnLayout { + Layout.margins: 16 + LabelTextType { + text: root.headerText + color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor + + visible: text !== "" + + Layout.fillWidth: true + } + + TextField { + id: textField + + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + enabled: root.textFieldEditable + color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor + + inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText + + placeholderTextColor: AmneziaStyle.color.charcoalGray + + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + + font.pixelSize: 16 + font.weight: 400 + font.family: "PT Root UI VF" + + height: 24 + Layout.fillWidth: true + + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + bottomPadding: 0 + + background: Rectangle { + anchors.fill: parent + color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor + } + + onTextChanged: { + root.errorText = "" + } + + onActiveFocusChanged: { + if (root.checkEmptyText && text === "") { + root.errorText = qsTr("The field can't be empty") + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: contextMenu.open() + enabled: true + } + + ContextMenuType { + id: contextMenu + textObj: textField + } + + onFocusChanged: { + backgroud.border.color = getBackgroundBorderColor(root.borderColor) + } + } + } + } + } + + SmallTextType { + id: errorField + + text: root.errorText + visible: root.errorText !== "" + color: AmneziaStyle.color.vibrantRed + + Layout.fillWidth: true + } + } + + MouseArea { + anchors.fill: root + cursorShape: Qt.IBeamCursor + + hoverEnabled: true + + onPressed: function(mouse) { + textField.forceActiveFocus() + mouse.accepted = false + + backgroud.border.color = getBackgroundBorderColor(root.borderColor) + } + + onEntered: { + backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor) + } + + + onExited: { + backgroud.border.color = getBackgroundBorderColor(root.borderColor) + } + } + + BasicButtonType { + visible: (root.buttonText !== "") || (root.buttonImageSource !== "") + + focusPolicy: Qt.NoFocus + text: root.buttonText + leftImageSource: root.buttonImageSource + + anchors.top: content.top + anchors.bottom: content.bottom + anchors.right: content.right + + height: content.implicitHeight + width: content.implicitHeight + squareLeftSide: true + + clickedFunc: function() { + if (root.clickedFunc && typeof root.clickedFunc === "function") { + root.clickedFunc() + } + } + } + + function getBackgroundBorderColor(noneFocusedColor) { + return textField.focus ? root.borderFocusedColor : noneFocusedColor + } + + Keys.onEnterPressed: { + if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") { + clickedFunc() + } + + // if (KeyNavigation.tab) { + // KeyNavigation.tab.forceActiveFocus(); + // } + } + + Keys.onReturnPressed: { + if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") { + clickedFunc() + } + + // if (KeyNavigation.tab) { + // KeyNavigation.tab.forceActiveFocus(); + // } + } +} diff --git a/client/ui/qml/Pages2/PageDeinstalling.qml b/client/ui/qml/Pages2/PageDeinstalling.qml index 69b1f319..03d26f8d 100644 --- a/client/ui/qml/Pages2/PageDeinstalling.qml +++ b/client/ui/qml/Pages2/PageDeinstalling.qml @@ -20,7 +20,9 @@ PageType { SortFilterProxyModel { id: proxyServersModel + sourceModel: ServersModel + filters: [ ValueFilter { roleName: "isCurrentlyProcessed" @@ -29,67 +31,55 @@ PageType { ] } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.fill: parent - contentHeight: content.height - Column { - id: content + spacing: 16 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: proxyServersModel - spacing: 16 + delegate: ColumnLayout { + width: listView.width - Repeater { - model: proxyServersModel - delegate: Item { - implicitWidth: parent.width - implicitHeight: delegateContent.implicitHeight + BaseHeaderType { + Layout.fillWidth: true + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - ColumnLayout { - id: delegateContent + headerText: qsTr("Removing services from %1").arg(name) + } - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 + ProgressBarType { + id: progressBar - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 20 + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - headerText: qsTr("Removing services from %1").arg(name) - } + Timer { + id: timer - ProgressBarType { - id: progressBar - - Layout.fillWidth: true - Layout.topMargin: 32 - - Timer { - id: timer - - interval: 300 - repeat: true - running: true - onTriggered: { - progressBar.value += 0.003 - } - } - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 8 - - text: qsTr("Usually it takes no more than 5 minutes") - } + interval: 300 + repeat: true + running: true + onTriggered: { + progressBar.value += 0.003 } } } + + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Usually it takes no more than 5 minutes") + } } } } diff --git a/client/ui/qml/Pages2/PageDevMenu.qml b/client/ui/qml/Pages2/PageDevMenu.qml index 5fccb43a..9f042fad 100644 --- a/client/ui/qml/Pages2/PageDevMenu.qml +++ b/client/ui/qml/Pages2/PageDevMenu.qml @@ -25,23 +25,17 @@ PageType { anchors.topMargin: 20 } - ListView { + ListViewType { id: listView anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - header: ColumnLayout { width: listView.width BaseHeaderType { - id: header - Layout.fillWidth: true Layout.rightMargin: 16 Layout.leftMargin: 16 @@ -50,16 +44,14 @@ PageType { } } - model: 1 - clip: true + model: 1 // fake model to force the ListView to be created without a model + spacing: 16 delegate: ColumnLayout { width: listView.width TextFieldWithHeaderType { - id: passwordTextField - Layout.fillWidth: true Layout.topMargin: 16 Layout.rightMargin: 16 @@ -87,8 +79,6 @@ PageType { width: listView.width SwitcherType { - id: switcher - Layout.fillWidth: true Layout.topMargin: 24 Layout.rightMargin: 16 diff --git a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml index d97d09e8..18db8119 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml @@ -16,349 +16,397 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - ListView { - id: listview + ListViewType { + id: listView anchors.top: backButtonLayout.bottom anchors.bottom: saveButton.top + anchors.right: parent.right + anchors.left: parent.left - width: parent.width + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - clip: true - - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() + headerText: qsTr("AmneziaWG settings") + } } model: AwgConfigModel - delegate: Item { - id: delegateItem - implicitWidth: listview.width - implicitHeight: col.implicitHeight + delegate: ColumnLayout { + width: listView.width - property alias mtuTextField: mtuTextField property bool isSaveButtonEnabled: mtuTextField.errorText === "" && junkPacketMaxSizeTextField.errorText === "" && junkPacketMinSizeTextField.errorText === "" && junkPacketCountTextField.errorText === "" - ColumnLayout { - id: col + spacing: 0 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + TextFieldWithHeaderType { + id: mtuTextField - anchors.leftMargin: 16 - anchors.rightMargin: 16 + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - spacing: 0 + headerText: qsTr("MTU") + textField.text: clientMtu + textField.validator: IntValidator { bottom: 576; top: 65535 } - BaseHeaderType { - Layout.fillWidth: true - - headerText: qsTr("AmneziaWG settings") - } - - TextFieldWithHeaderType { - id: mtuTextField - Layout.fillWidth: true - Layout.topMargin: 40 - - headerText: qsTr("MTU") - textField.text: clientMtu - textField.validator: IntValidator { bottom: 576; top: 65535 } - - textField.onEditingFinished: { - if (textField.text !== clientMtu) { - clientMtu = textField.text - } - } - checkEmptyText: true - KeyNavigation.tab: junkPacketCountTextField.textField - } - - AwgTextField { - id: junkPacketCountTextField - headerText: "Jc - Junk packet count" - textField.text: clientJunkPacketCount - - textField.onEditingFinished: { - if (textField.text !== clientJunkPacketCount) { - clientJunkPacketCount = textField.text - } - } - - KeyNavigation.tab: junkPacketMinSizeTextField.textField - } - - AwgTextField { - id: junkPacketMinSizeTextField - headerText: "Jmin - Junk packet minimum size" - textField.text: clientJunkPacketMinSize - - textField.onEditingFinished: { - if (textField.text !== clientJunkPacketMinSize) { - clientJunkPacketMinSize = textField.text - } - } - - KeyNavigation.tab: junkPacketMaxSizeTextField.textField - } - - AwgTextField { - id: junkPacketMaxSizeTextField - headerText: "Jmax - Junk packet maximum size" - textField.text: clientJunkPacketMaxSize - - textField.onEditingFinished: { - if (textField.text !== clientJunkPacketMaxSize) { - clientJunkPacketMaxSize = textField.text - } + textField.onEditingFinished: { + if (textField.text !== clientMtu) { + clientMtu = textField.text } } + checkEmptyText: true + } - AwgTextField { - id: specialJunk1TextField - headerText: qsTr("I1 - First special junk packet") - textField.text: clientSpecialJunk1 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: junkPacketCountTextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk1) { - clientSpecialJunk1 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: "Jc - Junk packet count" + textField.text: clientJunkPacketCount + + textField.onEditingFinished: { + if (textField.text !== clientJunkPacketCount) { + clientJunkPacketCount = textField.text } } + } - AwgTextField { - id: specialJunk2TextField - headerText: qsTr("I2 - Second special junk packet") - textField.text: clientSpecialJunk2 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: junkPacketMinSizeTextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk2) { - clientSpecialJunk2 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: "Jmin - Junk packet minimum size" + textField.text: clientJunkPacketMinSize + + textField.onEditingFinished: { + if (textField.text !== clientJunkPacketMinSize) { + clientJunkPacketMinSize = textField.text } } + } - AwgTextField { - id: specialJunk3TextField - headerText: qsTr("I3 - Third special junk packet") - textField.text: clientSpecialJunk3 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: junkPacketMaxSizeTextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk3) { - clientSpecialJunk3 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: "Jmax - Junk packet maximum size" + textField.text: clientJunkPacketMaxSize + + textField.onEditingFinished: { + if (textField.text !== clientJunkPacketMaxSize) { + clientJunkPacketMaxSize = textField.text } } + } - AwgTextField { - id: specialJunk4TextField - headerText: qsTr("I4 - Fourth special junk packet") - textField.text: clientSpecialJunk4 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk1TextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk4) { - clientSpecialJunk4 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("I1 - First special junk packet") + textField.text: clientSpecialJunk1 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk1) { + clientSpecialJunk1 = textField.text } } + } - AwgTextField { - id: specialJunk5TextField - headerText: qsTr("I5 - Fifth special junk packet") - textField.text: clientSpecialJunk5 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk2TextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk5 ) { - clientSpecialJunk5 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("I2 - Second special junk packet") + textField.text: clientSpecialJunk2 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk2) { + clientSpecialJunk2 = textField.text } } + } - AwgTextField { - id: controlledJunk1TextField - headerText: qsTr("J1 - First controlled junk packet") - textField.text: clientControlledJunk1 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk3TextField - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk1) { - clientControlledJunk1 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("I3 - Third special junk packet") + textField.text: clientSpecialJunk3 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk3) { + clientSpecialJunk3 = textField.text } } + } - AwgTextField { - id: controlledJunk2TextField - headerText: qsTr("J2 - Second controlled junk packet") - textField.text: clientControlledJunk2 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk4TextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk2) { - clientControlledJunk2 = textField.text - } + headerText: qsTr("I4 - Fourth special junk packet") + textField.text: clientSpecialJunk4 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk4) { + clientSpecialJunk4 = textField.text } } + } - AwgTextField { - id: controlledJunk3TextField - headerText: qsTr("J3 - Third controlled junk packet") - textField.text: clientControlledJunk3 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk5TextField - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk3) { - clientControlledJunk3 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("I5 - Fifth special junk packet") + textField.text: clientSpecialJunk5 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk5 ) { + clientSpecialJunk5 = textField.text } } + } - AwgTextField { - id: iTimeTextField - headerText: qsTr("Itime - Special handshake timeout") - textField.text: clientSpecialHandshakeTimeout - checkEmptyText: false + AwgTextField { + id: controlledJunk1TextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialHandshakeTimeout) { - clientSpecialHandshakeTimeout = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("J1 - First controlled junk packet") + textField.text: clientControlledJunk1 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientControlledJunk1) { + clientControlledJunk1 = textField.text } } + } - Header2TextType { - Layout.fillWidth: true - Layout.topMargin: 16 + AwgTextField { + id: controlledJunk2TextField - text: qsTr("Server settings") + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("J2 - Second controlled junk packet") + textField.text: clientControlledJunk2 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientControlledJunk2) { + clientControlledJunk2 = textField.text + } } + } - AwgTextField { - id: portTextField - enabled: false + AwgTextField { + id: controlledJunk3TextField - headerText: qsTr("Port") - textField.text: port + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("J3 - Third controlled junk packet") + textField.text: clientControlledJunk3 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientControlledJunk3) { + clientControlledJunk3 = textField.text + } } + } - AwgTextField { - id: initPacketJunkSizeTextField - enabled: false + AwgTextField { + id: iTimeTextField - headerText: "S1 - Init packet junk size" - textField.text: serverInitPacketJunkSize + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Itime - Special handshake timeout") + textField.text: clientSpecialHandshakeTimeout + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialHandshakeTimeout) { + clientSpecialHandshakeTimeout = textField.text + } } + } - AwgTextField { - id: responsePacketJunkSizeTextField - enabled: false + Header2TextType { + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - headerText: "S2 - Response packet junk size" - textField.text: serverResponsePacketJunkSize - } + text: qsTr("Server settings") + } - // AwgTextField { - // id: cookieReplyPacketJunkSizeTextField - // enabled: false + AwgTextField { + id: portTextField - // headerText: "S3 - Cookie Reply packet junk size" - // textField.text: serverCookieReplyPacketJunkSize - // } + Layout.leftMargin: 16 + Layout.rightMargin: 16 - // AwgTextField { - // id: transportPacketJunkSizeTextField - // enabled: false + enabled: false - // headerText: "S4 - Transport packet junk size" - // textField.text: serverTransportPacketJunkSize - // } + headerText: qsTr("Port") + textField.text: port + } - AwgTextField { - id: initPacketMagicHeaderTextField - enabled: false + AwgTextField { + id: initPacketJunkSizeTextField - headerText: "H1 - Init packet magic header" - textField.text: serverInitPacketMagicHeader - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 - AwgTextField { - id: responsePacketMagicHeaderTextField - enabled: false + enabled: false - headerText: "H2 - Response packet magic header" - textField.text: serverResponsePacketMagicHeader - } + headerText: "S1 - Init packet junk size" + textField.text: serverInitPacketJunkSize + } - AwgTextField { - id: underloadPacketMagicHeaderTextField - enabled: false + AwgTextField { + id: responsePacketJunkSizeTextField - headerText: "H3 - Underload packet magic header" - textField.text: serverUnderloadPacketMagicHeader - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 - AwgTextField { - id: transportPacketMagicHeaderTextField - enabled: false + enabled: false - headerText: "H4 - Transport packet magic header" - textField.text: serverTransportPacketMagicHeader - } + headerText: "S2 - Response packet junk size" + textField.text: serverResponsePacketJunkSize + } + // AwgTextField { + // id: cookieReplyPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // enabled: false + + // headerText: "S3 - Cookie Reply packet junk size" + // textField.text: serverCookieReplyPacketJunkSize + // } + + // AwgTextField { + // id: transportPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // enabled: false + + // headerText: "S4 - Transport packet junk size" + // textField.text: serverTransportPacketJunkSize + // } + + AwgTextField { + id: initPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H1 - Init packet magic header" + textField.text: serverInitPacketMagicHeader + } + + AwgTextField { + id: responsePacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H2 - Response packet magic header" + textField.text: serverResponsePacketMagicHeader + } + + AwgTextField { + id: underloadPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H3 - Underload packet magic header" + textField.text: serverUnderloadPacketMagicHeader + } + + AwgTextField { + id: transportPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H4 - Transport packet magic header" + textField.text: serverTransportPacketMagicHeader } } } @@ -375,18 +423,17 @@ PageType { anchors.rightMargin: 16 anchors.leftMargin: 16 - enabled: listview.currentItem.isSaveButtonEnabled + enabled: listView.currentItem.isSaveButtonEnabled text: qsTr("Save") onActiveFocusChanged: { if(activeFocus) { - listview.positionViewAtEnd() + listView.positionViewAtEnd() } } clickedFunc: function() { - forceActiveFocus() var headerText = qsTr("Save settings?") var descriptionText = qsTr("Only the settings for this device will be changed") var yesButtonText = qsTr("Continue") @@ -401,11 +448,9 @@ PageType { PageController.goToPage(PageEnum.PageSetupWizardInstalling); InstallController.updateContainer(AwgConfigModel.getConfig()) } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } + + var noButtonFunction = function() {} + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index 699ae724..2140f740 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -19,334 +19,343 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - ListView { - id: listview - - property bool isFocusable: true + ListViewType { + id: listView anchors.top: backButtonLayout.bottom anchors.bottom: parent.bottom - - width: parent.width - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - clip: true + anchors.left: parent.left + anchors.right: parent.right model: AwgConfigModel - delegate: Item { + delegate: ColumnLayout { id: delegateItem - implicitWidth: listview.width - implicitHeight: col.implicitHeight + + width: listView.width property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - ColumnLayout { - id: col + spacing: 0 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - anchors.leftMargin: 16 - anchors.rightMargin: 16 + headerText: qsTr("AmneziaWG settings") + } - spacing: 0 + TextFieldWithHeaderType { + id: vpnAddressSubnetTextField - BaseHeaderType { - Layout.fillWidth: true + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - headerText: qsTr("AmneziaWG settings") - } + enabled: delegateItem.isEnabled - TextFieldWithHeaderType { - id: vpnAddressSubnetTextField + headerText: qsTr("VPN address subnet") + textField.text: subnetAddress - Layout.fillWidth: true - Layout.topMargin: 40 - - enabled: delegateItem.isEnabled - - headerText: qsTr("VPN address subnet") - textField.text: subnetAddress - - textField.onEditingFinished: { - if (textField.text !== subnetAddress) { - subnetAddress = textField.text - } - } - - checkEmptyText: true - } - - TextFieldWithHeaderType { - id: portTextField - Layout.fillWidth: true - Layout.topMargin: 16 - - enabled: delegateItem.isEnabled - - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - - textField.onEditingFinished: { - if (textField.text !== port) { - port = textField.text - } - } - - checkEmptyText: true - } - - AwgTextField { - id: junkPacketCountTextField - headerText: qsTr("Jc - Junk packet count") - textField.text: serverJunkPacketCount - - textField.onEditingFinished: { - if (textField.text !== serverJunkPacketCount) { - serverJunkPacketCount = textField.text - } + textField.onEditingFinished: { + if (textField.text !== subnetAddress) { + subnetAddress = textField.text } } - AwgTextField { - id: junkPacketMinSizeTextField - headerText: qsTr("Jmin - Junk packet minimum size") - textField.text: serverJunkPacketMinSize + checkEmptyText: true + } - textField.onEditingFinished: { - if (textField.text !== serverJunkPacketMinSize) { - serverJunkPacketMinSize = textField.text - } + TextFieldWithHeaderType { + id: portTextField + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: delegateItem.isEnabled + + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } + + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text } } - AwgTextField { - id: junkPacketMaxSizeTextField - headerText: qsTr("Jmax - Junk packet maximum size") - textField.text: serverJunkPacketMaxSize + checkEmptyText: true + } - textField.onEditingFinished: { - if (textField.text !== serverJunkPacketMaxSize) { - serverJunkPacketMaxSize = textField.text - } + AwgTextField { + id: junkPacketCountTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Jc - Junk packet count") + textField.text: serverJunkPacketCount + + textField.onEditingFinished: { + if (textField.text !== serverJunkPacketCount) { + serverJunkPacketCount = textField.text + } + } + } + + AwgTextField { + id: junkPacketMinSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Jmin - Junk packet minimum size") + textField.text: serverJunkPacketMinSize + + textField.onEditingFinished: { + if (textField.text !== serverJunkPacketMinSize) { + serverJunkPacketMinSize = textField.text + } + } + } + + AwgTextField { + id: junkPacketMaxSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Jmax - Junk packet maximum size") + textField.text: serverJunkPacketMaxSize + + textField.onEditingFinished: { + if (textField.text !== serverJunkPacketMaxSize) { + serverJunkPacketMaxSize = textField.text + } + } + } + + AwgTextField { + id: initPacketJunkSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("S1 - Init packet junk size") + textField.text: serverInitPacketJunkSize + + textField.onEditingFinished: { + if (textField.text !== serverInitPacketJunkSize) { + serverInitPacketJunkSize = textField.text + } + } + } + + AwgTextField { + id: responsePacketJunkSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("S2 - Response packet junk size") + textField.text: serverResponsePacketJunkSize + + textField.onEditingFinished: { + if (textField.text !== serverResponsePacketJunkSize) { + serverResponsePacketJunkSize = textField.text + } + } + } + + // AwgTextField { + // id: cookieReplyPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // headerText: qsTr("S3 - Cookie reply packet junk size") + // textField.text: serverCookieReplyPacketJunkSize + + // textField.onEditingFinished: { + // if (textField.text !== serverCookieReplyPacketJunkSize) { + // serverCookieReplyPacketJunkSize = textField.text + // } + // } + // } + + // AwgTextField { + // id: transportPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // headerText: qsTr("S4 - Transport packet junk size") + // textField.text: serverTransportPacketJunkSize + + // textField.onEditingFinished: { + // if (textField.text !== serverTransportPacketJunkSize) { + // serverTransportPacketJunkSize = textField.text + // } + // } + // } + + AwgTextField { + id: initPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H1 - Init packet magic header") + textField.text: serverInitPacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverInitPacketMagicHeader) { + serverInitPacketMagicHeader = textField.text + } + } + } + + AwgTextField { + id: responsePacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H2 - Response packet magic header") + textField.text: serverResponsePacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverResponsePacketMagicHeader) { + serverResponsePacketMagicHeader = textField.text + } + } + } + + AwgTextField { + id: underloadPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H3 - Underload packet magic header") + textField.text: serverUnderloadPacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverUnderloadPacketMagicHeader) { + serverUnderloadPacketMagicHeader = textField.text + } + } + } + + AwgTextField { + id: transportPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H4 - Transport packet magic header") + textField.text: serverTransportPacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverTransportPacketMagicHeader) { + serverTransportPacketMagicHeader = textField.text + } + } + } + + BasicButtonType { + id: saveRestartButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: underloadPacketMagicHeaderTextField.errorText === "" && + transportPacketMagicHeaderTextField.errorText === "" && + responsePacketMagicHeaderTextField.errorText === "" && + initPacketMagicHeaderTextField.errorText === "" && + responsePacketJunkSizeTextField.errorText === "" && + // cookieReplyHeaderJunkTextField.errorText === "" && + // transportHeaderJunkTextField.errorText === "" && + initPacketJunkSizeTextField.errorText === "" && + junkPacketMaxSizeTextField.errorText === "" && + junkPacketMinSizeTextField.errorText === "" && + junkPacketCountTextField.errorText === "" && + portTextField.errorText === "" && + vpnAddressSubnetTextField.errorText === "" + + text: qsTr("Save") + + onActiveFocusChanged: { + if(activeFocus) { + listView.positionViewAtEnd() } } - AwgTextField { - id: initPacketJunkSizeTextField - headerText: qsTr("S1 - Init packet junk size") - textField.text: serverInitPacketJunkSize - - textField.onEditingFinished: { - if (textField.text !== serverInitPacketJunkSize) { - serverInitPacketJunkSize = textField.text + clickedFunc: function() { + if (delegateItem.isEnabled) { + if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text, + transportPacketMagicHeaderTextField.textField.text, + responsePacketMagicHeaderTextField.textField.text, + initPacketMagicHeaderTextField.textField.text)) { + PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique")) + return } - } - } - AwgTextField { - id: responsePacketJunkSizeTextField - headerText: qsTr("S2 - Response packet junk size") - textField.text: serverResponsePacketJunkSize - - textField.onEditingFinished: { - if (textField.text !== serverResponsePacketJunkSize) { - serverResponsePacketJunkSize = textField.text - } - } - } - - // AwgTextField { - // id: cookieReplyPacketJunkSizeTextField - // headerText: qsTr("S3 - Cookie reply packet junk size") - // textField.text: serverCookieReplyPacketJunkSize - - // textField.onEditingFinished: { - // if (textField.text !== serverCookieReplyPacketJunkSize) { - // serverCookieReplyPacketJunkSize = textField.text - // } - // } - // } - - // AwgTextField { - // id: transportPacketJunkSizeTextField - // headerText: qsTr("S4 - Transport packet junk size") - // textField.text: serverTransportPacketJunkSize - - // textField.onEditingFinished: { - // if (textField.text !== serverTransportPacketJunkSize) { - // serverTransportPacketJunkSize = textField.text - // } - // } - // } - - AwgTextField { - id: initPacketMagicHeaderTextField - headerText: qsTr("H1 - Init packet magic header") - textField.text: serverInitPacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverInitPacketMagicHeader) { - serverInitPacketMagicHeader = textField.text - } - } - } - - AwgTextField { - id: responsePacketMagicHeaderTextField - headerText: qsTr("H2 - Response packet magic header") - textField.text: serverResponsePacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverResponsePacketMagicHeader) { - serverResponsePacketMagicHeader = textField.text - } - } - } - - AwgTextField { - id: underloadPacketMagicHeaderTextField - headerText: qsTr("H3 - Underload packet magic header") - textField.text: serverUnderloadPacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverUnderloadPacketMagicHeader) { - serverUnderloadPacketMagicHeader = textField.text - } - } - } - - AwgTextField { - id: transportPacketMagicHeaderTextField - headerText: qsTr("H4 - Transport packet magic header") - textField.text: serverTransportPacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverTransportPacketMagicHeader) { - serverTransportPacketMagicHeader = textField.text - } - } - } - - - BasicButtonType { - id: saveRestartButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - enabled: underloadPacketMagicHeaderTextField.errorText === "" && - transportPacketMagicHeaderTextField.errorText === "" && - responsePacketMagicHeaderTextField.errorText === "" && - initPacketMagicHeaderTextField.errorText === "" && - responsePacketJunkSizeTextField.errorText === "" && - // cookieReplyHeaderJunkTextField.errorText === "" && - // transportHeaderJunkTextField.errorText === "" && - initPacketJunkSizeTextField.errorText === "" && - junkPacketMaxSizeTextField.errorText === "" && - junkPacketMinSizeTextField.errorText === "" && - junkPacketCountTextField.errorText === "" && - portTextField.errorText === "" && - vpnAddressSubnetTextField.errorText === "" - - text: qsTr("Save") - - onActiveFocusChanged: { - if(activeFocus) { - listview.positionViewAtEnd() + if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text), + parseInt(responsePacketJunkSizeTextField.textField.text))) { + PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)")) + return } + // if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text), + // parseInt(responsePacketJunkSizeTextField.textField.text), + // parseInt(cookieReplyPacketJunkSizeTextField.textField.text), + // parseInt(transportPacketJunkSizeTextField.textField.text))) { + // PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) + S3 + cookie reply size (64) + S4 + transport packet size (32)")) + // return + // } } - clickedFunc: function() { - forceActiveFocus() + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") - if (delegateItem.isEnabled) { - if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text, - transportPacketMagicHeaderTextField.textField.text, - responsePacketMagicHeaderTextField.textField.text, - initPacketMagicHeaderTextField.textField.text)) { - PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique")) - return - } - - if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text), - parseInt(responsePacketJunkSizeTextField.textField.text))) { - PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)")) - return - } - // if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text), - // parseInt(responsePacketJunkSizeTextField.textField.text), - // parseInt(cookieReplyPacketJunkSizeTextField.textField.text), - // parseInt(transportPacketJunkSizeTextField.textField.text))) { - // PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) + S3 + cookie reply size (64) + S4 + transport packet size (32)")) - // return - // } + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return } - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(AwgConfigModel.getConfig()) - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveRestartButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(AwgConfigModel.getConfig()) } + + var noButtonFunction = function() {} + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } } diff --git a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml index 8e5129b0..51d4c9e2 100644 --- a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml @@ -16,212 +16,192 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.left: parent.left + anchors.right: parent.right - Column { - id: content + property int selectedIndex: 0 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + enabled: ServersModel.isProcessedServerHasWriteAccess() - enabled: ServersModel.isProcessedServerHasWriteAccess() + header: ColumnLayout { + width: listView.width - ListView { - id: listview + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - property int selectedIndex: 0 + headerText: qsTr("Cloak settings") + } + } - width: parent.width - height: listview.contentItem.height + model: CloakConfigModel - clip: true - reuseItems: true + delegate: ColumnLayout { + width: listView.width - model: CloakConfigModel + property alias trafficFromField: trafficFromField - delegate: Item { - id: delegateItem + spacing: 0 - property alias trafficFromField: trafficFromField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() + TextFieldWithHeaderType { + id: trafficFromField - implicitWidth: listview.width - implicitHeight: col.implicitHeight + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - ColumnLayout { - id: col + headerText: qsTr("Disguised as traffic from") + textField.text: site - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + textField.onEditingFinished: { + if (textField.text !== site) { + var tmpText = textField.text + tmpText = tmpText.toLocaleLowerCase() - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - spacing: 0 - - BaseHeaderType { - Layout.fillWidth: true - headerText: qsTr("Cloak settings") + var indexHttps = tmpText.indexOf("https://") + if (indexHttps === 0) { + tmpText = textField.text.substring(8) + } else { + site = textField.text } + } + } - TextFieldWithHeaderType { - id: trafficFromField + checkEmptyText: true + } - Layout.fillWidth: true - Layout.topMargin: 32 + TextFieldWithHeaderType { + id: portTextField - enabled: delegateItem.isEnabled + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - headerText: qsTr("Disguised as traffic from") - textField.text: site + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } - textField.onEditingFinished: { - if (textField.text !== site) { - var tmpText = textField.text - tmpText = tmpText.toLocaleLowerCase() + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text + } + } - var indexHttps = tmpText.indexOf("https://") - if (indexHttps === 0) { - tmpText = textField.text.substring(8) - } else { - site = textField.text - } - } + checkEmptyText: true + } + + DropDownType { + id: cipherDropDown + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + descriptionText: qsTr("Cipher") + headerText: qsTr("Cipher") + + drawerParent: root + + listView: ListViewWithRadioButtonType { + id: cipherListView + + rootWidth: root.width + + model: ListModel { + ListElement { name : "chacha20-ietf-poly1305" } + ListElement { name : "xchacha20-ietf-poly1305" } + ListElement { name : "aes-256-gcm" } + ListElement { name : "aes-192-gcm" } + ListElement { name : "aes-128-gcm" } + } + + clickedFunction: function() { + cipherDropDown.text = selectedText + cipher = cipherDropDown.text + cipherDropDown.closeTriggered() + } + + Component.onCompleted: { + cipherDropDown.text = cipher + + for (var i = 0; i < cipherListView.model.count; i++) { + if (cipherListView.model.get(i).name === cipherDropDown.text) { + selectedIndex = i } - - checkEmptyText: true - } - - TextFieldWithHeaderType { - id: portTextField - - Layout.fillWidth: true - Layout.topMargin: 16 - - enabled: delegateItem.isEnabled - - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - - textField.onEditingFinished: { - if (textField.text !== port) { - port = textField.text - } - } - - checkEmptyText: true - } - - DropDownType { - id: cipherDropDown - Layout.fillWidth: true - Layout.topMargin: 16 - - enabled: delegateItem.isEnabled - - descriptionText: qsTr("Cipher") - headerText: qsTr("Cipher") - - drawerParent: root - - listView: ListViewWithRadioButtonType { - id: cipherListView - - rootWidth: root.width - - model: ListModel { - ListElement { name : "chacha20-ietf-poly1305" } - ListElement { name : "xchacha20-ietf-poly1305" } - ListElement { name : "aes-256-gcm" } - ListElement { name : "aes-192-gcm" } - ListElement { name : "aes-128-gcm" } - } - - clickedFunction: function() { - cipherDropDown.text = selectedText - cipher = cipherDropDown.text - cipherDropDown.closeTriggered() - } - - Component.onCompleted: { - cipherDropDown.text = cipher - - for (var i = 0; i < cipherListView.model.count; i++) { - if (cipherListView.model.get(i).name === cipherDropDown.text) { - selectedIndex = i - } - } - } - } - } - - BasicButtonType { - id: saveButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - enabled: trafficFromField.errorText === "" && - portTextField.errorText === "" - - text: qsTr("Save") - - clickedFunc: function() { - forceActiveFocus() - - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling) - InstallController.updateContainer(CloakConfigModel.getConfig()) - } - - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() } } } } + + BasicButtonType { + id: saveButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: trafficFromField.errorText === "" && + portTextField.errorText === "" + + text: qsTr("Save") + + clickedFunc: function() { + forceActiveFocus() + + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling) + InstallController.updateContainer(CloakConfigModel.getConfig()) + } + + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + Keys.onEnterPressed: saveButton.clicked() + Keys.onReturnPressed: saveButton.clicked() + } } } } diff --git a/client/ui/qml/Pages2/PageProtocolRaw.qml b/client/ui/qml/Pages2/PageProtocolRaw.qml index bba3eafe..b90af6f6 100644 --- a/client/ui/qml/Pages2/PageProtocolRaw.qml +++ b/client/ui/qml/Pages2/PageProtocolRaw.qml @@ -19,164 +19,154 @@ import "../Components" PageType { id: root - ColumnLayout { - id: header + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton - } - - BaseHeaderType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: header.bottom - anchors.left: parent.left + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom anchors.right: parent.right - contentHeight: content.height + anchors.left: parent.left - Column { - id: content + header: ColumnLayout { + width: listView.width - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 32 + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - ListView { - id: listView - width: parent.width - height: contentItem.height - clip: true - interactive: false - model: ProtocolsModel + headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") + } + } - activeFocusOnTab: true - focus: true + model: ProtocolsModel - delegate: Item { - implicitWidth: parent.width - implicitHeight: delegateContent.implicitHeight + delegate: ColumnLayout { + width: listView.width - property alias focusItem: button + LabelWithButtonType { + id: button - ColumnLayout { - id: delegateContent + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - anchors.fill: parent + text: qsTr("Show connection options") - LabelWithButtonType { - id: button + clickedFunction: function() { + configContentDrawer.openTriggered() + } - Layout.fillWidth: true + MouseArea { + anchors.fill: button + cursorShape: Qt.PointingHandCursor + enabled: false + } + } - text: qsTr("Show connection options") + DividerType {} - clickedFunction: function() { - configContentDrawer.openTriggered() - } + DrawerType2 { + id: configContentDrawer - MouseArea { - anchors.fill: button - cursorShape: Qt.PointingHandCursor - enabled: false + expandedHeight: root.height * 0.9 + + parent: root + anchors.fill: parent + + expandedStateContent: Item { + implicitHeight: configContentDrawer.expandedHeight + + BackButtonType { + id: drawerBackButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 + + backButtonFunction: function() { + configContentDrawer.closeTriggered() + } + } + + ListViewType { + id: drawerListView + + anchors.top: drawerBackButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + header: ColumnLayout { + width: drawerListView.width + + Header2Type { + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Connection options %1").arg(protocolName) } } - DividerType {} + model: 1 // fake model to force the ListView to be created without a model - DrawerType2 { - id: configContentDrawer + delegate: ColumnLayout { + width: drawerListView.width - expandedHeight: root.height * 0.9 + TextArea { + id: configText - parent: root - anchors.fill: parent + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - expandedStateContent: Item { - implicitHeight: configContentDrawer.expandedHeight + padding: 0 + height: 24 - BackButtonType { - id: backButton1 + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" - backButtonFunction: function() { - configContentDrawer.closeTriggered() - } - } + text: rawConfig - FlickableType { - anchors.top: backButton1.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin + wrapMode: Text.Wrap - ColumnLayout { - id: configContent - - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 - - Header2Type { - Layout.fillWidth: true - Layout.topMargin: 16 - - headerText: qsTr("Connection options %1").arg(protocolName) - } - - TextArea { - id: configText - - Layout.fillWidth: true - Layout.topMargin: 16 - Layout.bottomMargin: 16 - - padding: 0 - leftPadding: 0 - height: 24 - - color: AmneziaStyle.color.paleGray - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - - font.pixelSize: 16 - font.weight: Font.Medium - font.family: "PT Root UI VF" - - text: rawConfig - - wrapMode: Text.Wrap - - background: Rectangle { - color: AmneziaStyle.color.transparent - } - } - } + background: Rectangle { + color: AmneziaStyle.color.transparent } } } } } } + } + + footer: ColumnLayout { + width: listView.width LabelWithButtonType { id: removeButton @@ -198,11 +188,7 @@ PageType { PageController.goToPage(PageEnum.PageDeinstalling) InstallController.removeProcessedContainer() } - var noButtonFunction = function() { - if (!GC.isMobile()) { - focusItem.forceActiveFocus() - } - } + var noButtonFunction = function() {} showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } diff --git a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml index 92df3ec7..4d587539 100644 --- a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml @@ -16,179 +16,158 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + enabled: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: ShadowSocksConfigModel - enabled: ServersModel.isProcessedServerHasWriteAccess() + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + spacing: 0 - width: parent.width - height: listview.contentItem.height + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - clip: true - interactive: false + headerText: qsTr("Shadowsocks settings") + } - model: ShadowSocksConfigModel + TextFieldWithHeaderType { + id: portTextField - delegate: Item { - id: delegateItem + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() + enabled: listView.enabled - implicitWidth: listview.width - implicitHeight: col.implicitHeight + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } - ColumnLayout { - id: col + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text + } + } - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + checkEmptyText: true + } - anchors.leftMargin: 16 - anchors.rightMargin: 16 + DropDownType { + id: cipherDropDown - spacing: 0 + Layout.fillWidth: true + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - BaseHeaderType { - Layout.fillWidth: true - headerText: qsTr("Shadowsocks settings") - } + enabled: listView.enabled - TextFieldWithHeaderType { - id: portTextField + descriptionText: qsTr("Cipher") + headerText: qsTr("Cipher") - Layout.fillWidth: true - Layout.topMargin: 40 + drawerParent: root - enabled: delegateItem.isEnabled + listView: ListViewWithRadioButtonType { - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } + id: cipherListView - textField.onEditingFinished: { - if (textField.text !== port) { - port = textField.text - } + rootWidth: root.width + + model: ListModel { + ListElement { name : "chacha20-ietf-poly1305" } + ListElement { name : "xchacha20-ietf-poly1305" } + ListElement { name : "aes-256-gcm" } + ListElement { name : "aes-192-gcm" } + ListElement { name : "aes-128-gcm" } + } + + clickedFunction: function() { + cipherDropDown.text = selectedText + cipher = cipherDropDown.text + cipherDropDown.closeTriggered() + } + + Component.onCompleted: { + cipherDropDown.text = cipher + + for (var i = 0; i < cipherListView.model.count; i++) { + if (cipherListView.model.get(i).name === cipherDropDown.text) { + currentIndex = i } - - checkEmptyText: true - } - - DropDownType { - id: cipherDropDown - Layout.fillWidth: true - Layout.topMargin: 20 - - enabled: delegateItem.isEnabled - - descriptionText: qsTr("Cipher") - headerText: qsTr("Cipher") - - drawerParent: root - - listView: ListViewWithRadioButtonType { - - id: cipherListView - - rootWidth: root.width - - model: ListModel { - ListElement { name : "chacha20-ietf-poly1305" } - ListElement { name : "xchacha20-ietf-poly1305" } - ListElement { name : "aes-256-gcm" } - ListElement { name : "aes-192-gcm" } - ListElement { name : "aes-128-gcm" } - } - - clickedFunction: function() { - cipherDropDown.text = selectedText - cipher = cipherDropDown.text - cipherDropDown.closeTriggered() - } - - Component.onCompleted: { - cipherDropDown.text = cipher - - for (var i = 0; i < cipherListView.model.count; i++) { - if (cipherListView.model.get(i).name === cipherDropDown.text) { - currentIndex = i - } - } - } - } - } - - BasicButtonType { - id: saveButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - enabled: portTextField.errorText === "" - - text: qsTr("Save") - - clickedFunc: function() { - forceActiveFocus() - - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(ShadowSocksConfigModel.getConfig()) - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() } } } } + + BasicButtonType { + id: saveButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: portTextField.errorText === "" + + text: qsTr("Save") + + clickedFunc: function() { + forceActiveFocus() + + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(ShadowSocksConfigModel.getConfig()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + Keys.onEnterPressed: saveButton.clicked() + Keys.onReturnPressed: saveButton.clicked() + } } } } diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml index 96ec1dc6..ef2490c7 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml @@ -16,160 +16,124 @@ import "../Components" PageType { id: root - Item { - id: focusItem - onFocusChanged: { - if (activeFocus) { - fl.ensureVisible(focusItem) - } - } - KeyNavigation.tab: backButton - } - - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton - KeyNavigation.tab: listview.currentItem.mtuTextField.textField + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + model: WireGuardConfigModel - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + property alias mtuTextField: mtuTextField + property bool isSaveButtonEnabled: mtuTextField.errorText === "" - width: parent.width - height: listview.contentItem.height + spacing: 0 - clip: true - interactive: false + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - model: WireGuardConfigModel + headerText: qsTr("WG settings") + } - delegate: Item { - id: delegateItem - implicitWidth: listview.width - implicitHeight: col.implicitHeight + TextFieldWithHeaderType { + id: mtuTextField + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - property alias mtuTextField: mtuTextField - property bool isSaveButtonEnabled: mtuTextField.errorText === "" + headerText: qsTr("MTU") + textField.text: clientMtu + textField.validator: IntValidator { bottom: 576; top: 65535 } - ColumnLayout { - id: col - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - spacing: 0 - - BaseHeaderType { - Layout.fillWidth: true - - headerText: qsTr("WG settings") - } - - TextFieldWithHeaderType { - id: mtuTextField - Layout.fillWidth: true - Layout.topMargin: 40 - - headerText: qsTr("MTU") - textField.text: clientMtu - textField.validator: IntValidator { bottom: 576; top: 65535 } - - textField.onEditingFinished: { - if (textField.text !== clientMtu) { - clientMtu = textField.text - } - } - checkEmptyText: true - KeyNavigation.tab: saveButton - } - - Header2TextType { - Layout.fillWidth: true - Layout.topMargin: 16 - - text: qsTr("Server settings") - } - - TextFieldWithHeaderType { - id: portTextField - Layout.fillWidth: true - Layout.topMargin: 8 - - enabled: false - - headerText: qsTr("Port") - textField.text: port - } - } + textField.onEditingFinished: { + if (textField.text !== clientMtu) { + clientMtu = textField.text + } } + checkEmptyText: true + } + + Header2TextType { + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Server settings") + } + + TextFieldWithHeaderType { + id: portTextField + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: qsTr("Port") + textField.text: port } } - } - BasicButtonType { - id: saveButton + footer: ColumnLayout { + width: listView.width - anchors.right: root.right - anchors.left: root.left - anchors.bottom: root.bottom + BasicButtonType { + id: saveButton - anchors.topMargin: 24 - anchors.bottomMargin: 24 - anchors.rightMargin: 16 - anchors.leftMargin: 16 + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.rightMargin: 16 + Layout.leftMargin: 16 - enabled: listview.currentItem.isSaveButtonEnabled + enabled: listView.currentItem.isSaveButtonEnabled - text: qsTr("Save") + text: qsTr("Save") - clickedFunc: function() { - forceActiveFocus() - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("Only the settings for this device will be changed") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") + clickedFunc: function() { + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("Only the settings for this device will be changed") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(WireGuardConfigModel.getConfig()) - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(WireGuardConfigModel.getConfig()) + } + var noButtonFunction = function() {} + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } } diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index 3122267f..d8ea1d95 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -16,153 +16,134 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + enabled: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: WireGuardConfigModel - enabled: ServersModel.isProcessedServerHasWriteAccess() + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - width: parent.width - height: listview.contentItem.height + spacing: 0 - clip: true - interactive: false + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - model: WireGuardConfigModel + headerText: qsTr("WG settings") + } - delegate: Item { - id: delegateItem + TextFieldWithHeaderType { + id: vpnAddressSubnetTextField - property alias focusItemId: vpnAddressSubnetTextField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - implicitWidth: listview.width - implicitHeight: col.implicitHeight + enabled: delegateItem.isEnabled - ColumnLayout { - id: col + headerText: qsTr("VPN address subnet") + textField.text: subnetAddress - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - spacing: 0 - - BaseHeaderType { - Layout.fillWidth: true - headerText: qsTr("WG settings") - } - - TextFieldWithHeaderType { - id: vpnAddressSubnetTextField - Layout.fillWidth: true - Layout.topMargin: 40 - - enabled: delegateItem.isEnabled - - headerText: qsTr("VPN address subnet") - textField.text: subnetAddress - - textField.onEditingFinished: { - if (textField.text !== subnetAddress) { - subnetAddress = textField.text - } - } - - checkEmptyText: true - } - - TextFieldWithHeaderType { - id: portTextField - Layout.fillWidth: true - Layout.topMargin: 16 - - enabled: delegateItem.isEnabled - - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - - textField.onEditingFinished: { - if (textField.text !== port) { - port = textField.text - } - } - - checkEmptyText: true - } - - BasicButtonType { - id: saveButton - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - enabled: portTextField.errorText === "" && - vpnAddressSubnetTextField.errorText === "" - - text: qsTr("Save") - - onClicked: function() { - forceActiveFocus() - - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(WireGuardConfigModel.getConfig()) - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - - Keys.onEnterPressed: this.clicked() - Keys.onReturnPressed: this.clicked() - } + textField.onEditingFinished: { + if (textField.text !== subnetAddress) { + subnetAddress = textField.text } } + + checkEmptyText: true + } + + TextFieldWithHeaderType { + id: portTextField + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: delegateItem.isEnabled + + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } + + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text + } + } + + checkEmptyText: true + } + + BasicButtonType { + id: saveButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: portTextField.errorText === "" && + vpnAddressSubnetTextField.errorText === "" + + text: qsTr("Save") + + onClicked: function() { + forceActiveFocus() + + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(WireGuardConfigModel.getConfig()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + Keys.onEnterPressed: saveButton.clicked() + Keys.onReturnPressed: saveButton.clicked() } } } diff --git a/client/ui/qml/Pages2/PageProtocolXraySettings.qml b/client/ui/qml/Pages2/PageProtocolXraySettings.qml index 0bcd14de..8de36035 100644 --- a/client/ui/qml/Pages2/PageProtocolXraySettings.qml +++ b/client/ui/qml/Pages2/PageProtocolXraySettings.qml @@ -17,163 +17,141 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton - } - } - - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom - anchors.bottom: parent.bottom - contentHeight: content.implicitHeight - - Column { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - enabled: ServersModel.isProcessedServerHasWriteAccess() - - ListView { - id: listview - - width: parent.width - height: listview.contentItem.height - - clip: true - interactive: false - - model: XrayConfigModel - - delegate: Item { - id: delegateItem - - property alias focusItemId: textFieldWithHeaderType.textField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - - implicitWidth: listview.width - implicitHeight: col.implicitHeight - - ColumnLayout { - id: col - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - spacing: 0 - - BaseHeaderType { - Layout.fillWidth: true - headerText: qsTr("XRay settings") - } - - TextFieldWithHeaderType { - id: textFieldWithHeaderType - Layout.fillWidth: true - Layout.topMargin: 32 - - enabled: delegateItem.isEnabled - - headerText: qsTr("Disguised as traffic from") - textField.text: site - - textField.onEditingFinished: { - if (textField.text !== site) { - var tmpText = textField.text - tmpText = tmpText.toLocaleLowerCase() - - if (tmpText.startsWith("https://")) { - tmpText = textField.text.substring(8) - site = tmpText - } else { - site = textField.text - } - } - } - - checkEmptyText: true - } - - TextFieldWithHeaderType { - id: portTextField - Layout.fillWidth: true - Layout.topMargin: 16 - - enabled: delegateItem.isEnabled - - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - - textField.onEditingFinished: { - if (textField.text !== port) { - port = textField.text - } - } - - checkEmptyText: true - } - - BasicButtonType { - id: saveButton - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - enabled: portTextField.errorText === "" - - text: qsTr("Save") - - onClicked: function() { - forceActiveFocus() - - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(XrayConfigModel.getConfig()) - //focusItem.forceActiveFocus() - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() - } - } - } + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() } } } + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + enabled: ServersModel.isProcessedServerHasWriteAccess() + model: XrayConfigModel + + delegate: ColumnLayout { + width: listView.width + + property alias focusItemId: textFieldWithHeaderType.textField + + spacing: 0 + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + headerText: qsTr("XRay settings") + } + + TextFieldWithHeaderType { + id: textFieldWithHeaderType + + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: listView.enabled + + headerText: qsTr("Disguised as traffic from") + textField.text: site + + textField.onEditingFinished: { + if (textField.text !== site) { + var tmpText = textField.text + tmpText = tmpText.toLocaleLowerCase() + + if (tmpText.startsWith("https://")) { + tmpText = textField.text.substring(8) + site = tmpText + } else { + site = textField.text + } + } + } + + checkEmptyText: true + } + + TextFieldWithHeaderType { + id: portTextField + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: listView.enabled + + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } + + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text + } + } + + checkEmptyText: true + } + + BasicButtonType { + id: saveButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: portTextField.errorText === "" + + text: qsTr("Save") + + onClicked: function() { + forceActiveFocus() + + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(XrayConfigModel.getConfig()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + Keys.onEnterPressed: saveButton.clicked() + Keys.onReturnPressed: saveButton.clicked() + } + } + } } diff --git a/client/ui/qml/Pages2/PageServiceDnsSettings.qml b/client/ui/qml/Pages2/PageServiceDnsSettings.qml index d534f991..442dc544 100644 --- a/client/ui/qml/Pages2/PageServiceDnsSettings.qml +++ b/client/ui/qml/Pages2/PageServiceDnsSettings.qml @@ -16,50 +16,53 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - - BackButtonType { - id: backButton + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + header: ColumnLayout { + width: listView.width BaseHeaderType { - id: header - Layout.fillWidth: true Layout.rightMargin: 16 Layout.leftMargin: 16 + Layout.bottomMargin: 24 headerText: "AmneziaDNS" descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") + qsTr("The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab.") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { + width: listView.width LabelWithButtonType { - id: removeButton - - Layout.topMargin: 24 - width: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() textColor: AmneziaStyle.color.vibrantRed @@ -71,19 +74,14 @@ PageType { var yesButtonFunction = function() { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected - && SettingsController.isAmneziaDnsEnabled()) { + && SettingsController.isAmneziaDnsEnabled()) { PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server")) - } else - { + } else { PageController.goToPage(PageEnum.PageDeinstalling) InstallController.removeProcessedContainer() } } - var noButtonFunction = function() { - if (!GC.isMobile()) { - removeButton.rightButton.forceActiveFocus() - } - } + var noButtonFunction = function() {} showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } diff --git a/client/ui/qml/Pages2/PageServiceSftpSettings.qml b/client/ui/qml/Pages2/PageServiceSftpSettings.qml index b58cb2e0..9fe0bac5 100644 --- a/client/ui/qml/Pages2/PageServiceSftpSettings.qml +++ b/client/ui/qml/Pages2/PageServiceSftpSettings.qml @@ -24,258 +24,215 @@ PageType { } } - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + enabled: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: SftpConfigModel - enabled: ServersModel.isProcessedServerHasWriteAccess() + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + spacing: 0 - width: parent.width - height: listview.contentItem.height + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - clip: true - interactive: false + headerText: qsTr("SFTP settings") + } - model: SftpConfigModel + LabelWithButtonType { + id: hostLabel - onFocusChanged: { - if (focus) { - listview.currentItem.listViewFocusItem.forceActiveFocus() - } + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Host") + descriptionText: ServersModel.getProcessedServerData("hostName") + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + LabelWithButtonType { + id: portLabel + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Port") + descriptionText: port + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + LabelWithButtonType { + id: usernameLabel + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("User name") + descriptionText: username + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + LabelWithButtonType { + id: passwordLabel + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Password") + descriptionText: password + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg" + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + BasicButtonType { + id: mountButton + + visible: !GC.isMobile() + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: qsTr("Mount folder on device") + + clickedFunc: function() { + PageController.showBusyIndicator(true) + InstallController.mountSftpDrive(port, password, username) + PageController.showBusyIndicator(false) + } + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + readonly property string windowsFirstLink: "WinFsp" + readonly property string windowsSecondLink: "SSHFS-Win" + + readonly property string macosFirstLink: "macFUSE" + readonly property string macosSecondLink: "SSHFS" + + onLinkActivated: function(link) { + Qt.openUrlExternally(link) + } + textFormat: Text.RichText + text: { + var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps:
") + if (Qt.platform.os === "windows") { + str += qsTr("
1. Install the latest version of ") + windowsFirstLink + "\n" + str += qsTr("
2. Install the latest version of ") + windowsSecondLink + "\n" + } else if (Qt.platform.os === "osx") { + str += qsTr("
1. Install the latest version of ") + macosFirstLink + "\n" + str += qsTr("
2. Install the latest version of ") + macosSecondLink + "\n" + } else if (Qt.platform.os === "linux") { + return "" + } else return "" + + return str } - delegate: Item { - implicitWidth: listview.width - implicitHeight: col.implicitHeight + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } - property alias listViewFocusItem: hostLabel.rightButton + BasicButtonType { + id: detailedInstructionsButton - ColumnLayout { - id: col + Layout.topMargin: 16 + Layout.bottomMargin: 16 + Layout.leftMargin: 8 + implicitHeight: 32 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot - spacing: 0 + text: qsTr("Detailed instructions") - BaseHeaderType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - headerText: qsTr("SFTP settings") - } - - LabelWithButtonType { - id: hostLabel - Layout.fillWidth: true - Layout.topMargin: 32 - - parentFlickable: fl - - text: qsTr("Host") - descriptionText: ServersModel.getProcessedServerData("hostName") - - descriptionOnTop: true - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } - } - } - - LabelWithButtonType { - id: portLabel - Layout.fillWidth: true - - text: qsTr("Port") - descriptionText: port - - descriptionOnTop: true - - parentFlickable: fl - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } - } - } - - LabelWithButtonType { - id: usernameLabel - Layout.fillWidth: true - - text: qsTr("User name") - descriptionText: username - - descriptionOnTop: true - - parentFlickable: fl - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } - } - } - - LabelWithButtonType { - id: passwordLabel - Layout.fillWidth: true - - text: qsTr("Password") - descriptionText: password - - descriptionOnTop: true - - parentFlickable: fl - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg" - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } - } - } - - BasicButtonType { - id: mountButton - visible: !GC.isMobile() - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - parentFlickable: fl - - text: qsTr("Mount folder on device") - - clickedFunc: function() { - PageController.showBusyIndicator(true) - InstallController.mountSftpDrive(port, password, username) - PageController.showBusyIndicator(false) - } - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - readonly property string windowsFirstLink: "WinFsp" - readonly property string windowsSecondLink: "SSHFS-Win" - - readonly property string macosFirstLink: "macFUSE" - readonly property string macosSecondLink: "SSHFS" - - onLinkActivated: function(link) { - Qt.openUrlExternally(link) - } - textFormat: Text.RichText - text: { - var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps:
") - if (Qt.platform.os === "windows") { - str += qsTr("
1. Install the latest version of ") + windowsFirstLink + "\n" - str += qsTr("
2. Install the latest version of ") + windowsSecondLink + "\n" - } else if (Qt.platform.os === "osx") { - str += qsTr("
1. Install the latest version of ") + macosFirstLink + "\n" - str += qsTr("
2. Install the latest version of ") + macosSecondLink + "\n" - } else if (Qt.platform.os === "linux") { - return "" - } else return "" - - return str - } - - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - - BasicButtonType { - id: detailedInstructionsButton - Layout.topMargin: 16 - Layout.bottomMargin: 16 - Layout.leftMargin: 8 - implicitHeight: 32 - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.goldenApricot - - text: qsTr("Detailed instructions") - - parentFlickable: fl - - clickedFunc: function() { -// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") - } - } - } + clickedFunc: function() { + // Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") } } } diff --git a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml index b1daa0fb..f96872e0 100644 --- a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml +++ b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml @@ -25,327 +25,290 @@ PageType { } } - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: listview.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ListView { - id: listview + model: Socks5ProxyConfigModel - width: parent.width - height: listview.contentItem.height + delegate: ColumnLayout { + width: listView.width - clip: true - interactive: false + spacing: 0 - model: Socks5ProxyConfigModel + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - onFocusChanged: { - if (focus) { - listview.currentItem.focusItemId.forceActiveFocus() + headerText: qsTr("SOCKS5 settings") + } + + LabelWithButtonType { + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 + + text: qsTr("Host") + descriptionText: ServersModel.getProcessedServerData("hostName") + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) } } - delegate: Item { - implicitWidth: listview.width - implicitHeight: content.implicitHeight + LabelWithButtonType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - property alias focusItemId: hostLabel.rightButton + text: qsTr("Port") + descriptionText: port - ColumnLayout { - id: content + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + LabelWithButtonType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.bottomMargin: 16 + + text: qsTr("User name") + descriptionText: username + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + LabelWithButtonType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.bottomMargin: 16 + + text: qsTr("Password") + descriptionText: password + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg" + + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + DrawerType2 { + id: changeSettingsDrawer + parent: root + + anchors.fill: parent + expandedHeight: root.height * 0.9 + + expandedStateContent: ColumnLayout { + property string tempPort: port + property string tempUsername: username + property string tempPassword: password anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - + anchors.topMargin: 32 + anchors.leftMargin: 16 + anchors.rightMargin: 16 spacing: 0 + Connections { + target: changeSettingsDrawer + function onOpened() { + tempPort = port + tempUsername = username + tempPassword = password + } + function onClosed() { + port = tempPort + username = tempUsername + password = tempPassword + portTextField.textField.text = port + usernameTextField.textField.text = username + passwordTextField.textField.text = password + } + } + BaseHeaderType { Layout.fillWidth: true - Layout.leftMargin: 16 Layout.rightMargin: 16 + Layout.bottomMargin: 16 headerText: qsTr("SOCKS5 settings") } - LabelWithButtonType { - id: hostLabel + TextFieldWithHeaderType { + id: portTextField + Layout.fillWidth: true - Layout.topMargin: 32 + Layout.topMargin: 40 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - parentFlickable: fl + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } - text: qsTr("Host") - descriptionText: ServersModel.getProcessedServerData("hostName") - - descriptionOnTop: true - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() + textField.onEditingFinished: { + textField.text = textField.text.replace(/^\s+|\s+$/g, '') + if (textField.text !== port) { + port = textField.text } } } - LabelWithButtonType { - id: portLabel + TextFieldWithHeaderType { + id: usernameTextField + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - text: qsTr("Port") - descriptionText: port + headerText: qsTr("Username") + textField.placeholderText: "username" + textField.text: username + textField.maximumLength: 32 - descriptionOnTop: true - - parentFlickable: fl - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() + textField.onEditingFinished: { + textField.text = textField.text.replace(/^\s+|\s+$/g, '') + if (textField.text !== username) { + username = textField.text } } } - LabelWithButtonType { - id: usernameLabel + TextFieldWithHeaderType { + id: passwordTextField + + property bool hidePassword: true + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - text: qsTr("User name") - descriptionText: username + headerText: qsTr("Password") + textField.placeholderText: "password" + textField.text: password + textField.maximumLength: 32 - descriptionOnTop: true + textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal + buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") + : "" - parentFlickable: fl - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } + clickedFunc: function() { + hidePassword = !hidePassword } - } - LabelWithButtonType { - id: passwordLabel - Layout.fillWidth: true - - text: qsTr("Password") - descriptionText: password - - descriptionOnTop: true - - parentFlickable: fl - - rightImageSource: "qrc:/images/controls/copy.svg" - rightImageColor: AmneziaStyle.color.paleGray - - buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg" - - clickedFunction: function() { - GC.copyToClipBoard(descriptionText) - PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } - } - } - - DrawerType2 { - id: changeSettingsDrawer - parent: root - - anchors.fill: parent - expandedHeight: root.height * 0.9 - - expandedStateContent: ColumnLayout { - property string tempPort: port - property string tempUsername: username - property string tempPassword: password - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 32 - anchors.leftMargin: 16 - anchors.rightMargin: 16 - spacing: 0 - - Connections { - target: changeSettingsDrawer - function onOpened() { - tempPort = port - tempUsername = username - tempPassword = password - } - function onClosed() { - port = tempPort - username = tempUsername - password = tempPassword - portTextField.textField.text = port - usernameTextField.textField.text = username - passwordTextField.textField.text = password - } - } - - BaseHeaderType { - Layout.fillWidth: true - - headerText: qsTr("SOCKS5 settings") - } - - TextFieldWithHeaderType { - id: portTextField - - Layout.fillWidth: true - Layout.topMargin: 40 - parentFlickable: fl - - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - - textField.onEditingFinished: { - textField.text = textField.text.replace(/^\s+|\s+$/g, '') - if (textField.text !== port) { - port = textField.text - } - } - } - - TextFieldWithHeaderType { - id: usernameTextField - - Layout.fillWidth: true - Layout.topMargin: 16 - parentFlickable: fl - - headerText: qsTr("Username") - textField.placeholderText: "username" - textField.text: username - textField.maximumLength: 32 - - textField.onEditingFinished: { - textField.text = textField.text.replace(/^\s+|\s+$/g, '') - if (textField.text !== username) { - username = textField.text - } - } - } - - TextFieldWithHeaderType { - id: passwordTextField - - property bool hidePassword: true - - Layout.fillWidth: true - Layout.topMargin: 16 - parentFlickable: fl - - headerText: qsTr("Password") - textField.placeholderText: "password" - textField.text: password - textField.maximumLength: 32 - - textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal - buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") - : "" - - clickedFunc: function() { - hidePassword = !hidePassword - } - - textField.onFocusChanged: { - textField.text = textField.text.replace(/^\s+|\s+$/g, '') - if (textField.text !== password) { - password = textField.text - } - } - } - - BasicButtonType { - id: saveButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - text: qsTr("Change connection settings") - - clickedFunc: function() { - forceActiveFocus() - - if (!portTextField.textField.acceptableInput) { - portTextField.errorText = qsTr("The port must be in the range of 1 to 65535") - return - } - if (usernameTextField.textField.text && passwordTextField.textField.text === "") { - passwordTextField.errorText = qsTr("Password cannot be empty") - return - } else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) { - usernameTextField.errorText = qsTr("Username cannot be empty") - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling) - InstallController.updateContainer(Socks5ProxyConfigModel.getConfig()) - tempPort = portTextField.textField.text - tempUsername = usernameTextField.textField.text - tempPassword = passwordTextField.textField.text - changeSettingsDrawer.closeTriggered() - } + textField.onFocusChanged: { + textField.text = textField.text.replace(/^\s+|\s+$/g, '') + if (textField.text !== password) { + password = textField.text } } } BasicButtonType { - id: changeSettingsButton + id: saveButton Layout.fillWidth: true Layout.topMargin: 24 Layout.bottomMargin: 24 - Layout.leftMargin: 16 Layout.rightMargin: 16 text: qsTr("Change connection settings") clickedFunc: function() { - forceActiveFocus() - changeSettingsDrawer.openTriggered() + if (!portTextField.textField.acceptableInput) { + portTextField.errorText = qsTr("The port must be in the range of 1 to 65535") + return + } + if (usernameTextField.textField.text && passwordTextField.textField.text === "") { + passwordTextField.errorText = qsTr("Password cannot be empty") + return + } else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) { + usernameTextField.errorText = qsTr("Username cannot be empty") + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling) + InstallController.updateContainer(Socks5ProxyConfigModel.getConfig()) + tempPort = portTextField.textField.text + tempUsername = usernameTextField.textField.text + tempPassword = passwordTextField.textField.text + changeSettingsDrawer.closeTriggered() } } } } + + BasicButtonType { + id: changeSettingsButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Change connection settings") + + clickedFunc: function() { + changeSettingsDrawer.openTriggered() + } + } } } } diff --git a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml index 200beeb8..1ea1f814 100644 --- a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml +++ b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml @@ -25,34 +25,31 @@ PageType { } } - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - - BackButtonType { - id: backButton + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 + header: ColumnLayout { + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -61,11 +58,19 @@ PageType { headerText: qsTr("Tor website settings") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser after migrate to 6.9 + width: listView.width LabelWithButtonType { id: websiteName + Layout.fillWidth: true Layout.topMargin: 32 + Layout.bottomMargin: 24 text: qsTr("Website address") descriptionText: { @@ -83,15 +88,16 @@ PageType { clickedFunction: function() { GC.copyToClipBoard(descriptionText) PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } } } + } + + footer: ColumnLayout { + width: listView.width ParagraphTextType { Layout.fillWidth: true - Layout.topMargin: 40 + Layout.topMargin: 16 Layout.leftMargin: 16 Layout.rightMargin: 16 diff --git a/client/ui/qml/Pages2/PageSettings.qml b/client/ui/qml/Pages2/PageSettings.qml index bb83ec92..f331f912 100644 --- a/client/ui/qml/Pages2/PageSettings.qml +++ b/client/ui/qml/Pages2/PageSettings.qml @@ -1,156 +1,167 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" - -PageType { - id: root - - FlickableType { - id: fl - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 - - BaseHeaderType { - id: header - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - - headerText: qsTr("Settings") - } - - LabelWithButtonType { - id: account - Layout.fillWidth: true - Layout.topMargin: 16 - - text: qsTr("Servers") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/server.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsServersList) - } - } - - DividerType {} - - LabelWithButtonType { - id: connection - Layout.fillWidth: true - - text: qsTr("Connection") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/radio.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsConnection) - } - } - - DividerType {} - - LabelWithButtonType { - id: application - Layout.fillWidth: true - - text: qsTr("Application") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/app.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsApplication) - } - } - - DividerType {} - - LabelWithButtonType { - id: backup - Layout.fillWidth: true - - text: qsTr("Backup") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/save.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsBackup) - } - } - - DividerType {} - - LabelWithButtonType { - id: about - Layout.fillWidth: true - - text: qsTr("About AmneziaVPN") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/amnezia.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsAbout) - } - } - - DividerType {} - - LabelWithButtonType { - id: devConsole - visible: SettingsController.isDevModeEnabled - Layout.fillWidth: true - - text: qsTr("Dev console") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/bug.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageDevMenu) - } - } - - DividerType { - visible: SettingsController.isDevModeEnabled - } - - LabelWithButtonType { - id: close - visible: GC.isDesktop() - Layout.fillWidth: true - Layout.preferredHeight: about.height - - text: qsTr("Close application") - leftImageSource: "qrc:/images/controls/x-circle.svg" - isLeftImageHoverEnabled: false - - clickedFunction: function() { - PageController.closeApplication() - } - } - - DividerType { - visible: GC.isDesktop() - } - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" + +PageType { + id: root + + ListViewType { + id: listView + + anchors.fill: parent + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + id: header + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Settings") + } + } + + model: settingsEntries + + delegate: ColumnLayout { + width: listView.width + + spacing: 0 + + LabelWithButtonType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: isVisible + + text: title + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: leftImagePath + + clickedFunction: clickedHandler + } + + DividerType { + visible: isVisible + } + } + + footer: ColumnLayout { + width: listView.width + + LabelWithButtonType { + id: close + + visible: GC.isDesktop() + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Close application") + leftImageSource: "qrc:/images/controls/x-circle.svg" + isLeftImageHoverEnabled: false + + clickedFunction: function() { + PageController.closeApplication() + } + } + + DividerType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: GC.isDesktop() + } + } + } + + property list settingsEntries: [ + servers, + connection, + application, + backup, + about, + devConsole + ] + + QtObject { + id: servers + + property string title: qsTr("Servers") + readonly property string leftImagePath: "qrc:/images/controls/server.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsServersList) + } + } + + QtObject { + id: connection + + property string title: qsTr("Connection") + readonly property string leftImagePath: "qrc:/images/controls/radio.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsConnection) + } + } + + QtObject { + id: application + + property string title: qsTr("Application") + readonly property string leftImagePath: "qrc:/images/controls/app.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsApplication) + } + } + + QtObject { + id: backup + + property string title: qsTr("Backup") + readonly property string leftImagePath: "qrc:/images/controls/save.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsBackup) + } + } + + QtObject { + id: about + + property string title: qsTr("About AmneziaVPN") + readonly property string leftImagePath: "qrc:/images/controls/amnezia.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsAbout) + } + } + + QtObject { + id: devConsole + + property string title: qsTr("Dev console") + readonly property string leftImagePath: "qrc:/images/controls/bug.svg" + property bool isVisible: SettingsController.isDevModeEnabled + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageDevMenu) + } + } +} diff --git a/client/ui/qml/Pages2/PageSettingsAbout.qml b/client/ui/qml/Pages2/PageSettingsAbout.qml index 6342ce66..a3c2b884 100644 --- a/client/ui/qml/Pages2/PageSettingsAbout.qml +++ b/client/ui/qml/Pages2/PageSettingsAbout.qml @@ -29,58 +29,7 @@ PageType { } } - QtObject { - id: telegramGroup - - readonly property string title: qsTr("Telegram group") - readonly property string description: qsTr("To discuss features") - readonly property string imageSource: "qrc:/images/controls/telegram.svg" - readonly property var handler: function() { - Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en")) - } - } - - QtObject { - id: mail - - readonly property string title: qsTr("support@amnezia.org") - readonly property string description: qsTr("For reviews and bug reports") - readonly property string imageSource: "qrc:/images/controls/mail.svg" - readonly property var handler: function() { - Qt.openUrlExternally(qsTr("mailto:support@amnezia.org")) - } - } - - QtObject { - id: github - - readonly property string title: qsTr("GitHub") - readonly property string description: qsTr("Discover the source code") - readonly property string imageSource: "qrc:/images/controls/github.svg" - readonly property var handler: function() { - Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client")) - } - } - - QtObject { - id: website - - readonly property string title: qsTr("Website") - readonly property string description: qsTr("Visit official website") - readonly property string imageSource: "qrc:/images/controls/amnezia.svg" - readonly property var handler: function() { - Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl()) - } - } - - property list contacts: [ - telegramGroup, - mail, - github, - website - ] - - ListView { + ListViewType { id: listView anchors.top: backButton.bottom @@ -88,38 +37,6 @@ PageType { anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - ScrollBar.vertical: ScrollBarType {} - - model: contacts - - clip: true - header: ColumnLayout { width: listView.width @@ -170,11 +87,12 @@ PageType { } } + model: contacts + delegate: ColumnLayout { width: listView.width LabelWithButtonType { - id: telegramButton Layout.fillWidth: true Layout.topMargin: 6 @@ -257,4 +175,55 @@ PageType { } } } + + property list contacts: [ + telegramGroup, + mail, + github, + website + ] + + QtObject { + id: telegramGroup + + readonly property string title: qsTr("Telegram group") + readonly property string description: qsTr("To discuss features") + readonly property string imageSource: "qrc:/images/controls/telegram.svg" + readonly property var handler: function() { + Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en")) + } + } + + QtObject { + id: mail + + readonly property string title: qsTr("support@amnezia.org") + readonly property string description: qsTr("For reviews and bug reports") + readonly property string imageSource: "qrc:/images/controls/mail.svg" + readonly property var handler: function() { + Qt.openUrlExternally(qsTr("mailto:support@amnezia.org")) + } + } + + QtObject { + id: github + + readonly property string title: qsTr("GitHub") + readonly property string description: qsTr("Discover the source code") + readonly property string imageSource: "qrc:/images/controls/github.svg" + readonly property var handler: function() { + Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client")) + } + } + + QtObject { + id: website + + readonly property string title: qsTr("Website") + readonly property string description: qsTr("Visit official website") + readonly property string imageSource: "qrc:/images/controls/amnezia.svg" + readonly property var handler: function() { + Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl()) + } + } } diff --git a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml index 8fa85a33..39e2e626 100644 --- a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml +++ b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml @@ -1,221 +1,243 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import QtCore - -import SortFilterProxyModel 0.2 - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" -import "../Components" - -PageType { - id: root - - property string configExtension: ".conf" - property string configCaption: qsTr("Save AmneziaVPN config") - - ListViewType { - id: listView - - anchors.fill: parent - anchors.topMargin: 20 - anchors.bottomMargin: 24 - - model: ApiCountryModel - - header: ColumnLayout { - width: listView.width - - BackButtonType { - id: backButton - } - - BaseHeaderType { - id: header - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - - headerText: qsTr("Configuration Files") - descriptionText: qsTr("For router setup or the AmneziaWG app") - } - } - - delegate: ColumnLayout { - width: listView.width - - LabelWithButtonType { - Layout.fillWidth: true - Layout.topMargin: 6 - - text: countryName - descriptionText: isWorkerExpired ? qsTr("Download the update") : "" - hideDescription: false - descriptionColor: AmneziaStyle.color.mutedGray - - leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg" - rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg" - - clickedFunction: function() { - if (isIssued) { - moreOptionsDrawer.countryName = countryName - moreOptionsDrawer.countryCode = countryCode - moreOptionsDrawer.openTriggered() - } else { - issueConfig(countryCode) - } - } - } - - DividerType {} - } - } - - DrawerType2 { - id: moreOptionsDrawer - - property string countryName - property string countryCode - - anchors.fill: parent - expandedHeight: parent.height * 0.4375 - - expandedStateContent: Item { - implicitHeight: moreOptionsDrawer.expandedHeight - - BackButtonType { - id: moreOptionsDrawerBackButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 - - backButtonFunction: function() { - moreOptionsDrawer.closeTriggered() - } - } - - FlickableType { - anchors.top: moreOptionsDrawerBackButton.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - - contentHeight: moreOptionsDrawerContent.height - - ColumnLayout { - id: moreOptionsDrawerContent - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - Header2Type { - Layout.fillWidth: true - Layout.margins: 16 - - headerText: moreOptionsDrawer.countryName + qsTr(" configuration file") - } - - LabelWithButtonType { - Layout.fillWidth: true - - text: qsTr("Generate a new configuration file") - descriptionText: qsTr("The previously created one will stop working") - - clickedFunction: function() { - showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) - } - } - - DividerType {} - - LabelWithButtonType { - Layout.fillWidth: true - text: qsTr("Revoke the current configuration file") - - clickedFunction: function() { - showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) - } - } - - DividerType {} - } - } - } - } - - function issueConfig(countryCode) { - var fileName = "" - if (GC.isMobile()) { - fileName = countryCode + configExtension - } else { - fileName = SystemController.getFileName(configCaption, - qsTr("Config files (*" + configExtension + ")"), - StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode, - true, - configExtension) - } - if (fileName !== "") { - PageController.showBusyIndicator(true) - let result = ApiConfigsController.exportNativeConfig(countryCode, fileName) - if (result) { - ApiSettingsController.getAccountInfo(true) - } - - PageController.showBusyIndicator(false) - if (result) { - PageController.showNotificationMessage(qsTr("Config file saved")) - } - } - } - - function revokeConfig(countryCode) { - PageController.showBusyIndicator(true) - let result = ApiConfigsController.revokeNativeConfig(countryCode) - if (result) { - ApiSettingsController.getAccountInfo(true) - } - PageController.showBusyIndicator(false) - - if (result) { - PageController.showNotificationMessage(qsTr("The config has been revoked")) - } - } - - function showQuestion(isConfigIssue, countryCode, countryName) { - var headerText - if (isConfigIssue) { - headerText = qsTr("Generate a new %1 configuration file?").arg(countryName) - } else { - headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName) - } - - var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it") - var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (isConfigIssue) { - issueConfig(countryCode) - } else { - revokeConfig(countryCode) - } - moreOptionsDrawer.closeTriggered() - } - var noButtonFunction = function() { - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import QtCore + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + property string configExtension: ".conf" + property string configCaption: qsTr("Save AmneziaVPN config") + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + model: ApiCountryModel + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + id: header + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Configuration Files") + descriptionText: qsTr("For router setup or the AmneziaWG app") + } + } + + delegate: ColumnLayout { + width: listView.width + + LabelWithButtonType { + Layout.fillWidth: true + Layout.topMargin: 6 + + text: countryName + descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : "" + hideDescription: isWorkerExpired : true : false + descriptionColor: AmneziaStyle.color.vibrantRed + + leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg" + rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg" + + clickedFunction: function() { + if (isIssued) { + moreOptionsDrawer.countryName = countryName + moreOptionsDrawer.countryCode = countryCode + moreOptionsDrawer.openTriggered() + } else { + issueConfig(countryCode) + } + } + } + + DividerType {} + } + } + + DrawerType2 { + id: moreOptionsDrawer + + property string countryName + property string countryCode + + anchors.fill: parent + expandedHeight: parent.height * 0.4375 + + expandedStateContent: Item { + implicitHeight: moreOptionsDrawer.expandedHeight + + BackButtonType { + id: moreOptionsDrawerBackButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 + + backButtonFunction: function() { + moreOptionsDrawer.closeTriggered() + } + } + + ListViewType { + id: drawerListView + + anchors.top: moreOptionsDrawerBackButton.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + header: ColumnLayout { + width: drawerListView.width + + Header2Type { + Layout.fillWidth: true + Layout.margins: 16 + + headerText: moreOptionsDrawer.countryName + qsTr(" configuration file") + } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { + width: drawerListView.width + + LabelWithButtonType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Generate a new configuration file") + descriptionText: qsTr("The previously created one will stop working") + + clickedFunction: function() { + showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) + } + } + + DividerType {} + } + + footer: ColumnLayout { + width: drawerListView.width + + LabelWithButtonType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Revoke the current configuration file") + + clickedFunction: function() { + showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) + } + } + + DividerType {} + } + } + } + } + + function issueConfig(countryCode) { + var fileName = "" + if (GC.isMobile()) { + fileName = countryCode + configExtension + } else { + fileName = SystemController.getFileName(configCaption, + qsTr("Config files (*" + configExtension + ")"), + StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode, + true, + configExtension) + } + if (fileName !== "") { + PageController.showBusyIndicator(true) + let result = ApiConfigsController.exportNativeConfig(countryCode, fileName) + if (result) { + ApiSettingsController.getAccountInfo(true) + } + + PageController.showBusyIndicator(false) + if (result) { + PageController.showNotificationMessage(qsTr("Config file saved")) + } + } + } + + function revokeConfig(countryCode) { + PageController.showBusyIndicator(true) + let result = ApiConfigsController.revokeNativeConfig(countryCode) + if (result) { + ApiSettingsController.getAccountInfo(true) + } + PageController.showBusyIndicator(false) + + if (result) { + PageController.showNotificationMessage(qsTr("The config has been revoked")) + } + } + + function showQuestion(isConfigIssue, countryCode, countryName) { + var headerText + if (isConfigIssue) { + headerText = qsTr("Generate a new %1 configuration file?").arg(countryName) + } else { + headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName) + } + + var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it") + var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (isConfigIssue) { + issueConfig(countryCode) + } else { + revokeConfig(countryCode) + } + moreOptionsDrawer.closeTriggered() + } + var noButtonFunction = function() {} + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } +} diff --git a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml index e31c92db..60b59f45 100644 --- a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml @@ -50,6 +50,7 @@ PageType { readonly property string name: qsTr("Only the apps from the list should have access via VPN") readonly property int type: routeMode.onlyForwardApps } + QtObject { id: allExceptApps @@ -111,7 +112,7 @@ PageType { headerText: qsTr("Mode") - enabled: Qt.platform.os === "android" && root.pageEnabled + enabled: (Qt.platform.os === "android") && root.pageEnabled listView: ListViewWithRadioButtonType { rootWidth: root.width @@ -146,77 +147,56 @@ PageType { } } - FlickableType { + ListViewType { + id: listView + anchors.top: header.bottom - anchors.topMargin: 16 - contentHeight: col.implicitHeight + addAppButton.implicitHeight + addAppButton.anchors.bottomMargin + addAppButton.anchors.topMargin + anchors.bottom: addAppButton.top + anchors.left: parent.left + anchors.right: parent.right - enabled: root.pageEnabled + model: SortFilterProxyModel { + id: proxyAppSplitTunnelingModel + sourceModel: AppSplitTunnelingModel + filters: RegExpFilter { + roleName: "appPath" + pattern: ".*" + searchField.textField.text + ".*" + caseSensitivity: Qt.CaseInsensitive + } + sorters: [ + RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder } + ] + } - Column { - id: col - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + delegate: ColumnLayout { + width: listView.width - ListView { - id: apps - width: parent.width - height: apps.contentItem.height + LabelWithButtonType { + Layout.fillWidth: true - model: SortFilterProxyModel { - id: proxyAppSplitTunnelingModel - sourceModel: AppSplitTunnelingModel - filters: RegExpFilter { - roleName: "appPath" - pattern: ".*" + searchField.textField.text + ".*" - caseSensitivity: Qt.CaseInsensitive + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: appPath + rightImageSource: "qrc:/images/controls/trash.svg" + rightImageColor: AmneziaStyle.color.paleGray + + clickedFunction: function() { + var headerText = qsTr("Remove ") + appPath + "?" + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index)) } - sorters: [ - RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder } - ] - } - - clip: true - interactive: false - - delegate: Item { - implicitWidth: apps.width - implicitHeight: delegateContent.implicitHeight - - ColumnLayout { - id: delegateContent - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - LabelWithButtonType { - Layout.fillWidth: true - - text: appPath - rightImageSource: "qrc:/images/controls/trash.svg" - rightImageColor: AmneziaStyle.color.paleGray - - clickedFunction: function() { - var headerText = qsTr("Remove ") + appPath + "?" - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index)) - } - var noButtonFunction = function() { - } - - showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - } - - DividerType {} + var noButtonFunction = function() { } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } + + DividerType {} } } diff --git a/client/ui/qml/Pages2/PageSettingsApplication.qml b/client/ui/qml/Pages2/PageSettingsApplication.qml index 5f4ada82..981bbecb 100644 --- a/client/ui/qml/Pages2/PageSettingsApplication.qml +++ b/client/ui/qml/Pages2/PageSettingsApplication.qml @@ -21,22 +21,24 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 + header: ColumnLayout { + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -45,9 +47,17 @@ PageType { headerText: qsTr("Application") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser when have migrated to 6.9 + + width: listView.width SwitcherType { - id: switcher + id: switcherAllowScreenshots + visible: GC.isMobile() Layout.fillWidth: true @@ -61,10 +71,6 @@ PageType { SettingsController.toggleScreenshotsEnabled(checked) } } - - // KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ? - // labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton - parentFlickable: fl } DividerType { @@ -73,15 +79,15 @@ PageType { LabelWithButtonType { id: labelWithButtonNotification + visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted + Layout.fillWidth: true text: qsTr("Enable notifications") descriptionText: qsTr("Enable notifications to show the VPN state in the status bar") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { SettingsController.requestNotificationPermission() } @@ -93,6 +99,7 @@ PageType { SwitcherType { id: switcherAutoStart + visible: !GC.isMobile() Layout.fillWidth: true @@ -101,8 +108,6 @@ PageType { text: qsTr("Auto start") descriptionText: qsTr("Launch the application every time the device is starts") - parentFlickable: fl - checked: SettingsController.isAutoStartEnabled() onCheckedChanged: { if (checked !== SettingsController.isAutoStartEnabled()) { @@ -117,6 +122,7 @@ PageType { SwitcherType { id: switcherAutoConnect + visible: !GC.isMobile() Layout.fillWidth: true @@ -125,8 +131,6 @@ PageType { text: qsTr("Auto connect") descriptionText: qsTr("Connect to VPN on app start") - parentFlickable: fl - checked: SettingsController.isAutoConnectEnabled() onCheckedChanged: { if (checked !== SettingsController.isAutoConnectEnabled()) { @@ -141,6 +145,7 @@ PageType { SwitcherType { id: switcherStartMinimized + visible: !GC.isMobile() Layout.fillWidth: true @@ -152,8 +157,6 @@ PageType { enabled: switcherAutoStart.checked opacity: enabled ? 1.0 : 0.5 - parentFlickable: fl - checked: SettingsController.isStartMinimizedEnabled() onCheckedChanged: { if (checked !== SettingsController.isStartMinimizedEnabled()) { @@ -165,17 +168,21 @@ PageType { DividerType { visible: !GC.isMobile() } + } + + footer: ColumnLayout { + + width: listView.width LabelWithButtonType { id: labelWithButtonLanguage + Layout.fillWidth: true text: qsTr("Language") descriptionText: LanguageModel.currentLanguageName rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { selectLanguageDrawer.openTriggered() } @@ -185,14 +192,13 @@ PageType { LabelWithButtonType { id: labelWithButtonLogging + Layout.fillWidth: true text: qsTr("Logging") descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsLogging) } @@ -202,14 +208,13 @@ PageType { LabelWithButtonType { id: labelWithButtonReset + Layout.fillWidth: true text: qsTr("Reset settings and remove all data from the application") rightImageSource: "qrc:/images/controls/chevron-right.svg" textColor: AmneziaStyle.color.vibrantRed - parentFlickable: fl - clickedFunction: function() { var headerText = qsTr("Reset settings and remove all data from the application?") var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.") diff --git a/client/ui/qml/Pages2/PageSettingsBackup.qml b/client/ui/qml/Pages2/PageSettingsBackup.qml index 83e0f567..a8ea9da7 100644 --- a/client/ui/qml/Pages2/PageSettingsBackup.qml +++ b/client/ui/qml/Pages2/PageSettingsBackup.qml @@ -41,51 +41,68 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right - ColumnLayout { - id: content + header: ColumnLayout { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 + width: listView.width spacing: 16 BaseHeaderType { Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 headerText: qsTr("Back up your configuration") descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser when have migrated to 6.9 + + width: listView.width + + spacing: 16 WarningType { - Layout.topMargin: 16 Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 textString: qsTr("The backup will contain your passwords and private keys for all servers added " + - "to AmneziaVPN. Keep this information in a secure place.") + "to AmneziaVPN. Keep this information in a secure place.") iconPath: "qrc:/images/controls/alert-circle.svg" } BasicButtonType { id: makeBackupButton + Layout.fillWidth: true Layout.topMargin: 14 + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: qsTr("Make a backup") - parentFlickable: fl - clickedFunc: function() { var fileName = "" if (GC.isMobile()) { @@ -108,8 +125,11 @@ PageType { BasicButtonType { id: restoreBackupButton + Layout.fillWidth: true Layout.topMargin: -8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 defaultColor: AmneziaStyle.color.transparent hoveredColor: AmneziaStyle.color.translucentWhite @@ -120,8 +140,6 @@ PageType { text: qsTr("Restore from backup") - parentFlickable: fl - clickedFunc: function() { var filePath = SystemController.getFileName(qsTr("Open backup file"), qsTr("Backup files (*.backup)")) diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index 84b98230..60323629 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -21,20 +21,25 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right - ColumnLayout { - id: content + header: ColumnLayout { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -43,9 +48,17 @@ PageType { headerText: qsTr("Connection") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser when have migrated to 6.9 + + width: listView.width SwitcherType { id: amneziaDnsSwitch + Layout.fillWidth: true Layout.margins: 16 @@ -64,14 +77,13 @@ PageType { LabelWithButtonType { id: dnsServersButton + Layout.fillWidth: true text: qsTr("DNS servers") descriptionText: qsTr("When AmneziaDNS is not used or installed") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsDns) } @@ -81,14 +93,13 @@ PageType { LabelWithButtonType { id: splitTunnelingButton + Layout.fillWidth: true text: qsTr("Site-based split tunneling") descriptionText: qsTr("Allows you to select which sites you want to access through the VPN") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsSplitTunneling) } @@ -96,8 +107,15 @@ PageType { DividerType {} + } + + footer: ColumnLayout { // TODO(CyAn84): move to delegate,add DelegateChooser when have migrated to 6.9 + + width: listView.width + LabelWithButtonType { id: splitTunnelingButton2 + visible: root.isAppSplitTinnelingEnabled Layout.fillWidth: true @@ -106,8 +124,6 @@ PageType { descriptionText: qsTr("Allows you to use the VPN only for certain Apps") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) } @@ -127,8 +143,6 @@ PageType { descriptionText: qsTr("Blocks network connections without VPN") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsKillSwitch) } diff --git a/client/ui/qml/Pages2/PageSettingsDns.qml b/client/ui/qml/Pages2/PageSettingsDns.qml index d5e2c52b..a510f928 100644 --- a/client/ui/qml/Pages2/PageSettingsDns.qml +++ b/client/ui/qml/Pages2/PageSettingsDns.qml @@ -1,140 +1,167 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Config" -import "../Controls2/TextTypes" -import "../Components" - -PageType { - id: root - - BackButtonType { - id: backButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 20 - } - - FlickableType { - id: fl - anchors.top: backButton.bottom - anchors.bottom: parent.bottom - contentHeight: content.height - - property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) - - enabled: !isServerFromApi - - Component.onCompleted: { - if (isServerFromApi) { - PageController.showNotificationMessage(qsTr("Default server does not support custom DNS")) - } - } - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - spacing: 16 - - BaseHeaderType { - Layout.fillWidth: true - - headerText: qsTr("DNS servers") - } - - ParagraphTextType { - Layout.fillWidth: true - text: qsTr("If AmneziaDNS is not used or installed") - } - - TextFieldWithHeaderType { - id: primaryDns - - Layout.fillWidth: true - headerText: qsTr("Primary DNS") - - textField.text: SettingsController.primaryDns - textField.validator: RegularExpressionValidator { - regularExpression: InstallController.ipAddressRegExp() - } - } - - TextFieldWithHeaderType { - id: secondaryDns - - Layout.fillWidth: true - headerText: qsTr("Secondary DNS") - - textField.text: SettingsController.secondaryDns - textField.validator: RegularExpressionValidator { - regularExpression: InstallController.ipAddressRegExp() - } - } - - BasicButtonType { - id: restoreDefaultButton - Layout.fillWidth: true - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - text: qsTr("Restore default") - - clickedFunc: function() { - var headerText = qsTr("Restore default DNS settings?") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - SettingsController.primaryDns = "1.1.1.1" - primaryDns.textField.text = SettingsController.primaryDns - SettingsController.secondaryDns = "1.0.0.1" - secondaryDns.textField.text = SettingsController.secondaryDns - PageController.showNotificationMessage(qsTr("Settings have been reset")) - } - var noButtonFunction = function() { - } - - showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - } - - BasicButtonType { - id: saveButton - - Layout.fillWidth: true - - text: qsTr("Save") - - clickedFunc: function() { - if (primaryDns.textField.text !== SettingsController.primaryDns) { - SettingsController.primaryDns = primaryDns.textField.text - } - if (secondaryDns.textField.text !== SettingsController.secondaryDns) { - SettingsController.secondaryDns = secondaryDns.textField.text - } - PageController.showNotificationMessage(qsTr("Settings saved")) - } - } - } - } - -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Config" +import "../Controls2/TextTypes" +import "../Components" + +PageType { + id: root + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) + + enabled: !isServerFromApi + + Component.onCompleted: { + if (isServerFromApi) { + PageController.showNotificationMessage(qsTr("Default server does not support custom DNS")) + } + } + + header: ColumnLayout { + width: listView.width + spacing: 16 + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("DNS servers") + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("If AmneziaDNS is not used or installed") + } + + TextFieldWithHeaderType { + id: primaryDns + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Primary DNS") + + textField.text: SettingsController.primaryDns + textField.validator: RegularExpressionValidator { + regularExpression: InstallController.ipAddressRegExp() + } + } + + TextFieldWithHeaderType { + id: secondaryDns + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Secondary DNS") + + textField.text: SettingsController.secondaryDns + textField.validator: RegularExpressionValidator { + regularExpression: InstallController.ipAddressRegExp() + } + } + } + + model: 1 // fake model to force the ListView to be created without a model + spacing: 16 + + delegate: ColumnLayout { + width: listView.width + + BasicButtonType { + id: restoreDefaultButton + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: qsTr("Restore default") + + clickedFunc: function() { + var headerText = qsTr("Restore default DNS settings?") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + SettingsController.primaryDns = "1.1.1.1" + primaryDns.textField.text = SettingsController.primaryDns + SettingsController.secondaryDns = "1.0.0.1" + secondaryDns.textField.text = SettingsController.secondaryDns + PageController.showNotificationMessage(qsTr("Settings have been reset")) + } + var noButtonFunction = function() { + } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } + } + + footer: ColumnLayout { + width: listView.width + + BasicButtonType { + id: saveButton + + Layout.fillWidth: true + Layout.margins: 16 + + text: qsTr("Save") + + clickedFunc: function() { + if (primaryDns.textField.text !== SettingsController.primaryDns) { + SettingsController.primaryDns = primaryDns.textField.text + } + if (secondaryDns.textField.text !== SettingsController.secondaryDns) { + SettingsController.secondaryDns = secondaryDns.textField.text + } + PageController.showNotificationMessage(qsTr("Settings saved")) + } + } + } + } +} diff --git a/client/ui/qml/Pages2/PageSettingsLogging.qml b/client/ui/qml/Pages2/PageSettingsLogging.qml index 5b20936c..fda58175 100644 --- a/client/ui/qml/Pages2/PageSettingsLogging.qml +++ b/client/ui/qml/Pages2/PageSettingsLogging.qml @@ -23,9 +23,15 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } } - ListView { + ListViewType { id: listView anchors.top: backButton.bottom @@ -33,10 +39,6 @@ PageType { anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - header: ColumnLayout { width: listView.width @@ -101,8 +103,7 @@ PageType { } model: logTypes - clip: true - reuseItems: true + snapMode: ListView.SnapOneItem delegate: ColumnLayout { diff --git a/client/ui/qml/Pages2/PageSettingsServerData.qml b/client/ui/qml/Pages2/PageSettingsServerData.qml index 82552958..1a496b5b 100644 --- a/client/ui/qml/Pages2/PageSettingsServerData.qml +++ b/client/ui/qml/Pages2/PageSettingsServerData.qml @@ -18,10 +18,6 @@ PageType { signal lastItemTabClickedSignal() - onFocusChanged: content.isServerWithWriteAccess ? - labelWithButton.forceActiveFocus() : - labelWithButton3.forceActiveFocus() - Connections { target: InstallController @@ -63,218 +59,194 @@ PageType { target: ServersModel function onProcessedServerIndexChanged() { - content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() + listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() } } - FlickableType { - id: fl - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height + ListViewType { + id: listView - ColumnLayout { - id: content + property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + anchors.fill: parent - property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() + model: serverActions + + delegate: ColumnLayout { + width: listView.width LabelWithButtonType { - id: labelWithButton - visible: content.isServerWithWriteAccess Layout.fillWidth: true - text: qsTr("Check the server for previously installed Amnezia services") - descriptionText: qsTr("Add them to the application if they were not displayed") + visible: isVisible + + text: title + descriptionText: description + textColor: tColor clickedFunction: function() { + clickedHandler() + } + } + + DividerType { + visible: isVisible + } + } + } + + property list serverActions: [ + check, + reboot, + remove, + clear, + reset, + switch_to_premium, + ] + + QtObject { + id: check + + property bool isVisible: true + readonly property string title: qsTr("Check the server for previously installed Amnezia services") + readonly property string description: qsTr("Add them to the application if they were not displayed") + readonly property var tColor: AmneziaStyle.color.paleGray + readonly property var clickedHandler: function() { + PageController.showBusyIndicator(true) + InstallController.scanServerForInstalledContainers() + PageController.showBusyIndicator(false) + } + } + + QtObject { + id: reboot + + property bool isVisible: true + readonly property string title: qsTr("Reboot server") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + readonly property var clickedHandler: function() { + var headerText = qsTr("Do you want to reboot the server?") + var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection")) + } else { PageController.showBusyIndicator(true) - InstallController.scanServerForInstalledContainers() + InstallController.rebootProcessedServer() PageController.showBusyIndicator(false) } } + var noButtonFunction = function() { - DividerType { - visible: content.isServerWithWriteAccess } - LabelWithButtonType { - id: labelWithButton2 - visible: content.isServerWithWriteAccess - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Reboot server") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: remove - clickedFunction: function() { - var headerText = qsTr("Do you want to reboot the server?") - var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") + property bool isVisible: true + readonly property string title: qsTr("Remove server from application") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + readonly property var clickedHandler: function() { + var headerText = qsTr("Do you want to remove the server from application?") + var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") - var yesButtonFunction = function() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection")) - } else { - PageController.showBusyIndicator(true) - InstallController.rebootProcessedServer() - PageController.showBusyIndicator(false) - } - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - labelWithButton2.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot remove server during active connection")) + } else { + PageController.showBusyIndicator(true) + InstallController.removeProcessedServer() + PageController.showBusyIndicator(false) } } + var noButtonFunction = function() { - DividerType { - visible: content.isServerWithWriteAccess } - LabelWithButtonType { - id: labelWithButton3 - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Remove server from application") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: clear - clickedFunction: function() { - var headerText = qsTr("Do you want to remove the server from application?") - var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") + property bool isVisible: true + readonly property string title: qsTr("Clear server from Amnezia software") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + readonly property var clickedHandler: function() { + var headerText = qsTr("Do you want to clear server from Amnezia software?") + var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") - var yesButtonFunction = function() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot remove server during active connection")) - } else { - PageController.showBusyIndicator(true) - InstallController.removeProcessedServer() - PageController.showBusyIndicator(false) - } - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - labelWithButton3.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection")) + } else { + PageController.goToPage(PageEnum.PageDeinstalling) + InstallController.removeAllContainers() } } + var noButtonFunction = function() { - DividerType {} + } - LabelWithButtonType { - id: labelWithButton4 - visible: content.isServerWithWriteAccess - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Clear server from Amnezia software") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: reset - clickedFunction: function() { - var headerText = qsTr("Do you want to clear server from Amnezia software?") - var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") + property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") + readonly property string title: qsTr("Reset API config") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + readonly property var clickedHandler: function() { + var headerText = qsTr("Do you want to reset API config?") + var descriptionText = "" + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") - var yesButtonFunction = function() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection")) - } else { - PageController.goToPage(PageEnum.PageDeinstalling) - InstallController.removeAllContainers() - } - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - labelWithButton4.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection")) + } else { + PageController.showBusyIndicator(true) + InstallController.removeApiConfig(ServersModel.processedIndex) + PageController.showBusyIndicator(false) } } + var noButtonFunction = function() { - DividerType { - visible: content.isServerWithWriteAccess } - LabelWithButtonType { - id: labelWithButton5 - visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Reset API config") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: switch_to_premium - clickedFunction: function() { - var headerText = qsTr("Do you want to reset API config?") - var descriptionText = "" - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection")) - } else { - PageController.showBusyIndicator(true) - InstallController.removeApiConfig(ServersModel.processedIndex) - PageController.showBusyIndicator(false) - } - - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - } - - DividerType { - visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") - } - - LabelWithButtonType { - id: labelWithButton6 - visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium - Layout.fillWidth: true - - text: qsTr("Switch to the new Amnezia Premium subscription") - textColor: AmneziaStyle.color.vibrantRed - - clickedFunction: function() { - PageController.goToPageHome() - ApiPremV1MigrationController.showMigrationDrawer() - } - } - - DividerType { - visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium - } + property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") + readonly property string title: qsTr("Switch to the new Amnezia Premium subscription") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + readonly property var clickedHandler: function() { + PageController.goToPageHome() + ApiPremV1MigrationController.showMigrationDrawer() } } } diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml index fce9b2a3..a17149c9 100644 --- a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml +++ b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml @@ -21,249 +21,211 @@ PageType { property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex()) - ColumnLayout { - id: header + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - - BackButtonType { - id: backButton + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } + } - BaseHeaderType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - Layout.bottomMargin: 32 + ListViewType { + id: listView - headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") - } + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left - ListView { - id: protocols - Layout.fillWidth: true - height: protocols.contentItem.height - clip: true - interactive: true + header: ColumnLayout { + width: listView.width - property bool isFocusable: true + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 32 - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - model: ProtocolsModel - - delegate: Item { - implicitWidth: protocols.width - implicitHeight: delegateContent.implicitHeight - - ColumnLayout { - id: delegateContent - - anchors.fill: parent - - property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg - property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess() - - LabelWithButtonType { - id: clientSettings - - Layout.fillWidth: true - - text: protocolName + qsTr(" connection settings") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - visible: delegateContent.isClientSettingsVisible - - clickedFunction: function() { - if (isClientProtocolExists) { - switch (protocolIndex) { - case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break; - } - PageController.goToPage(clientProtocolPage); - } else { - PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration")) - } - } - - MouseArea { - anchors.fill: clientSettings - cursorShape: Qt.PointingHandCursor - enabled: false - } - } - - DividerType { - visible: delegateContent.isClientSettingsVisible - } - - LabelWithButtonType { - id: serverSettings - - Layout.fillWidth: true - - text: protocolName + qsTr(" server settings") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - visible: delegateContent.isServerSettingsVisible - - clickedFunction: function() { - switch (protocolIndex) { - case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break; - case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break; - } - PageController.goToPage(serverProtocolPage); - } - - MouseArea { - anchors.fill: serverSettings - cursorShape: Qt.PointingHandCursor - enabled: false - } - } - - DividerType { - visible: delegateContent.isServerSettingsVisible - } - } - } - - footer: ColumnLayout { - width: header.width - - LabelWithButtonType { - id: clearCacheButton - - Layout.fillWidth: true - - visible: root.isClearCacheVisible - - text: qsTr("Clear profile") - - clickedFunction: function() { - var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName()) - var descriptionText = qsTr("The connection configuration will be deleted for this device only") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName()) - PageController.showNotificationMessage(message) - return - } - - PageController.showBusyIndicator(true) - InstallController.clearCachedProfile() - PageController.showBusyIndicator(false) - } - var noButtonFunction = function() { - // if (!GC.isMobile()) { - // focusItem.forceActiveFocus() - // } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - - MouseArea { - anchors.fill: clearCacheButton - cursorShape: Qt.PointingHandCursor - enabled: false - } - } - - DividerType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: root.isClearCacheVisible - } - - LabelWithButtonType { - id: removeButton - - Layout.fillWidth: true - - visible: ServersModel.isProcessedServerHasWriteAccess() - - text: qsTr("Remove ") - textColor: AmneziaStyle.color.vibrantRed - - clickedFunction: function() { - var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName()) - var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected - && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Cannot remove active container")) - } else - { - PageController.goToPage(PageEnum.PageDeinstalling) - InstallController.removeProcessedContainer() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - focusItem.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - - MouseArea { - anchors.fill: removeButton - cursorShape: Qt.PointingHandCursor - enabled: false - } - } - - DividerType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: ServersModel.isProcessedServerHasWriteAccess() - } + headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") } } + model: ProtocolsModel + + delegate: ColumnLayout { + id: delegateContent + + width: listView.width + + property bool isClientSettingsVisible: (protocolIndex === ProtocolEnum.WireGuard) || (protocolIndex === ProtocolEnum.Awg) + property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess() + + LabelWithButtonType { + id: clientSettings + + Layout.fillWidth: true + + text: protocolName + qsTr(" connection settings") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + visible: delegateContent.isClientSettingsVisible + + clickedFunction: function() { + if (isClientProtocolExists) { + switch (protocolIndex) { + case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break; + } + PageController.goToPage(clientProtocolPage); + } else { + PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration")) + } + } + + MouseArea { + anchors.fill: clientSettings + cursorShape: Qt.PointingHandCursor + enabled: false + } + } + + DividerType { + visible: delegateContent.isClientSettingsVisible + } + + LabelWithButtonType { + id: serverSettings + + Layout.fillWidth: true + + text: protocolName + qsTr(" server settings") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + visible: delegateContent.isServerSettingsVisible + + clickedFunction: function() { + switch (protocolIndex) { + case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break; + } + PageController.goToPage(serverProtocolPage); + } + + MouseArea { + anchors.fill: serverSettings + cursorShape: Qt.PointingHandCursor + enabled: false + } + } + + DividerType { + visible: delegateContent.isServerSettingsVisible + } + } + + footer: ColumnLayout { + + width: listView.width + + LabelWithButtonType { + id: clearCacheButton + + Layout.fillWidth: true + + visible: root.isClearCacheVisible + + text: qsTr("Clear profile") + + clickedFunction: function() { + var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName()) + var descriptionText = qsTr("The connection configuration will be deleted for this device only") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName()) + PageController.showNotificationMessage(message) + return + } + + PageController.showBusyIndicator(true) + InstallController.clearCachedProfile() + PageController.showBusyIndicator(false) + } + + var noButtonFunction = function() { + } + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + MouseArea { + anchors.fill: clearCacheButton + cursorShape: Qt.PointingHandCursor + enabled: false + } + } + + DividerType { + visible: root.isClearCacheVisible + } + + LabelWithButtonType { + id: removeButton + + Layout.fillWidth: true + + visible: ServersModel.isProcessedServerHasWriteAccess() + + text: qsTr("Remove ") + textColor: AmneziaStyle.color.vibrantRed + + clickedFunction: function() { + var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName()) + var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected + && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Cannot remove active container")) + } else + { + PageController.goToPage(PageEnum.PageDeinstalling) + InstallController.removeProcessedContainer() + } + } + var noButtonFunction = function() { + + } + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + MouseArea { + anchors.fill: removeButton + cursorShape: Qt.PointingHandCursor + enabled: false + } + } + + DividerType { + visible: ServersModel.isProcessedServerHasWriteAccess() + } + } } } - diff --git a/client/ui/qml/Pages2/PageSettingsServersList.qml b/client/ui/qml/Pages2/PageSettingsServersList.qml index 57e39ae8..f7222236 100644 --- a/client/ui/qml/Pages2/PageSettingsServersList.qml +++ b/client/ui/qml/Pages2/PageSettingsServersList.qml @@ -40,25 +40,20 @@ PageType { } } - ListView { + ListViewType { id: servers objectName: "servers" width: parent.width anchors.top: header.bottom anchors.topMargin: 16 + anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - height: 500 - - property bool isFocusable: true model: ServersModel - clip: true - reuseItems: true - delegate: Item { implicitWidth: servers.width implicitHeight: delegateContent.implicitHeight diff --git a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml index 0cbed7c8..7d0ba599 100644 --- a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml @@ -161,7 +161,7 @@ PageType { } } - ListView { + ListViewType { id: listView anchors.top: header.bottom @@ -172,8 +172,6 @@ PageType { enabled: root.pageEnabled - property bool isFocusable: true - model: SortFilterProxyModel { id: proxySitesModel sourceModel: SitesModel @@ -193,13 +191,7 @@ PageType { ] } - clip: true - - reuseItems: true - delegate: ColumnLayout { - id: delegateContent - width: listView.width LabelWithButtonType { @@ -236,7 +228,6 @@ PageType { } } - Rectangle { anchors.fill: addSiteButton anchors.bottomMargin: -24 @@ -286,8 +277,8 @@ PageType { moreActionsDrawer.openTriggered() } - Keys.onReturnPressed: this.clicked() - Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: addSiteButtonImage.clicked() + Keys.onEnterPressed: addSiteButtonImage.clicked() } } @@ -351,7 +342,7 @@ PageType { } DividerType {} - + LabelWithButtonType { id: clearSitesButton Layout.fillWidth: true @@ -402,22 +393,24 @@ PageType { backButtonFunction: function() { importSitesDrawer.closeTriggered() } + + onFocusChanged: { + if (this.activeFocus) { + importSitesDrawerListView.positionViewAtBeginning() + } + } } - FlickableType { + ListViewType { + id: importSitesDrawerListView + anchors.top: importSitesDrawerBackButton.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom - contentHeight: importSitesDrawerContent.height - - ColumnLayout { - id: importSitesDrawerContent - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + header: ColumnLayout { + width: importSitesDrawerListView.width Header2Type { Layout.fillWidth: true @@ -425,49 +418,67 @@ PageType { headerText: qsTr("Import a list of sites") } + } + + model: importOptions + + delegate: ColumnLayout { + width: importSitesDrawerListView.width LabelWithButtonType { - id: importSitesButton2 Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - text: qsTr("Replace site list") + text: title clickedFunction: function() { - var fileName = SystemController.getFileName(qsTr("Open sites file"), - qsTr("Sites files (*.json)")) - if (fileName !== "") { - importSitesDrawerContent.importSites(fileName, true) - } + clickedHandler() } } DividerType {} - - LabelWithButtonType { - id: importSitesButton3 - Layout.fillWidth: true - text: qsTr("Add imported sites to existing ones") - - clickedFunction: function() { - var fileName = SystemController.getFileName(qsTr("Open sites file"), - qsTr("Sites files (*.json)")) - if (fileName !== "") { - importSitesDrawerContent.importSites(fileName, false) - } - } - } - - function importSites(fileName, replaceExistingSites) { - PageController.showBusyIndicator(true) - SitesController.importSites(fileName, replaceExistingSites) - PageController.showBusyIndicator(false) - importSitesDrawer.closeTriggered() - moreActionsDrawer.closeTriggered() - } - - DividerType {} } } } } + + property list importOptions: [ + replaceOption, + addOption, + ] + + QtObject { + id: replaceOption + + readonly property string title: qsTr("Replace site list") + readonly property var clickedHandler: function() { + var fileName = SystemController.getFileName(qsTr("Open sites file"), + qsTr("Sites files (*.json)")) + if (fileName !== "") { + root.importSites(fileName, true) + } + } + } + + QtObject { + id: addOption + + readonly property string title: qsTr("Add imported sites to existing ones") + readonly property var clickedHandler: function() { + var fileName = SystemController.getFileName(qsTr("Open sites file"), + qsTr("Sites files (*.json)")) + if (fileName !== "") { + root.importSites(fileName, false) + } + } + } + + function importSites(fileName, replaceExistingSites) { + PageController.showBusyIndicator(true) + SitesController.importSites(fileName, replaceExistingSites) + PageController.showBusyIndicator(false) + importSitesDrawer.closeTriggered() + moreActionsDrawer.closeTriggered() + } } diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml index cfc07fd1..1f76c97d 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml @@ -1,146 +1,177 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" -import "../Components" - -PageType { - id: root - - FlickableType { - id: fl - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 - - BackButtonType { - id: backButton - Layout.topMargin: 20 - } - - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 8 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: 32 - - headerText: ApiServicesModel.getSelectedServiceData("name") - descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/map-pin.svg" - leftText: qsTr("For the region") - rightText: ApiServicesModel.getSelectedServiceData("region") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/tag.svg" - leftText: qsTr("Price") - rightText: ApiServicesModel.getSelectedServiceData("price") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/history.svg" - leftText: qsTr("Work period") - rightText: ApiServicesModel.getSelectedServiceData("timeLimit") - - visible: rightText !== "" - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/gauge.svg" - leftText: qsTr("Speed") - rightText: ApiServicesModel.getSelectedServiceData("speed") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/info.svg" - leftText: qsTr("Features") - rightText: "" - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - - onLinkActivated: function(link) { - Qt.openUrlExternally(link) - } - textFormat: Text.RichText - text: { - var text = ApiServicesModel.getSelectedServiceData("features") - return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")) - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - } - } - - BasicButtonType { - id: continueButton - - anchors.right: parent.right - anchors.left: parent.left - anchors.bottom: parent.bottom - - anchors.topMargin: 32 - anchors.rightMargin: 16 - anchors.leftMargin: 16 - anchors.bottomMargin: 32 - - text: qsTr("Connect") - - clickedFunc: function() { - var endpoint = ApiServicesModel.getStoreEndpoint() - if (endpoint !== undefined && endpoint !== "") { - Qt.openUrlExternally(endpoint) - PageController.closePage() - PageController.closePage() - } else { - PageController.showBusyIndicator(true) - ApiConfigsController.importServiceFromGateway() - PageController.showBusyIndicator(false) - } - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 32 + + headerText: ApiServicesModel.getSelectedServiceData("name") + descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") + } + } + + model: inputFields + spacing: 0 + + delegate: ColumnLayout { + width: listView.width + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: imagePath + leftText: lText + rightText: rText + } + } + + footer: ColumnLayout { + width: listView.width + + spacing: 0 + + ParagraphTextType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + onLinkActivated: function(link) { + Qt.openUrlExternally(link) + } + textFormat: Text.RichText + text: { + var text = ApiServicesModel.getSelectedServiceData("features") + return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")) + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } + + BasicButtonType { + id: continueButton + + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.bottomMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Connect") + + clickedFunc: function() { + var endpoint = ApiServicesModel.getStoreEndpoint() + if (endpoint !== undefined && endpoint !== "") { + Qt.openUrlExternally(endpoint) + PageController.closePage() + PageController.closePage() + } else { + PageController.showBusyIndicator(true) + ApiConfigsController.importServiceFromGateway() + PageController.showBusyIndicator(false) + } + } + } + } + } + + property list inputFields: [ + region, + price, + timeLimit, + speed, + features + ] + + QtObject { + id: region + + readonly property string imagePath: "qrc:/images/controls/map-pin.svg" + readonly property string lText: qsTr("For the region") + readonly property string rText: ApiServicesModel.getSelectedServiceData("region") + property bool isVisible: true + } + + QtObject { + id: price + + readonly property string imagePath: "qrc:/images/controls/tag.svg" + readonly property string lText: qsTr("Price") + readonly property string rText: ApiServicesModel.getSelectedServiceData("price") + property bool isVisible: true + } + + QtObject { + id: timeLimit + + readonly property string imagePath: "qrc:/images/controls/history.svg" + readonly property string lText: qsTr("Work period") + readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit") + property bool isVisible: rText !== "" + } + + QtObject { + id: speed + + readonly property string imagePath: "qrc:/images/controls/gauge.svg" + readonly property string lText: qsTr("Speed") + readonly property string rText: ApiServicesModel.getSelectedServiceData("speed") + property bool isVisible: true + } + + QtObject { + id: features + + readonly property string imagePath: "qrc:/images/controls/info.svg" + readonly property string lText: qsTr("Features") + readonly property string rText: "" + property bool isVisible: true + } +} diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml index 207c305e..51fdee36 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml @@ -14,86 +14,77 @@ import "../Config" PageType { id: root - ColumnLayout { - id: header + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right + Layout.topMargin: 20 - spacing: 0 - - BackButtonType { - id: backButton - Layout.topMargin: 20 - } - - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 8 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: 16 - - headerText: qsTr("VPN by Amnezia") - descriptionText: qsTr("Choose a VPN service that suits your needs.") + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - ListView { - id: servicesListView + ListViewType { + id: listView - anchors.top: header.bottom + anchors.top: backButton.bottom anchors.right: parent.right anchors.left: parent.left anchors.bottom: parent.bottom anchors.topMargin: 16 - spacing: 0 - property bool isFocusable: true - - clip: true - reuseItems: true + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 24 + + headerText: qsTr("VPN by Amnezia") + descriptionText: qsTr("Choose a VPN service that suits your needs.") + } + } + + spacing: 0 model: ApiServicesModel - ScrollBar.vertical: ScrollBarType {} + delegate: ColumnLayout { - delegate: Item { - implicitWidth: servicesListView.width - implicitHeight: delegateContent.implicitHeight + width: listView.width enabled: isServiceAvailable - ColumnLayout { - id: delegateContent + CardWithIconsType { + id: card - anchors.fill: parent + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 - CardWithIconsType { - id: card + headerText: name + bodyText: cardDescription + footerText: price - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: 16 + rightImageSource: "qrc:/images/controls/chevron-right.svg" - headerText: name - bodyText: cardDescription - footerText: price - - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - onClicked: { - if (isServiceAvailable) { - ApiServicesModel.setServiceIndex(index) - PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) - } + onClicked: { + if (isServiceAvailable) { + ApiServicesModel.setServiceIndex(index) + PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) } - - Keys.onEnterPressed: this.clicked() - Keys.onReturnPressed: this.clicked() } + + Keys.onEnterPressed: clicked() + Keys.onReturnPressed: clicked() } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 520dc5d3..f88745d4 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -27,21 +27,11 @@ PageType { } } - ListView { + ListViewType { id: listView anchors.fill: parent - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - - model: variants - - clip: true - - reuseItems: true - header: ColumnLayout { width: listView.width @@ -216,6 +206,8 @@ PageType { } } + model: variants + delegate: ColumnLayout { width: listView.width diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index fd9404e0..6a30dbb7 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -28,41 +28,14 @@ PageType { } } - ListView { + ListViewType { id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - ScrollBar.vertical: ScrollBarType {} - header: ColumnLayout { width: listView.width @@ -78,8 +51,6 @@ PageType { model: inputFields spacing: 16 - clip: true - reuseItems: true delegate: ColumnLayout { width: listView.width diff --git a/client/ui/qml/Pages2/PageSetupWizardEasy.qml b/client/ui/qml/Pages2/PageSetupWizardEasy.qml index 599464cf..9bc5cf3f 100644 --- a/client/ui/qml/Pages2/PageSetupWizardEasy.qml +++ b/client/ui/qml/Pages2/PageSetupWizardEasy.qml @@ -20,6 +20,7 @@ PageType { SortFilterProxyModel { id: proxyContainersModel + sourceModel: ContainersModel filters: [ ValueFilter { @@ -40,107 +41,98 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ButtonGroup { + id: buttonGroup + } + + ListViewType { + id: listView + + property int dockerContainer + property int containerDefaultPort + property int containerDefaultTransportProto + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + setupLaterButton.anchors.bottomMargin + anchors.left: parent.left + anchors.right: parent.right - Column { - id: content + spacing: 16 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + header: ColumnLayout { + width: listView.width spacing: 16 BaseHeaderType { id: header - implicitWidth: parent.width + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + headerTextMaximumLineCount: 10 headerText: qsTr("Choose Installation Type") } + } - ButtonGroup { - id: buttonGroup - } + model: proxyContainersModel + currentIndex: 0 - ListView { - id: containers - width: parent.width - height: containers.contentItem.height - spacing: 16 + delegate: ColumnLayout { + width: listView.width - currentIndex: 0 - clip: true - interactive: false - model: proxyContainersModel + CardType { + id: card - property int dockerContainer - property int containerDefaultPort - property int containerDefaultTransportProto + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 - property bool isFocusable: true + headerText: easySetupHeader + bodyText: easySetupDescription - delegate: Item { - implicitWidth: containers.width - implicitHeight: delegateContent.implicitHeight + ButtonGroup.group: buttonGroup - ColumnLayout { - id: delegateContent + onClicked: function() { + isEasySetup = true + var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - CardType { - id: card - - Layout.fillWidth: true - - headerText: easySetupHeader - bodyText: easySetupDescription - - ButtonGroup.group: buttonGroup - - onClicked: function() { - isEasySetup = true - var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) - - containers.dockerContainer = dockerContainer - containers.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto) - containers.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto) - } - - Keys.onEnterPressed: this.clicked() - Keys.onReturnPressed: this.clicked() - } - } + listView.dockerContainer = dockerContainer + listView.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto) + listView.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto) } - Component.onCompleted: { - var item = containers.itemAtIndex(containers.currentIndex) - if (item !== null) { - var button = item.children[0].children[0] - button.checked = true - button.clicked() - } - } + Keys.onReturnPressed: this.clicked() + Keys.onEnterPressed: this.clicked() } + } + + footer: ColumnLayout { + width: listView.width + spacing: 16 DividerType { - implicitWidth: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 } CardType { - implicitWidth: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 headerText: qsTr("Manual") bodyText: qsTr("Choose a VPN protocol") @@ -149,6 +141,7 @@ PageType { onClicked: function() { isEasySetup = false + checked = true } Keys.onEnterPressed: this.clicked() @@ -158,19 +151,19 @@ PageType { BasicButtonType { id: continueButton - implicitWidth: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: qsTr("Continue") - - parentFlickable: fl clickedFunc: function() { if (root.isEasySetup) { - ContainersModel.setProcessedContainerIndex(containers.dockerContainer) + ContainersModel.setProcessedContainerIndex(listView.dockerContainer) PageController.goToPage(PageEnum.PageSetupWizardInstalling) - InstallController.install(containers.dockerContainer, - containers.containerDefaultPort, - containers.containerDefaultTransportProto) + InstallController.install(listView.dockerContainer, + listView.containerDefaultPort, + listView.containerDefaultTransportProto) } else { PageController.goToPage(PageEnum.PageSetupWizardProtocols) } @@ -180,9 +173,11 @@ PageType { BasicButtonType { id: setupLaterButton - implicitWidth: parent.width - anchors.topMargin: 8 - anchors.bottomMargin: 24 + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 defaultColor: AmneziaStyle.color.transparent hoveredColor: AmneziaStyle.color.translucentWhite @@ -191,9 +186,6 @@ PageType { textColor: AmneziaStyle.color.paleGray borderWidth: 1 - Keys.onTabPressed: lastItemTabClicked(focusItem) - parentFlickable: fl - visible: { if (PageController.isTriggeredByConnectButton()) { PageController.setTriggeredByConnectButton(false) @@ -211,5 +203,15 @@ PageType { } } } + + Component.onCompleted: { + var item = listView.itemAtIndex(listView.currentIndex) + if (item !== null) { + var button = item.children[0] + button.checked = true + button.clicked() + } + } } } + diff --git a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml index 822931b8..efabeb9f 100644 --- a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml +++ b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml @@ -85,92 +85,76 @@ PageType { ] } - FlickableType { + ListViewType { + id: listView + anchors.fill: parent - contentHeight: content.height - Column { - id: content + currentIndex: -1 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: proxyContainersModel - spacing: 16 + delegate: ColumnLayout { + width: listView.width - ListView { - id: container - width: parent.width - height: container.contentItem.height - currentIndex: -1 - clip: true - interactive: false - model: proxyContainersModel + BaseHeaderType { + Layout.fillWidth: true + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - delegate: Item { - implicitWidth: container.width - implicitHeight: delegateContent.implicitHeight + headerText: qsTr("Installing") + descriptionText: name + } - ColumnLayout { - id: delegateContent + ProgressBarType { + id: progressBar - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 20 + Timer { + id: timer - headerText: qsTr("Installing") - descriptionText: name - } - - ProgressBarType { - id: progressBar - - Layout.fillWidth: true - Layout.topMargin: 32 - - Timer { - id: timer - - interval: 300 - repeat: true - running: root.isTimerRunning - onTriggered: { - progressBar.value += 0.003 - } - } - } - - ParagraphTextType { - id: progressText - - Layout.fillWidth: true - Layout.topMargin: 8 - - text: root.progressBarText - } - - BasicButtonType { - id: cancelIntallationButton - - Layout.fillWidth: true - Layout.topMargin: 24 - - visible: root.isCancelButtonVisible - - text: qsTr("Cancel installation") - - clickedFunc: function() { - InstallController.cancelInstallation() - PageController.showBusyIndicator(true) - } - } + interval: 300 + repeat: true + running: root.isTimerRunning + onTriggered: { + progressBar.value += 0.003 } } } + + ParagraphTextType { + id: progressText + + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: root.progressBarText + } + + BasicButtonType { + id: cancelIntallationButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: root.isCancelButtonVisible + + text: qsTr("Cancel installation") + + clickedFunc: function() { + InstallController.cancelInstallation() + PageController.showBusyIndicator(true) + } + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml index ac7fc4b2..4d914a1d 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml @@ -29,256 +29,239 @@ PageType { ] } - FlickableType { - anchors.fill: parent - contentHeight: content.height + BackButtonType { + id: backButton - Column { - id: content + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } - ListView { - id: processedContainerListView - width: parent.width - height: contentItem.height - currentIndex: -1 - clip: true - interactive: false - model: proxyContainersModel + ListViewType { + id: listView - property bool isFocusable: true + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left - Keys.onTabPressed: { - FocusController.nextKeyTabItem() + currentIndex: -1 + + model: proxyContainersModel + + delegate: ColumnLayout { + width: listView.width + + BaseHeaderType { + id: header + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Installing %1").arg(name) + descriptionText: description + } + + BasicButtonType { + id: showDetailsButton + + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + implicitHeight: 32 + + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot + + text: qsTr("More detailed") + + clickedFunc: function() { + showDetailsDrawer.openTriggered() } + } - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } + DrawerType2 { + id: showDetailsDrawer + parent: root - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } + anchors.fill: parent + expandedHeight: parent.height * 0.9 + expandedStateContent: Item { + implicitHeight: showDetailsDrawer.expandedHeight - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } + BackButtonType { + id: showDetailsBackButton - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - delegate: Item { - implicitWidth: processedContainerListView.width - implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height - - property alias port:port - - ColumnLayout { - id: delegateContent - - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 - - BackButtonType { - id: backButton - - Layout.topMargin: 20 - Layout.rightMargin: -16 - Layout.leftMargin: -16 + backButtonFunction: function() { + showDetailsDrawer.closeTriggered() } + } - BaseHeaderType { - id: header + ListViewType { + id: showDetailsListView - Layout.fillWidth: true + anchors.top: showDetailsBackButton.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom - headerText: qsTr("Installing %1").arg(name) - descriptionText: description - } + header: ColumnLayout { + width: showDetailsListView.width - BasicButtonType { - id: showDetailsButton + Header2Type { + id: showDetailsDrawerHeader - Layout.topMargin: 16 - Layout.leftMargin: -8 + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 - implicitHeight: 32 - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.goldenApricot - - text: qsTr("More detailed") - KeyNavigation.tab: transportProtoSelector - - clickedFunc: function() { - showDetailsDrawer.openTriggered() + headerText: name } } - DrawerType2 { - id: showDetailsDrawer - parent: root + model: 1 // fake model to force the ListView to be created without a model - anchors.fill: parent - expandedHeight: parent.height * 0.9 - expandedStateContent: Item { - implicitHeight: showDetailsDrawer.expandedHeight + delegate: ColumnLayout { + width: showDetailsListView.width - BackButtonType { - id: showDetailsBackButton + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.bottomMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 + text: detailedDescription + textFormat: Text.MarkdownText + } - backButtonFunction: function() { - showDetailsDrawer.closeTriggered() - } - } + Rectangle { + Layout.fillHeight: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - FlickableType { - id: fl - anchors.top: showDetailsBackButton.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - contentHeight: { - var emptySpaceHeight = parent.height - showDetailsBackButton.implicitHeight - showDetailsBackButton.anchors.topMargin - return (showDetailsDrawerContent.height > emptySpaceHeight) ? - showDetailsDrawerContent.height : emptySpaceHeight - } + color: AmneziaStyle.color.transparent + } + } - ColumnLayout { - id: showDetailsDrawerContent + footer: ColumnLayout { + width: showDetailsListView.width - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + BasicButtonType { + id: showDetailsCloseButton + Layout.fillWidth: true + Layout.bottomMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - Header2Type { - id: showDetailsDrawerHeader - Layout.fillWidth: true - Layout.topMargin: 16 + text: qsTr("Close") - headerText: name - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 16 - Layout.bottomMargin: 16 - - text: detailedDescription - textFormat: Text.MarkdownText - } - - Rectangle { - Layout.fillHeight: true - color: AmneziaStyle.color.transparent - } - - BasicButtonType { - id: showDetailsCloseButton - Layout.fillWidth: true - Layout.bottomMargin: 32 - parentFlickable: fl - - text: qsTr("Close") - - clickedFunc: function() { - showDetailsDrawer.closeTriggered() - } - } - } + clickedFunc: function() { + showDetailsDrawer.closeTriggered() } } } - - ParagraphTextType { - id: transportProtoHeader - - Layout.topMargin: 16 - - text: qsTr("Network protocol") - } - - TransportProtoSelector { - id: transportProtoSelector - - Layout.fillWidth: true - rootWidth: root.width - } - - TextFieldWithHeaderType { - id: port - - Layout.fillWidth: true - Layout.topMargin: 16 - - headerText: qsTr("Port") - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - } - - Rectangle { - Layout.fillHeight: true - color: AmneziaStyle.color.transparent - } - - BasicButtonType { - id: installButton - - Layout.fillWidth: true - Layout.bottomMargin: 32 - - text: qsTr("Install") - - clickedFunc: function() { - if (!port.textField.acceptableInput && - ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" && - ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") { - port.errorText = qsTr("The port must be in the range of 1 to 65535") - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.install(dockerContainer, port.textField.text, transportProtoSelector.currentIndex) - } - } - - Component.onCompleted: { - var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) - - if (ProtocolProps.defaultPort(defaultContainerProto) < 0) { - port.visible = false - } else { - port.textField.text = ProtocolProps.getPortForInstall(defaultContainerProto) - } - transportProtoSelector.currentIndex = ProtocolProps.defaultTransportProto(defaultContainerProto) - - port.enabled = ProtocolProps.defaultPortChangeable(defaultContainerProto) - var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto) - transportProtoSelector.visible = protocolSelectorVisible - transportProtoHeader.visible = protocolSelectorVisible - } } } } + + ParagraphTextType { + id: transportProtoHeader + + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + text: qsTr("Network protocol") + } + + TransportProtoSelector { + id: transportProtoSelector + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + rootWidth: root.width + } + + TextFieldWithHeaderType { + id: port + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Port") + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } + } + + Rectangle { + Layout.fillHeight: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + color: AmneziaStyle.color.transparent + } + + BasicButtonType { + id: installButton + + Layout.fillWidth: true + Layout.bottomMargin: 32 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + text: qsTr("Install") + + clickedFunc: function() { + if (!port.textField.acceptableInput && + ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" && + ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") { + port.errorText = qsTr("The port must be in the range of 1 to 65535") + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.install(dockerContainer, port.textField.text, transportProtoSelector.currentIndex) + } + } + + Component.onCompleted: { + var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) + + if (ProtocolProps.defaultPort(defaultContainerProto) < 0) { + port.visible = false + } else { + port.textField.text = ProtocolProps.getPortForInstall(defaultContainerProto) + } + transportProtoSelector.currentIndex = ProtocolProps.defaultTransportProto(defaultContainerProto) + + port.enabled = ProtocolProps.defaultPortChangeable(defaultContainerProto) + var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto) + transportProtoSelector.visible = protocolSelectorVisible + transportProtoHeader.visible = protocolSelectorVisible + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml index 7afab630..da1edee6 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml @@ -42,19 +42,21 @@ PageType { anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - ListView { + ListViewType { id: listView anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - header: ColumnLayout { width: listView.width @@ -72,9 +74,8 @@ PageType { } model: proxyContainersModel - clip: true + spacing: 0 - reuseItems: true snapMode: ListView.SnapToItem delegate: ColumnLayout { @@ -87,9 +88,9 @@ PageType { descriptionText: description rightImageSource: "qrc:/images/controls/chevron-right.svg" - clickedFunction: function() { - ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index)) - PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) + clickedFunction: function () { + ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index)); + PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings); } } diff --git a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml index 930efb57..3a0f7832 100644 --- a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml +++ b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml @@ -13,25 +13,31 @@ import "../Config" PageType { id: root - FlickableType { - id: fl + BackButtonType { + id: backButton + anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 16 - - BackButtonType { - id: backButton - Layout.topMargin: 20 + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + header: ColumnLayout { + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -41,6 +47,13 @@ PageType { headerText: qsTr("Connection key") descriptionText: qsTr("A line that starts with vpn://...") } + } + + spacing: 16 + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { + width: listView.width TextFieldWithHeaderType { id: textKey @@ -60,23 +73,26 @@ PageType { } } } - } - BasicButtonType { - id: continueButton + footer: ColumnLayout { + width: listView.width - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 - anchors.bottomMargin: 32 + BasicButtonType { + id: continueButton - text: qsTr("Continue") + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: 32 - clickedFunc: function() { - if (ImportController.extractConfigFromData(textKey.textField.text)) { - PageController.goToPage(PageEnum.PageSetupWizardViewConfig) + text: qsTr("Continue") + + clickedFunc: function() { + if (ImportController.extractConfigFromData(textKey.textField.text)) { + PageController.goToPage(PageEnum.PageSetupWizardViewConfig) + } + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml index cfa9c90f..bffa66a2 100644 --- a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml +++ b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml @@ -23,6 +23,12 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } Connections { @@ -46,27 +52,29 @@ PageType { } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + connectButton.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + header: ColumnLayout { + width: listView.width BaseHeaderType { + Layout.leftMargin: 16 + Layout.rightMargin: 16 + headerText: qsTr("New connection") } RowLayout { Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + spacing: 8 visible: fileName.text !== "" @@ -88,7 +96,9 @@ PageType { BasicButtonType { id: showContentButton Layout.topMargin: 16 - Layout.leftMargin: -8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + implicitHeight: 32 defaultColor: AmneziaStyle.color.transparent @@ -99,8 +109,6 @@ PageType { text: showContent ? qsTr("Collapse content") : qsTr("Show content") - parentFlickable: fl - clickedFunc: function() { showContent = !showContent } @@ -108,16 +116,28 @@ PageType { CheckBoxType { id: cloakingCheckBox + objectName: "cloakingCheckBox" visible: ImportController.isNativeWireGuardConfig() Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + text: qsTr("Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider.") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser after have migrated to 6.9 + width: listView.width WarningType { - Layout.topMargin: 16 Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 textString: ImportController.getMaliciousWarningText() textFormat: Qt.RichText @@ -130,8 +150,10 @@ PageType { } WarningType { - Layout.topMargin: 16 Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 textString: qsTr("Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data.") @@ -140,7 +162,10 @@ PageType { Rectangle { Layout.fillWidth: true + Layout.topMargin: 16 Layout.bottomMargin: 48 + Layout.rightMargin: 16 + Layout.leftMargin: 16 implicitHeight: configContent.implicitHeight @@ -161,34 +186,38 @@ PageType { } } } - } - Rectangle { - anchors.fill: columnContent - anchors.bottomMargin: -24 - color: AmneziaStyle.color.midnightBlack - opacity: 0.8 - } + footer: ColumnLayout { + width: listView.width - ColumnLayout { - id: columnContent - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + BasicButtonType { + id: connectButton - BasicButtonType { - id: connectButton - Layout.fillWidth: true - Layout.bottomMargin: 32 + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.bottomMargin: 32 + Layout.rightMargin: 16 + Layout.leftMargin: 16 - text: qsTr("Connect") - clickedFunc: function() { - if (cloakingCheckBox.checked) { - ImportController.processNativeWireGuardConfig() + text: qsTr("Connect") + clickedFunc: function() { + const headerItem = listView.headerItem; + if (!headerItem) { + console.error("Header item not found in ListView") + return + } + + const cloakingCheckBoxItem = listView.findChildWithObjectName(headerItem.children, "cloakingCheckBox"); + if (!cloakingCheckBoxItem) { + console.error("cloakingCheckBox not found") + return + } + + if (cloakingCheckBoxItem.checked) { + ImportController.processNativeWireGuardConfig() + } + ImportController.importConfig() } - ImportController.importConfig() } } } diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 327b59b6..d0d2a4de 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -510,9 +510,6 @@ PageType { text: qsTr("Share") leftImageSource: "qrc:/images/controls/share-2.svg" - - parentFlickable: a - clickedFunc: function(){ if (clientNameTextField.textField.text !== "") { ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type) diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 062d0d1b..8a6b7a28 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -1,150 +1,170 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import SortFilterProxyModel 0.2 - -import PageEnum 1.0 -import ContainerProps 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Components" -import "../Config" - - -PageType { - id: root - - BackButtonType { - id: backButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 20 - } - - FlickableType { - anchors.top: backButton.bottom - anchors.bottom: parent.bottom - contentHeight: content.height - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - anchors.rightMargin: 16 - anchors.leftMargin: 16 - - spacing: 0 - - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 24 - - headerText: qsTr("Full access to the server and VPN") - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") + - qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ") - color: AmneziaStyle.color.mutedGray - } - - DropDownType { - id: serverSelector - - signal severSelectorIndexChanged - property int currentIndex: 0 - - Layout.fillWidth: true - Layout.topMargin: 16 - - drawerHeight: 0.4375 - drawerParent: root - - descriptionText: qsTr("Server") - headerText: qsTr("Server") - - listView: ListViewWithRadioButtonType { - id: serverSelectorListView - - rootWidth: root.width - imageSource: "qrc:/images/controls/check.svg" - - model: SortFilterProxyModel { - id: proxyServersModel - sourceModel: ServersModel - filters: [ - ValueFilter { - roleName: "hasWriteAccess" - value: true - } - ] - } - - clickedFunction: function() { - handler() - - if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) { - serverSelector.currentIndex = serverSelectorListView.currentIndex - } - - shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text - shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text - serverSelector.closeTriggered() - } - - Component.onCompleted: { - serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ? - proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0 - serverSelectorListView.triggerCurrentItem() - } - - function handler() { - serverSelector.text = selectedText - ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex) - } - } - } - - BasicButtonType { - id: shareButton - Layout.fillWidth: true - Layout.topMargin: 40 - - text: qsTr("Share") - leftImageSource: "qrc:/images/controls/share-2.svg" - - clickedFunc: function() { - PageController.showBusyIndicator(true) - - if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) { - PageController.showBusyIndicator(false) - ExportController.exportErrorOccurred(qsTr("Access error!")) - return - } else { - ExportController.generateFullAccessConfig() - } - - PageController.showBusyIndicator(false) - - PageController.goToPage(PageEnum.PageShareConnection) - } - } - } - } - -} - +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import ContainerProps 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Components" +import "../Config" + + +PageType { + id: root + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 24 + + headerText: qsTr("Full access to the server and VPN") + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 24 + Layout.bottomMargin: 24 + + text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") + + qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ") + color: AmneziaStyle.color.mutedGray + } + + DropDownType { + id: serverSelector + objectName: "serverSelector" + + signal severSelectorIndexChanged + property int currentIndex: 0 + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 16 + + drawerHeight: 0.4375 + drawerParent: root + + descriptionText: qsTr("Server") + headerText: qsTr("Server") + + listView: ListViewWithRadioButtonType { + id: serverSelectorListView + + rootWidth: root.width + imageSource: "qrc:/images/controls/check.svg" + + model: SortFilterProxyModel { + id: proxyServersModel + sourceModel: ServersModel + filters: [ + ValueFilter { + roleName: "hasWriteAccess" + value: true + } + ] + } + + clickedFunction: function() { + handler() + + if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) { + serverSelector.currentIndex = serverSelectorListView.currentIndex + } + + shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text + shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text + serverSelector.closeTriggered() + } + + Component.onCompleted: { + serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ? + proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0 + serverSelectorListView.triggerCurrentItem() + } + + function handler() { + serverSelector.text = selectedText + ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex) + } + } + } + } + + model: 1 // fake model to force the ListView to be created without a model + spacing: 0 + + delegate: ColumnLayout { + width: listView.width + + BasicButtonType { + id: shareButton + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Share") + leftImageSource: "qrc:/images/controls/share-2.svg" + + clickedFunc: function() { + PageController.showBusyIndicator(true) + + if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) { + PageController.showBusyIndicator(false) + ExportController.exportErrorOccurred(qsTr("Access error!")) + return + } else { + ExportController.generateFullAccessConfig() + } + + PageController.showBusyIndicator(false) + + PageController.goToPage(PageEnum.PageShareConnection) + } + } + } + } + + ShareConnectionDrawer { + id: shareConnectionDrawer + + anchors.fill: parent + } +} From 2608ea43672e8edaceb35f1ce3e22cfc37908274 Mon Sep 17 00:00:00 2001 From: Nethius Date: Wed, 6 Aug 2025 11:00:43 +0800 Subject: [PATCH 17/40] chore: fix typo (#1769) --- client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml index 39e2e626..dc3f63c6 100644 --- a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml +++ b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml @@ -71,7 +71,7 @@ PageType { text: countryName descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : "" - hideDescription: isWorkerExpired : true : false + hideDescription: isWorkerExpired ? true : false descriptionColor: AmneziaStyle.color.vibrantRed leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg" From 53c7fd4d81cabe678e0c88f963a241c0a2376df2 Mon Sep 17 00:00:00 2001 From: Mitternacht822 Date: Thu, 7 Aug 2025 07:12:09 +0400 Subject: [PATCH 18/40] fix: android build (#1768) * added signal-slot connection between corecontroller and systemtraynofificationhandler updating websiteurl * cleared up the commented lines * fixed andorid includes for systemtraynotificationhandler --- client/core/controllers/coreController.cpp | 2 +- client/core/controllers/coreController.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/core/controllers/coreController.cpp b/client/core/controllers/coreController.cpp index de14d0c9..3d657c5a 100644 --- a/client/core/controllers/coreController.cpp +++ b/client/core/controllers/coreController.cpp @@ -245,10 +245,10 @@ void CoreController::initNotificationHandler() connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(), &ConnectionController::closeConnection); connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated); -#endif auto* trayHandler = qobject_cast(m_notificationHandler.get()); connect(this, &CoreController::websiteUrlChanged, trayHandler, &SystemTrayNotificationHandler::updateWebsiteUrl); +#endif } void CoreController::updateTranslator(const QLocale &locale) diff --git a/client/core/controllers/coreController.h b/client/core/controllers/coreController.h index 2b18dca1..1fe7cea7 100644 --- a/client/core/controllers/coreController.h +++ b/client/core/controllers/coreController.h @@ -5,7 +5,9 @@ #include #include -#include "ui/systemtray_notificationhandler.h" +#ifndef Q_OS_ANDROID + #include "ui/systemtray_notificationhandler.h" +#endif #include "ui/controllers/api/apiConfigsController.h" #include "ui/controllers/api/apiSettingsController.h" From a6e6de33c852099415a25db922fa399b7ee7c2ec Mon Sep 17 00:00:00 2001 From: serj95reg <80643902+serj95reg@users.noreply.github.com> Date: Fri, 8 Aug 2025 05:34:51 +0300 Subject: [PATCH 19/40] feat: updated xray version in dockerfile to 25.8.3 (#1771) --- client/server_scripts/xray/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/server_scripts/xray/Dockerfile b/client/server_scripts/xray/Dockerfile index b43d8a83..f084221a 100644 --- a/client/server_scripts/xray/Dockerfile +++ b/client/server_scripts/xray/Dockerfile @@ -1,7 +1,7 @@ FROM alpine:3.15 LABEL maintainer="AmneziaVPN" -ARG XRAY_RELEASE="v1.8.6" +ARG XRAY_RELEASE="v25.8.3" RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz RUN apk --update upgrade --no-cache From 9fdcf5ab1315111992b5b8495d3ed1b77bc2f4e6 Mon Sep 17 00:00:00 2001 From: Yaroslav Date: Sun, 10 Aug 2025 06:12:19 +0300 Subject: [PATCH 20/40] feat: macos with network extension Implementation (#1468) * There's a common issue of building iOS apps on Qt 6.8 because of new introduced ffmpeg dependency in multimedia Qt package ref: https://community.esri.com/t5/qt-maps-sdk-questions/build-failure-on-ios-with-qt-6-8/m-p/1548701#M5339 * Cmake related changes * Source code changes * Various entitlements * Ci-cd config update * Resources changes * Submodules updated * Remove me * QtWidget exclusion omitted * Distribution errors fixed * Outdated files deleted * macos_ne cmake fixed * fix: update provisioning profile specifiers for macOS network extension * fix: update provisioning profile specifiers and code sign flags for macOS build * Revert me (temporary 3rd-build commit pointer) * fix: Welcome screen fix * fix: ci/cd hanging forever fix * fix: Fixed error popup on macos on file save * refactor: rename networkextension target to AmneziaVPNNetworkExtension in macos build configuration * feat: add autostart support for Mac App Store builds on macOS Fixes: QA-8 * feat: add debug logging to Autostart functionality on macOS * Revert "feat: add autostart support for Mac App Store builds on macOS" This reverts commit 3bd25656fb4986d01e5bd6dd265f7279a73bd2a8. * feat: add platform-specific close window behavior for macOS App Store build with Network Extension Closes: QA-12 * When the application starts with "Start minimized" enabled on macOS (especially the sandboxed App-Store build compiled with MACOS_NE), fully hiding the window prevents it from being restored by clicking the Dock icon. The proper behaviour is to start the window in the *minimized* state instead. That way the window is still part of the window list and the system automatically brings it back when the user clicks the Dock icon, replicating the native experience. On the other platforms we keep the old behaviour (hide the window completely and rely on the tray icon), therefore we switch at runtime by checking the current OS. Closes: QA-7 Closes: QA-8 * Revert "When the application starts with "Start minimized" enabled on macOS (especially the" This reverts commit 7b0d17987cdfdbc4cedc3822bf3fd2e4973da452. * feat: MACOS_NE systray menu support * feat: add macOS notification handler and install event filter on main window * feat: implement custom close behavior for Amnezia application on different platforms * fix: update provisioning profile specifiers for macos builds * fix: Fatal error in logs CLI-216 * fix: disabled unavailable on macos ne service logs * fix: dock icon now hides only when window is closed; menubar icon shows always Initial state of the docker icon to be presented follows "Start minimized" setting in app settings. * temp-fix: temporary disable all OpenVPN options of VPN on MACOS_NE since it's not working yet. * fix: build script updated * feat: add macOS NE build workflow to GitHub Actions * fix: Not working Auto start toggle is hidden * fix: Log spamming during xray connection fixed * 3rd-prebuild points to commit that stores macos_ne universal binaries. * fix: missing native dependency on linking stage fixed * chore: update link to submodule --------- Co-authored-by: vladimir.kuznetsov --- .github/workflows/deploy.yml | 63 ++++++- CMakeLists.txt | 12 +- client/3rd-prebuilt | 2 +- client/CMakeLists.txt | 26 ++- client/amnezia_application.cpp | 62 +++++-- client/amnezia_application.h | 12 +- client/cmake/3rdparty.cmake | 12 +- client/cmake/macos.cmake | 5 +- client/cmake/macos_ne.cmake | 168 +++++++++++++++++ client/cmake/sources.cmake | 18 +- client/configurators/openvpn_configurator.cpp | 2 +- client/configurators/ssh_configurator.cpp | 9 +- client/containers/containers_defs.cpp | 19 +- client/core/networkUtilities.cpp | 4 +- .../AppIcon.appiconset/128.png | Bin 1922 -> 11497 bytes .../AppIcon.appiconset/128@2x.png | Bin 4593 -> 33632 bytes .../Images.xcassets/AppIcon.appiconset/16.png | Bin 336 -> 682 bytes .../AppIcon.appiconset/16@2x.png | Bin 593 -> 1565 bytes .../AppIcon.appiconset/256.png | Bin 4611 -> 33632 bytes .../AppIcon.appiconset/256@2x.png | Bin 11015 -> 104323 bytes .../Images.xcassets/AppIcon.appiconset/32.png | Bin 593 -> 1565 bytes .../AppIcon.appiconset/32@2x.png | Bin 1097 -> 4256 bytes .../AppIcon.appiconset/512.png | Bin 10991 -> 104323 bytes .../AppIcon.appiconset/512@2x.png | Bin 24361 -> 348168 bytes .../Images.xcassets/AppIcon.appiconset/64.png | Bin 0 -> 4256 bytes .../AppIcon.appiconset/64@2x.png | Bin 0 -> 11497 bytes .../macos/app/Images.xcassets/Contents.json | 68 ++++++- client/macos/app/Info.plist.in | 172 ++++++++++++++++++ client/macos/app/app.entitlements | 48 ++--- .../AmneziaVPNNetworkExtension.entitlements | 31 +--- client/macos/networkextension/CMakeLists.txt | 138 ++++++++++++++ .../{Info.plist => Info.plist.in} | 29 ++- .../networkextension/PrivacyInfo.xcprivacy | 25 +++ ...ireGuardNetworkExtension-Bridging-Header.h | 11 +- .../wireguard-go-version.h.in | 3 + client/main.cpp | 4 +- .../ios/PacketTunnelProvider+OpenVPN.swift | 2 +- .../ios/PacketTunnelProvider+WireGuard.swift | 12 +- client/platforms/ios/QRCodeReaderBase.mm | 17 ++ client/platforms/ios/QtAppDelegate.h | 3 +- client/platforms/ios/QtAppDelegate.mm | 4 +- client/platforms/ios/ScreenProtection.swift | 11 ++ client/platforms/ios/ios_controller.h | 1 + client/platforms/ios/ios_controller.mm | 30 ++- client/platforms/ios/ios_controller_wrapper.h | 7 +- .../platforms/ios/ios_controller_wrapper.mm | 6 +- .../platforms/ios/iosnotificationhandler.mm | 85 +++++++++ client/protocols/protocols_defs.h | 4 +- client/protocols/vpnprotocol.cpp | 4 +- .../ui/controllers/connectionController.cpp | 7 +- client/ui/controllers/importController.cpp | 4 +- client/ui/controllers/pageController.cpp | 24 ++- client/ui/controllers/settingsController.cpp | 14 +- client/ui/controllers/systemController.cpp | 4 +- client/ui/models/servers_model.cpp | 4 +- client/ui/ne_notificationhandler.h | 36 ++++ client/ui/notificationhandler.cpp | 8 +- .../ui/qml/Pages2/PageSettingsApplication.qml | 2 +- client/ui/qml/Pages2/PageSettingsLogging.qml | 8 +- client/ui/qml/main2.qml | 3 +- client/ui/systemtray_notificationhandler.cpp | 8 +- client/utilities.cpp | 2 +- client/vpnconnection.cpp | 38 ++-- deploy/build_ios.sh | 2 +- deploy/build_macos_ne.sh | 122 +++++++++++++ service/CMakeLists.txt | 2 +- 66 files changed, 1235 insertions(+), 182 deletions(-) create mode 100644 client/cmake/macos_ne.cmake create mode 100644 client/macos/app/Images.xcassets/AppIcon.appiconset/64.png create mode 100644 client/macos/app/Images.xcassets/AppIcon.appiconset/64@2x.png create mode 100644 client/macos/app/Info.plist.in create mode 100644 client/macos/networkextension/CMakeLists.txt rename client/macos/networkextension/{Info.plist => Info.plist.in} (63%) create mode 100644 client/macos/networkextension/PrivacyInfo.xcprivacy create mode 100644 client/macos/networkextension/wireguard-go-version.h.in create mode 100644 client/ui/ne_notificationhandler.h create mode 100755 deploy/build_macos_ne.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3fd06279..3975e710 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -358,7 +358,7 @@ jobs: - name: 'Setup xcode' uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '15.4.0' + xcode-version: '16.2.0' - name: 'Install Qt' uses: jurplel/install-qt-action@v3 @@ -402,6 +402,67 @@ jobs: path: deploy/build/client/AmneziaVPN.app retention-days: 7 + Build-MacOS-NE: + runs-on: macos-latest + + env: + QT_VERSION: 6.8.3 + + MAC_TEAM_ID: ${{ secrets.MAC_TEAM_ID }} + + MAC_APP_CERT_CERT: ${{ secrets.MAC_APP_CERT_CERT }} + MAC_SIGNER_ID: ${{ secrets.MAC_SIGNER_ID }} + MAC_APP_CERT_PW: ${{ secrets.MAC_APP_CERT_PW }} + + PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} + PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} + DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} + DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }} + DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }} + FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }} + PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }} + + steps: + - name: 'Setup xcode' + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '16.2.0' + + - name: 'Install Qt' + uses: jurplel/install-qt-action@v3 + with: + version: ${{ env.QT_VERSION }} + host: 'mac' + target: 'desktop' + arch: 'clang_64' + modules: 'qtremoteobjects qt5compat qtshadertools' + dir: ${{ runner.temp }} + setup-python: 'true' + set-env: 'true' + extra: '--external 7z --base ${{ env.QT_MIRROR }}' + + + - name: 'Get sources' + uses: actions/checkout@v4 + with: + submodules: 'true' + fetch-depth: 10 + + - name: 'Setup ccache' + uses: hendrikmuhs/ccache-action@v1.2 + + - name: 'Build project' + run: | + export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin" + bash deploy/build_macos_ne.sh + + - name: 'Upload unpacked artifact' + uses: actions/upload-artifact@v4 + with: + name: AmneziaVPN_MacOS_unpacked + path: deploy/build/client/AmneziaVPN.app + retention-days: 7 + # ------------------------------------------------------ Build-Android: diff --git a/CMakeLists.txt b/CMakeLists.txt index 368e0d7e..e839d1a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,13 +32,19 @@ set(QT_BUILD_TOOLS_WHEN_CROSS_COMPILING ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(APPLE AND NOT IOS) - set(CMAKE_OSX_ARCHITECTURES "x86_64") +if(APPLE) + if(IOS) + set(CMAKE_OSX_ARCHITECTURES "arm64") + elseif(MACOS_NE) + set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") + else() + set(CMAKE_OSX_ARCHITECTURES "x86_64") + endif() endif() add_subdirectory(client) -if(NOT IOS AND NOT ANDROID) +if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE) add_subdirectory(service) include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake) diff --git a/client/3rd-prebuilt b/client/3rd-prebuilt index 522e8d33..02a00ee0 160000 --- a/client/3rd-prebuilt +++ b/client/3rd-prebuilt @@ -1 +1 @@ -Subproject commit 522e8d33a959b4d550fd0d72debf5d356a94945f +Subproject commit 02a00ee00d893e773dd4682aef49a2adec2002c5 diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a454142d..96cb0424 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) project(${PROJECT}) - set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Autogen") set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen") @@ -53,6 +52,9 @@ endif() qt_standard_project_setup() qt_add_executable(${PROJECT} MANUAL_FINALIZATION) +target_include_directories(${PROJECT} PUBLIC + $ +) if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep) @@ -110,6 +112,15 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) +if(MACOS_NE) + message("MACOS_NE is ON") + add_definitions(-DQ_OS_MAC) + add_definitions(-DMACOS_NE) + message("Add macros for MacOS Network Extension") +else() + message("MACOS_NE is OFF") +endif() + include_directories(mozilla) include_directories(mozilla/shared) include_directories(mozilla/models) @@ -139,7 +150,7 @@ if(WIN32) endif() if(APPLE) - cmake_policy(SET CMP0099 OLD) + cmake_policy(SET CMP0099 NEW) cmake_policy(SET CMP0114 NEW) if(NOT BUILD_OSX_APP_IDENTIFIER) @@ -158,7 +169,6 @@ if(APPLE) set(CMAKE_XCODE_GENERATE_SCHEME FALSE) set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM}) set(CMAKE_XCODE_ATTRIBUTE_GROUP_ID_IOS ${BUILD_IOS_GROUP_IDENTIFIER}) - endif() if(LINUX AND NOT ANDROID) @@ -166,8 +176,7 @@ if(LINUX AND NOT ANDROID) link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux) endif() -if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID)) - message("Client desktop build") +if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID)) add_compile_definitions(AMNEZIA_DESKTOP) endif() @@ -178,7 +187,9 @@ endif() if(IOS) include(cmake/ios.cmake) include(cmake/ios-arch-fixup.cmake) -elseif(APPLE AND NOT IOS) +elseif(APPLE AND MACOS_NE) + include(cmake/macos_ne.cmake) +elseif(APPLE) include(cmake/osxtools.cmake) include(cmake/macos.cmake) endif() @@ -199,7 +210,7 @@ elseif(APPLE AND NOT IOS) set(DEPLOY_PLATFORM_PATH "macos") endif() -if(NOT IOS AND NOT ANDROID) +if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE) add_custom_command( TARGET ${PROJECT} POST_BUILD COMMAND ${CMAKE_COMMAND} -E $,copy_directory,true> @@ -214,7 +225,6 @@ if(NOT IOS AND NOT ANDROID) $ COMMAND_EXPAND_LISTS ) - endif() target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC}) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index f32d525a..1728b5f2 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "logger.h" #include "ui/controllers/pageController.h" @@ -21,6 +22,8 @@ #include "platforms/ios/QRCodeReaderBase.h" #include "protocols/qml_register_protocols.h" +#include // for QQuickWindow +#include // for qobject_cast AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv) { @@ -48,8 +51,17 @@ AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_C AmneziaApplication::~AmneziaApplication() { + if (m_vpnConnection) { + QMetaObject::invokeMethod(m_vpnConnection.get(), "disconnectFromVpn", Qt::QueuedConnection); + QMetaObject::invokeMethod(m_vpnConnection.get(), "deleteLater", Qt::QueuedConnection); + } + m_vpnConnectionThread.quit(); - m_vpnConnectionThread.wait(3000); + + if (!m_vpnConnectionThread.wait(5000)) { + m_vpnConnectionThread.terminate(); + m_vpnConnectionThread.wait(); + } if (m_engine) { QObject::disconnect(m_engine, 0, 0, 0); @@ -63,15 +75,28 @@ void AmneziaApplication::init() const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml")); QObject::connect( - m_engine, &QQmlApplicationEngine::objectCreated, this, - [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, - Qt::QueuedConnection); + m_engine, &QQmlApplicationEngine::objectCreated, this, + [this, url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) { + QCoreApplication::exit(-1); + return; + } + // install filter on main window + if (auto win = qobject_cast(obj)) { + win->installEventFilter(this); + win->show(); + } + }, + Qt::QueuedConnection); m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance()); +#ifdef MACOS_NE + m_engine->rootContext()->setContextProperty("IsMacOsNeBuild", true); +#else + m_engine->rootContext()->setContextProperty("IsMacOsNeBuild", false); +#endif + m_vpnConnection.reset(new VpnConnection(m_settings)); m_vpnConnection->moveToThread(&m_vpnConnectionThread); m_vpnConnectionThread.start(); @@ -167,7 +192,7 @@ bool AmneziaApplication::parseCommands() QCommandLineOption c_cleanup { { "c", "cleanup" }, "Cleanup logs" }; m_parser.addOption(c_cleanup); - + m_parser.process(*this); if (m_parser.isSet(c_cleanup)) { @@ -179,9 +204,8 @@ bool AmneziaApplication::parseCommands() return true; } -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) -void AmneziaApplication::startLocalServer() -{ +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) +void AmneziaApplication::startLocalServer() { const QString serverName("AmneziaVPNInstance"); QLocalServer::removeServer(serverName); @@ -198,6 +222,22 @@ void AmneziaApplication::startLocalServer() } #endif +bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::Close) { +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) + quit(); +#else + if (m_coreController && m_coreController->pageController()) { + m_coreController->pageController()->hideMainWindow(); + } +#endif + return true; // eat the close + } + // call base QObject::eventFilter + return QObject::eventFilter(watched, event); +} + QQmlApplicationEngine *AmneziaApplication::qmlEngine() const { return m_engine; diff --git a/client/amnezia_application.h b/client/amnezia_application.h index ea5f6f52..28aefab0 100644 --- a/client/amnezia_application.h +++ b/client/amnezia_application.h @@ -7,9 +7,9 @@ #include #include #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - #include + #include #else - #include + #include #endif #include @@ -20,9 +20,9 @@ #define amnApp (static_cast(QCoreApplication::instance())) #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - #define AMNEZIA_BASE_CLASS QGuiApplication + #define AMNEZIA_BASE_CLASS QGuiApplication #else - #define AMNEZIA_BASE_CLASS QApplication + #define AMNEZIA_BASE_CLASS QApplication #endif class AmneziaApplication : public AMNEZIA_BASE_CLASS @@ -37,7 +37,7 @@ public: void loadFonts(); bool parseCommands(); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) void startLocalServer(); #endif @@ -60,6 +60,8 @@ private: QThread m_vpnConnectionThread; QNetworkAccessManager *m_nam; +protected: + bool eventFilter(QObject *watched, QEvent *event) override; }; #endif // AMNEZIA_APPLICATION_H diff --git a/client/cmake/3rdparty.cmake b/client/cmake/3rdparty.cmake index 2b5036c5..6c372614 100644 --- a/client/cmake/3rdparty.cmake +++ b/client/cmake/3rdparty.cmake @@ -27,9 +27,15 @@ if(WIN32) set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib") endif() elseif(APPLE AND NOT IOS) - set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a") - set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a") - set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64") + if(MACOS_NE) + set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libssh.a") + set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libz.a") + set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/universal2") + else() + set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a") + set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a") + set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64") + endif() set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/macos/include") set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libssl.a") set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a") diff --git a/client/cmake/macos.cmake b/client/cmake/macos.cmake index cedbce1b..09c23b2d 100644 --- a/client/cmake/macos.cmake +++ b/client/cmake/macos.cmake @@ -14,7 +14,7 @@ set(LIBS ${LIBS} ${FW_SECURITY} ${FW_COREWLAN} ${FW_NETWORK} - ${FW_USERNOTIFICATIONS} + ${FW_USER_NOTIFICATIONS} ${FW_NETWORK_EXTENSION} ) @@ -35,6 +35,8 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.mm ) + + set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns) set(MACOSX_BUNDLE_ICON_FILE app.icns) set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) @@ -53,4 +55,3 @@ execute_process( ) message("OSX_SDK_PATH is: ${OSX_SDK_PATH}") - diff --git a/client/cmake/macos_ne.cmake b/client/cmake/macos_ne.cmake new file mode 100644 index 00000000..90876a35 --- /dev/null +++ b/client/cmake/macos_ne.cmake @@ -0,0 +1,168 @@ +message("Client ==> MacOS NE build") + +set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE) +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15) + +set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) + +enable_language(OBJC) +enable_language(Swift) + +find_package(Qt6 REQUIRED COMPONENTS ShaderTools Widgets) +# Link Qt Widgets for QWidget, QMenu, QAction etc. +set(LIBS ${LIBS} Qt6::ShaderTools Qt6::Widgets) + +find_library(FW_AUTHENTICATIONSERVICES AuthenticationServices) +find_library(FW_AVFOUNDATION AVFoundation) +find_library(FW_FOUNDATION Foundation) +find_library(FW_STOREKIT StoreKit) +find_library(FW_SERVICEMGMT ServiceManagement) +find_library(FW_USERNOTIFICATIONS UserNotifications) +find_library(FW_NETWORKEXTENSION NetworkExtension) + +set(LIBS ${LIBS} + ${FW_AUTHENTICATIONSERVICES} + ${FW_AVFOUNDATION} + ${FW_FOUNDATION} + ${FW_STOREKIT} + ${FW_SERVICEMGMT} + ${FW_USERNOTIFICATIONS} + ${FW_NETWORKEXTENSION} +) + + +set(HEADERS ${HEADERS} + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.h + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate-C-Interface.h +) +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h PROPERTIES OBJECTIVE_CPP_HEADER TRUE) + + +set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm + ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm +) + +set(ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/images/app.icns) +set(MACOSX_BUNDLE_ICON_FILE app.icns) +set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) +set(SOURCES ${SOURCES} ${ICON_FILE}) + + +target_include_directories(${PROJECT} PRIVATE + ${Qt6Gui_PRIVATE_INCLUDE_DIRS} + ${Qt6Widgets_PRIVATE_INCLUDE_DIRS} +) + + +set_target_properties(${PROJECT} PROPERTIES + XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Info.plist.in + MACOSX_BUNDLE_ICON_FILE "AppIcon" + MACOSX_BUNDLE_INFO_STRING "AmneziaVPN" + MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN" + MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLE_PROJECT_VERSION}-${CMAKE_PROJECT_VERSION_TWEAK}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}" + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/macos/app/app.entitlements" + XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}" + XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}" + XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN" + XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN" + XCODE_GENERATE_SCHEME TRUE + XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon" + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" + XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "NO" + XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY "YES" + XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "11.0" + + XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks" + XCODE_EMBED_APP_EXTENSIONS AmneziaVPNNetworkExtension +) + +if(DEPLOY) + set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.AmneziaVPN" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev macos.org.amnezia.AmneziaVPN" + ) +else() + set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic + ) +endif() + +set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_SWIFT_VERSION "5.0" + XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES" + XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO" + XCODE_ATTRIBUTE_SWIFT_OBJC_INTERFACE_HEADER_NAME "AmneziaVPN-Swift.h" + XCODE_ATTRIBUTE_SWIFT_OBJC_INTEROP_MODE "objcxx" +) +set_target_properties(${PROJECT} PROPERTIES + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK" +) +target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) +target_compile_options(${PROJECT} PRIVATE + -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\" + -DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\" +) + +set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/amneziawg-apple/Sources) + +target_sources(${PROJECT} PRIVATE + ${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c + ${CLIENT_ROOT_DIR}/platforms/ios/LogController.swift + ${CLIENT_ROOT_DIR}/platforms/ios/Log.swift + ${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift + ${CLIENT_ROOT_DIR}/platforms/ios/ScreenProtection.swift + ${CLIENT_ROOT_DIR}/platforms/ios/VPNCController.swift +) + +target_sources(${PROJECT} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets + ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy +) + +set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets + ${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy +) + +add_subdirectory(macos/networkextension) +add_dependencies(${PROJECT} AmneziaVPNNetworkExtension) + +get_target_property(QtCore_location Qt6::Core LOCATION) +message("QtCore_location") +message(${QtCore_location}) + +get_filename_component(QT_BIN_DIR_DETECTED "${QtCore_location}/../../../../../bin" ABSOLUTE) + +set_property(TARGET ${PROJECT} PROPERTY XCODE_EMBED_FRAMEWORKS + "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework" +) + +set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos) +target_link_libraries("AmneziaVPNNetworkExtension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework") + +add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Contents/Frameworks + COMMAND /usr/bin/find "$/Contents/Frameworks/OpenVPNAdapter.framework" -name "*.sha256" -delete + COMMAND /usr/bin/codesign --force --sign "Apple Distribution" + "$/Contents/Frameworks/OpenVPNAdapter.framework/Versions/Current/OpenVPNAdapter" + COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $ -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Signing OpenVPNAdapter framework" +) diff --git a/client/cmake/sources.cmake b/client/cmake/sources.cmake index c3af531a..cef9ff83 100644 --- a/client/cmake/sources.cmake +++ b/client/cmake/sources.cmake @@ -39,7 +39,7 @@ set(HEADERS ${HEADERS} ${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h ) -if(NOT IOS) +if(NOT IOS AND NOT MACOS_NE) set(HEADERS ${HEADERS} ${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.h ) @@ -89,12 +89,26 @@ set(SOURCES ${SOURCES} ${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp ) -if(NOT IOS) +if(NOT IOS AND NOT MACOS_NE) set(SOURCES ${SOURCES} ${CLIENT_ROOT_DIR}/platforms/ios/QRCodeReaderBase.cpp ) endif() +# Include native macOS platform helpers (dock/status-item) +if(APPLE AND NOT IOS) + list(APPEND HEADERS + ${CLIENT_ROOT_DIR}/platforms/macos/macosutils.h + ${CLIENT_ROOT_DIR}/platforms/macos/macosstatusicon.h + ${CLIENT_ROOT_DIR}/ui/macos_util.h + ) + list(APPEND SOURCES + ${CLIENT_ROOT_DIR}/platforms/macos/macosutils.mm + ${CLIENT_ROOT_DIR}/platforms/macos/macosstatusicon.mm + ${CLIENT_ROOT_DIR}/ui/macos_util.mm + ) +endif() + if(NOT ANDROID) set(SOURCES ${SOURCES} ${CLIENT_ROOT_DIR}/ui/notificationhandler.cpp diff --git a/client/configurators/openvpn_configurator.cpp b/client/configurators/openvpn_configurator.cpp index f6996320..bb3dbd4c 100644 --- a/client/configurators/openvpn_configurator.cpp +++ b/client/configurators/openvpn_configurator.cpp @@ -131,7 +131,7 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPairrouteMode() == Settings::VpnAllExceptSites) { -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n"); // Prevent ipv6 leak #endif diff --git a/client/configurators/ssh_configurator.cpp b/client/configurators/ssh_configurator.cpp index 308f5947..8e190103 100644 --- a/client/configurators/ssh_configurator.cpp +++ b/client/configurators/ssh_configurator.cpp @@ -8,7 +8,7 @@ #include #include #include -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -24,7 +24,7 @@ SshConfigurator::SshConfigurator(std::shared_ptr settings, const QShar QString SshConfigurator::convertOpenSShKey(const QString &key) { -#ifndef Q_OS_IOS +#if !defined(Q_OS_IOS) && !defined(MACOS_NE) QProcess p; p.setProcessChannelMode(QProcess::MergedChannels); @@ -67,9 +67,10 @@ QString SshConfigurator::convertOpenSShKey(const QString &key) #endif } +// DEAD CODE. void SshConfigurator::openSshTerminal(const ServerCredentials &credentials) { -#ifndef Q_OS_IOS +#if !defined(Q_OS_IOS) && !defined(MACOS_NE) QProcess *p = new QProcess(); p->setProcessChannelMode(QProcess::SeparateChannels); @@ -101,7 +102,7 @@ QProcessEnvironment SshConfigurator::prepareEnv() pathEnvVar.clear(); pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;"); pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;"); -#elif defined(Q_OS_MACX) +#elif defined(Q_OS_MACX) && !defined(MACOS_NE) pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS"); #endif diff --git a/client/containers/containers_defs.cpp b/client/containers/containers_defs.cpp index 214e2a51..2267767d 100644 --- a/client/containers/containers_defs.cpp +++ b/client/containers/containers_defs.cpp @@ -261,6 +261,7 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c) return true; #elif defined(Q_OS_IOS) + // Standard iOS build (without Network Extension limitations) switch (c) { case DockerContainer::WireGuard: return true; case DockerContainer::OpenVpn: return true; @@ -269,7 +270,23 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c) case DockerContainer::Cloak: return true; case DockerContainer::SSXray: return true; // case DockerContainer::ShadowSocks: return true; - default: return false; + default: + return false; + } + +#elif defined(MACOS_NE) + // macOS build using Network Extension – hide OpenVPN-based containers + switch (c) { + case DockerContainer::WireGuard: return true; + case DockerContainer::Awg: return true; + case DockerContainer::Xray: return true; + case DockerContainer::SSXray: return true; + case DockerContainer::OpenVpn: + case DockerContainer::Cloak: + case DockerContainer::ShadowSocks: + return false; + default: + return false; } #elif defined(Q_OS_MAC) switch (c) { diff --git a/client/core/networkUtilities.cpp b/client/core/networkUtilities.cpp index cf33fa55..9c245948 100644 --- a/client/core/networkUtilities.cpp +++ b/client/core/networkUtilities.cpp @@ -23,7 +23,7 @@ #include #include #endif -#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE) #include #include #include @@ -390,7 +390,7 @@ QString NetworkUtilities::getGatewayAndIface() close(sock); return gateway_address; #endif -#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) && !defined(MACOS_NE) QString gateway; int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS, RTF_GATEWAY}; int afinet_type[] = {AF_INET, AF_INET6}; diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/128.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/128.png index 1be4f3f58ad7eb5c53cda6e249f57a5573813048..e355ae480d3b23d7ab39a05a9b1d61a558489ba7 100644 GIT binary patch literal 11497 zcmZ{KRag`Zu=Y~RA`2{`ba$t8Eg&tWNOyO4cb7J zA;9I`LNOs;`Wt7qU|C12)pC8E`q=R3cGIG+_mcZ4XY9NS_fcv;g~4{dt>}1^9r^

jjt_jJ1qUMMa*B%j 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 I!Z7&%0q}DIWB>pF delta 1858 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 literal 4593 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 diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/16.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/16.png index 8eec5064dad713542677b5877633f54c12e44b03..ac8a934601beff0d7263d8a0953f65a1b144e35a 100644 GIT binary patch delta 608 zcmV-m0-ycR0;&a&Reu6MNklsE9uYYoP}Zf+qzPtsz1}RiuehTO*5ZY@1EhbWKe*yBlYw zyGvq^?FWzDnR)N~-n{n)*dR#jB9TZW2_YeCEeL{rrt3O4hkwH%rqk)Ebp-Kve1ry% zQe#eh&lik9S(c!#R+|)r8cZ9_WHOhzh#8zT3}f6PvmE;mB%o<3B`LKAGfM`8!Pk-` ziB1-vs%nU-GIa)TU>9OXk0Bg8%-4h4>KM6t1)mFFIDvVkKKA9gQg!=|9bH}6fA%#0 z|1p<`QWTNP&wpV2#ux^oG24$BgVQPyQ)f0XbOQ4)UO`X@7Ui3s15MN5cDu2Cc?I*&Uc&DQqgwolU!?_H96kl!K#yL#Z=+6xyv_*8g; zqWpn3Man5;uwO^Gy9ueHQ+1ww)4oEZ(ZCj`2jb#exO^)5_H^Uh;=86)RZ*?wCFO0~?hNT=>&_{>RM8`?|eKIXYb#JASoS(#Pe;H_jevkB;iXmvtp zRB-F=Jz3Oib?n|j5b!$j;C+MVdoUnyF-Aar#kNuQ`~72d_Af9J(*dop28e;G-zk^N u=i3NOk|XRfF_qSb^dFHZ%koof7XAVKbUIl`(e`Wr0000z~000XU0RWnu7?Cy~e+9BhL_t(|0qs{^OjB1J|6N*a`6!fP zDMbPz6esAMI;1RG@nf3lhDMhVlO=OsiE+us!;!YL)Ve{Z*uNrTU%S}epnIkSw-@+hpZLaQ^- z-+1f!JyHanObwzaHY)K_6qeTpgTV%+e-%6to{&bDfx?APB?9G#!1j}|L&iu-fPimF z2Bv&Y*XP2#U>@dGtwdV3AunPuDe<}2# z*)eDCg(NsdKkDl?!)CSO&G+7gb96LDCnF?R6q1ENnLI3pDVkZZY+O&l={}#I&NDtQ zou?+o;F-8h*XBGEzWC^4*s5!gCM-~S05en@nhU^>vtX3{j)fRl%4Zk(7WU35DG9G8EM; zr{KTsKY;$0vnVHtJT*QBXJ3zW;q(z~vo1rv(TJuq&C<@@@4(}`19Nr|2lv%u@Af5V zTpL75mjB@d64i0(Y8!ob>F_b!9daNoD;L>@a`d(TA@37Lx;vo@%wW^Ae`_e=0<#`o z{{U2)5#*tv^TF!T1b!`>4Y+4MnP9olM;GdoWlxZgM;g5ZA-=omcrj(QbiFr&rwG_;i@_QV@ zxpTiqndjw{z}tHrnvf2Qe-^FB>Xqg25fYtUL$Kt!vFE!cboSgt-LgFFU6Y9ewQg)X zu7-OiTnWmuRwv2&QGM9F|q{Ol#py9YWXTZcI;$m~Sb^ z@}dk1E{icRir^UVnO(q?7`9$Ue`pB!Ip9*mD+VynY!h_p`H%^Oe*zNRzENDg*$mgz z0NXDSR>Iph8J0G8zX=zHxnN7onR4>{}I9d+@Iy^FT~_C(Qxop8nzXXu4{&TC7{Uk=%eJ=yf9h zQHctRt9>{`tX5%uu7FclgZREH7-L)_d0;1$M{n;rQq#>ae;NWvC5g3r=T@Pr%n-MC zX+H3ET`ICPVKTkrp@f$ir6@h%W!A8MAkP;s*il`Phu;2S>8*7pVfzazNYkV|-S@33 z&4xAjqW}VSnTb?0sQHZm;RW>6=}7C zeOSVwi}(9J-(AUXCwSd)w_>Bw_>)?#ex5Pr4|70q4Mkxk?Ru>Hv2Orzf7AH*cpblA zrBvYa`A%xJ+EQ|EA*Ya69ycrBlngvGDRQPKjPjy)7=D P00000NkvXXu0mjfxIERw delta 533 zcmV+w0_y#p4ABITD+?AS000&x0ZCFM@R2qje*xx6L_t(|0qs|@k-{(#T>g{KpahrT zkkE8M2S7v!rO<)h0fe7X0(4+fB0~lKTMhEaMn)1Co`9XX0c&L4YHv@rfe+pkk;Fp^(geqR?!Dw_g>!)@imIe(nwD9XssAJ-s`!$)pTKxLu9EAq z^?I$wrqgLKfiDDtwKsoFhzfWVPWEveS0&)ix7)4ypXa$M4+0hFSqRj?or>(rx}8#MqY*Z# zNrGk2^BvvcCa_#CuiUQdeG8k-rkbxwa4mGv1wN-;zu(6rs7b2pNfmSnD6{Rr2`rhL z0D}jM2@;~wG(j4WMq~mSvkA^`Ih-mu+mJ0MNmYAEeN`EFEq=HggBjz{2b0{U5Cy8U0C1(L5CJD<<$_a)DQW_RdbZ*hBY338tWY~2wc ze}0R=%5xF5+r?s`BH%@Yk=`N@;W=-_=I$dn5aT&-#sxfH%S|ORboXJhLcoW~2QS4R XRi##k_xbPU00000NkvXXu0mjfAO-vt diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/256.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/256.png index 957085916a5cf0ded248cd4ae37a4d8db243c5d7..89743ecab5172828e879e924a64a437816cdf799 100644 GIT binary patch literal 33632 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 literal 4611 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 literal 11015 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%0Au+0ot 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 P>Y5DBn&=d3**yGztF`@& diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/32.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/32.png index 4f12879dc18ead2372936349eaaef6d173fcbae6..7e8391e3434439c367034aa50f0d22a40fc5ce42 100644 GIT binary patch delta 1498 zcmV<01tt2?1f2|!ReuGtNkl4rv^5R)ZyUx{(a#>0~7V&b-B58KRGOqR@L%Y4`#bk48g3zH2eY}hfKAQOow2rURw zk$!NoA9v@T_SDncR+qi_;y*b#=k}iS|NZ`-_Y`<6k646cFMn37SWzoU(q=N|3WA^~ z1M*;!l9H0}TqqO*IYZZx`EPRWWLsNX>whL-wOYR=hjuVf9++PjR@A_8r6UR~zvICb zL_XJOG#|9KwodX`ac0!i)HIT52U8#qSvj+e&GIO$utKXd(BF9L`8`quolFg)C^jnb zQWTcg27|!{rGFJX5uT7nmx02CPbC87hrsreu|vj4N`QcGNd~5TPS@wcykH*YRjou? zwjs`2WJpRf5sb||rkZ~shZgfOmJjjIvZSV`;mHkKQMu|l`kXVT2=)6K@k+5Chfkfv zfp5NIU;+b;=#oWNHa95&-tANa0hcWy8Bdix)36H$OMfZ!q1iEK?u8^cML+86Hp6DM z;?4Kog>!T?MkgaAR}_+kK$$!&hAEm^uxwmU!RbDqpUyKrFP*0*#^9N_P1oi;6TbN9 zW7w)|kSGK!VG|NiWV}G)MM+e?xCQe!ZGhkBL-&zm=s0?a?mu(zQ%v0+gVu8gFTL?H z-rxTT9DgGtFq=$hc=dIdatu+U(pABj9+8xQA_;}u@-h_FET`bV?LUD2ma`})i99tv z24`Q7bm8<7Y_l#yzR`%LGtJV@-S5ETy90A}5C`|wWAFAQXj~gaNtXZN1QOM8>1rE& zcj@pk+#PZtEh`t>zM3|h{2V0CR3wrpAq zvrZ!3ap0ex0hDPb@!^ksaNncQ(WaD?0Eu}_JGB(dmGXNW!nt$5N15m4l)&429h#61 zi+>ia$Lf{k@DUQ7T|=|K+I1GR2!JFbR%CR_>1vQ{U`0k$bE zvr@P=sD*Rn7OmkNT`{r+3w(|s%1mqFO&vnlG_Zegnt4O+`dsOS3yBO%N}xEun$+@y)HQevTBC}5c+yc~d77>Vot?aw1io>7X&0fJ z1?*cDR(tTTAoD;>c_+;Q=AQoH_Gr3lv|6lNyOG?0BrM&M66a}ey)I1 zSA+PzD;Q&3B6(mZlt*vxIa1TjFn<~XNF|B2d*@c6s>~3#cWFNGbzLg5G+{EmEHI{^e71^O>~x3F(jP#llYd%B-Uoy| zHcgzx5uJSxB5;C?T~LTgJ&o=@4_NH&!vXy1keB|L#uaI`f_+%Rp^NwXKHpu*Zzp)& zakpZl(fE^Et$v;{<_~i~aScUbCGC2w`>}5TaeveJ_;?+^U!_#w^Z8C{wc1j0ZXu_T zR~|Pj-{byuEIJd*n^Y>*Yf~PN$A<@bAR_5{y?z_HiftrBD)|@k^-S(;+_O>_?Rt@Y za#G(Q^HG<}bqaFK6q59xk&+PppZJjg^s(^rFHVVGOua2Go&W#<07*qoM6N<$f&;kI AasU7T delta 518 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 X^AZebyQhsN00000NkvXXu0mjf`CCy} delta 1041 zcmV+s1n&EwA;}1kD+?AS000&x0ZCFM@R2qje*@l0L_t(|0qvUKRogHW#y{G=lMToQ zumSMaH^Kxl6C|AgHh>A5FhO8}nhk&jYFMCwxAvt%pA+XKvg}CqwH-0KttUq1WqSG#VicLqt&& z8$S<+LsSF@KR^K(TScG7(b19816EnEjQ2>li-l(K=25Z}{eEA~=X13U-cx}SA{0Qh z6M0YGHWQ@VM*+kd4}u^y$nkir^nMVRfAh1++1c6WalmXgOAX$<=j!TepcT?P>Tah-rn9)*GwnXMJ*0^etzEgP90#PmqqSxnm}y* zot&JcHaV_wULOnwN>Be(Im;ybfC7j$u2r7$ft#je`)JYuzJsR*plFh6A6p#oe+>fY zX$&2=S35V?@7>)U4h{}dyE`|)tPPLR;o{-~FE1|}*Y$FU+c-QtT-Cw)Z*Ol=mc5*^ zt)Vvld6OgUHj;27B-%cS=#OyJ-8O zQ=9j?$Y+n-!JFI)eY8D0>AS9Ne~}^2xrwYs9S*Q*drDajl24;-SYtgVH#aw{`fa&` zOIYN=ac#Ri5c*N#Q(ge|&tr`rYg6 z>ndl+tIve>o}Zt`Qrdw%=Zj06rwuneCPPUyNRlC6ZEs7I5(lm)L;QY!e;>Eufov|| zYra#PP;mg#TDP`AW2P zfZd%99QYrUd^y^c0E<^?Mc*bx{@}8VQ~l?%Pt9ah9UUDV9WCVp?8jWUi&R=G00000 LNkvXXu0mjfV3+N- diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/512.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/512.png index 0c636cfe2b28031742e21d6f9eb1cc5fc9b6d447..f02ea1b04f663f0cde5d65a0dbf50c700be33ac3 100644 GIT binary patch literal 104323 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 literal 10991 zcmd72_g7O**e*N?Ra!u4f&zll1OW-sNtCM6n}Bpwnsh{Zf`#6}ic+LXM|uw;0wNtj zKnN((k={viHazcpzF)pS;AE|=WXhhIJ#&}qzUGe5)mEpc;h+Hk(BITh(FXty{e=T+ zO6X_Hcjy56IpwZl>IDGpnd2`EynV+GRl>aV)o*~}o^uOOf!zMO)^z~N;%JX-C;$+C zc2niLp)YJ@qVewCyD#U~9~B7aMLe`my71{6ovA(A_)JK7C*$Y}wd~sznBHT`9)I45 zLIL=Pg$PDdt!D%_je8Rb#pR0{LBXf%*qW_lCwnZNS6Ao!hWTC~H2SYX1G|F}pBNSde1dSJ$}IS z4Q2K9RL-bFfUc*U?-)+P7_FD6m2iU@v1{+)FXWZ&*kKMm#S*^|0ClzS zcZcskG#@+61hsuY`WT6kVBLq|;^w(Vg98a9qoaw^Ytf)^q_}^H3ad(2@KbV_vap+* zZs~&}p;~PNs;kIn|LL8A9L5S^e+>5hAQk<#Cj%nRBRTT9$V<4Vp~m4*gFav5Reu5~ zbyBvwWt|O8c3$zL&iEm*9tMnEs?ckwg1rX7Y|BZT9dnJ&1o2%QW0_U4+3LP~dEnk1E^Tx&ROg zs#y4qj>O7(FyM~Npp^nKZ?W0$FDS&};%P7Y`v5L8qfE>F3NzT2SVn**iSy!AG+2KP zB48v_MQatp^3)Mq7xu}pn7TWU>BWAZ!@hD%!;Ax|A_GzwF2KO=0b8^v&5^?%oB~&E_SF&t zIyy@uUF_^}Y(FX1L`4sr&jKDc(G;b63Y}8QsoQ2-yX7$8Ihg<3iv=U8DNeCgZ_GkQ z24*x3V1-oTIpDzq0Rjwc;%GRE<< z`iUOUoFm+&1cIG?G0I_@PM=}IzARhh2Dk1k7h@A2!`^X% zbnmv=C;GJ5Dv2!wczuN&UkQI9M}hl{0=Vy`ky@8EBci}~91LI`uBXd=3A(Hi!3Urj zfz_Z7PV2J6U28{YFm}B6fwwck`O6xP|26jtIWebaF=49`j$oko@<{>slK}Qr-Y)4Y zjqW#U^f+`7(2g@(??dUyvh}$_Q!$pDeO5&Q2xbn!^yNTRE@D&b?6I8iU!8} z)TGlX^ucee52kx%zjG+vq2z}Gj&!2}LtzTO458pa}x=r;Z z)i*-_M)}>gUP>A7;9%F>+}u#HZnYcU4dPRMX$87}&Y7usiU5ZEy#iQ|cfG~ozP;1n zTpo4b`d2w)cK3M$7EF2cObw-VJ5b*;Y&twV?A#~pNm%e%6c{OXGMZ#qbZN#S$Og>m zA0ukgRleS+-d{NNG$0^A!G}FHPok+TdgdBDyiQQKd z?!w${qv1Rf+vZ|duFw@^Ou$;F`;>wX?xAf-dTq^S{Ll!#Zi9~i`t;b>ufjV&25oUG zD=RlIfQ!gN+ri@j#INyWv{;J^!At#@>9A+UPQ|P8eRpKyQN&!#_QNES4jdG*#S-x* z*IEN)W56;;uZtS*t)oSP9RW$xx4KKOp>j9ilT2|U6R@W6{)u?oGK{|XvfBnN%K{4P zZk(ngNZ%fLOC@|Eaf zm`(3)Q^s(WPjBEIj^ya1(t1kdv*(xvM`mm}tgkefCE#TU%2dgW5-B*QP!ZZy>2Fzr zKp?D+9&>VXCOuKRyTTje;J`dJFBsKt@}>Wi<_r>^UTo5ZrBqoUT%NYFvKsI1)>=vZ zq?8hipTOf0>*ATxZj+^~K#RjnEf+Rxdv7oaoU&c%U)ug^8KaizAtfhK?7wjv)05B6 z{#fq4htYC$x*+bQuj#+vGW5F}tZMy02Md!rE( zM$NGZ3;56a`_Nvt1KYpgv)I-Y0ov(iUH8Ej|l$Mr$Ny7)wiqNv?h13D>Hql-w z_{ia7DJ94YgM+*a_w{eS(PVqEq1f!d{S7okLv=QGcCGpmr3WNuA-tr)$-`JLW&nmm zAV7p@sim**Jf(m?ByVe`1ld3PO<1Ob+Vi;GL-MR>uO0oS{&{Y`tawW~A$R~xQA zo+DzWmYD$aJ$tfd7Z)a4?8Jn{?Mr_h=>O+E;MN!n{=?|#XqlnR)Bjo9-@z5+yVOtW ziefP)S?}QK04!zz;G_}6MQUjYQSD#w7Re6p)du=|of{I@tYa!_M1JgCi$Onhb>%-F zk*BOkg3M6X$U=9DG-aVFYi$w}NY5FHtI?V$FaEQ(7B3(Gzpe{_RM5dzr@ow$l1~sn zc5-}S;bV64fjpe|c&^3W!#B1{p_3k7dRTAQ65Z|E_eVvq>F+1vw>+Fn>`g?Q~IIyWx zizhj=v9VF6n=`S-GM;^A{MPwGs`QVcFExvAN>;p<@WuWFySV%W>c=b3I^_O)g*eL+ z>7D%XmEsDNCGdR0 zT>;kD-%`bGytWjLAG{%Z{zU-_(`c<7wa@Ayls9gw&k?-{A#ISj-JV)6UueLPCV@yS9GJxKOg@%7ue|Bs z$VEj0w{7V`DY%3|#5IfRE%L>~?C60meRj|L5XV|M?& zhsC-xmr61N6QM+mKgR|H2dbACCd+6fga&`d1pxxFqKs>RT?II>!mKg|gb>gWMO%rAiNazez`SuUf z{{-D6qRUOluxb@%MR>~>-Yh!Zu199;MJVaAjg*3~mToT#uy{-JY?riYE) znv45|$5A}z$e(4;hgLT?qiPp~SZn*c?R?G*EkLm9F)jVsB}L}~?oQPCAj~ade?Xnn zYFJoUQkA#6d+E+j$x^nh^_!iz7ac;6AJ}Lj<har@ea@y}G*E{&7L^95=Vlq`}0l z5#?L}{OE7t6J2h=5^1~%eZ^Q%3 z0};J|JiT#D_4s{5>&D}OxptY>zwRp5G5!1ZFZ331QD{lNkG^4KDJE0@_ef>j&_Az- zBxbntspDa5V$59w^|}*DgRfcOOigDR+dI4lYO63oIeCL(+GNLG>x#11yNg8crdLO4 zp>uu?jRHkX5%2DOh+*!&ofabnzf5~F4$bzk=UcDX`Ro}|TWUv_#Oa03Yx z3~=FO1`$~lsyd&|QDbg-`FlPbXYAqw&(zKw|Mjb)+6}KwBrYU;*9lq`G&^6jwYIi4 zE)*@RcUUspRy4R^(&(j60 zk1arw2r{rM9^-$Jgw%_P);$UiD~>4E%38hZaqNEuZaVZJ7K~bZGRCyDSJHm(wmYO$ zp6pFb*baLIh5!~ zTFUk*4!bSEf@22f`p^8W+0VYdp`+6}SV7u0$Y>L^Q(}j80AE1{SWQc@;^0;aNZFzn(c^kApH=;E>(TX zIrba91Jm0%?ift-%V+cZYI(NpcATBE-rb7&oEGhT-j1YyCrWYq`RPLG%>KNDRII-d zmjq3pd7k}p|0hMFTn1i(Q0!-5eHeB;nEo*YP0brAN%1sDvqE*c>=(s%F!Jn&a zbNbg**1K9purfEVapI#Ve-|<2`;taS5llpnOf2nN&hzJeZlyhjlEMI070h;X;D_v`(mQ#V-D7 zS65f3((=$2*R^Zc%pbmyL!svG;iLwy$s)EC0~|@erxj=#!#<}W7#ZdO`5&9r@*N2` zH@EuH!>&y0{)?3uMY7LbFeN9F924@9N7i9WinLoH<2&;32McTpj}lW9LHl3}x4#%9 zW|HZrQWKlMk6{+^ouk*)!k@x<7!j?%?CtHZ#9jFjUpUEGs%<&mJed@>!#%xqV@7BI zp7@-1JKw6PX(uqKf@bvaqhokiz~P-NC7zGtD|O9kmm@{Q;fxxK()qn2?9hW?7n_ z$=H?LoNlEeGZxZ6Y_6>>Oa2*ihKd5s_%Wd3qnq$%O-+rs^$Une5%h1g9N?0Xhy6|m z)VzPiUNG#2BeQaMzlA86uvA`(yG%+;sv}4eSdSkT!hAditi0Plr|y2KO5S+!AzC6P!$9Qjv^jD1hY+7$bS}cQBi< z`1n;hQQQYGAfTyj(6R zp9mP@(I~VkV9ESf$U$e_M8ELX7dX$~fCu#GbIjm+)=~Bt9$)R?M7@ zMf<{&1Kk)&t>_$M7=KjeB#eWC#qRp2PoHM3Sn<7p#)M=neyH~nN>)~4mA66ti?_f3 zVz4M~f4?@HdA&2@QYN6jxXtG(1)uV}V%V8Bi5gaQ>GC>6DJf}B5~Ym7WlYEz!;PzQ zEo};>8&_6b9tQ+H`ZM@Tpw!ig^f79^#x{VNN|>%Wc-;?t^Nc2%Qxxm(s-`>0tUHqT(gY ziTU{Nx$NJ+f7>ocBw8g&w>VMzZb&Mw_i>6`($>*wPeo1;x62(!ohKge_VZkuzO&mv zTU&ehp!Ua7fA5;0s#xjJ+E3#Bi4`k|tDCd4 zIT?O>TnAefgn~we$Kk9isALgO0SdIWT#CZt=&lu>JdAPiw)Y02?6*BNq+qP$}m zUuMw5d-!N6$)&x@prA)?fQD(pMtb@gu83R@GrV{Q_U-SS`` zsuRV{49@l=K|OpJLQ&E7sRB13pS;T&O5FU+jDFz#bSOq&TC*@#TYRVw_4cu^ugsgr zYI21KBuWFYrrtUTnPR)w{?ENP2c=XuAzz_1q zc4IYGa;A?xrcUN{CUMjWKsrQkU?h&A*`Tj3`H=dC&Y2T9Re9nwZ+;kDh+c2#cR(u1 z$WU*;pFJ%gAYhlJzJB+A&|Fnj)z_yj*3n`MZ|BEU4z75ef?^oqUK%Obrql~~iafn+Jn;>v$PL=F7}&P!erEv*FM`^MnyVdPd*YzDz-FksoI z9=~Ffcr+M3NqkRvtX#j;83y6~Zh;&{Yd^^aZSH!dyC^-@^c+P%^Gi_43b!MTVf?Mgv;RpxQ zX$;@VDfCICBn`vlxLo~Zw|oq1++_^pHqV7-lHQ*#%H8SBCw}FlJ&DxNZ=9Njc6N6K zO3I%;7*?fvc}#9IIDk0)j_7Jx*Wa!EA;8!7b;DxLt3i655sgmF#7(l^ zyZrl@-a^8X(F$f~&hJGZ@o6S-4~65({9-@6pE&Z&;d@=+$gC_^piM+==pUw4?(2_X zCm zqqCtCJrgI@$@};!)B{F!l%>8w6%5f@CS^%UXJU7>qGu2d(L%ubdGcQ62sebg`++vx zI}{FXmd%SPCZae#a{$mRuc&xwUtkM@G>Ita5(%PjlYJQw2ztkN@86r|4oW~bOcX#Q zB7;ZEOZXibUU80?uO(K^J|o)Ug?zLk zaPrw1k4dZcDTtfZnf)@NO4^y7oxQi(C}6ZPM{S+%o{+E3>zKj9$8G%4%{snODHgYlf(R_bsqS;m!A1Q=3>IMC!e&?jDBE$XXt{`~n%X*6q} z)X2iI5WjhIZYDRYk(hd?cByeeG3SKqv*F~?9dtmxJtvp+#D7?BzWwl;v<0_IlBVDL z$p$|=+}kpGM#1N&&GNJOM@B|2?9^O_Sy@_|2_M9MQ0QdTh&iTGw|{>cQeN8BElWH- z_`j5Ez>CFw%+X%|hdx(qawdx=3~V1Wj#(l=;bBS2NOyNk_GgHVLO{GI83is7g0c@E zK4izff>0A)GDvLmjy}9#cmo6ES z;Qv2zR*#eRf5=&V*S1XXTIZQPKj4Da(32g^(88+qnWp<-;%g7qml!#{>KEczLcsp=sx(yob7oLt}aDV+PU~w1O4KtJ=M^F@yZzW z|K35Iv&?}#fN&f~Gv&dX)Oq>!0i|%>6IY-zB_kul9*{}?Qw3pyYP}1)$Pu$Pq!zw> z0s&Q~`j9vWBu79+F?6f(fH2O5+Jyk-$p39$JB9=S+0XL0)`iu`6$FTHT&tI=-ZPG> zvHG$?Was&>2A5Pf{~a9opO$MY{pUqqkp@{l%!Y0nwa$g;wP^Bt0#UziLPjQUWU2ON zmF0ZVd#s2+k2(p57&{Ip> z0F1@`xXQyMO5V`eSXopg+PVncPYZ+^-Roz30|&+`v~YZ5fV5wm)56=UTZlqqZ37GP-+SGGV=?mORSlFN~1ZFvkO3k@7s#;mCmHSQg#b@dIDLGf(bt) zTv7x3;O%K#pm(>-U6}U$@^7!apvt#JmbuhT$g;T6%-_d}7rS6V9Q*XPv zM26{$UKA%3vvhLD-XE0lG9wo(WPNh??cjsQxXp^G)wwjxHC!#GLUYCt95qJzuqeD@ zadmtQRB_ebKA)j$2w0C});@;QyzbM20qoT0M-N?GVyK?B)OgoX8c8rO*7HTi-tE$G zRfpM^E0X!8h#y?n!G<kA8xdCoeFz2tNLROzj)d{V+se6M|Ag_nOJ9c(Y@j->De zGb+61#acxD$fN$+GVy)fkJe?>a99x_`LyFn$_zs^r({7{}w&jz-Cf zW=5Er#s)eh5%EGUgMM~zIxE4vk%t5ND+FPer>1aFw9J7r)eYE%5&-y1mj9^3T=Qj0 zzt5O~3Mg|%H{7W>NS`r}QTKW}YH8K@`r*!t8E!7F;M;o&g;dWS?<7nNHh78x?>W0J z%E)V%X;Pb-{I{Jp4jy@k%g4__83)(c>G(@HdPeX`%dqi6NTi?z#NX|5@23RmdIaGe z=vMPQ#nDg<43xf0y)Qh+1ae>ibba&Ov-0GE^?kXI2f#!Ve^rZ^=mq1^Bm;o;M|t#L z1qz|2YE}<5)>yTIN_+JZ(1o3^r9>k}2)Z_Ahce3od;4e>3Ab?Z`HeRXxpf6p<=039bSH8P zRRModMZNYBQ|$<=a0b}Z?@e0}(U<+m(G}-)Gl3`>NWSMlapfo=e@GQ8=|3z<3x}mE zwBZkLr@~*KHD1q&#E1j*sjX)}F=d}$C{c*F8Um1PW71ZorH+kKgRRN?PyjSB(qfw= zl>>rvEnsN{P!Z{z*dykEsa`KZ(A4G+Ku1?;q@vwCiIy4QbGHG< zsj0FSz?i~%=-7|%TYEmx3-j%17oOwFQ0~o|=3uqiy4BH5j93Q9i{piM zmT$i|1a7S)n!*Z$Uf%aAa_6A;xeIpl>{vxe5E5Y7%2P>wx}1C<%0>?AZv7K;JsOCp z(QDDihTQ^axjL$(BepNHAnGuHh14!10Dyj<5{WNmGO7&FVE+ zATZ9fYO_y?B|jPkU@1L=h$;O2xfIC?D>m->$xjWI#48pSf|oy=F{uIL+dmd!v}m!- z?7*7k;On*K7n#6Bkp*UUuA>eT+f=UZVjB$WVG+9lSo(1_ha6ZlDcf~mie#v)8$*pA zj(gWbn1E|S^3m$W{SqcV&^=o8!8w`|;JiYwO^oBE3(rG!3wO#K2MGlLE4DD1XNkf0 zQLBLg2O|&5wh$P4^x&Gse7ifQRS*m~-SM#1qy#TZ(z;U@%dQcTv1YQVAx*Ib(cc<(=V7!gb zi6D(lou)w32?IH!X>yUCp5ZLN%j10FZ|B)pFNAu&zh0FVr-?_;t z(B{Wy#Y_hD=Q(epkWhAD#X~dlWmMBuEnxj4dFI91DwoyGgO>jXPjFBNgq}MT zb>O)u8M&jO5s>}&LPyKYrb2y)?*3l!9a_aG-Tr^yw~w|uTFdlYX@MOS=^>y+j)02OnEU(B)j6QkL@Tx{G)sRw;f*=Q%HsKRLF)Pi=_vDB` zyiclxSbKrbOyzHkaU-AZ3Pv(B^P*FU3RxPavSi513$qrykbI*2)QBrFP-%FcSr#nU zGRW_DT-&z@d)yJ;$$S6+cb|jlyC48&KPJd)F)Ui)ZrWhPoS?)?8Y%a`<9}E1zbN=$ zBK!{v{y)K?k9(0J3WVF_&nH!RR~lM_oFNZOnkKDY$C2B2eKE8*@WV>y-8=Er;{Z3) zurhC+wm9KcpUs9eQ)pnoeFr_SVTXJ3ON&x>ZE;?}05|}*kDc6=wFEAHbV_qOYI#Rr zo8(+R-B58nR1k1Iw!OT#I~#c4VNPu$T2bFIRzXxx=d$O%iRUU(AKe)6@~nCL!3gUc zvOVr=Ma@(}W2g}Qu^~^N?V$C&9BK5oG3RLx#*b*JT)>*|E8WyaWVAf7A}G3$U9k6}JUb|_?65Wn(z7}+ zYlg%fz|?7O`WPlWD6T#+eox)@xxaFA5LcaBz13dIaQ}`gCCqP7Hu{R!Z`&^b942Lw zReHpH=_-8vf=|H-4HdS2v9cTOto{91_s{lL%%q6>fJj-UhcHG)Bm>ml=h45LtRu9@ z=ab~=iez>2IhAUT=hFe>`jk;k*``FKm2*UD~xy}0R5 z5=Oph(oy=dEoS{P9OKK$4&u|~x7RXQ#Gf$HgAU|vtPIV4NeRhv3;*r0dFjur-lYFS z(<^JwmhE>^k~Vea$Y9h2ymZrr49#lQ+=)U`cTR20>f76D>TU~T?!2WhXA&0#4NW$NEhH7;HL z|87gQtFn+c^6|w$b36O4>U(5I{h%8X53Yk(@Yvf+6xyCs?5BHTA@mJnfw>~_edj`* z!LBHkbB)>to~<69iR@C4*VpziJ?!bXztG_=QrPXr;9RtHGiHfOTY)HFB4N2EMm2M} zcTJ6WJp%Nt#uZqy(3SakR=RECBzXPnNjml)A{9y(;k4S*`UiR$=4Sucu5G@1%P98O z9`Av2vL+#X!hth(pD(c=Is+Z@0VZO6(;6C1*-}6P_L;M5sRGHXm)c5~jEwW?YF?Ux z*xw$}HvIj{yM-CWc5N zS{yJcN*p@^4`=_(5z*p;8|608rANfkPDI@>nG%%33={n{kBEb(j@f=ydRKJ98pI|qrlIkhq zOy8K+!=lqwXbzC<80_dPqH09(C0!rZO!1e~UNB%5x48p z5>NbS9oaegK*oT5PKT;hDezOcyYLHvnKAMpNBo(Y_}u|7ulMt5aax?p?G@}uVa(4? zXv^+LIQ)@v8(m*v-+^NkPW=c)H_J5!T-x2m5lOff{^BZwh0+{lAnCM$KZxjxz)c_R z_rg)H$2Ye)Rd_gM61u2wDOvfAq4MBgSuM;_ooi`DABb|(F8K|5lp)AZ7L*BJNXC2ajV;m|J2v!GPCN^ttc-LK&05P~Gwht}KM6$U2zYaBxA8eS1o z&OlB_y)19&5S4Wcr1Q$ziv0Gcau*g`di&7yqHs!vJP+?u;Pc5sAh)=kxcjd?*39Y5 zxY=`WVh9)vg8JJ&v<{hKL9dOW*R82a%ebY@=q_Ukv}lpN#%QXA5Ty&}rJUYC#U5O; zpk`<3O6QmHHPB=eo@GxM))Br>$1=*h@{sY9BS^`rN3UN%{_Jsrz5;dm$8MqdI#{lT zum&Y%l*Ss4h09M#l(PmWDQ2*aw+OU6V||H(ZXoM@oV2F(TvvSRt?(aU8prn(PJ8X_ zSZMP`)70ko*gM4$95~}%FZlr%b({}DR_1=c%n|-Ih{n5ccxWUH$(`AtU};}A-$uO; zolwZ+>K@Q&Lb|sq0rx&y5hMrDgjWge4i4n8n-b{@&2YdkVsnlt59)`2U&H)1V}#9y zVuDeTqxc^P5mTjF0@rh3$i><~o=N2%)Pu9bkv*@ZUYn_w8Nbe|`!D*Cn1Z)F?m^bV zov(3YVS^Pa;+;5oi}dz9P@#y@EDDk3xbEv z!IghV(-NeZa-NS9(|aCEkN&)3oHY%^xe|P`!1Me__r+rC@?a)Uldk?Udv0Ay9)?wan$ROm!CnyNfY+ouDM~ zrir`Dk~yKt+vlWtH&^2BC{1DkByzH(+WaKGQRs)}?`pcrQpTv`kj}Mbcqdy6#yobH z_F1?E6C=Bi$-gxr`Z#i1&pN&l?f9nwe(i7Z=k4jGZpKIOE`;!>5o|gy-&lQkr6gU- zC@TC)bJ*YwNc&=$ErTrHEmR=hp}aFNIq28rcdsKIw%6IusBXEgnAJuHH3|b`kyH2K zuwaJ|#l(~okjaH7ZaH2)M-B>q^w<(i-+!=8TBk!qG^f`TB_J>Bv}($BB-D;Z`m$2c zO)2^qojiv3KEwY%-48sHOOIecO zaTa2M-V0PB+3*dwY;Sy4QfD(Y(PBAfS4d~&31eb)93$PiDz4&V@gGo$0i0WG={zK1 zGcQ_wOx`=CCy9wd&N+t3>KLiK+LpX3AQy%6cD) z{XrxUYoKvb31+)bT{?xBZ8`If>vrv>V$DnQP`{ZY%#m5zYcNR_t?l~Y4v={WxjAh1 zR@fVCNP|>}w&*D}%I$o0WDv8&2!GQO!0Ro=XS$v3cW`I+%0M?a{a_o>#x^en<)Q^& zgPVg$o@^^|nxPGeV}+J_NqdVPj@%K*C%Q((sNZ8M2| zq(iVMZs*KIzCk#w%~>1YS4_9t`_VktHW*$TFOYmXTBQcPWoJnoylDZ6I84|dJ^;@J(b zK+~oHUdB=Am-H;CD+^#^@fq98hLnmxe}DvJyFw8E}MkNuT=oN0xSnB;Xx z_{Vk{2dZ&bG7k$EdaQvS!e{lVpC!(@9(o#7GeAAgLf&7=_QUJFn#F5|J!5gn>G&DN zyUrb?B|a#o$a&DqMamWsX4E^0z{CaI@|W4DdijTpdKhtcS8r_{UVuNle^yD=+GRm7 zj7P@mE_<1I=$ZsV;}5GfX^#U%L7pPI(axWb*U8jd9HQj1z7_N6>njE z(ra-rkTLgTFDhar2<(F@e;s$?&`a@3l%o}gs%BGveTnCP6B4k_h&*J^rm znLApr$aHoShKWIyVHq{XiFb%0!YNGF^#WH`iJL81Ay|G&821&Kdp!Y(lKa`$#)T!f zul@ZTtKIo=yE6;@LNEDr9%Jr^Mon3}-W%Y>O|1!(yW*l(w-pj!>aY1lZaFh05st8F z6t<|dtr3$Ie|ipH7YpsD&Q2*Eo;Ij+>&~BbaLcaUw$lgVC}zJuIuSI2(f>U3Vr7A{ z?=t=w-<03-O+r|`SW9f9uwx34rvu=gw1c?2lkmoK1qI7nZ%5bSp)=1c3l@ZdKr&(^ zV?n(Jzm7W#<~VH*lNi%@v~|R)Facbbnf*U6oCB+Ebx3_jG(J=7S!WY`1Z?)a%JuwU z{mxn9YFrkAm@xncjF3k5O8(t0+LL4EBZTAvE_Z;`qonqWt}t^svvbj0a&$p)=OWe} z!_u69BrHLrdAzrG<;N)nByU`zVhQ)2gtC(ibD1?-3fi{%wQ^jKNXXSiziG*wG$kyO zo_46(cc<*^GHKEd77(VNMi{3d-ef=0tRmjh_6m8rw%M+vsEN_evX>PVmkcpttk~T> zy@DQU?StZ+FE1v3*H68x5j)_mk*SHrGd8Eh;-K(@g9i`55ULA zlhlAK`Vbxz+r0v8_8>mDQR)Z4`eAv*#n?)V=i$uqQzh0D!V_zz45hXo>%PlyHDGL7 zocG)>vOMD$mZ%>2PTTW)hZx^cqt*pp9dW2gDMwOqJ6}8G%f8{1;B`qz{vVKh+Gk3c zGavns_bUDr+5O*0yJgH5CN{2Z_Hv&ht={Th;SjRptt%wSboN^`(?u04IEl#D<#yTh z%MRPeRAowGp_?DzWQAJq9{1<6w#g!n)F-!5PG#%JMklji8E+(u3thm<|FO)7xH4 zbWDh4-Ug#XmriPSDjZ6291Fo+8w|Q7+_uiMvWf8@q+#t$NkgN_ zc*|EJ99^*$$qPhcfqd0`1bL8DTILOtso|reRtc|bNUGv2Bx*Y#y))Xj?HkgdDN*y{ zy*(ra+WH|@Ku&DLE53iD*h3#k`KGT@b4SPV-otD~-rUa%iO*MO_pyi`A4mgEKer6=(zd8uFQi zVez$NhpX+y9I@1~JM^3udR~S?Z0^5C;d}{7(dQdcyd6ON9WcG_(!2p}Ylo2Ec}4Q% zaBobtX%dNuD97~`nuD=9K8~~ZoenDCO*~Bx7ewPD3JTqF*!=nslgN)h;FZ*>9k7Gh zUyx7iyIr26E)MFG;&_Jr%@3XP!s;d8`+kxbIyB;0t$%9CTj9!9c%%fms_B>(8CnwB zfM26DFqrSgdE@qfr6lkTNtc{nI>_ro;{z4T!O{bH1x|VYU(m%9|{dCz$+anW+NT? z7!(ASu&)^RF-$)X(;xoG=-8BBh@f98_1N+GFyL-OTfDJK{V)^(9ou0+QKXsm_X*0( z2_j;Zo5qjCd6jfXvyh9AXK|wmnntwoFLcL$E_wu;Z7r*Ey_I<<)z*G|dZ4IWkrS$o z7Vbfj^UdkeeTC%Bvl8z86}m~Ek8aV&dQ8LUsqj$&tjpCH+&Z}~i-ENKk)&XDrXMXA zqY37@mY=B3YsW4`xN@YE&W4|=bzN8gGV&4k0Ie;~hQ!eDh!Yxzob22z_QG>RYp=i~ zT@DMwq9CaBKEx7)(NSca6Y-@xNUpRtLjzniFK1y%{N~r&kFa=RaUHL0^+h0sPg zLLQH8oJ&|DJ+QtaK_bpFyDtgu{2cTp+*2Rk9fK}^Dwbw#0l>y>f{{sT0%D(S?f~iM z=YCDDa>%Yyi4A819AzL4Ddl~+Gcv{?gwf$(Z9`jyqTIOreV_!TC;l5`c|IGAh$2Xx z$v)ss1cuopd$?=WesbT!sb-q(k$Pij5_?a$aAH!Ot1>9^%El6=Rc zmN#DR!|boGWGW#|Yz5r$j}Lq5LOCyT^ls%K9~@7D$g9`y$vMS|c(pbw-#o|H&#W94px z^b$Ln2!*u5XnYP(3UkBlk+vMmC_fLqB>Y!9N*7A>w8GYGYlfhte`u!ZJJH|JC(+i4 zOcdEPai(605R%e}Z3F7HWY>4lrP=-W?%>0-6A}s!4K`)J-J89?)p~O!2l5qv8NgZ$ z*c$~$ZhnGkuUb8s`Lf6VehiX|yU#`Dak-<&(zo1iP{}2+mpZR1ERx-i-sk5{mW*CBlz=EF0BzISa|;mJ<(z|8 zCgG{tQ6CcoR0lqCKeD7XLy2xTje&=aQjN12?$#(_gwB9ckDZkG&2#Y8)s!ZzBM<@S z#>KtV(F%MlmS$=@z|m-S&(=15^>(W9k`E{NErd~Y;bT>G=z0nUjR6iGI>-~jfYhj) ziapji%5j=u?`YX)7y-T+Y%Gj9D*r6Ccz#BQ9VTJ@hq5*4V>l6=^RGsUq9|`rbYI+- zeX;-s)Fnx@nRD>2cr&vKqLZ>cJ-C}IJk#$stP|QY z{f!U?hjq!v%k*BU$h=Uobpo3!h?@x)#0wo!X#wuM@;VHCRx_Qm>$P>885rN_x!l(` zC-SfV?HuIl*U)(yam|H+^J?4u+@&PCv(&VXLu!*^lSy5?lEj)}^yK9j2$)HW|%3Uvy0hL2yjnF%1L99Pq@eSPt^v0AU9cD!~gg!TPXNw z(TsgpP$N9tKv2%8c7bespi$U~R#GkQGp?s~VyfytLvnI{=V4sz0PLN+WktekBmo4wtc1?3`U+rBDoQfd&>p%hXPlXmvwqC#Jn6=Y!NtcU~%2~ zp1KQs*G<`RwwBCYIU@xu=HqtgBihq5^Ss!m&%UDXKKH5k z*S+_>$*t@Kq4u+wfE1}ng3z~A{Re+9lfpY9&FeCpv!Q|_r%tuJWXgP4PU*>RXu^fu z8#Y1{3{Gf&1l$tmSv#bxr z^EDV~c)cv3osbg{=>KlEA%8s+U7+P1vLXrB(~5RYj1lJAniqH6Zqk~?HVLUnP4}$L z*Dx{Uv(H03w{Ij8*I=0TE#ydcb?sOO=p?`2ZPu8_z=_IM4a>!qso2^1YrHFvxQO#F zPPFl5vU`}q%)CE^9=J%3gWY_vq6Fevx7CM_&l8ZT%|v;N$* zAg*+5pJ^uas9nx^IfYV zI11iQI!-vSVLdcs44B%wYZY?F(19}!dv2 zlcw=~T}~vCZ5c5YM1-L@XWn6XfKtDZrmix~86yD-BiSbg3v7#nI=) z!M8i~v=sdd)Y7jn-88xjZ1FLz;mbc=$RAB!OecDJN(<>R!yLo)a)!ei%i>1G3w;>} ztXYTF|I{ie=BN&2a=%w1W+x1OwRz8zuW-S>M>R`e*)#>IMR3>u2K9pLNL*eZ7|+{E zfC29-`f{3ms5(>pJ;5O~Lw$jtCo6?m2EtKPMsx@j0~G-Zkqu)#1Gh)#KGX=|O#3VB z&uRr^1$nEYbI}&jvn`o=KImgP?dK?Cjgz&ftkgP+vBpM}PO`jJyf zRF4nLqHJLJc8Zj$|E|_05h|3D?|O}~bF~;jV4rnt|1MY#zLkHyYVx^iTXeSN)u)nn zW5wG0Cv?L|RhS@JTOV$a(gHeGzllV4^Q zp@mt6l3^doM#IP#MBe%7ZT4!oM9{2Pso zJHoy0flsixB_PM*TXX;i1i0gYUQH#pQ6p5H=cu2r2ngZLDxJG$_m8$w09clO`O8;n zw8Az0Dd=R+B(DHJ_D>2wc?yB~2BJrZ%Wc*bKw%a#EGBF|eN8Nk{=G_b$@hqHUt}Ck z5Mg*$3pp7>G*|lX@aO%q_Hr#k%@0Jn6fkin_|$e`=I`b~kddL)0Cz-T-o{JoO=I77 zMu3OzhrCSxhlaE};pmK7p@rVz&Su9rB#a>+}tSx9&sDENQ$r*xw z#GSn<7@zDv5Nz+a1dUJl#YEQs{*n=Usf;KuYWDD{3+eb-uvQy0y%J?EM`n?F-KHX5 zh^&6S43n>3d=37lUk=Y1<8Mj!j2I$QEUQmCL3jI!;z!(YDHWfPOOl^to$W#s@Vp|x z?``qbA+s3G#Cs0Xs)ftlPs#o@F|ssr54Cr1q9EuWlj+QKfm@%9bATV|)q6Vt%;7Cb z+Jj$+rmoDhZSfv(7eZ&xDjGeT_6ckH07ZCj9sSv2!3h{~3_~76@o$6@eDYm|F$+<8 zY|z7mOno!C`4i-=dlr0*rLIn4V#U?AMg%I-?>qwsU-*r z4JvD9ey5k|?)CFn8~xkmd#{jVNrtl3-&B92r>>%;U8nm`^wfDypB#p^zh>H4`%FDV zM)$NS+b+40gwQW|P0hGo$ZX_yvwDj$Bgt7Gfx)daLGHS8y^jB{Qxgqktji@wL!)PE z2J__9`;c+{1L#^oZPIcCqYlWR4Dj3aK5&*W%+pohhfvURSaIy*&$jFv>_ftW9lI_| z6_pfA0PAD+1_MgRRtwMA{cNm?k?Q+y%r*zz3gTG4a^SbYyWH(eoGT|00|0Zig!J;n zas{y+Hx6h@Uy__-w+RZoq_qwhzFi#25(b>Xj~kRgnsgXx zBrXoudL%A&fBw2+;Fe;p1l9F+84zU_s1Rf;MD(puXm8p&TXAb^?Qy5G6gGZe)(H*{ zh0vbH3dh!d3wt-=XLN)$lnC;=(RK+E7{iJ(6Htvf7%h*3e_#CgZm%w5KaYy`AB;g$ zTe^R<`W1dA8@kM!*|SDP=&h{BaK8ThTBlTzH1tRU61_4%`sL&w-r{hViY}TKKRhdhr~gh z$iE&A3S@_V@D@H7hTnMnQFH2eHqu|_ao|pjLNuF>v#-4VzQ?<6;p_=b#IAw~Ur+|s z`rbDboPFg;&AS%&2dKRkkA6S8;C)IfCp>%lLae=@=xS42dRh>xB{e9=Ni;1|e?|Gr z8zmVr>p^*!mr2NSmm5O|q1#$Fv%JvPf;Lp0u^17g4m8s3>pwcb?P%w{aiTQ;0%Z^R zBq%kp<4!%wA0TX>l)2L|<(}4zh4&r*lltDw>IZX1mLoPV>-90>3wj=u8Piyr^%5`j zvQukpDVFvm|y-->~N z?R$I6I_Lw3=42JKf$pEflz_i9rCx+_N)-!NGn;mZxE+r4N{xQST^}NLpH&nzW+}Z~ z0Wj5zT0b=KIKBrcUP}dXZFeJ~I33T%Qs{xoyXs(MR!$xWODM$A$w0VtOhCS6;y2sS zgmi-$w|C&{HA;t-)>;%r?OwpoR$8tsb)h)C-^~M?UEE&c76oL{>8ClEQ<~X$vdh}U zb!EDlcrpk7@&r;Xai-`+stQ7L@k$GWh{t3_!GE4O%l9@&g+D=VtNO8rq`xub-R#UJ z>*jp&oz!cgB$9ebqpdWZn7H=7}k#6SmPbQhxGEq%`HNK_03gC*!36}vRI0%m^Uq`uUtUU1(s_p%UJm+3o zEguK??^>&nr~h8XbzKb)x0iu=*MJQuUfPr;q1tP&sUG4@uLh2@5MPWjmoBjWS2k6Efq%yG;;s(;46Zw({EC?vVUe z7wX5{Kl7lv8k{b5Mdh+nY5HTo#L0U7@}7(6Z7H97v$upbzn^^KUN^)c1}_t~Ymn}> z<6tnDZKMxaSY3L5mY*1!eqJwm(RN{L-NUU=BhHpLEKAQiZ2cU&%am~(bi0IQ-DFow zc2;g_Yy5<+=tkLGM{~l^QyP?Pz_!VsZdmU4#Ed_e_+-xRg;YBehE}a zUaXutEIy7xuHA3qpzvF9qzit`mE1^PzHutoqLFu1j0*YZ6-c1bK4^l+Dr3~5%C`YY zHqv_WW)d>>rQq2@HWwnI8if_UakCj|cn@UPcX#jMjPvkke(=hzR4e|;{`WtHg+?a< zbl%nr{jk#ti##3#Pzq$cmG8h?(vzd>z1Vm3QOk$<1dh}JC70Ic*3t$IvDe!@FdN82 zBjmwdx<8o=CCeLR(~oeF-f|7rj!8XitzTBsBb|70zMN)E|2z+~h$YRM!Shu9-pwgZ za8RBv!pSfdCD3`#!zpkGjxD;=LJ-+5VmLbq7mABD*8b!Vro<_xhrZnVj6-!Mmaonp zz`Ul{=4Bw1&b!u(7b3=tgE#fWzI7iyKfSmHJ|D*}_ODRG+6h@b@#$rZt(1}ne@t}y zxnkF6RN(Igi1dAgTS05u59N{6CZiA&_syh4g+GYU}|7r*rw`qf3M%q zKpn52D@Td34dp`j&{CxMpF8@Ys@I1<&R7Un{GAFSoYaN?O^3yv>_aE{8u$zI5=^C3 z0g@v3@2eRXrK_SX-$!Dupu_j2T+?NFw~d`0+y78v4~Bd*H2`nw4w8D)`2AxsH9eBt{gkR7e7TO!D* z@t9!nU@S{T(d8hCUUk$l5$0j3ri_lfSSKDWYXHT!SD`^2v}5#s6f%c!gDw*NGM$mS zTEY-eMbpHQ$Em3LL1BUNu-#X_=-5^%N$FZ4nLQ!#29@$Bu8<;W)+eNmeAUsGg{6Vn z3fabVken&^M4wkLeMWmt;7uaVHicS18S&qD^jz$fF+(-NmhD#JXcw^SlB=j|+NdWe#|5%uthe7mLoEfF z=EGlJkkLlzB*k#wJU5HF(_=t0AI_w$%~2Q zV3@J_n$4*>i=YvV?DXPCp$Rz2BY(|W(6wva{?JWPB&9{OS|azOjXV7FE)B{DZ8&pgX;H!3j_Gw=Y69D>|? zL#`AdS3l}UoI`;B8k?`7mk4e{r&+KaJysr@8x?twi`$VS z0j|t5UGIOGxF`+ZN=$!aQ0{Daw6Y+0PhVzV==sGg;rnv6`1F%+QhOz3=6YDAgfWJ& z{jXlMh-_9C#CYypKDA9iA5~~oY#PScA3}_^mxIywB%N{}lQ2`cX&Uhkf*VvE$yah7 zH3wGInD?%WB|egk=XKl5%9snP&@qvGY9_Ku-73D?atz?i)dIJ8sTibt=X)lR6+>Rb z#C)&Ly%!aMM<^{j5KAnDu)qlru*huSrv;T1PA+Kw%o|N3U0P&s{)8YNKU>YgLKwg} z;KbLAv(8Il+AS8vOWm{2$^6J>FF%E#en$9leA+hE3G4ozZqjMT(><6!{zLV*@KWbf zn7})Pccw1wM4rl7IQ+D~H0sAn*nI3c-J&HO!QSb!y|FsL;4pu75Xudxv%%Lc}C*pz&44Y!rp2lNmm$>k5o?=fNP(FZ06h?3bz1Z8|;O`yS)0odF zSf|BS_v1DQXEcXC=ny-adWTcj)Wk>@S^Wek+?tQs!Q&Skz-y z;z|B{;-utpQ552`+o&I4U;9}Vb9&K9jOvCqAIp6)X3Re1$_=r7sVRB6xxx?Nqf&)< zUK|RA60Fq;U<*?{2)PY=gCio?WbiHIbU$EMfSmp9V!CV#3=;_$$Q z|H(?6Xma?hU}ZciNo3Qgud^n^7} zy0>r=naruJBD97#S_2NG0ei>19zyspcDJ5{0A5#S@&o7@aTeW#;fgidjr{x!1oX4~ zw#fJJK<*|`A5f)+b!#Mz(MFA=m!jqcY~0!rV!5{l7+=H!t*`R>Xmiq#d5gq+@%?r{ z+#!d9YH$mox?c@{;%@mQe4hE9m_GM z@guSG7C)_AJ0F(dD9iU&;&TR#S<`j#sXo5eHZd5_S%eLI6xLcNQybpKw9}*GiC4y zH}^sKnC_J~{wrFX0se#Vg?;L!4_Sn&DOk&%2=IRS8#4uE?D4S*9--!HENMqqD{V z3LL~K9Ab~yDrJ~FCA1R#qx~Wv5Jv0Vc0NZ$`NJ%@CO}4AU_i9>7Uj|R2E@#8(zSQ~ zpNsKdj~OAmkYpYd(e+(>{0*73;n5zx_@}38%i5IHSyG}EALCUujIa6Ix}=$?24v-ulDQ*!R!l_@9dVRr#Sgafx`&)#eN z(|-Zq_F=%vAoAdo{&er2o3X>gCzKTD;IQeA2tJ~C+-gvZFzWYCe)dnAGUQ4F$Nmos zeJR~zSMVpORUNa$cfl~ExNv$ZN>@>+EOm`2 zLJ1f-dJpG?b6OTT2zAb?9MsPs$=61J+pX7K?~FY+TP*DRrNMm)8PJ+cxlsO>Tw3j=Jj zO8a!ZetxWJtSmrc#@XxxDzF=W$piia&^Yag;vP_)Qy6vhSKmYq0C zj*Bj2c5OhKJo~rXsH+W!%_O$tyfBXSJRRMKB=R`vE_Z|H*fCyiVf1l&9Lj`_^@L3e z_d+tPxMEvd+;JoBore9Je{C@+_DTrM?Q-#Pe_1_SexWH~MtESsRDfY6s&6OE>O(*C zr)`B-53Ta+!)2gLM?B9@$wJMXOp(4~MQo>^gN8)fX0zqhX3m=h-@~53Wz8tcEw&Hs zR%VlT1)u-=;-3plMA`t(Y_E$-@NMLiW!t|l_zjFOB=X#ldN{c8I zUM;)SUo(S>VLCwb}e(txSYfenE` zFj01;^-1#PuCzcQ;p}vOy*8Mg^f~{%e_M;BC&3Nh*^dTwrntj3<*dWPIiscLPQ12_ zYbNwFEYBM@#gydIy_1!DFZAt+-dCGBrW6*1T9I#KTgmQ)S*k?GNjRWiOx|DA22%db z`*H)b{L<>m+>SrKurbNLYBswMV*f0WHiE`M?SSEuts{k#sUp+G_H8ZiT8*7&wJ{Og zV562thP^q)DYL5?;$=!b98k-?3N8i$SC7LJjy<1im|pvzntuS!4Fz9b5xjagmw8$N z?18Hp;$+&KHlGL}Atiw}EY^>pg*6qSFMHlq0geHY#1j*4>D+b(u4;m*T>>G*_}9>H zA|deQE5;=p&&J9#%9*a_b+X^UOqb_E1%n1G5OF;Rbp4-bKlGQokRzeV*`){7Ge12c zH}gOLyY$~$EpXU#9>HZOy12d_gz4lQjL^*Y(`!7yg`wLDIH4--JXnVX3I#H;*|4&kAe0?O7s>CHKbVS1vJz8f^k5+D&l zC(T*9hTFHeLpm6RA1}nL@}PjQHN(7#Co({mo2$*^$~QoSw(imA`gG z?l>utJSow-lw;Fum)2pka1*-wRu!72m!O-eao584Icwel?kt(7ge%oOiG9n0Al_Tp zL*x=HBTo$j#a!$FDC8RA1m_Ta-$pOLvUpE(0FvDYaz}bPlIdT$uEDN`JPm;y_PgfF zKaq)eHU`NVKvcz?N8?-F-J@)Cm<|Buf`XQ5X61&7$V>>!WtH6 z*`o>IOs33{`hfkF8aNH?w{vwb@<=~|oq2iO09vyHoTIQ(P*=$`1jG}}7_)=^z)6OL zL`X&dX!ultx#{-1YGPe)77p1?gWRX3iR**>n1NB3|JE)B#L-A^2_E%-T`Y_RHb`7g z>u3f(EWwbi5jDh>IJbuVhZT7vGg0s1jW7o2^xchGB{#-56g4M-M0p4>3F&I0 zm+yq4_Z()u!k82HbEL8wlqi$sJzH(=1L*ya%0fp&S~NVbiPR#6p|dtOao8{fN{q9r zTE-WL$;q|taIb~*X#a?Ge zXuM*5ALS%uZ|cy|&G?1ghr@MvT_{18Aj*Z&Pzj(QWwM|<4RPpq#6(&TDI%f1 z(Zv?UB@{5?vx~~d!OF*t|6~uZ(%QpA)M8#R3e)`igK=D&tq!W};W~4bU~uj&^w^6W zBX{J?_|(CQv{!}((e|F}2gCx3jgHrMeIS9`MP5u!q|)U4^mCEeV>?zP?f9>dgg;`_ zJvU$B&bIyQa?id?3}9jI;^o-A0hx|(2h1?JVti;goo4`1(}kU7R$2%!}Z3}ZpXT*MwHo$^z5Wmsjc>bhHqVxunb~?eO0*Lc*5X<4*>@ae|TyPrwH8#n< zr+2++ne+WaUX_2hX3nRJ7y$t|${#EOek5}taE-L8u`c=#r-r#1g(>Wlj*8j}0A~j; zk_HCLZL)|s-q)wtXi_DJRby;HVTJ$Oc014Md(O#gfCNTi_u{;a9l+!IDV`Vp+9RzE zR^Ke4l108K)%Wa=l9F>0>cW#<&w`6w^S`3Uh!Yj(Eb6TXIr2WQ#;7V z5?)FAkV{V6lU;)WO>#~_`Ysx0g9ukimYgS=YC#an05nn5j2PN+j47TNLu?n~3rSw6 z>wR|d$L6oV%d-H+$B*)PHNOaR4#bzx#MyLEh8nuNdqnVIN@49yqh2~revF=zB@%@cg*X_xIKP*}|(5o2m`(hx!K|7$^_-oDm z*}|w10{6=(pH)Hjj52WQsn`JCkNSfI|6`JQOEzBM0Xf_ZoPZQIPXVNlnR_inBT-Tr zI2S;Z(2Aydg`*SnypI-og94;>*h6Vae-LTp=@ZnB;W@qRS9*{plDO}YLd5y7HiL>Y zjq`5(EpG{*_}i)zGp))&2^Zry`>pBfr`eof^~8U4?3r%@`A6le>%OM->aF{5i#ZlT z@f7U;yk+VNvLmN*L+khWl%;b%+Zc`ZnU0k*v(*u!P1EDz$6gFaHo@PbwMO`ST?c&t zT{bi5<(DpQ2bs0W;rj8k*XFW`q4`VOm1m2(Bm%Q#!q6&SP{{$g&+`D{1R|2k;gY95 z&ERCeJBKUAot7zx7!PWLZMt^*v`;o}UT>`(veRrE@bY{jyN{PHdu$JCbT?ct#^|K* zhJHINRzvXlA*F%op|jf#9NG|*XfAJXnX|W#D!Vg6eBGA84-RI%FFjP?vIlb*xiko2 z^r{#)$GQ0$iyg#o%Vz#$U47(~!MbKz= zA?R+D_jbPR>*Y=VOb!Mb_1nAe@!|9+0YEzpz!iHrU{VBd%z={u-od^oK4(~)@1-gV zqK=Xbp*tz3EGiwe>$xl_O$$b%dlw1)`;EsLe!Im;xC_5{YezNjbLkDzMaS?W!;Gkj>4IiO@=y8-*c9f7IW!brt%r=A(;K!mGqkNdTWicAw&guT~(sT`dNvV-g)!f#7qwO z)Bh8Ywkfz@_-j@#i4a!u@HMlGW`7}Lb zX*{z`_9q9~I;LAE@AhmTh(+`Y<)Bw|1DnnG-VBA=2J1i?#{Aan-vpl#^s}mTYmRz(rEzg|MejpX;EfA zJPA#6|22$~ieKr+!1pO&-;F93_}89w%^Zz949&K}NIYWE;L*F#_0<*i=jf>(>_^j0 zwETx5R9jy`ED>D3WE+@0bsGJU3KXRB`KyOkDTcvf?NEUKEu?|GlmfFtdIk8q9BWcR+jLy@pU(AjLC$82%Ie1f&qi#ypoiR_^sFZ*K8 z;!QD`i$cW9^DqV4K3OaAzZnQJVTa99OQ+qUpJo%lhY&;3!EZ9&&A`Kd6&DyY?K;&Q zEo>0~*EiY}dwDjAhBUO%!e>b#e7;%oD@7PN%$_u%SP;b`R%n_ zMeUf8MBg)cPw^HnZaahM8@f6 zE48UtJ0Qm;9w7eoyP0B@O0Owcl`pECgeBcFAq)`$vA|-*GI)$Exn6H_X`BqHX+Cgy zyro-Ztd5`a^KZ3-7?Zq_!oiq$1uQE>xSL*Cexk1T!Wjy)|eYu6O0V}fC_ts$V?o%=$ z5O+LW_IB+ozDK`SMWnk5Tw!qasn2FQYbAOQbRS-4x(5uW_p<(y=C;bTB^~%ORdn+R ziaU7wbGBAHCRosdgE2C;PvW1wI2@K@LG@DCE*^3EaL2V)TE#FyqZH%9j?fZ*z4`c+ z7*lT!r^>RHoP1-9r1?Wl+@C4`yEOFum_H3RT|6m2#*S_fJYD75!js*|&XM1MEg`PZ z3BOetKjcL2!yBTJ@kafS_V2|0-YNgE@u|L5?*6*e$E22%ApH`q`HOq^!2O?P$|E|x+q<@oMd*0`X8mL6x3q(}E zp$jHR!bUg_an42dlq4G#3#cp;kCfmLj>ayCkffl>dShi8m!i+BVK2_C5z2^BDP?xt=9^IiQ(c$yw(b&IuJi}`E1B~D+8enXPH0u;upECj;;Vj`9xuo zp6CI!aYC9Gf{7-g4b>_USI}d>P$+w49VxS=E=uXFsubApW4w(T57WHK8@C;DgEKF9 zp}<);0=7qI>~6v$sr@qZUUeGo_HtM5@N+*30a;qM<^!o7I^t_UExfVfC$sgIp?)Z^ z>+!fgKRfJjz!MJYw9T4@b^7iIMtn3vDCweL+@|j7xhFi{9PJCvak==!?5qEu^lpw@ zKn+2W!>~J1Cm0HG2=nBGwI)}G;DwKg;cZVTYf4Fg;g3?1FIh$S3%ObwPO=m%X9q_} z>*@%Vg{p`Sl7;lIR4{+KR*Zopg$Z4EG_bn*Y4B#vnD5U>)nEd_ga)E2+|G4Aia|hm07Wg7{I7}&zTh`O@gPfoq<3Bkc+cB1m zei>n_cJMC&{Fc02+EA986CAU{e}58>w@hb{frsB>FrJ2iv8$3CF+&62>@>n&Y;_MbSC|XL??^To<=#X1swX&JHb+uRHqI zZ>vXipV>50+q-IuA4<89G{fO{xCrk60fD(K(z|~iyhVG}cPCa=6&{RUZ->+flcLJ~ zdzZw-i}NK+nD-^AZi4KOL+%}!h=cuz9LJg7Ls?I#;hYmz7OaKA@}%ak*1YtAEC6m* zSk}DEux9d%30S#V(A!vM_NLtD>|9aIV0#D5N^px+nvgYbAK1~tZuJ%%0W-Cmmq6&% zD$X*8p454}>&qiUl|ylKy%dTq8W}Ryon0MdhPG6FX`3CTjNzFzo*!0wv!)6-tN|`D z?V}7@DlO(vwDr@xwe(Awec|yfq%aN9F0ShzzMb*_>i=o7G2tkC*{BWNJirXVpSiB= zM7%VBpfLIR#tn|K3F3H?@xoF>FgO`%knMjxZ;*4;_q{drOn>txK=!{g;pWeIC;%f0 zZWJzHIfhPU0-OuM5dQ4^z?wHd`^iP+c*P4}(8#Os2VQt-$l8>iUVw;H>F|k3i{4_4 zl|;yX&QNd+Kc<2>2fPS$)}p}^9Ad?5RHw<}>ewZNvTQ7R64m@TqnpzFW#|Y_-nl ze%bcPZU#J;CGTxOW6O2NPq4-uWv(y63L|?o;rN{zP0Lq<-&x-&2)?D8>rTV#KGKrS z1kgN5jCmqPioF#SL%oCFHmd{1K3;3D%6r?PA zSH+jB=foZa@4)+f{|^!4cEt>*>Z$n6lxp#nZ!^HoX|VC+2TsRaEJ{H#6URMN2c zTOd}1{RyAUkm_#t5(%97C}0m5pW#Bf1niqwV*M>gXl^Ub%_#%@J?{QhsLRaX^&V>g z>(nCzr1G$(YUIg!*W4->pmil2*<3?^^8tvw(FCfs(nE5)SkiQNue03wCm+U$N5jIX-%`oG6{pn75G zm2J)={rRqlD$>L<~7q3c@TrQee<*xN02t*ch?WX^j2gubw@ZUOS<*a=&$FP$t$1tm;w- zz0UkcRXwt7Sf`Owe<^h;+l)_2b@vEsUk$Sn_i!HfAHyw6xpE|a!>i<50{;aKWy4uh zAaeD~3~%Y07H+IkIp(B1Qco{@JL&4(0cfHS(c{9Jc140!kK4f1)&#{+^c(#ekduoK zXO?M@6|S-w{y-dH(Q#}s%Uq!nB-*(tUg)9>R4+_0Q2GN;x9Kn6GtK&x7=**AvYaj z%&L;3r)2<#Zv#oL2k{blVn7Tzf;dMG0jaMXmkLt1@Yw}Ivz^@NgYKF8vl8eDDg8_q z-)Z8T)TQi{GN!tiH8hP(4h}|Rg5V`urk9vDx2kL-|Iv_6h@OVjNnOHB?x_1g z62X>mcp9I(^P>2dS-%sS#imKk7cN^rm!Ap8VQMnRcV}#5m~Qs16LHL)nOh64Ut&aM zapCB)yY^g39%@Ktrq)d+1PJ-O?wEVy%V^@1?^EnCNDxI7###KE|0&0pcV@iUCJG;R z9f-5BdA%0IFnSQy%X({SH8}_T<-KJ2fq(HRaPV_~^F4dacv=S$x733t$GtiO133hC z=n=d42H>~{EI`#-M3BAJGnRUBNY7g43N=rumwKs-@Kd}WB!To~(i6k6a^Ef5v2a&< z$;`sdqWb1Z1aI73hFC2yXcEpnDZ_ z!Uq^lDonI~WiS|SAAt3~pKNGQ2k=2wN!)07C?Iz|%K-Hx=Dh!MyK*fwDY58}XVp96 z;N!tK;06@I7}c>O|8^m3qib~#d^ccV7Ut{fNEtc!pV7o1a-+@Z4GNf9MHoAQ*Z{~d zf(LLU?tneDB9}Z8OWa8sRO#sI!4Nlf4=a7PYy5b;n4VdIg*>*7krintTN^v*@t2wO zMN11jzDV}zh=HpaLzVqiG)qo#<4zryTml!?kCOw?S;MlxyM2Gse@;(wn4;~O{r@fF z6?nIObjH9me{z=BVlT{X=6zyEK2*{uc<3~3y?pVS($avg(vA+NkK{NMCpyFoD(ZBI z81)m%lZ}CgFY?Fg0865WAU~$znR&L=xMCog%z9AoM>>vRHgwfS#3o&Faaa`>&f@HILk9TqE*O2V&(I>`PLaS(MmT;%nc&RAPb?%EOH$r|QJ zm5e_dvJ%3pTQv*&wyURYs5Y;0ro>1qM)R*r1Or!iaS$QqtPA!DjPI25Jud;%Wb6c+?!qnclG zN@I$5)VvDvJ>p%)tTIQ6%O*q8oD<5wj3|*`+dtZBWfn*kWZ^B)II_87zSoY#uJo7o z|7^R7;(W%1eTUAy?MQ9l?(dwMPB7LP_?KC|19)0(l>9^x;Dr&Mfyhw}*|&1c0>!(V zG=I$Rf4UCHD3|ZvLD19=v$?AQ-){jQM*+!O-dfvZ)~|1A5I|x~?!)s{6MX+5T=db@ zkRqxVKTX&$@m!%}?A#7<|2Ar0}jp^|ZR{ z2&ahHU!iL&OuMX|*aKWjt!$8cry=b64KzIjYg2=MT~L+RN0a~Wh2YCd4b&tI8)Fkf zpYSbYnr@W}(@mG;2VQS6!?W5Jkq)8&1p0ST2n+X1ZP*NwvuD~#47$?Wq~T*&;CXhU`2Hs)+?YP8vL3!j|hKJOOf?Pi88k#z?jbH z7Y2fHJW;D%o;`C+Qn#b>1i!s}G=(wFvT6Ktx#q^~T9 zDLB0k1iyavWyW}3e2V19BN|aZF2`SAm$V#?-{e!P>*fw){VeLd9Cpj!TlabIUW0n9 zEMu`5?z2>?C9Js*8v44qY67G{ub*{GJWU5IXXUehwWMZgBuT6TDJI1}Wt{*z4k#fq z1!4HJAF*eF(!P#91Ex-1B2^?@7#`T3{BcZbsRGFC11E1T!N>yxpwrdh_(GHw7Wt3( z-FM1V`A}+9`HvDQv^|KAnc@1v?S+b^m!_A<9K~xpr-oMrigE@aSd#TL|44e)b9!Sv zb`w&P1P&{IDb*fZgct2JPYNL__QC@FHr-yG4p{GXwd<6P{&2>>jCE)pCLON`K6;H5 zf>J2ED?7{tgnQ&Qo?kC*m#EQynqB}2(Ul(t&ZPMY{(avqw@emCa zGciLNS>%g`&t$izk3&wQ_H~i2X?Y#$GHRX{uyJ=kLNtwz6RE8Jhe81B5L6#>s*5;P zC~c%YYiiDB1z;-lgQO!QgB#+9KI8BkPdF9|))`Gae|`h(Y1| zLJZ)LDeAFq(0wBVWYhV!5*Rss7&+D7tCf;97&cvc=`xz&g~7%fGCamBnFM{<;)w4D zm{7ZW{1D_3z49=^2D~a`4 zZcl8fG{4@DjKncAj<6?BPsrSa%Z*gzhxr`zbQ@DyWJi73tz~f#AqcY=ek7?LXF=tV zFG$y1UqnZ{ndLvvS7|)`MovH#CD3j~t9#YC;8=T`8Rb%Uu@9Hg7! zx~o8K8nPn6fW-Hd3i9LIqzt9~f{o!2`5i`k9R=gS^2rRc)mATzm)r`ca<=|KA`Bk%EI>MLmJvWZWtpsKJk+K;1gAIpdiG}^y} zIuVS?T>N~J7tm;i`_(tl?>!!<%QW}}`wlSggX(RNHUaqpN=EsT zW-=EJ!-N*2YbJX@e=RkWXu{{~&ECy5ozTS5viJ4$kTQ>vYhcg#Zb=*gnkY#u*YSJ8 zvJ!8aO{%2DfC@OzXGZSbpYsMHFr-Pf1@Bw}Bf7a5D&c2nWuJNLRsT zgYi95f&qC9vA|Q}6ge!i~*mR%Wc;(63v z_PC%t8}PcXHcJBtuMw} z(*x)uddNYsYJEk3@gj55T9kZ^0cm<04(mKr2E5RBaV|dKX89|Ad$1Q|t$(MXP)k>z z-9H$bH&X8UZe5atR4H@uiW#v$IVK~9xo$tnTHDmEV>lryIKJ~G;4m7xvBFjmez zgIFW42ha?Ki2ZC@$>;n=hX+v1d>Q)z+pvxT{zYJXBTns;b>`%(%3Inq+Pm5p6>^9y z%?{)33bfqs{${n->Fd(SL^Ix2*!zD8RwphR`qkoGo-p`mmXLK z4%O-|9yb$6crrf5Ghy)4F=y<&HwC!_aMxDiP2vQxn_-qcF;A9T>4=~dg#0dpVpwA~GK`Ri!K!6{8OU9r4hMHc+fOcZv8cJq8s+06ay zK05t4HWoG6SUzlPR?XDE={Z!hapgN!F;i%fm(sAawd{vJooyRDq*91&Mee{k4Mb)r zH!dF|)803~%ZwVny6a#hT1D2&JJd8>s0l=C>ZhL$#L;a(TOqajZZ9_(`X%1AY{w>W zy{9uwtHQ71@!)QlG@28#W&a1SU(_V`j_P-hmf4F-S$9HySLw|aaK|HmxYu(aABB7wCYMSO2LSO zS?z`4k8Zzjh)O?&U$eK3;q3vA$kcXVQ>xRe1V|4x1E?6;&j7P&Pw&#sLh1`(+-I){ z&u%%Ud(|Z_xY6p~?AqJh$X&+oMCtxZ;c0ez9i^-9HiCJr7&v6DQFT*r`ZtTX+dzBg zkZyx7F!pv<{zfW>qbuOdXe{VM0+y!9SsX~f9XWX--DQoTkFBz??G3jf z5WYC5C5m}(-oC3B_^F7+`u<(8P1?7|$?igo4%En$S6e(^N;AJGss*((#0T}9=sys; zQ~8Wov^WgA993=3q){u;<5~WGWSIKGTh{2e9>TfR_WY0FrgG`a z_g=w$ld}^HoIZ<>7*6X@x;fMn+pAo%$s)m5EBmGPx`APWG=DBymi_il%#dC!_t?zU zDKbJ;LNkYh)~jQ2ir2DezNpB8p55au!5ZB;CR;){7`edv;@00XU((90-c!d z-b!hqvVD>f%rUWk?wiUrVWupm?<*ti4%%(JGa?{hU9cTpT;q=w_$a3*Bil3Br z0rMJYF*~YE=<%2k7$NL{yf{~}NhG(9W_4$8QioBBVy6r8swg;!v@pKI^;v9Ocp+&V*xj>o@4l;d zg+~9h+m%6EB$se-LW9M(>aLS!9f)w;h75ikmb`&(;mYCQzt*5~7W^wyxOW(Fh#g5f z#%ls1!0IBwbxx0J<8Gt=vRY1Yt+ycS^Y@(c+z6i#tB-I5UY{LG$(tbktJ1L9f^Am4 z|D*d*O;GQXzu!6*mM0)|LIV+TyM{P{6}hO4dU2W2+w5->q>GDGG>>=fA6>MdhQm)z z9$_%XqsM-8aN~IU!=|MZE!QYHAJ(@oN6odY)=W9yJoA@$dc3Dx1Plb68@7byz;au4 zL=?v+VqoEPbIud{!_{S08hPq&g#=6KqkEvM>8#35aCZ98{k^#c`Zc+Z{P4GbXZZKE zn^M0TCNO%4E(V6sCAn>V%nsqqFOG$mSHKDr^J~Snh$3aPD(OYLgK!5w*4=-0vp;gT zoXDssft*uE%@Y6Eoxj&4^XLueMeZaUMpcKn_@oej|{VfHy`=({ipVvQjTs<{b%b3SJo}pbi9H$@;0B%6KpN->s-#` zdNWKV*c*(;XJSuhhe*soUdB7qA}fn}6GVIyP;$(s(6Ra?dgxb=l|zD@mM8RcBo;~O zP4P14yv@{xC&JzvUswN(YjesO*cDtcbC;~$-!@9UJ#6~;@i+yUv#AM`m|4OecAuUz zc!D-8#ZRxE^UMMI-eD-7sUUv2iSBDVJG$Y!GL(?hO7^{-(RhpEG4_$Z{MQf!-%NlS zAXlF;9M%UkS899eoC{3=<|~OYJCc(pZ41o`8ODfjUl(cC8Y!(ZE=m!ccE7XCf1SVb zm;l@)e_6cR)OgAyx+MDvYBgh8w%??Hv|;XVa??Q;y>>w0(EcOA1jE24OdW8Iz&HMH z+2Z~y*?754;YM*#pPe)igkOd)U(P<`z1NfF%eescwg&o{jrJNB$Mmfgej$=f7V%+i zEi*<}%i|Q>V--tAT&={-4PR?y`8R&2Y>ahN?BPtI$`v#51^E3QDXAX?^`+@S+-@!l z6Klza=3{7d^xDJZBWmOyL8mIS?|dds6bzicqUot$ZeQjY=o;AOXwHJXe)mwDPOCy} zO~pU1(j~v^45Wd}jmI3C{$u4+6Rmg$$l*URbZTOG3{!EdyWmIL?(TNV5mKJNxTQu1 zZyQd=88IHMAUl{(2DEuu%qxlwJZqG)9HO@vzQ<^g4k}JGqPx%@{kA!(THN65W9`_| ztJTuXQs6hlzH+2v$#QXLm(m60{j)B3+-9n99Acl3AbEf!52+@%x6R|iVePT*>d=cw zXY_b3v^>Jmj`;v!k`3s@<1vi|!o}l7NaO)B-=%%RTmMR-0$|)ENydR=44|$y3aaH= zCB5W72GV-lWz_d!4MilqtpbZZ&ZM7A*{^xOYAv<+xXt5uOSU|g9RNS?`0r%M>yRad zxU<<`PZ}4)D}nJ3*0=j|LUZbO6QzB!701o(^jS|+DbylcT=@gI)*Zft?&Wn&9vd-y zlQ^Ag8^Y~%^_$id*EwmpA~d71wan;SH_ss-o2WgPU?8vQvgW7=bc?x+J`8u=+h)Qk zhEvOt<3Te0&_Nc*i{zk7=JUQoWr^;&W)0ucU8D>6HNlv9Tl&vW`#4$S4v4Hd{(04Q35=cCqh%JJ#_c*1IOG$)H5}Y6sFqDu1ajZ(iG{WJ zN!w$s@w?&e$aG}HuHa*$#g@6Qal`V_2j;9pi*Pre{nh(+vCGo|%dfD|4_+fFr|uKD zv;&69c*5Swyu>(n4A-$iPsZPKo*gkzD?L^kGp5Qqw4w6&J%6GXG}d1^l85C#ti4xD zWIA1bm9aeTOIc0=h+snBUTv%MRfZDzsrKY(r2F2$M{gRxAXR)rWE{x!*q%tjCD2B;JW2C( z33M4-_BV7iV5{6L?qO5b=jWzR{79Mh~2n)c*nWK-1pb0ud)ze&)4;|KoUG0@XMgy$5kX>VLXn zi#6l5cXT`XeFdEz#ZpAUYGIF7N$cZuY8kVy0W+Dkfx z!=8ax91_wl6!5fzejy`QrV2IQIJgH|;C(<$j!In)Y2D{z;G1l=op>d$ZO=zG|5uBB zD=u2Ts-gK&>3?juZOME;H_ABR)NE;E6Qqe768BF29(G8>&EC!ZSH9U$QP2RfCQL+- zPL1?gWsoJp1}n$BbFP!NW2UvGaK3e+{wZ;`j1_db+M}ovez|d#_L}c)GM~wBf9J?m z8>UAQ!BHbVmeUfcRkZNf<~>|2bK;Bie{_R4-kwcUEnjv2pty;WUCav+9TF)aRIkYj zcd=lihyQB8iq0yS)vilkdO&q1wm2H5w$a7p4_ACbZ}lm>xec$rBsbh%;g1~kerpZ=S=}T=Qoz5g0%0ymi8i>_EQX2*n-BHa)Syo9 zAivfH5fEB{>{9G8Som^dw-vk%^uydy;PYpnZA%-8t6u|TiH zkxGn+(wW=8xZhs52=E&qIswdl&j&$2q?dk3EyppL;0(U9|` z@JdL3nNP>^`D9ilL}w%$=9XX(nqp;K6ig+y)2=5G*0jRpzos9IrrA`3L)aeGQIkH{ zUxC)9hYBl|WB2wBZZj@h3H@sP+^@s!!|5)w*Or-Y*Lk_h+)E|1jmhWvbN}k4d80`P z1|r3zFUS{zP|lr(I=n6>dAf0|x7sz0^CpwBbcJxJgRbnP@=xd{&jlLwx>$dQ`{z90 zZVC1*KSad(0x2{SaxTUF)!_QEy0}Ud_`vN0khC6w=LY)}7O)gtBk+Eg2bB1PW_dmd8yL{n65=9-xMa$L! zjK(RkK5lWgYk}s?i@9Sxm?R(P+A6$sVuGWBF1uLrTrNn~i##}&LiT=wz z_>maH8gX4NeZ%GLc*Wc+_{b?`TY+ope;{tBat~v3*S)rEqSQRJ6s`jppiP8XH0yliYw}c(%1QFOElW| z)vL!=IlyT%8iP0({u8<2I(t$>DC>p8MoIsUpOTULVF|jNm}rM?KCd8<+lK^6bLW2< ziQTeTSy(^rZ~8Z*@M@9+Qb8X(Ubg9xe*Wm2B4C5x@WZ2pCqTumW>gu((MF5aG31Ot zzdQ6T#FFlK>l-UR7{(qw9IU0FY75+ik@aOo3Y!sL; z58MKG13^XrFUD*>t&K8of_^*_jXN55(XLFhDFA|)LJ^=Z)MfWM(Wsl>(_+6hk3-IO zCIM7Aa5}o!`fpgJa=sFv1|avVs1D%Q_u(DUKdlTNL;qSf(_`JE4>C;AGJro_zXs#n zM!Rw&;oc1J9N~lwqTE|2mj{o|02r|=qjS8;=M>-$7tv86MCC2rKA7ts1s)Df5=@8D znyJv#>3IGWu-q*@1N?X=oW^CQT5U&$nS;8!M(JA%1S=2EZ#_|qit z7RWt;0cTxgKrfm-buh68p5_*9d+g-0#fTA!$27I^79i~hipZeMB1xl~^~QZO_%+%^ z^jb7-tHWl|YL7n==9j+w_~~c7<()%Zkc-2uY`WdCXO0SA>B2zJ^%$38yYI>2y3xn9 zK<$L8XXatz>Q_UINJ zfd(Z6p;-Z5stTLg0ADMk%A)88hO1|Vam{#D*GE7kZ$LKWp3PJb!H$H%QEr@H^ZfCz zrPc9!Ns58K=&Y^c>Q!Ma2AI3dI&o$>@ZMyP??)=ie~Xp5(VsJ5UNea0#PF$@i0jl*Z9YaLYmmdU zdKb$GxWo6?r+C;n>&fBt!~@lWeB@7zrl{#|2|5oitRwOoPjElHV9`taFk2;`P)oaOfH`lkDTk`5qE8oTrmh?-u z_hXiIMtZ-b;>ZMqbV>U~mC%o8>G!{}WSF4jW`ufh^C7dyP`?B}y5vJ)i0WMek7%Gi06tun?6W*S9Yt|64u= z@`q0w#5<6kKlnrNWy|ksI={xE%P@PxCu2}*i6aIxNt%R)|E%^fBQ2*mjI7w8XZf-v zgl+0w+JXV68#E3llHow1l`_J02pZ^nR zBHy>4AAd+Lp*%n6t|Lp}&J@BWr5h0IkXp0@>5_2AvJY($Dt@&j%A*Esa4&Czi(#&)7b{3<(d zhk5abnTEEyma9_{{koZ|TsQ0d8d_^2KffV0(#Xv~%hw{=QgH-CqUNq9i^VRzyASw)iabsPZSd-{qX$G zD=EJrS)HEuX%k9R&R$PQlb$G@6?{int3Qv3k7k=&$gwCe#)~Ny#TL)j+S)Bur9dcY7y`_-SNW+K zTOv(4jsMOB-z~<~e-;i)9{c2>*9w|4peY)Me8?y#z1N61xKz5LC(fh)ioXzRL{Dr9ZR{nd|p#xZ5hSWPCzb*2b z3m}7rE?OE(J+Whh8~CgE;~Jg#bq2qV%NhsD$t3qz&vgPvA*jo4Fp+KKzyC}Z_J*-t z|O59m$E8X z^K8$4KVtCmXB7djlVy35=TM0`_5|k)DL=edBfb5~Z_WCXoSf=)k)nc5Z^2M6R(_7_ zFY1tMTr6lD8F7R*X>t~q|95kF$8Gw7^~z2f8qT~5kvBN~Xj8G+(_sUSN1E6d$i2s> zHD4p`M78X$vY8QkYWiN?1n?K?nT8dNXfD$g*<-8^t2*Xo58v+jq-NPaN?zL;0F9N2 z$4vX6gRo;K!M;l%nN{I@La`)j6)T(7$PM8? zG@)feO`o+1Bzk(39Rx~ouYT5{O%yHw3bg9cyJDn7%K-k7F~ALm7N|ujVP!B?lQ8{Lo8G*^MAYM~s$ko%I69;W4mHzk1uVSP6!qpk;b< zvW`6j#JZ0k9I2uoN-7hB%0kR5_OS<3m8}wT_%(hHF^bJkTW3!A28HcN?+#(c)lWOT z`-Oq2n^dOgPm1-UczCQto}Nsn zjOj~*rTj*5XZg504|9*?tq@b`8SsYRA00-NR$>+_nm0E;7If18?Bdl3^XDh7 zb5cY)iaC2oH~RwHjkRxA9TCt0B(5vn@EbRF+5MkbLq0`7US(m-;G^x8GQe6tzn#>3 zO`Kb@!zEQ1gD>UN?<6<-6Sy=B_2uaGKN`+W)Low!Z1RMvV%1h5$T(iAspXM*Qc(&_ z1DFkLh=SYO$81cGmixa&sx;bs{SeiL%y1wdR3sF6^3R4#LMIaqL(oH0U-u+^XTv9Y z3H0hVuV0_o8UUqLU^&=8kt4LOhmc}nSQ^P!;Kn(i?+`%STimHdh%f@PgUP?Pw zANQ95Hb#1elCO?u!{RkXSwTdyyWN+*3{J5^YW#fTb0$vo_VicoG5_qLYDKr*d4KDJ z1*~9_NYQE+jM|M%cLe01rcbQ!(m#~^Om9)Ufd2TWgx%|-O&w0%?}$217! zLW)i{?7agmioZ5MEp4ia${6$9Zv`49stCT1(mazu?lvW&HZc!jA1r^|FW_y%XB6V+ zTRZEFkxj7O@a&7l{HzL1Ku)AVkl30Los6-!=w9>Aff+;FzA64vYm;P@N)%u?9k_zv z+ut+@cACyY=pbLOY^B4!WL~47_kkXJek2Fi3kI8j4lun$Brf&TIOe%6F&fLhW_eT^ zVVE27hVc$Eo7B$d)bvq;cH8nK)#~>?^&!!jRG;`i7sDOCJfK6IA;d%JB0d8*MWTF9WibT)pnV%7jjRkNXfV)X;5~W;BXV}Q^WZxWJ%5Te&bEZEdtRce ziBCqc^5Qg+u+5@b2}f-yiq(-00S@O3ImIFp&i61vq83uz$>j{ltXkIPu9gJa)JcbL zmFuCHu4H7;fcGXkNWqE&L$2$(XQj?j)GP5B->Wfn#0VH|-%CpXm*72Gzpf=ZJm#4n8P~ z4tqHUL5tW)h}HLoK}y8{MHU4}{zba0MNw4ED{kj)6rR7Q2;Sj@_x4WL%?W#;_dRU0 zl^J1csqmA!x9`OwEn0V}uVM_kG!1^rPVS*0QKdLRs|ZF|DXmq<}cy-w1+Q|WJhb~&Z7Wp>~B6hAA@aEK#q9= zxEC)9*(o}@vtSE7@bG_V>!pa5#nUM@T z3^anR>+bJL>xg(eR<+=uRz0tvwg>jlE-Z`gOqp>}Vgblb#T(4fkUz#YsCeJny|?G{fy#8M+YgQuTg8dW#LjlCLC;W2cQieE*_Sh^URwSqurGAwV1 zZn0#0y;?U-2f;V?emO#nXx6LRZVK@{i*|3dz&^_zPp7^I0^GqNU=4>J8fb{c^}`$E zl>xoyzhs&*LjvfnRc)%v7a3TM@qK58ObH)AY~1T6Jn1Urp!jAIw6_L8_zwU{(q)di ze<4gETk5%uSS>B>q{lwAZ1?56nBu-w z(@*G|z`IPD?eWayjO%b!@bh(U##KBPKE;czJNQ)@;d9Y=5@3Yce3L_5G`Qfg&L*7q zD*3MIv0+LcwD-!ghR?M11H8Pr-GDvd3FFreH_>{-%2%qF5@+-Kpusv^gqGbT@qTUT zwfbV~5=KN7iY_pJ_1UwkqwG>(!0~+US2H))K9;=+KzGk#Mm<~3GYOdmA6D;!CY9wN zMF3U6D;w#`oeT7(xhlvliTFg~vG^~YWQXYxji8+X;IXG)ZNCd|@Ld6h>X&nKAJ
    VCQGAtQyda;OHZ2%Xdk>z#;;^} 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�PZO8N_bLId5PG$@Pb9V|kKy~uCO}m{8K9#4 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%0D)+_ATRm!J3@Pu^W#%Y++GuZZVDnW5&A&G! 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

    ~U2I>+`HH-bV`$vpy8=l!ZK3-IrxCfWRh8e@YVX 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 CwCF|v diff --git a/client/macos/app/Images.xcassets/AppIcon.appiconset/64.png b/client/macos/app/Images.xcassets/AppIcon.appiconset/64.png new file mode 100644 index 0000000000000000000000000000000000000000..3f13a4c7f7e1ddd267f8d3c27cb2faba50330fdc GIT binary patch literal 4256 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

    jjt_jJ1qUMMa*B%j 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 I!Z7&%0q}DIWB>pF literal 0 HcmV?d00001 diff --git a/client/macos/app/Images.xcassets/Contents.json b/client/macos/app/Images.xcassets/Contents.json index 73c00596..ed48d1a9 100644 --- a/client/macos/app/Images.xcassets/Contents.json +++ b/client/macos/app/Images.xcassets/Contents.json @@ -1,6 +1,68 @@ { - "info" : { - "author" : "xcode", - "version" : 1 + "images": [ + { + "idiom": "mac", + "size": "16x16", + "scale": "1x", + "filename": "16.png" + }, + { + "idiom": "mac", + "size": "16x16", + "scale": "2x", + "filename": "16@2x.png" + }, + { + "idiom": "mac", + "size": "32x32", + "scale": "1x", + "filename": "32.png" + }, + { + "idiom": "mac", + "size": "32x32", + "scale": "2x", + "filename": "32@2x.png" + }, + { + "idiom": "mac", + "size": "128x128", + "scale": "1x", + "filename": "128.png" + }, + { + "idiom": "mac", + "size": "128x128", + "scale": "2x", + "filename": "128@2x.png" + }, + { + "idiom": "mac", + "size": "256x256", + "scale": "1x", + "filename": "256.png" + }, + { + "idiom": "mac", + "size": "256x256", + "scale": "2x", + "filename": "256@2x.png" + }, + { + "idiom": "mac", + "size": "512x512", + "scale": "1x", + "filename": "512.png" + }, + { + "idiom": "mac", + "size": "512x512", + "scale": "2x", + "filename": "512@2x.png" + } + ], + "info": { + "version": 1, + "author": "xcode" } } diff --git a/client/macos/app/Info.plist.in b/client/macos/app/Info.plist.in new file mode 100644 index 00000000..1c9ad48e --- /dev/null +++ b/client/macos/app/Info.plist.in @@ -0,0 +1,172 @@ + + + + + CFBundleAllowMixedLocalizations + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${QT_INTERNAL_DOLLAR_VAR}{PRODUCT_NAME} + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + ITSAppUsesNonExemptEncryption + + LSApplicationCategoryType + public.app-category.utilities + + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + LSSupportsOpeningDocumentsInPlace + + com.wireguard.ios.app_group_id + group.org.amnezia.AmneziaVPN + NSCameraUsageDescription + Amnezia VPN needs access to the camera for reading QR-codes. + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + CFBundleIcons + + UTImportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Amnezia VPN config + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.amnezia-config + UTTypeTagSpecification + + public.filename-extension + + vpn + + public.mime-type + + text/plain + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + WireGuard config + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.wireguard-config + UTTypeTagSpecification + + public.filename-extension + + conf + cfg + + public.mime-type + + text/plain + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + OpenVPN config + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.openvpn-config + UTTypeTagSpecification + + public.filename-extension + + ovpn + + public.mime-type + + text/plain + + + + + UTTypeConformsTo + + public.data + + UTTypeDescription + AmneziaVPN backup file + UTTypeIconFiles + + UTTypeIdentifier + org.amnezia.AmneziaVPN.backup-config + UTTypeTagSpecification + + public.filename-extension + + backup + + public.mime-type + + text/plain + + + + + CFBundleDocumentTypes + + + CFBundleTypeName + Amnezia VPN config + LSHandlerRank + Alternate + LSItemContentTypes + + org.amnezia.AmneziaVPN.amnezia-config + org.amnezia.AmneziaVPN.wireguard-config + org.amnezia.AmneziaVPN.openvpn-config + org.amnezia.AmneziaVPN.backup-config + + + + NSExtensions + + + NSExtensionPointIdentifier + com.apple.networkextension.packet-tunnel + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).PacketTunnelProvider + + + + + diff --git a/client/macos/app/app.entitlements b/client/macos/app/app.entitlements index 1eaae6ec..d4d7195f 100644 --- a/client/macos/app/app.entitlements +++ b/client/macos/app/app.entitlements @@ -2,34 +2,40 @@ - com.apple.application-identifier - $(DEVELOPMENT_TEAM).$(APP_ID_MACOS) - + com.apple.developer.networking.custom-protocol + com.apple.developer.networking.networkextension + app-proxy-provider packet-tunnel-provider + dns-settings + relay + content-filter-provider + dns-proxy - + com.apple.developer.system-extension.install + + com.apple.developer.networking.vpn.api + + allow-vpn + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.org.amnezia.AmneziaVPN + + com.apple.security.files.user-selected.read-only + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.network.server + keychain-access-groups $(DEVELOPMENT_TEAM).* - - com.apple.developer.team-identifier - $(DEVELOPMENT_TEAM) - - com.apple.security.app-sandbox - - - com.apple.security.application-groups - - $(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS) - - - com.apple.security.network.client - - - com.apple.security.network.server - diff --git a/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements b/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements index b4f08784..7e2b2072 100644 --- a/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements +++ b/client/macos/networkextension/AmneziaVPNNetworkExtension.entitlements @@ -2,41 +2,30 @@ - com.apple.application-identifier - $(DEVELOPMENT_TEAM).$(NETEXT_ID_MACOS) - + com.apple.developer.networking.custom-protocol + com.apple.developer.networking.networkextension + dns-settings + relay packet-tunnel-provider + content-filter-provider + dns-proxy + app-proxy-provider - - keychain-access-groups + com.apple.developer.networking.vpn.api - $(DEVELOPMENT_TEAM).* + allow-vpn - - com.apple.developer.team-identifier - $(DEVELOPMENT_TEAM) - - com.apple.developer.system-extension.install - - com.apple.security.app-sandbox - com.apple.security.application-groups - $(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS) + group.org.amnezia.AmneziaVPN - com.apple.security.network.client - com.apple.security.network.server - com.apple.security.app-sandbox - - com.apple.private.network.socket-delegate - diff --git a/client/macos/networkextension/CMakeLists.txt b/client/macos/networkextension/CMakeLists.txt new file mode 100644 index 00000000..efe1b835 --- /dev/null +++ b/client/macos/networkextension/CMakeLists.txt @@ -0,0 +1,138 @@ +enable_language(Swift) +message("Client message >> macos build >> AmneziaVPNNetworkExtension") +set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) + +add_executable(AmneziaVPNNetworkExtension) + +message("executable_path is: @executable_path/../../Frameworks") +set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + # MACOSX_BUNDLE YES + BUNDLE_EXTENSION appex + MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}" + MACOSX_BUNDLE_INFO_STRING "AmneziaVPNNetworkExtension" + MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPNNetworkExtension" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_NAME "${BUILD_IOS_APP_IDENTIFIER}.network-extension" + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/AmneziaVPNNetworkExtension.entitlements + XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}" + XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${BUILD_ID}" + XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPNNetworkExtension" + + XCODE_ATTRIBUTE_APPLICATION_EXTENSION_API_ONLY "YES" + XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" + XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "11.0" + + XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../../../../Frameworks @loader_path/../../../../Frameworks" +) + +if(DEPLOY) + message("DEPLOY is ON") + set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "distr macos.org.amnezia.amneziaVPN.NE" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "dev macos.org.amnezia.amneziaVPN.NE" + ) +else() + set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic + ) +endif() + +set_target_properties(AmneziaVPNNetworkExtension PROPERTIES + XCODE_ATTRIBUTE_SWIFT_VERSION "5.0" + XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES" + XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/WireGuardNetworkExtension-Bridging-Header.h" + XCODE_ATTRIBUTE_SWIFT_OPTIMIZATION_LEVEL "-Onone" + XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO" +) + +set_target_properties("AmneziaVPNNetworkExtension" PROPERTIES + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK" +) + +find_library(FW_ASSETS_LIBRARY AssetsLibrary) +find_library(FW_MOBILE_CORE MobileCoreServices) +find_library(FW_UI_KIT UIKit) +find_library(FW_LIBRESOLV libresolv.9.tbd) + + +# Set the root directory +set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) + +target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${FW_LIBRESOLV}) + +target_compile_options(AmneziaVPNNetworkExtension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\") +target_compile_options(AmneziaVPNNetworkExtension PRIVATE -DNETWORK_EXTENSION=1) + +set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/amneziawg-apple/Sources) + +message("WG_APPLE_SOURCE_DIR is: ${WG_APPLE_SOURCE_DIR}") +message("CLIENT_ROOT_DIR is: ${CLIENT_ROOT_DIR}") + +target_sources(AmneziaVPNNetworkExtension PRIVATE + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/PacketTunnelSettingsGenerator.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSResolver.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardNetworkExtension/ErrorNotifier.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Keychain.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Model/TunnelConfiguration+WgQuickConfig.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Model/NETunnelProviderProtocol+Extension.swift + ${WG_APPLE_SOURCE_DIR}/Shared/Model/String+ArrayConversion.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/TunnelConfiguration.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddressRange.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/Endpoint.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSServer.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/InterfaceConfiguration.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/PeerConfiguration.swift + ${WG_APPLE_SOURCE_DIR}/Shared/FileManager+Extension.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/Array+ConcurrentMap.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddress+AddrInfo.swift + ${WG_APPLE_SOURCE_DIR}/WireGuardKit/PrivateKey.swift + ${CLIENT_ROOT_DIR}/platforms/ios/HevSocksTunnel.swift + ${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift + ${CLIENT_ROOT_DIR}/platforms/ios/Log.swift + ${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+WireGuard.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPN.swift + ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+Xray.swift + ${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift + ${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm + ${CLIENT_ROOT_DIR}/platforms/ios/XrayConfig.swift +) + +target_sources(AmneziaVPNNetworkExtension PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy +) + +set_property(TARGET AmneziaVPNNetworkExtension APPEND PROPERTY RESOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy +) + +## Build wireguard-go-version.h +execute_process( + COMMAND go list -m golang.zx2c4.com/wireguard + WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo + OUTPUT_VARIABLE WG_VERSION_FULL +) +string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h) +target_sources(AmneziaVPNNetworkExtension PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h) + +target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}) +target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/macos/universal2/libwg-go.a) + +message(${CLIENT_ROOT_DIR}) +message(${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a) +target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a) + +target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/Headers) diff --git a/client/macos/networkextension/Info.plist b/client/macos/networkextension/Info.plist.in similarity index 63% rename from client/macos/networkextension/Info.plist rename to client/macos/networkextension/Info.plist.in index 96d82459..fa307001 100644 --- a/client/macos/networkextension/Info.plist +++ b/client/macos/networkextension/Info.plist.in @@ -3,27 +3,32 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - AmneziaVPNNetworkExtension + en CFBundleExecutable - $(EXECUTABLE_NAME) + AmneziaVPNNetworkExtension + CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) + org.amnezia.AmneziaVPN.network-extension CFBundleInfoDictionaryVersion 6.0 CFBundleName - $(PRODUCT_NAME) + AmneziaVPNNetworkExtension CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - $(MARKETING_VERSION) + ${APPLE_PROJECT_VERSION} CFBundleVersion - $(CURRENT_PROJECT_VERSION) + ${CMAKE_PROJECT_VERSION_TWEAK} + ITSAppUsesNonExemptEncryption + LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) + ${CMAKE_OSX_DEPLOYMENT_TARGET} + + CFBundleDisplayName + AmneziaVPNNetworkExtension + NSExtension NSExtensionPointIdentifier @@ -31,5 +36,11 @@ NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).PacketTunnelProvider + + com.wireguard.ios.app_group_id + group.org.amnezia.AmneziaVPN + + com.wireguard.macos.app_group_id + ${BUILD_VPN_DEVELOPMENT_TEAM}.group.org.amnezia.AmneziaVPN diff --git a/client/macos/networkextension/PrivacyInfo.xcprivacy b/client/macos/networkextension/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..380e0b7b --- /dev/null +++ b/client/macos/networkextension/PrivacyInfo.xcprivacy @@ -0,0 +1,25 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + diff --git a/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h b/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h index 4ae7bded..12bf89be 100644 --- a/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h +++ b/client/macos/networkextension/WireGuardNetworkExtension-Bridging-Header.h @@ -1,10 +1,10 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "macos/gobridge/wireguard.h" + #include "wireguard-go-version.h" -#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h" +#include "3rd/amneziawg-apple/Sources/WireGuardKitGo/wireguard.h" +#include "3rd/amneziawg-apple/Sources/WireGuardKitC/WireGuardKitC.h" #include #include @@ -23,3 +23,8 @@ bool key_from_hex(uint8_t key[WG_KEY_LEN], const char* hex); bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]); void write_msg_to_log(const char* tag, const char* msg); + +// init function definition in C +void hev_socks5_tunnel_quit(void); +// Updated function definition in C +int hev_socks5_tunnel_main(const char* configFile, int fd); diff --git a/client/macos/networkextension/wireguard-go-version.h.in b/client/macos/networkextension/wireguard-go-version.h.in new file mode 100644 index 00000000..860bc3c3 --- /dev/null +++ b/client/macos/networkextension/wireguard-go-version.h.in @@ -0,0 +1,3 @@ +#ifndef WIREGUARD_GO_VERSION +#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@" +#endif // WIREGUARD_GO_VERSION \ No newline at end of file diff --git a/client/main.cpp b/client/main.cpp index aca9e62b..40af3f7e 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -15,7 +15,7 @@ #include "platforms/ios/QtAppDelegate-C-Interface.h" #endif -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) bool isAnotherInstanceRunning() { QLocalSocket socket; @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) AmneziaApplication app(argc, argv); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) if (isAnotherInstanceRunning()) { QTimer::singleShot(1000, &app, [&]() { app.quit(); }); return app.exec(); diff --git a/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift b/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift index 3e0a4a07..bfd1165f 100644 --- a/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift +++ b/client/platforms/ios/PacketTunnelProvider+OpenVPN.swift @@ -73,7 +73,7 @@ extension PacketTunnelProvider { startHandler = completionHandler ovpnAdapter?.connect(using: packetFlow) } - + func handleOpenVPNStatusMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) { guard let completionHandler = completionHandler else { return } let bytesin = ovpnAdapter?.transportStatistics.bytesIn diff --git a/client/platforms/ios/PacketTunnelProvider+WireGuard.swift b/client/platforms/ios/PacketTunnelProvider+WireGuard.swift index 18200c7f..5d6e66de 100644 --- a/client/platforms/ios/PacketTunnelProvider+WireGuard.swift +++ b/client/platforms/ios/PacketTunnelProvider+WireGuard.swift @@ -112,9 +112,19 @@ extension PacketTunnelProvider { } } + let lastHandshakeString = settingsDictionary["last_handshake_time_sec"] + let lastHandshake: Int64 + + if let lastHandshakeValue = lastHandshakeString, let handshakeValue = Int64(lastHandshakeValue) { + lastHandshake = handshakeValue + } else { + lastHandshake = -2 // Return an error if there is no value for `last_handshake_time_sec` + } + let response: [String: Any] = [ "rx_bytes": settingsDictionary["rx_bytes"] ?? "0", - "tx_bytes": settingsDictionary["tx_bytes"] ?? "0" + "tx_bytes": settingsDictionary["tx_bytes"] ?? "0", + "last_handshake_time_sec": lastHandshake ] completionHandler(try? JSONSerialization.data(withJSONObject: response, options: [])) diff --git a/client/platforms/ios/QRCodeReaderBase.mm b/client/platforms/ios/QRCodeReaderBase.mm index af879e2f..963c35a8 100644 --- a/client/platforms/ios/QRCodeReaderBase.mm +++ b/client/platforms/ios/QRCodeReaderBase.mm @@ -1,3 +1,4 @@ +#if !MACOS_NE #include "QRCodeReaderBase.h" #import @@ -108,3 +109,19 @@ void QRCodeReader::startReading() { void QRCodeReader::stopReading() { [m_qrCodeReader stopReading]; } +#else +#include "QRCodeReaderBase.h" + +QRCodeReader::QRCodeReader() +{ + +} + +QRect QRCodeReader::cameraSize() { + return QRect(); +} + +void QRCodeReader::startReading() {} +void QRCodeReader::stopReading() {} +void QRCodeReader::setCameraSize(QRect) {} +#endif diff --git a/client/platforms/ios/QtAppDelegate.h b/client/platforms/ios/QtAppDelegate.h index c2c1d2d3..1668f4c3 100644 --- a/client/platforms/ios/QtAppDelegate.h +++ b/client/platforms/ios/QtAppDelegate.h @@ -1,5 +1,6 @@ +#if !MACOS_NE #import - +#endif @interface QIOSApplicationDelegate @end diff --git a/client/platforms/ios/QtAppDelegate.mm b/client/platforms/ios/QtAppDelegate.mm index bd7ad6b1..64ee9425 100644 --- a/client/platforms/ios/QtAppDelegate.mm +++ b/client/platforms/ios/QtAppDelegate.mm @@ -5,7 +5,7 @@ @implementation QIOSApplicationDelegate (AmneziaVPNDelegate) - +#if !MACOS_NE - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum]; @@ -57,5 +57,5 @@ } return NO; } - +#endif @end diff --git a/client/platforms/ios/ScreenProtection.swift b/client/platforms/ios/ScreenProtection.swift index 200cf0cb..98758f30 100644 --- a/client/platforms/ios/ScreenProtection.swift +++ b/client/platforms/ios/ScreenProtection.swift @@ -1,3 +1,13 @@ +#if MACOS_NE +public func toggleScreenshots(_ isEnabled: Bool) { + +} + +class ScreenProtection { + + +} +#else import UIKit public func toggleScreenshots(_ isEnabled: Bool) { @@ -90,3 +100,4 @@ struct ProtectionPair { textField.removeFromSuperview() } } +#endif diff --git a/client/platforms/ios/ios_controller.h b/client/platforms/ios/ios_controller.h index 85580769..7e815bde 100644 --- a/client/platforms/ios/ios_controller.h +++ b/client/platforms/ios/ios_controller.h @@ -46,6 +46,7 @@ public: void disconnectVpn(); void vpnStatusDidChange(void *pNotification); + void vpnConfigurationDidChange(void *pNotification); void getBackendLogs(std::function &&callback); diff --git a/client/platforms/ios/ios_controller.mm b/client/platforms/ios/ios_controller.mm index e64c6dce..b57f8d1d 100644 --- a/client/platforms/ios/ios_controller.mm +++ b/client/platforms/ios/ios_controller.mm @@ -27,6 +27,7 @@ const char* MessageKey::isOnDemand = "is-on-demand"; const char* MessageKey::SplitTunnelType = "SplitTunnelType"; const char* MessageKey::SplitTunnelSites = "SplitTunnelSites"; +#if !MACOS_NE static UIViewController* getViewController() { NSArray *windows = [[UIApplication sharedApplication]windows]; for (UIWindow *window in windows) { @@ -36,6 +37,7 @@ static UIViewController* getViewController() { } return nil; } +#endif Vpn::ConnectionState iosStatusToState(NEVPNStatus status) { switch (status) { @@ -249,6 +251,21 @@ void IosController::checkStatus() sendVpnExtensionMessage(message, [&](NSDictionary* response){ uint64_t txBytes = [response[@"tx_bytes"] intValue]; uint64_t rxBytes = [response[@"rx_bytes"] intValue]; + + uint64_t last_handshake_time_sec = 0; +#if !MACOS_NE + if (response[@"last_handshake_time_sec"] && ![response[@"last_handshake_time_sec"] isKindOfClass:[NSNull class]]) { + last_handshake_time_sec = [response[@"last_handshake_time_sec"] intValue]; + } else { + qDebug() << "Key last_handshake_time_sec is missing or null"; + } + + if (last_handshake_time_sec < 0) { + disconnectVpn(); + qDebug() << "Invalid handshake time, disconnecting VPN."; + } +#endif + emit bytesChanged(rxBytes - m_rxBytes, txBytes - m_txBytes); m_rxBytes = rxBytes; m_txBytes = txBytes; @@ -803,14 +820,14 @@ bool IosController::shareText(const QStringList& filesToSend) { NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()]; [sharingItems addObject:logFileUrl]; } - +#if !MACOS_NE UIViewController *qtController = getViewController(); if (!qtController) return; UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil]; - +#endif __block bool isAccepted = false; - +#if !MACOS_NE [activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) { isAccepted = completed; emit finished(); @@ -823,6 +840,7 @@ bool IosController::shareText(const QStringList& filesToSend) { popController.sourceRect = CGRectMake(100, 100, 100, 100); } +#endif QEventLoop wait; QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit); wait.exec(); @@ -831,6 +849,7 @@ bool IosController::shareText(const QStringList& filesToSend) { } QString IosController::openFile() { +#if !MACOS_NE UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen]; DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init]; @@ -841,8 +860,9 @@ QString IosController::openFile() { [qtController presentViewController:documentPicker animated:YES completion:nil]; +#endif __block QString filePath; - +#if !MACOS_NE documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) { if (path) { filePath = QString::fromUtf8(path.UTF8String); @@ -851,7 +871,7 @@ QString IosController::openFile() { } emit finished(); }; - +#endif QEventLoop wait; QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit); wait.exec(); diff --git a/client/platforms/ios/ios_controller_wrapper.h b/client/platforms/ios/ios_controller_wrapper.h index f0333d77..ab325154 100644 --- a/client/platforms/ios/ios_controller_wrapper.h +++ b/client/platforms/ios/ios_controller_wrapper.h @@ -1,7 +1,11 @@ #import #import #import + +#if !MACOS_NE #include +#endif + #include class IosController; @@ -17,9 +21,10 @@ class IosController; @end typedef void (^DocumentPickerClosedCallback)(NSString *path); - +#if !MACOS_NE @interface DocumentPickerDelegate : NSObject @property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback; @end +#endif diff --git a/client/platforms/ios/ios_controller_wrapper.mm b/client/platforms/ios/ios_controller_wrapper.mm index 1f8c938f..38eb2d22 100644 --- a/client/platforms/ios/ios_controller_wrapper.mm +++ b/client/platforms/ios/ios_controller_wrapper.mm @@ -26,7 +26,8 @@ @end -@implementation DocumentPickerDelegate +#if !MACOS_NE +@implementation DocumentPickerDelegate - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray *)urls { for (NSURL *url in urls) { @@ -42,4 +43,5 @@ } } -@end \ No newline at end of file +@end +#endif diff --git a/client/platforms/ios/iosnotificationhandler.mm b/client/platforms/ios/iosnotificationhandler.mm index efa48385..773c6297 100644 --- a/client/platforms/ios/iosnotificationhandler.mm +++ b/client/platforms/ios/iosnotificationhandler.mm @@ -6,6 +6,8 @@ #import #import + +#if !MACOS_NE #import @interface IOSNotificationDelegate @@ -87,3 +89,86 @@ void IOSNotificationHandler::notify(NotificationHandler::Message type, const QSt } }]; } +#else + +// Removed the UIResponder and UIApplicationDelegate references as these are not available in macOS +@interface IOSNotificationDelegate + : NSObject { + IOSNotificationHandler* m_iosNotificationHandler; +} +@end + +@implementation IOSNotificationDelegate + +- (id)initWithObject:(IOSNotificationHandler*)notification { + self = [super init]; // Removed `super init` as it refers to UIResponder, which is iOS specific + if (self) { + m_iosNotificationHandler = notification; + } + return self; +} + +- (void)userNotificationCenter:(UNUserNotificationCenter*)center + willPresentNotification:(UNNotification*)notification + withCompletionHandler: + (void (^)(UNNotificationPresentationOptions options))completionHandler { + Q_UNUSED(center) + completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner); +} + +- (void)userNotificationCenter:(UNUserNotificationCenter*)center + didReceiveNotificationResponse:(UNNotificationResponse*)response + withCompletionHandler:(void (^)())completionHandler { + Q_UNUSED(center) + Q_UNUSED(response) + completionHandler(); +} +@end + +IOSNotificationHandler::IOSNotificationHandler(QObject* parent) : NotificationHandler(parent) { + + UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; + [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | + UNAuthorizationOptionBadge) + completionHandler:^(BOOL granted, NSError* _Nullable error) { + Q_UNUSED(granted); + if (!error) { + m_delegate = [[IOSNotificationDelegate alloc] initWithObject:this]; + } + }]; +} + +IOSNotificationHandler::~IOSNotificationHandler() { } + +void IOSNotificationHandler::notify(NotificationHandler::Message type, const QString& title, + const QString& message, int timerMsec) { + Q_UNUSED(type); + + if (!m_delegate) { + return; + } + + UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init]; + content.title = title.toNSString(); + content.body = message.toNSString(); + content.sound = [UNNotificationSound defaultSound]; + + int timerSec = timerMsec / 1000; + UNTimeIntervalNotificationTrigger* trigger = + [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timerSec repeats:NO]; + + UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"amneziavpn" + content:content + trigger:trigger]; + + UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; + center.delegate = (id)m_delegate; + + [center addNotificationRequest:request + withCompletionHandler:^(NSError* _Nullable error) { + if (error) { + NSLog(@"Local Notification failed"); + } + }]; +} +#endif diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index b4cbb6de..53432294 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -192,7 +192,7 @@ namespace amnezia constexpr char defaultPort[] = "51820"; -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) constexpr char defaultMtu[] = "1280"; #else constexpr char defaultMtu[] = "1376"; @@ -212,7 +212,7 @@ namespace amnezia namespace awg { constexpr char defaultPort[] = "55424"; -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) constexpr char defaultMtu[] = "1280"; #else constexpr char defaultMtu[] = "1376"; diff --git a/client/protocols/vpnprotocol.cpp b/client/protocols/vpnprotocol.cpp index 056089b8..4b3edca5 100644 --- a/client/protocols/vpnprotocol.cpp +++ b/client/protocols/vpnprotocol.cpp @@ -4,7 +4,7 @@ #include "core/errorstrings.h" #include "vpnprotocol.h" -#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) +#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) #include "openvpnovercloakprotocol.h" #include "openvpnprotocol.h" #include "shadowsocksvpnprotocol.h" @@ -109,7 +109,7 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject & #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)) +#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (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); diff --git a/client/ui/controllers/connectionController.cpp b/client/ui/controllers/connectionController.cpp index 9fc60493..c85367da 100644 --- a/client/ui/controllers/connectionController.cpp +++ b/client/ui/controllers/connectionController.cpp @@ -1,6 +1,6 @@ #include "connectionController.h" -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -32,8 +32,9 @@ ConnectionController::ConnectionController(const QSharedPointer &s void ConnectionController::openConnection() { -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) { +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) + if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) + { emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning); return; } diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index ea1d5d8e..33d95e8c 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -19,7 +19,7 @@ #ifdef Q_OS_ANDROID #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include #endif @@ -595,7 +595,7 @@ void ImportController::startDecodingQr() m_totalQrCodeChunksCount = 0; m_receivedQrCodeChunksCount = 0; - #if defined Q_OS_IOS + #if defined(Q_OS_IOS) || defined(MACOS_NE) m_isQrCodeProcessed = true; #endif #if defined Q_OS_ANDROID diff --git a/client/ui/controllers/pageController.cpp b/client/ui/controllers/pageController.cpp index d515df49..38c75346 100644 --- a/client/ui/controllers/pageController.cpp +++ b/client/ui/controllers/pageController.cpp @@ -1,8 +1,11 @@ #include "pageController.h" #include "utils/converter.h" #include "core/errorstrings.h" +#if defined(MACOS_NE) +#include "platforms/ios/ios_controller.h" +#endif -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE) #include #else #include @@ -25,8 +28,12 @@ PageController::PageController(const QSharedPointer &serversModel, #endif #if defined Q_OS_MACX - connect(this, &PageController::raiseMainWindow, []() { setDockIconVisible(true); }); - connect(this, &PageController::hideMainWindow, []() { setDockIconVisible(false); }); + connect(this, &PageController::raiseMainWindow, []() { + setDockIconVisible(true); + }); + connect(this, &PageController::hideMainWindow, []() { + setDockIconVisible(false); + }); #endif connect(this, qOverload(&PageController::showErrorMessage), this, &PageController::onShowErrorMessage); @@ -56,14 +63,11 @@ QString PageController::getPagePath(PageLoader::PageEnum page) void PageController::closeWindow() { -#ifdef Q_OS_ANDROID +// On mobile platforms, quit app on close; on desktop, just hide window +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) qApp->quit(); #else - if (m_serversModel->getServersCount() == 0) { - qApp->quit(); - } else { - emit hideMainWindow(); - } + emit hideMainWindow(); #endif } @@ -114,7 +118,7 @@ void PageController::showOnStartup() } else { #if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) emit hideMainWindow(); -#elif defined Q_OS_MACX +#elif defined(Q_OS_MACX) setDockIconVisible(false); #endif } diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index 25de134e..2e3dfa30 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -10,7 +10,7 @@ #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include #endif @@ -93,7 +93,7 @@ bool SettingsController::isLoggingEnabled() void SettingsController::toggleLogging(bool enable) { m_settings->setSaveLogs(enable); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) AmneziaVPN::toggleLogging(enable); #endif if (enable == true) { @@ -157,8 +157,12 @@ void SettingsController::backupAppConfig(const QString &fileName) void SettingsController::restoreAppConfig(const QString &fileName) { - QByteArray data; - SystemController::readFile(fileName, data); + QFile file(fileName); + + file.open(QIODevice::ReadOnly); + + QByteArray data = file.readAll(); + restoreAppConfigFromData(data); } @@ -237,7 +241,7 @@ void SettingsController::clearSettings() emit changeSettingsFinished(tr("All settings have been reset to default values")); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) AmneziaVPN::clearSettings(); #endif } diff --git a/client/ui/controllers/systemController.cpp b/client/ui/controllers/systemController.cpp index 52ca1294..12b86990 100644 --- a/client/ui/controllers/systemController.cpp +++ b/client/ui/controllers/systemController.cpp @@ -14,7 +14,7 @@ #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include "platforms/ios/ios_controller.h" #include #endif @@ -58,8 +58,10 @@ void SystemController::saveFile(const QString &fileName, const QString &data) const auto url = fi.absoluteDir().absolutePath(); #endif +#ifndef MACOS_NE QDesktopServices::openUrl(url); #endif +#endif } bool SystemController::readFile(const QString &fileName, QByteArray &data) diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index 22813312..b53e70f7 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -4,7 +4,7 @@ #include "core/controllers/serverController.h" #include "core/networkUtilities.h" -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include #endif @@ -782,7 +782,7 @@ void ServersModel::removeApiConfig(const int serverIndex) { auto serverConfig = getServerConfig(serverIndex); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) QString vpncName = QString("%1 (%2) %3") .arg(serverConfig[config_key::description].toString()) .arg(serverConfig[config_key::hostName].toString()) diff --git a/client/ui/ne_notificationhandler.h b/client/ui/ne_notificationhandler.h new file mode 100644 index 00000000..e84d8068 --- /dev/null +++ b/client/ui/ne_notificationhandler.h @@ -0,0 +1,36 @@ +#ifndef NE_NOTIFICATION_HANDLER_H +#define NE_NOTIFICATION_HANDLER_H + +#include "notificationhandler.h" +#include +#include + +class MacOSStatusIcon; + +class NEStatusBarNotificationHandler : public NotificationHandler { + Q_OBJECT +public: + explicit NEStatusBarNotificationHandler(QObject* parent); + ~NEStatusBarNotificationHandler() override; + + void setConnectionState(Vpn::ConnectionState state) override; + void onTranslationsUpdated() override; + +protected: + void notify(Message type, const QString& title, + const QString& message, int timerMsec) override; + +private: + void buildMenu(); + + QMenu m_menu; + MacOSStatusIcon* m_statusIcon; + + QAction* m_actionShow; + QAction* m_actionConnect; + QAction* m_actionDisconnect; + QAction* m_actionVisitWebsite; + QAction* m_actionQuit; +}; + +#endif // NE_NOTIFICATION_HANDLER_H diff --git a/client/ui/notificationhandler.cpp b/client/ui/notificationhandler.cpp index 5efb45c4..4ccdcdf1 100644 --- a/client/ui/notificationhandler.cpp +++ b/client/ui/notificationhandler.cpp @@ -11,18 +11,12 @@ # include "systemtray_notificationhandler.h" #endif + // static NotificationHandler* NotificationHandler::create(QObject* parent) { #if defined(Q_OS_IOS) return new IOSNotificationHandler(parent); #else - -# if defined(Q_OS_LINUX) - //if (LinuxSystemTrayNotificationHandler::requiredCustomImpl()) { - // return new LinuxSystemTrayNotificationHandler(parent); - //} -# endif - return new SystemTrayNotificationHandler(parent); #endif } diff --git a/client/ui/qml/Pages2/PageSettingsApplication.qml b/client/ui/qml/Pages2/PageSettingsApplication.qml index 981bbecb..9718f819 100644 --- a/client/ui/qml/Pages2/PageSettingsApplication.qml +++ b/client/ui/qml/Pages2/PageSettingsApplication.qml @@ -140,7 +140,7 @@ PageType { } DividerType { - visible: !GC.isMobile() + visible: !GC.isMobile() && !IsMacOsNeBuild } SwitcherType { diff --git a/client/ui/qml/Pages2/PageSettingsLogging.qml b/client/ui/qml/Pages2/PageSettingsLogging.qml index fda58175..1359ecdf 100644 --- a/client/ui/qml/Pages2/PageSettingsLogging.qml +++ b/client/ui/qml/Pages2/PageSettingsLogging.qml @@ -165,7 +165,11 @@ PageType { } } - property list logTypes: [ + // Show service logs only if this is NOT a macOS build with + // Network-Extension (IsMacOsNeBuild is injected from C++ at run-time) + property list logTypes: IsMacOsNeBuild ? [ + clientLogs + ] : [ clientLogs, serviceLogs ] @@ -204,7 +208,7 @@ PageType { readonly property string title: qsTr("Service logs") readonly property string description: qsTr("AmneziaVPN-service logs") - readonly property bool isVisible: !GC.isMobile() + readonly property bool isVisible: !GC.isMobile() && !IsMacOsNeBuild readonly property var openLogsHandler: function() { SettingsController.openServiceLogsFolder() } diff --git a/client/ui/qml/main2.qml b/client/ui/qml/main2.qml index 7cd5790b..69c244d3 100644 --- a/client/ui/qml/main2.qml +++ b/client/ui/qml/main2.qml @@ -26,7 +26,8 @@ Window { color: AmneziaStyle.color.midnightBlack - onClosing: function() { + onClosing: function(close) { + close.accepted = false PageController.closeWindow() } diff --git a/client/ui/systemtray_notificationhandler.cpp b/client/ui/systemtray_notificationhandler.cpp index edb65530..11a1b651 100644 --- a/client/ui/systemtray_notificationhandler.cpp +++ b/client/ui/systemtray_notificationhandler.cpp @@ -38,9 +38,11 @@ SystemTrayNotificationHandler::SystemTrayNotificationHandler(QObject* parent) : QDesktopServices::openUrl(QUrl(websiteUrl)); }); - m_trayActionQuit = m_menu.addAction(QIcon(":/images/tray/cancel.png"), tr("Quit") + " " + APPLICATION_NAME, this, [&](){ - qApp->quit(); - }); + // Quit action: disconnect VPN first on macOS NE, else quit directly + m_trayActionQuit = m_menu.addAction(QIcon(":/images/tray/cancel.png"), + tr("Quit") + " " + APPLICATION_NAME, + this, + [&](){ qApp->quit(); }); m_systemTrayIcon.setContextMenu(&m_menu); setTrayState(Vpn::ConnectionState::Disconnected); diff --git a/client/utilities.cpp b/client/utilities.cpp index 61944e51..51a9885a 100755 --- a/client/utilities.cpp +++ b/client/utilities.cpp @@ -190,7 +190,7 @@ bool Utils::processIsRunning(const QString &fileName, const bool fullFlag) CloseHandle(hSnapshot); return false; -#elif defined(Q_OS_IOS) || defined(Q_OS_ANDROID) +#elif defined(Q_OS_IOS) || defined(Q_OS_ANDROID) || defined(MACOS_NE) return false; #else QProcess process; diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 139dc3c3..f1a6cee1 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -22,7 +22,7 @@ #include "platforms/android/android_controller.h" #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) #include "platforms/ios/ios_controller.h" #endif @@ -33,7 +33,7 @@ VpnConnection::VpnConnection(std::shared_ptr settings, QObject *parent : QObject(parent), m_settings(settings), m_checkTimer(new QTimer(this)) { m_checkTimer.setInterval(1000); -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) connect(IosController::Instance(), &IosController::connectionStateChanged, this, &VpnConnection::onConnectionStateChanged); connect(IosController::Instance(), &IosController::bytesChanged, this, &VpnConnection::onBytesChanged); @@ -122,7 +122,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) } #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) if (state == Vpn::ConnectionState::Connected) { m_checkTimer.start(); } else { @@ -236,10 +236,11 @@ ErrorCode VpnConnection::lastError() const void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration) { - qDebug() << QString("Trying to connect to VPN, server index is %1, container is %2") + qDebug() << QString("ConnectToVpn, Server index is %1, container is %2, route mode is") .arg(serverIndex) - .arg(ContainerProps::containerToString(container)); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) + .arg(ContainerProps::containerToString(container)) + << m_settings->routeMode(); +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) if (!m_IpcClient) { m_IpcClient = new IpcClient(this); } @@ -270,7 +271,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede appendSplitTunnelingConfig(); -#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration)); if (!m_vpnProtocol) { emit connectionStateChanged(Vpn::ConnectionState::Error); @@ -282,7 +283,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede createAndroidConnections(); m_vpnProtocol.reset(androidVpnProtocol); -#elif defined Q_OS_IOS +#elif defined Q_OS_IOS || defined(MACOS_NE) Proto proto = ContainerProps::defaultProtocol(container); IosController::Instance()->connectVpn(proto, m_vpnConfiguration); connect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus); @@ -362,20 +363,20 @@ void VpnConnection::appendSplitTunnelingConfig() } } - Settings::RouteMode sitesRouteMode = Settings::RouteMode::VpnAllSites; + Settings::RouteMode routeMode = Settings::RouteMode::VpnAllSites; QJsonArray sitesJsonArray; if (m_settings->isSitesSplitTunnelingEnabled()) { - sitesRouteMode = m_settings->routeMode(); + routeMode = m_settings->routeMode(); if (allowSiteBasedSplitTunneling) { - auto sites = m_settings->getVpnIps(sitesRouteMode); + auto sites = m_settings->getVpnIps(routeMode); for (const auto &site : sites) { sitesJsonArray.append(site); } if (sitesJsonArray.isEmpty()) { - sitesRouteMode = Settings::RouteMode::VpnAllSites; - } else if (sitesRouteMode == Settings::VpnOnlyForwardSites) { + routeMode = Settings::RouteMode::VpnAllSites; + } else if (routeMode == Settings::VpnOnlyForwardSites) { // Allow traffic to Amnezia DNS sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString()); sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString()); @@ -383,7 +384,7 @@ void VpnConnection::appendSplitTunnelingConfig() } } - m_vpnConfiguration.insert(config_key::splitTunnelType, sitesRouteMode); + m_vpnConfiguration.insert(config_key::splitTunnelType, routeMode); m_vpnConfiguration.insert(config_key::splitTunnelSites, sitesJsonArray); Settings::AppsRouteMode appsRouteMode = Settings::AppsRouteMode::VpnAllApps; @@ -403,13 +404,6 @@ void VpnConnection::appendSplitTunnelingConfig() m_vpnConfiguration.insert(config_key::appSplitTunnelType, appsRouteMode); m_vpnConfiguration.insert(config_key::splitTunnelApps, appsJsonArray); - - qDebug() << QString("Site split tunneling is %1, route mode is %2") - .arg(m_settings->isSitesSplitTunnelingEnabled() ? "enabled" : "disabled") - .arg(sitesRouteMode); - qDebug() << QString("App split tunneling is %1, route mode is %2") - .arg(m_settings->isAppsSplitTunnelingEnabled() ? "enabled" : "disabled") - .arg(appsRouteMode); } #ifdef Q_OS_ANDROID @@ -471,7 +465,7 @@ void VpnConnection::disconnectFromVpn() } #endif -#ifdef Q_OS_IOS +#if defined(Q_OS_IOS) || defined(MACOS_NE) IosController::Instance()->disconnectVpn(); disconnect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus); #endif diff --git a/deploy/build_ios.sh b/deploy/build_ios.sh index 5dc11ff1..7619e146 100755 --- a/deploy/build_ios.sh +++ b/deploy/build_ios.sh @@ -32,7 +32,7 @@ cmake --version clang -v # Generate XCodeProj -$QT_BIN_DIR/qt-cmake . -B $BUILD_DIR -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR +$QT_BIN_DIR/qt-cmake . -B $BUILD_DIR -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR -DDEPLOY=ON KEYCHAIN=amnezia.build.ios.keychain KEYCHAIN_FILE=$HOME/Library/Keychains/${KEYCHAIN}-db diff --git a/deploy/build_macos_ne.sh b/deploy/build_macos_ne.sh new file mode 100755 index 00000000..fd3e0b74 --- /dev/null +++ b/deploy/build_macos_ne.sh @@ -0,0 +1,122 @@ +#!/bin/bash +echo "Build script for macOS Network Extension started ..." + +set -o errexit -o nounset + +while getopts n flag +do + case "${flag}" in + n) NOTARIZE_APP=1;; + esac +done + +# Hold on to current directory +PROJECT_DIR=$(pwd) +DEPLOY_DIR=$PROJECT_DIR/deploy + +mkdir -p $DEPLOY_DIR/build-macos +BUILD_DIR=$DEPLOY_DIR/build-macos + +echo "Project dir: ${PROJECT_DIR}" +echo "Build dir: ${BUILD_DIR}" + +APP_NAME=AmneziaVPN +APP_FILENAME=$APP_NAME.app +APP_DOMAIN=org.amneziavpn.package +PLIST_NAME=$APP_NAME.plist + +OUT_APP_DIR=$BUILD_DIR/client +BUNDLE_DIR=$OUT_APP_DIR/$APP_FILENAME + +PREBUILT_DEPLOY_DATA_DIR=$PROJECT_DIR/deploy/data/deploy-prebuilt/macos +DEPLOY_DATA_DIR=$PROJECT_DIR/deploy/data/macos + +INSTALLER_DATA_DIR=$BUILD_DIR/installer/packages/$APP_DOMAIN/data +INSTALLER_BUNDLE_DIR=$BUILD_DIR/installer/$APP_FILENAME +DMG_FILENAME=$PROJECT_DIR/${APP_NAME}.dmg + +echo "Import certificate" + +TRUST_CERT_CER=$BUILD_DIR/trust-cert.cer +SIGNING_CERT_P12=$BUILD_DIR/signing-cert.p12 + +echo $MAC_TRUST_CERT_BASE64 | base64 --decode > $TRUST_CERT_CER +echo $MAC_SIGNING_CERT_BASE64 | base64 --decode > $SIGNING_CERT_P12 + +shasum -a 256 $TRUST_CERT_CER +shasum -a 256 $SIGNING_CERT_P12 +KEYCHAIN_PASS=$MAC_SIGNING_CERT_PASSWORD + +# Keychain setup +KEYCHAIN=amnezia.build.macos.keychain +TEMP_PASS=tmp_pass +KEYCHAIN_FILE=$HOME/Library/Keychains/$KEYCHAIN-db + +security create-keychain -p $TEMP_PASS $KEYCHAIN || true +security default-keychain -s $KEYCHAIN +security unlock-keychain -p $TEMP_PASS $KEYCHAIN + +security default-keychain +security list-keychains + +# Import certificates into keychain +security import $TRUST_CERT_CER -k $KEYCHAIN -P "" -T /usr/bin/codesign || true +security import $SIGNING_CERT_P12 -k $KEYCHAIN -P $MAC_SIGNING_CERT_PASSWORD -T /usr/bin/codesign || true + +# Configure keychain settings +security set-key-partition-list -S apple-tool:,apple: -k $TEMP_PASS $KEYCHAIN +security find-identity -p codesigning + +# Setup provisioning profiles for main app and NE +echo "Setting up provisioning profiles..." + +# Copy provisioning prifiles +mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles/" + +echo $MAC_APP_PROVISIONING_PROFILE | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision +echo $MAC_NE_PROVISIONING_PROFILE | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision + +shasum -a 256 ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision +shasum -a 256 ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision + +profile_uuid=`grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision | grep -io "[-A-F0-9]\{36\}"` +echo $profile_uuid +profile_ne_uuid=`grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision | grep -io "[-A-F0-9]\{36\}"` +echo $profile_ne_uuid + +mv ~/Library/MobileDevice/Provisioning\ Profiles/app.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$profile_uuid.mobileprovision +mv ~/Library/MobileDevice/Provisioning\ Profiles/ne.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$profile_ne_uuid.mobileprovision + +# setup environment +QT_MACOS_BIN=$QT_BIN_DIR +export PATH=$PATH:~/go/bin +echo "QT_BIN_DIR: $QT_BIN_DIR" + + +# Build the Network Extension app +echo "Building MAC Network Extension App..." +mkdir -p build-macos + +$QT_MACOS_BIN/qt-cmake . -B build-macos -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR -DMACOS_NE=TRUE -DCMAKE_BUILD_TYPE=Release -DDEPLOY=ON + +# Build and run tests here + +echo "____________________________________" +echo "............Deploying..............." +echo "____________________________________" +echo "Deploying MAC Network Extension App..." + +echo "xcode build" +xcodebuild \ +"OTHER_CODE_SIGN_FLAGS=--keychain '$KEYCHAIN_FILE'" \ +-configuration Release \ +-scheme AmneziaVPN \ +-destination "platform=macOS" \ +-project $PROJECT_DIR/build-macos/AmneziaVPN.xcodeproj + + +# Restore keychain to default +echo "Restoring default keychain..." +security default-keychain -s "/Users/runner/Library/Keychains/login.keychain-db" + +echo "Build and signing process completed successfully!" \ No newline at end of file diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index 5ed98ab4..517a16be 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -6,6 +6,6 @@ project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(NOT IOS AND NOT ANDROID) +if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE) add_subdirectory(server) endif() From e9d4fd84829661b1b26a0d9316e072e460f3a4cf Mon Sep 17 00:00:00 2001 From: Cyril Anisimov Date: Sun, 10 Aug 2025 05:13:58 +0200 Subject: [PATCH 21/40] fix checkbox switch (#1777) --- client/ui/qml/Controls2/CheckBoxType.qml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/client/ui/qml/Controls2/CheckBoxType.qml b/client/ui/qml/Controls2/CheckBoxType.qml index 451fe01d..4c72a0d1 100644 --- a/client/ui/qml/Controls2/CheckBoxType.qml +++ b/client/ui/qml/Controls2/CheckBoxType.qml @@ -173,15 +173,17 @@ CheckBox { enabled: false } + Keys.onEnterPressed: event => handleSwitch(event) + Keys.onReturnPressed: event => handleSwitch(event) + Keys.onSpacePressed: event => handleSwitch(event) - Keys.onEnterPressed: { - root.checked = !root.checked + function handleSwitch(event) { + if (!event.isAutoRepeat) { + root.checked = !root.checked + root.checkedChanged() + } + event.accepted = true } - - Keys.onReturnPressed: { - root.checked = !root.checked - } - } From 16d92ddb7c526abe49a979bc184c056ddb6280bb Mon Sep 17 00:00:00 2001 From: Nethius Date: Mon, 11 Aug 2025 13:40:28 +0800 Subject: [PATCH 22/40] fix: UI fixes after merge with d20ed4a (#1779) * fix: ui fixes after merge with d20ed4a * update OpenVPN settings page * chore: page settings dns margins --------- Co-authored-by: Cyril Anisimov --- .../Pages2/PageProtocolAwgClientSettings.qml | 2 +- .../ui/qml/Pages2/PageProtocolAwgSettings.qml | 2 +- .../Pages2/PageProtocolOpenVpnSettings.qml | 760 +++++++++--------- .../Pages2/PageProtocolWireGuardSettings.qml | 4 - client/ui/qml/Pages2/PageSettings.qml | 4 - client/ui/qml/Pages2/PageSettingsDns.qml | 18 +- .../ui/qml/Pages2/PageSettingsServerData.qml | 14 +- client/ui/qml/Pages2/PageShareFullAccess.qml | 6 - 8 files changed, 389 insertions(+), 421 deletions(-) diff --git a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml index 18db8119..2db21d49 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml @@ -34,7 +34,7 @@ PageType { ListViewType { id: listView - anchors.top: backButtonLayout.bottom + anchors.top: backButton.bottom anchors.bottom: saveButton.top anchors.right: parent.right anchors.left: parent.left diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index 2140f740..dcf57a37 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -37,7 +37,7 @@ PageType { ListViewType { id: listView - anchors.top: backButtonLayout.bottom + anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right diff --git a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml index 62cbd1f6..d2db90b0 100644 --- a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml @@ -17,428 +17,414 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - - BackButtonType { - id: backButton + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + enabled: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + header: ColumnLayout { + width: listView.width - enabled: ServersModel.isProcessedServerHasWriteAccess() + BaseHeaderType { + id: header - ListView { - id: listview + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 - width: parent.width - height: listview.contentItem.height + headerText: qsTr("OpenVPN Settings") + } + } - clip: true - interactive: false + model: OpenVpnConfigModel - model: OpenVpnConfigModel + delegate: ColumnLayout { + width: listView.width - delegate: Item { - id: delegateItem + spacing: 0 - property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() + TextFieldWithHeaderType { + id: vpnAddressSubnetTextField - implicitWidth: listview.width - implicitHeight: col.implicitHeight + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - ColumnLayout { - id: col + enabled: listView.enabled - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + headerText: qsTr("VPN address subnet") + textField.text: subnetAddress - anchors.leftMargin: 16 - anchors.rightMargin: 16 + textField.onEditingFinished: { + if (textField.text !== subnetAddress) { + subnetAddress = textField.text + } + } - spacing: 0 + checkEmptyText: true + } - BaseHeaderType { - Layout.fillWidth: true - headerText: qsTr("OpenVPN settings") - } + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - TextFieldWithHeaderType { - id: vpnAddressSubnetTextField + text: qsTr("Network protocol") + } - Layout.fillWidth: true - Layout.topMargin: 32 + TransportProtoSelector { + id: transportProtoSelector + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - enabled: delegateItem.isEnabled + rootWidth: root.width - headerText: qsTr("VPN address subnet") - textField.text: subnetAddress + enabled: isTransportProtoEditable - parentFlickable: fl + currentIndex: { + return transportProto === "tcp" ? 1 : 0 + } - textField.onEditingFinished: { - if (textField.text !== subnetAddress) { - subnetAddress = textField.text - } + onCurrentIndexChanged: { + if (transportProto === "tcp" && currentIndex === 0) { + transportProto = "udp" + } else if (transportProto === "udp" && currentIndex === 1) { + transportProto = "tcp" + } + } + } + + TextFieldWithHeaderType { + id: portTextField + + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: listView.enabled + + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } + + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text + } + } + + checkEmptyText: true + } + + SwitcherType { + id: autoNegotiateEncryprionSwitcher + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Auto-negotiate encryption") + checked: autoNegotiateEncryprion + + onCheckedChanged: { + if (checked !== autoNegotiateEncryprion) { + autoNegotiateEncryprion = checked + } + } + } + + DropDownType { + id: hashDropDown + Layout.fillWidth: true + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: !autoNegotiateEncryprionSwitcher.checked + + descriptionText: qsTr("Hash") + headerText: qsTr("Hash") + + drawerParent: root + + listView: ListViewWithRadioButtonType { + id: hashListView + + rootWidth: root.width + + model: ListModel { + ListElement { name : qsTr("SHA512") } + ListElement { name : qsTr("SHA384") } + ListElement { name : qsTr("SHA256") } + ListElement { name : qsTr("SHA3-512") } + ListElement { name : qsTr("SHA3-384") } + ListElement { name : qsTr("SHA3-256") } + ListElement { name : qsTr("whirlpool") } + ListElement { name : qsTr("BLAKE2b512") } + ListElement { name : qsTr("BLAKE2s256") } + ListElement { name : qsTr("SHA1") } + } + + clickedFunction: function() { + hashDropDown.text = selectedText + hash = hashDropDown.text + hashDropDown.closeTriggered() + } + + Component.onCompleted: { + hashDropDown.text = hash + + for (var i = 0; i < hashListView.model.count; i++) { + if (hashListView.model.get(i).name === hashDropDown.text) { + currentIndex = i } - - checkEmptyText: true - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 32 - - text: qsTr("Network protocol") - } - - TransportProtoSelector { - id: transportProtoSelector - Layout.fillWidth: true - Layout.topMargin: 16 - rootWidth: root.width - - enabled: isTransportProtoEditable - - currentIndex: { - return transportProto === "tcp" ? 1 : 0 - } - - onCurrentIndexChanged: { - if (transportProto === "tcp" && currentIndex === 0) { - transportProto = "udp" - } else if (transportProto === "udp" && currentIndex === 1) { - transportProto = "tcp" - } - } - } - - TextFieldWithHeaderType { - id: portTextField - - Layout.fillWidth: true - Layout.topMargin: 40 - parentFlickable: fl - - enabled: delegateItem.isEnabled - - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - - textField.onEditingFinished: { - if (textField.text !== port) { - port = textField.text - } - } - - checkEmptyText: true - } - - SwitcherType { - id: autoNegotiateEncryprionSwitcher - - Layout.fillWidth: true - Layout.topMargin: 24 - parentFlickable: fl - - text: qsTr("Auto-negotiate encryption") - checked: autoNegotiateEncryprion - - onCheckedChanged: { - if (checked !== autoNegotiateEncryprion) { - autoNegotiateEncryprion = checked - } - } - } - - DropDownType { - id: hashDropDown - Layout.fillWidth: true - Layout.topMargin: 20 - - enabled: !autoNegotiateEncryprionSwitcher.checked - - descriptionText: qsTr("Hash") - headerText: qsTr("Hash") - - drawerParent: root - - listView: ListViewWithRadioButtonType { - id: hashListView - - rootWidth: root.width - - model: ListModel { - ListElement { name : qsTr("SHA512") } - ListElement { name : qsTr("SHA384") } - ListElement { name : qsTr("SHA256") } - ListElement { name : qsTr("SHA3-512") } - ListElement { name : qsTr("SHA3-384") } - ListElement { name : qsTr("SHA3-256") } - ListElement { name : qsTr("whirlpool") } - ListElement { name : qsTr("BLAKE2b512") } - ListElement { name : qsTr("BLAKE2s256") } - ListElement { name : qsTr("SHA1") } - } - - clickedFunction: function() { - hashDropDown.text = selectedText - hash = hashDropDown.text - hashDropDown.closeTriggered() - } - - Component.onCompleted: { - hashDropDown.text = hash - - for (var i = 0; i < hashListView.model.count; i++) { - if (hashListView.model.get(i).name === hashDropDown.text) { - currentIndex = i - } - } - } - } - } - - DropDownType { - id: cipherDropDown - Layout.fillWidth: true - Layout.topMargin: 16 - - enabled: !autoNegotiateEncryprionSwitcher.checked - - descriptionText: qsTr("Cipher") - headerText: qsTr("Cipher") - - drawerParent: root - - listView: ListViewWithRadioButtonType { - id: cipherListView - - rootWidth: root.width - - model: ListModel { - ListElement { name : qsTr("AES-256-GCM") } - ListElement { name : qsTr("AES-192-GCM") } - ListElement { name : qsTr("AES-128-GCM") } - ListElement { name : qsTr("AES-256-CBC") } - ListElement { name : qsTr("AES-192-CBC") } - ListElement { name : qsTr("AES-128-CBC") } - ListElement { name : qsTr("ChaCha20-Poly1305") } - ListElement { name : qsTr("ARIA-256-CBC") } - ListElement { name : qsTr("CAMELLIA-256-CBC") } - ListElement { name : qsTr("none") } - } - - clickedFunction: function() { - cipherDropDown.text = selectedText - cipher = cipherDropDown.text - cipherDropDown.closeTriggered() - } - - Component.onCompleted: { - cipherDropDown.text = cipher - - for (var i = 0; i < cipherListView.model.count; i++) { - if (cipherListView.model.get(i).name === cipherDropDown.text) { - currentIndex = i - } - } - } - } - } - - Rectangle { - id: contentRect - Layout.fillWidth: true - Layout.topMargin: 32 - Layout.preferredHeight: checkboxLayout.implicitHeight - color: AmneziaStyle.color.onyxBlack - radius: 16 - - Connections { - target: tlsAuthCheckBox - enabled: !GC.isMobile() - - function onFocusChanged() { - if (tlsAuthCheckBox.activeFocus) { - fl.ensureVisible(contentRect) - } - } - } - - ColumnLayout { - id: checkboxLayout - - anchors.fill: parent - CheckBoxType { - id: tlsAuthCheckBox - Layout.fillWidth: true - - text: qsTr("TLS auth") - checked: tlsAuth - - onCheckedChanged: { - if (checked !== tlsAuth) { - console.log("tlsAuth changed to: " + checked) - tlsAuth = checked - } - } - } - - DividerType {} - - CheckBoxType { - id: blockDnsCheckBox - Layout.fillWidth: true - - text: qsTr("Block DNS requests outside of VPN") - checked: blockDns - - onCheckedChanged: { - if (checked !== blockDns) { - blockDns = checked - } - } - } - } - } - - SwitcherType { - id: additionalClientCommandsSwitcher - Layout.fillWidth: true - Layout.topMargin: 32 - parentFlickable: fl - - checked: additionalClientCommands !== "" - - text: qsTr("Additional client configuration commands") - - onCheckedChanged: { - if (!checked) { - additionalClientCommands = "" - } - } - } - - TextAreaType { - id: additionalClientCommandsTextArea - Layout.fillWidth: true - Layout.topMargin: 16 - - visible: additionalClientCommandsSwitcher.checked - - parentFlickable: fl - - textAreaText: additionalClientCommands - placeholderText: qsTr("Commands:") - - textArea.onEditingFinished: { - if (additionalClientCommands !== textAreaText) { - additionalClientCommands = textAreaText - } - } - } - - SwitcherType { - id: additionalServerCommandsSwitcher - Layout.fillWidth: true - Layout.topMargin: 16 - parentFlickable: fl - - checked: additionalServerCommands !== "" - - text: qsTr("Additional server configuration commands") - - onCheckedChanged: { - if (!checked) { - additionalServerCommands = "" - } - } - } - - TextAreaType { - id: additionalServerCommandsTextArea - Layout.fillWidth: true - Layout.topMargin: 16 - - visible: additionalServerCommandsSwitcher.checked - - textAreaText: additionalServerCommands - placeholderText: qsTr("Commands:") - parentFlickable: fl - textArea.onEditingFinished: { - if (additionalServerCommands !== textAreaText) { - additionalServerCommands = textAreaText - } - } - } - - BasicButtonType { - id: saveButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - enabled: vpnAddressSubnetTextField.errorText === "" && - portTextField.errorText === "" - - text: qsTr("Save") - parentFlickable: fl - - onClicked: function() { - forceActiveFocus() - - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(OpenVpnConfigModel.getConfig()) - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - - Keys.onEnterPressed: saveButton.clicked() - Keys.onReturnPressed: saveButton.clicked() } } } } + + DropDownType { + id: cipherDropDown + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: !autoNegotiateEncryprionSwitcher.checked + + descriptionText: qsTr("Cipher") + headerText: qsTr("Cipher") + + drawerParent: root + + listView: ListViewWithRadioButtonType { + id: cipherListView + + rootWidth: root.width + + model: ListModel { + ListElement { name : qsTr("AES-256-GCM") } + ListElement { name : qsTr("AES-192-GCM") } + ListElement { name : qsTr("AES-128-GCM") } + ListElement { name : qsTr("AES-256-CBC") } + ListElement { name : qsTr("AES-192-CBC") } + ListElement { name : qsTr("AES-128-CBC") } + ListElement { name : qsTr("ChaCha20-Poly1305") } + ListElement { name : qsTr("ARIA-256-CBC") } + ListElement { name : qsTr("CAMELLIA-256-CBC") } + ListElement { name : qsTr("none") } + } + + clickedFunction: function() { + cipherDropDown.text = selectedText + cipher = cipherDropDown.text + cipherDropDown.closeTriggered() + } + + Component.onCompleted: { + cipherDropDown.text = cipher + + for (var i = 0; i < cipherListView.model.count; i++) { + if (cipherListView.model.get(i).name === cipherDropDown.text) { + currentIndex = i + } + } + } + } + } + + Rectangle { + id: contentRect + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + Layout.preferredHeight: checkboxLayout.implicitHeight + color: AmneziaStyle.color.onyxBlack + radius: 16 + + ColumnLayout { + id: checkboxLayout + + anchors.fill: parent + + CheckBoxType { + id: tlsAuthCheckBox + Layout.fillWidth: true + + text: qsTr("TLS auth") + checked: tlsAuth + + onCheckedChanged: { + if (checked !== tlsAuth) { + console.log("tlsAuth changed to: " + checked) + tlsAuth = checked + } + } + } + + DividerType {} + + CheckBoxType { + id: blockDnsCheckBox + Layout.fillWidth: true + + text: qsTr("Block DNS requests outside of VPN") + checked: blockDns + + onCheckedChanged: { + if (checked !== blockDns) { + blockDns = checked + } + } + } + } + } + + SwitcherType { + id: additionalClientCommandsSwitcher + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + checked: additionalClientCommands !== "" + + text: qsTr("Additional client configuration commands") + + onCheckedChanged: { + if (!checked) { + additionalClientCommands = "" + } + } + } + + TextAreaType { + id: additionalClientCommandsTextArea + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: additionalClientCommandsSwitcher.checked + + textAreaText: additionalClientCommands + placeholderText: qsTr("Commands:") + + textArea.onEditingFinished: { + if (additionalClientCommands !== textAreaText) { + additionalClientCommands = textAreaText + } + } + } + + SwitcherType { + id: additionalServerCommandsSwitcher + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + checked: additionalServerCommands !== "" + + text: qsTr("Additional server configuration commands") + + onCheckedChanged: { + if (!checked) { + additionalServerCommands = "" + } + } + } + + TextAreaType { + id: additionalServerCommandsTextArea + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: additionalServerCommandsSwitcher.checked + + textAreaText: additionalServerCommands + placeholderText: qsTr("Commands:") + + textArea.onEditingFinished: { + if (additionalServerCommands !== textAreaText) { + additionalServerCommands = textAreaText + } + } + } + + BasicButtonType { + id: saveButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: vpnAddressSubnetTextField.errorText === "" && + portTextField.errorText === "" + + text: qsTr("Save") + + onClicked: function() { + forceActiveFocus() + + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(OpenVpnConfigModel.getConfig()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + Keys.onEnterPressed: saveButton.clicked() + Keys.onReturnPressed: saveButton.clicked() + } } } } diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index d8ea1d95..e07e54e3 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -66,8 +66,6 @@ PageType { Layout.leftMargin: 16 Layout.rightMargin: 16 - enabled: delegateItem.isEnabled - headerText: qsTr("VPN address subnet") textField.text: subnetAddress @@ -87,8 +85,6 @@ PageType { Layout.leftMargin: 16 Layout.rightMargin: 16 - enabled: delegateItem.isEnabled - headerText: qsTr("Port") textField.text: port textField.maximumLength: 5 diff --git a/client/ui/qml/Pages2/PageSettings.qml b/client/ui/qml/Pages2/PageSettings.qml index f331f912..de8a0041 100644 --- a/client/ui/qml/Pages2/PageSettings.qml +++ b/client/ui/qml/Pages2/PageSettings.qml @@ -43,8 +43,6 @@ PageType { LabelWithButtonType { Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 visible: isVisible @@ -68,8 +66,6 @@ PageType { visible: GC.isDesktop() Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 text: qsTr("Close application") leftImageSource: "qrc:/images/controls/x-circle.svg" diff --git a/client/ui/qml/Pages2/PageSettingsDns.qml b/client/ui/qml/Pages2/PageSettingsDns.qml index a510f928..e8e1d8f1 100644 --- a/client/ui/qml/Pages2/PageSettingsDns.qml +++ b/client/ui/qml/Pages2/PageSettingsDns.qml @@ -66,6 +66,13 @@ PageType { text: qsTr("If AmneziaDNS is not used or installed") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { + width: listView.width + spacing: 16 TextFieldWithHeaderType { id: primaryDns @@ -96,13 +103,6 @@ PageType { regularExpression: InstallController.ipAddressRegExp() } } - } - - model: 1 // fake model to force the ListView to be created without a model - spacing: 16 - - delegate: ColumnLayout { - width: listView.width BasicButtonType { id: restoreDefaultButton @@ -139,10 +139,6 @@ PageType { showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } - } - - footer: ColumnLayout { - width: listView.width BasicButtonType { id: saveButton diff --git a/client/ui/qml/Pages2/PageSettingsServerData.qml b/client/ui/qml/Pages2/PageSettingsServerData.qml index 1a496b5b..b744a6da 100644 --- a/client/ui/qml/Pages2/PageSettingsServerData.qml +++ b/client/ui/qml/Pages2/PageSettingsServerData.qml @@ -18,6 +18,8 @@ PageType { signal lastItemTabClickedSignal() + property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() + Connections { target: InstallController @@ -59,15 +61,13 @@ PageType { target: ServersModel function onProcessedServerIndexChanged() { - listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() + root.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() } } ListViewType { id: listView - property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() - anchors.fill: parent model: serverActions @@ -107,7 +107,7 @@ PageType { QtObject { id: check - property bool isVisible: true + property bool isVisible: root.isServerWithWriteAccess readonly property string title: qsTr("Check the server for previously installed Amnezia services") readonly property string description: qsTr("Add them to the application if they were not displayed") readonly property var tColor: AmneziaStyle.color.paleGray @@ -121,7 +121,7 @@ PageType { QtObject { id: reboot - property bool isVisible: true + property bool isVisible: root.isServerWithWriteAccess readonly property string title: qsTr("Reboot server") readonly property string description: "" readonly property var tColor: AmneziaStyle.color.vibrantRed @@ -181,7 +181,7 @@ PageType { QtObject { id: clear - property bool isVisible: true + property bool isVisible: root.isServerWithWriteAccess readonly property string title: qsTr("Clear server from Amnezia software") readonly property string description: "" readonly property var tColor: AmneziaStyle.color.vibrantRed @@ -240,7 +240,7 @@ PageType { QtObject { id: switch_to_premium - property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") + property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium readonly property string title: qsTr("Switch to the new Amnezia Premium subscription") readonly property string description: "" readonly property var tColor: AmneziaStyle.color.vibrantRed diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 8a6b7a28..1465459f 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -161,10 +161,4 @@ PageType { } } } - - ShareConnectionDrawer { - id: shareConnectionDrawer - - anchors.fill: parent - } } From 251f2aa5db1bf91e6fb499d365deeed3fcbaf4b5 Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Tue, 19 Aug 2025 21:58:39 -0700 Subject: [PATCH 23/40] fix: remove double disconnect for Win IPSec (#1800) --- client/protocols/ikev2_vpn_protocol_windows.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/protocols/ikev2_vpn_protocol_windows.cpp b/client/protocols/ikev2_vpn_protocol_windows.cpp index b4110f03..97071f10 100644 --- a/client/protocols/ikev2_vpn_protocol_windows.cpp +++ b/client/protocols/ikev2_vpn_protocol_windows.cpp @@ -30,7 +30,6 @@ Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) Ikev2Protocol::~Ikev2Protocol() { qDebug() << "IpsecProtocol::~IpsecProtocol()"; - disconnect_vpn(); Ikev2Protocol::stop(); } @@ -38,7 +37,7 @@ void Ikev2Protocol::stop() { setConnectionState(Vpn::ConnectionState::Disconnecting); { - if (! disconnect_vpn() ){ + if (!disconnect_vpn()){ qDebug()<<"We don't disconnect"; setConnectionState(Vpn::ConnectionState::Error); } @@ -311,7 +310,9 @@ bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bool Ikev2Protocol::disconnect_vpn(){ if ( hRasConn != nullptr ){ - if ( RasHangUp(hRasConn) != ERROR_SUCCESS) + auto ret = RasHangUp(hRasConn); + qDebug() << "RasHangUp " << ret; + if (ret != ERROR_SUCCESS) return false; } QThread::msleep(3000); From 30d0f84a4f90ab66554141bf858cabddd908c59d Mon Sep 17 00:00:00 2001 From: Cyril Anisimov Date: Wed, 20 Aug 2025 06:59:57 +0200 Subject: [PATCH 24/40] fix: fixed focus view and reverse focus change in headers (#1791) * fix: add view movement on changing the focus in backwards direction * fix: return value in isFirstFocusItemInHeader function --- client/ui/controllers/listViewFocusController.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/ui/controllers/listViewFocusController.cpp b/client/ui/controllers/listViewFocusController.cpp index 6e91b78a..d94ec66e 100644 --- a/client/ui/controllers/listViewFocusController.cpp +++ b/client/ui/controllers/listViewFocusController.cpp @@ -112,6 +112,7 @@ void ListViewFocusController::previousDelegate() case Section::Default: { if (hasFooter()) { m_currentSection = Section::Footer; + viewAtCurrentIndex(); break; } [[fallthrough]]; @@ -127,9 +128,11 @@ void ListViewFocusController::previousDelegate() case Section::Delegate: { if (m_delegateIndex > 0) { setDelegateIndex(m_delegateIndex - 1); + viewAtCurrentIndex(); break; } else if (hasHeader()) { m_currentSection = Section::Header; + viewAtCurrentIndex(); break; } [[fallthrough]]; @@ -137,6 +140,7 @@ void ListViewFocusController::previousDelegate() case Section::Header: { m_isReturnNeeded = true; m_currentSection = Section::Default; + viewAtCurrentIndex(); break; } default: { @@ -275,7 +279,7 @@ bool ListViewFocusController::isFirstFocusItemInListView() const return isFirstFocusItemInDelegate() && (m_delegateIndex == 0) && !hasHeader(); } case Section::Header: { - isFirstFocusItemInDelegate(); + return isFirstFocusItemInDelegate(); } case Section::Default: { return true; From 3eb06916c76a19f3bb917ff85a4a2b2a42339528 Mon Sep 17 00:00:00 2001 From: vkamn Date: Wed, 20 Aug 2025 13:00:20 +0800 Subject: [PATCH 25/40] chore: bump version (#1802) * chore: bump version * fix: fixed ios build --- CMakeLists.txt | 4 ++-- client/core/controllers/coreController.cpp | 2 +- client/core/controllers/coreController.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e839d1a9..18149d46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) -set(AMNEZIAVPN_VERSION 4.8.9.2) +set(AMNEZIAVPN_VERSION 4.8.10.0) project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION} DESCRIPTION "AmneziaVPN" @@ -12,7 +12,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d") set(RELEASE_DATE "${CURRENT_DATE}") set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) -set(APP_ANDROID_VERSION_CODE 2092) +set(APP_ANDROID_VERSION_CODE 2093) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(MZ_PLATFORM_NAME "linux") diff --git a/client/core/controllers/coreController.cpp b/client/core/controllers/coreController.cpp index 3d657c5a..78da21a1 100644 --- a/client/core/controllers/coreController.cpp +++ b/client/core/controllers/coreController.cpp @@ -233,7 +233,7 @@ void CoreController::initSignalHandlers() void CoreController::initNotificationHandler() { -#ifndef Q_OS_ANDROID +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) m_notificationHandler.reset(NotificationHandler::create(nullptr)); connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(), diff --git a/client/core/controllers/coreController.h b/client/core/controllers/coreController.h index 1fe7cea7..66ddb72f 100644 --- a/client/core/controllers/coreController.h +++ b/client/core/controllers/coreController.h @@ -5,7 +5,7 @@ #include #include -#ifndef Q_OS_ANDROID +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) #include "ui/systemtray_notificationhandler.h" #endif @@ -48,7 +48,7 @@ #include "ui/models/services/socks5ProxyConfigModel.h" #include "ui/models/sites_model.h" -#ifndef Q_OS_ANDROID +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) #include "ui/notificationhandler.h" #endif @@ -97,7 +97,7 @@ private: QSharedPointer m_vpnConnection; QSharedPointer m_translator; -#ifndef Q_OS_ANDROID +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) QScopedPointer m_notificationHandler; #endif From beb1c6dbf2cf80a6db1bcb6729d989f77dca0b15 Mon Sep 17 00:00:00 2001 From: vkamn Date: Wed, 20 Aug 2025 13:00:35 +0800 Subject: [PATCH 26/40] feat: added cache for proxy bypass (#1797) --- client/core/controllers/gatewayController.cpp | 23 ++++++++++++++++--- client/core/controllers/gatewayController.h | 2 ++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/client/core/controllers/gatewayController.cpp b/client/core/controllers/gatewayController.cpp index 26855ae6..ade5979b 100644 --- a/client/core/controllers/gatewayController.cpp +++ b/client/core/controllers/gatewayController.cpp @@ -344,11 +344,14 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl std::mt19937 generator(randomDevice()); std::shuffle(proxyUrls.begin(), proxyUrls.end(), generator); - QEventLoop wait; - QList sslErrors; QByteArray responseBody; - for (const QString &proxyUrl : proxyUrls) { + auto bypassFunction = [this](const QString &endpoint, const QString &proxyUrl, QNetworkReply *reply, + std::function requestFunction, + std::function &sslErrors)> replyProcessingFunction) { + QEventLoop wait; + QList sslErrors; + qDebug() << "go to the next proxy endpoint"; reply->deleteLater(); // delete the previous reply reply = requestFunction(endpoint.arg(proxyUrl)); @@ -358,6 +361,20 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl wait.exec(); if (replyProcessingFunction(reply, sslErrors)) { + return true; + } + return false; + }; + + if (!m_proxyUrl.isEmpty()) { + if (bypassFunction(endpoint, m_proxyUrl, reply, requestFunction, replyProcessingFunction)) { + return; + } + } + + for (const QString &proxyUrl : proxyUrls) { + if (bypassFunction(endpoint, proxyUrl, reply, requestFunction, replyProcessingFunction)) { + m_proxyUrl = proxyUrl; break; } } diff --git a/client/core/controllers/gatewayController.h b/client/core/controllers/gatewayController.h index 9f91df53..4c247fc6 100644 --- a/client/core/controllers/gatewayController.h +++ b/client/core/controllers/gatewayController.h @@ -32,6 +32,8 @@ private: QString m_gatewayEndpoint; bool m_isDevEnvironment = false; bool m_isStrictKillSwitchEnabled = false; + + inline static QString m_proxyUrl; }; #endif // GATEWAYCONTROLLER_H From 8dc2a4b76ceb7fb71b645c79cdccbe711db1da3e Mon Sep 17 00:00:00 2001 From: vkamn Date: Wed, 20 Aug 2025 13:01:09 +0800 Subject: [PATCH 27/40] fix: fixed switcher behavior (#1801) --- client/ui/qml/Controls2/SwitcherType.qml | 2 +- client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml | 6 +++--- client/ui/qml/Pages2/PageSettingsApplication.qml | 8 ++++---- client/ui/qml/Pages2/PageSettingsConnection.qml | 2 +- client/ui/qml/Pages2/PageSettingsLogging.qml | 2 +- client/ui/qml/Pages2/PageSetupWizardConfigSource.qml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/ui/qml/Controls2/SwitcherType.qml b/client/ui/qml/Controls2/SwitcherType.qml index db9ef755..4b41fc26 100644 --- a/client/ui/qml/Controls2/SwitcherType.qml +++ b/client/ui/qml/Controls2/SwitcherType.qml @@ -155,7 +155,7 @@ Switch { function handleSwitch(event) { if (!event.isAutoRepeat) { root.checked = !root.checked - root.checkedChanged() + root.toggled() } event.accepted = true } diff --git a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml index d2db90b0..dcc02860 100644 --- a/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolOpenVpnSettings.qml @@ -153,7 +153,7 @@ PageType { text: qsTr("Auto-negotiate encryption") checked: autoNegotiateEncryprion - onCheckedChanged: { + onToggled: function() { if (checked !== autoNegotiateEncryprion) { autoNegotiateEncryprion = checked } @@ -320,7 +320,7 @@ PageType { text: qsTr("Additional client configuration commands") - onCheckedChanged: { + onToggled: function() { if (!checked) { additionalClientCommands = "" } @@ -357,7 +357,7 @@ PageType { text: qsTr("Additional server configuration commands") - onCheckedChanged: { + onToggled: function() { if (!checked) { additionalServerCommands = "" } diff --git a/client/ui/qml/Pages2/PageSettingsApplication.qml b/client/ui/qml/Pages2/PageSettingsApplication.qml index 9718f819..bd00be22 100644 --- a/client/ui/qml/Pages2/PageSettingsApplication.qml +++ b/client/ui/qml/Pages2/PageSettingsApplication.qml @@ -66,7 +66,7 @@ PageType { text: qsTr("Allow application screenshots") checked: SettingsController.isScreenshotsEnabled() - onCheckedChanged: { + onToggled: function() { if (checked !== SettingsController.isScreenshotsEnabled()) { SettingsController.toggleScreenshotsEnabled(checked) } @@ -109,7 +109,7 @@ PageType { descriptionText: qsTr("Launch the application every time the device is starts") checked: SettingsController.isAutoStartEnabled() - onCheckedChanged: { + onToggled: function() { if (checked !== SettingsController.isAutoStartEnabled()) { SettingsController.toggleAutoStart(checked) } @@ -132,7 +132,7 @@ PageType { descriptionText: qsTr("Connect to VPN on app start") checked: SettingsController.isAutoConnectEnabled() - onCheckedChanged: { + onToggled: function() { if (checked !== SettingsController.isAutoConnectEnabled()) { SettingsController.toggleAutoConnect(checked) } @@ -158,7 +158,7 @@ PageType { opacity: enabled ? 1.0 : 0.5 checked: SettingsController.isStartMinimizedEnabled() - onCheckedChanged: { + onToggled: function() { if (checked !== SettingsController.isStartMinimizedEnabled()) { SettingsController.toggleStartMinimized(checked) } diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index 60323629..59e56095 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -66,7 +66,7 @@ PageType { descriptionText: qsTr("If AmneziaDNS is installed on the server") checked: SettingsController.isAmneziaDnsEnabled() - onCheckedChanged: { + onToggled: function() { if (checked !== SettingsController.isAmneziaDnsEnabled()) { SettingsController.toggleAmneziaDns(checked) } diff --git a/client/ui/qml/Pages2/PageSettingsLogging.qml b/client/ui/qml/Pages2/PageSettingsLogging.qml index 1359ecdf..89cb41d9 100644 --- a/client/ui/qml/Pages2/PageSettingsLogging.qml +++ b/client/ui/qml/Pages2/PageSettingsLogging.qml @@ -64,7 +64,7 @@ PageType { checked: SettingsController.isLoggingEnabled - onCheckedChanged: { + onToggled: function() { if (checked !== SettingsController.isLoggingEnabled) { SettingsController.isLoggingEnabled = checked } diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index f88745d4..3410842d 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -86,7 +86,7 @@ PageType { visible: PageController.isStartPageVisible() checked: SettingsController.isLoggingEnabled - onCheckedChanged: { + onToggled: function() { if (checked !== SettingsController.isLoggingEnabled) { SettingsController.isLoggingEnabled = checked } From b802863de50b98cde422208f26c7b626bc68b884 Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Tue, 19 Aug 2025 23:19:22 -0700 Subject: [PATCH 28/40] fix: check for empty secondary DNS (#1799) --- client/daemon/interfaceconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/daemon/interfaceconfig.cpp b/client/daemon/interfaceconfig.cpp index 53da5d36..51e5b5b7 100644 --- a/client/daemon/interfaceconfig.cpp +++ b/client/daemon/interfaceconfig.cpp @@ -101,10 +101,10 @@ QString InterfaceConfig::toWgConf(const QMap& extra) const { out << "MTU = " << m_deviceMTU << "\n"; } - if (!m_primaryDnsServer.isNull()) { + if (!m_primaryDnsServer.isEmpty()) { QStringList dnsServers; dnsServers.append(m_primaryDnsServer); - if (!m_secondaryDnsServer.isNull()) { + if (!m_secondaryDnsServer.isEmpty()) { dnsServers.append(m_secondaryDnsServer); } // If the DNS is not the Gateway, it's a user defined DNS From 816dc3af95f5a474cb46048b7084fb532e7f4d28 Mon Sep 17 00:00:00 2001 From: vkamn Date: Thu, 21 Aug 2025 12:28:03 +0800 Subject: [PATCH 29/40] feat: add ping before request to proxy (#1805) --- client/core/controllers/gatewayController.cpp | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/client/core/controllers/gatewayController.cpp b/client/core/controllers/gatewayController.cpp index ade5979b..58a1ed60 100644 --- a/client/core/controllers/gatewayController.cpp +++ b/client/core/controllers/gatewayController.cpp @@ -61,7 +61,7 @@ ErrorCode GatewayController::get(const QString &endpoint, QByteArray &responseBo request.setTransferTimeout(m_requestTimeoutMsecs); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setUrl(QString(endpoint).arg(m_gatewayEndpoint)); + request.setUrl(QString(endpoint).arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl)); // bypass killSwitch exceptions for API-gateway #ifdef AMNEZIA_DESKTOP @@ -123,7 +123,7 @@ ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject api request.setTransferTimeout(m_requestTimeoutMsecs); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setUrl(endpoint.arg(m_gatewayEndpoint)); + request.setUrl(endpoint.arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl)); // bypass killSwitch exceptions for API-gateway #ifdef AMNEZIA_DESKTOP @@ -366,6 +366,36 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl return false; }; + if (m_proxyUrl.isEmpty()) { + QNetworkRequest request; + request.setTransferTimeout(1000); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QEventLoop wait; + QList sslErrors; + QNetworkReply *reply; + + for (const QString &proxyUrl : proxyUrls) { + request.setUrl(proxyUrl + "lmbd-health"); + reply = amnApp->networkManager()->get(request); + + connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit); + connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; }); + wait.exec(); + + if (reply->error() == QNetworkReply::NetworkError::NoError) { + reply->deleteLater(); + + m_proxyUrl = proxyUrl; + if (!m_proxyUrl.isEmpty()) { + break; + } + } else { + reply->deleteLater(); + } + } + } + if (!m_proxyUrl.isEmpty()) { if (bypassFunction(endpoint, m_proxyUrl, reply, requestFunction, replyProcessingFunction)) { return; From 169f11d9c760a9462c6adcdf389f29b77eefbcf0 Mon Sep 17 00:00:00 2001 From: MrMirDan <58086007+MrMirDan@users.noreply.github.com> Date: Thu, 21 Aug 2025 07:29:22 +0300 Subject: [PATCH 30/40] chore: added trimming I's and J's params on save (#1774) * trimming params on save * removed unused code --- client/ui/models/protocols/awgConfigModel.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/ui/models/protocols/awgConfigModel.cpp b/client/ui/models/protocols/awgConfigModel.cpp index e14a3152..b03b7856 100644 --- a/client/ui/models/protocols/awgConfigModel.cpp +++ b/client/ui/models/protocols/awgConfigModel.cpp @@ -191,14 +191,14 @@ QJsonObject AwgConfigModel::getConfig() jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount]; jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize]; jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize]; - jsonConfig[config_key::specialJunk1] = m_clientProtocolConfig[config_key::specialJunk1]; - jsonConfig[config_key::specialJunk2] = m_clientProtocolConfig[config_key::specialJunk2]; - jsonConfig[config_key::specialJunk3] = m_clientProtocolConfig[config_key::specialJunk3]; - jsonConfig[config_key::specialJunk4] = m_clientProtocolConfig[config_key::specialJunk4]; - jsonConfig[config_key::specialJunk5] = m_clientProtocolConfig[config_key::specialJunk5]; - jsonConfig[config_key::controlledJunk1] = m_clientProtocolConfig[config_key::controlledJunk1]; - jsonConfig[config_key::controlledJunk2] = m_clientProtocolConfig[config_key::controlledJunk2]; - jsonConfig[config_key::controlledJunk3] = m_clientProtocolConfig[config_key::controlledJunk3]; + jsonConfig[config_key::specialJunk1] = m_clientProtocolConfig[config_key::specialJunk1].toString().trimmed(); + jsonConfig[config_key::specialJunk2] = m_clientProtocolConfig[config_key::specialJunk2].toString().trimmed(); + jsonConfig[config_key::specialJunk3] = m_clientProtocolConfig[config_key::specialJunk3].toString().trimmed(); + jsonConfig[config_key::specialJunk4] = m_clientProtocolConfig[config_key::specialJunk4].toString().trimmed(); + jsonConfig[config_key::specialJunk5] = m_clientProtocolConfig[config_key::specialJunk5].toString().trimmed(); + jsonConfig[config_key::controlledJunk1] = m_clientProtocolConfig[config_key::controlledJunk1].toString().trimmed(); + jsonConfig[config_key::controlledJunk2] = m_clientProtocolConfig[config_key::controlledJunk2].toString().trimmed(); + jsonConfig[config_key::controlledJunk3] = m_clientProtocolConfig[config_key::controlledJunk3].toString().trimmed(); jsonConfig[config_key::specialHandshakeTimeout] = m_clientProtocolConfig[config_key::specialHandshakeTimeout]; m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); From 94a13b2b54b108d6e9ce82244a261bdc6fdc2e73 Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Sun, 24 Aug 2025 20:03:42 -0700 Subject: [PATCH 31/40] fix: set guid for windows tun2socks tun interface (#1808) --- ipc/ipctun2socksprocess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipc/ipctun2socksprocess.cpp b/ipc/ipctun2socksprocess.cpp index 2125f6ab..65d801b0 100644 --- a/ipc/ipctun2socksprocess.cpp +++ b/ipc/ipctun2socksprocess.cpp @@ -29,7 +29,7 @@ void IpcProcessTun2Socks::start() QString XrayConStr = "socks5://127.0.0.1:10808"; #ifdef Q_OS_WIN - QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr, "-tun-post-up", + QStringList arguments({"-device", "tun://tun2?guid={081A8A84-8D12-4DF5-B8C4-396D5B0053E4}", "-proxy", XrayConStr, "-tun-post-up", QString("cmd /c netsh interface ip set address name=\"tun2\" static %1 255.255.255.255") .arg(amnezia::protocols::xray::defaultLocalAddr)}); #endif From c907f5ca360b34720752ca006ebc5bc540e986ad Mon Sep 17 00:00:00 2001 From: MrMirDan <58086007+MrMirDan@users.noreply.github.com> Date: Mon, 25 Aug 2025 17:04:48 +0300 Subject: [PATCH 32/40] fix: removed service logs section for mobile platforms (#1810) --- client/ui/qml/Pages2/PageSettingsLogging.qml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/client/ui/qml/Pages2/PageSettingsLogging.qml b/client/ui/qml/Pages2/PageSettingsLogging.qml index 89cb41d9..240e8c8c 100644 --- a/client/ui/qml/Pages2/PageSettingsLogging.qml +++ b/client/ui/qml/Pages2/PageSettingsLogging.qml @@ -167,7 +167,8 @@ PageType { // Show service logs only if this is NOT a macOS build with // Network-Extension (IsMacOsNeBuild is injected from C++ at run-time) - property list logTypes: IsMacOsNeBuild ? [ + // or if this is NOT a mobile build + property list logTypes: (IsMacOsNeBuild || GC.isMobile()) ? [ clientLogs ] : [ clientLogs, @@ -214,15 +215,11 @@ PageType { } readonly property var exportLogsHandler: function() { var fileName = "" - if (GC.isMobile()) { - fileName = "AmneziaVPN-service.log" - } else { - fileName = SystemController.getFileName(qsTr("Save"), - qsTr("Logs files (*.log)"), - StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service", - true, - ".log") - } + fileName = SystemController.getFileName(qsTr("Save"), + qsTr("Logs files (*.log)"), + StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service", + true, + ".log") if (fileName !== "") { PageController.showBusyIndicator(true) SettingsController.exportServiceLogsFile(fileName) From 656070b1329cf61cfc9f2ac29387a369dcbc10de Mon Sep 17 00:00:00 2001 From: vkamn Date: Mon, 25 Aug 2025 22:05:00 +0800 Subject: [PATCH 33/40] feat: add request id (#1809) --- client/core/controllers/gatewayController.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/core/controllers/gatewayController.cpp b/client/core/controllers/gatewayController.cpp index 58a1ed60..54954063 100644 --- a/client/core/controllers/gatewayController.cpp +++ b/client/core/controllers/gatewayController.cpp @@ -60,6 +60,7 @@ ErrorCode GatewayController::get(const QString &endpoint, QByteArray &responseBo QNetworkRequest request; request.setTransferTimeout(m_requestTimeoutMsecs); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setRawHeader(QString("X-Client-Request-ID").toUtf8(), QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8()); request.setUrl(QString(endpoint).arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl)); @@ -122,6 +123,7 @@ ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject api QNetworkRequest request; request.setTransferTimeout(m_requestTimeoutMsecs); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setRawHeader(QString("X-Client-Request-ID").toUtf8(), QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8()); request.setUrl(endpoint.arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl)); From ad01f23bbea1b78b004a8c6a21bbe021e4173cbe Mon Sep 17 00:00:00 2001 From: vkamn Date: Tue, 26 Aug 2025 12:17:37 +0800 Subject: [PATCH 34/40] feat: add service description customization (#1811) --- .../controllers/api/apiConfigsController.cpp | 2 ++ client/ui/models/api/apiServicesModel.cpp | 31 +++++++++---------- client/ui/models/api/apiServicesModel.h | 4 +++ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/client/ui/controllers/api/apiConfigsController.cpp b/client/ui/controllers/api/apiConfigsController.cpp index 500c4896..b1e3ad7a 100644 --- a/client/ui/controllers/api/apiConfigsController.cpp +++ b/client/ui/controllers/api/apiConfigsController.cpp @@ -29,6 +29,7 @@ namespace constexpr char uuid[] = "installation_uuid"; constexpr char osVersion[] = "os_version"; constexpr char appVersion[] = "app_version"; + constexpr char appLanguage[] = "app_language"; constexpr char userCountryCode[] = "user_country_code"; constexpr char serverCountryCode[] = "server_country_code"; @@ -322,6 +323,7 @@ bool ApiConfigsController::fillAvailableServices() { QJsonObject apiPayload; apiPayload[configKey::osVersion] = QSysInfo::productType(); + apiPayload[configKey::appLanguage] = m_settings->getAppLanguage().name().split("_").first(); QByteArray responseBody; ErrorCode errorCode = executeRequest(QString("%1v1/services"), apiPayload, responseBody); diff --git a/client/ui/models/api/apiServicesModel.cpp b/client/ui/models/api/apiServicesModel.cpp index d3155292..1bd1f280 100644 --- a/client/ui/models/api/apiServicesModel.cpp +++ b/client/ui/models/api/apiServicesModel.cpp @@ -15,6 +15,7 @@ namespace constexpr char serviceInfo[] = "service_info"; constexpr char serviceType[] = "service_type"; constexpr char serviceProtocol[] = "service_protocol"; + constexpr char serviceDescription[] = "service_description"; constexpr char name[] = "name"; constexpr char price[] = "price"; @@ -22,6 +23,10 @@ namespace constexpr char timelimit[] = "timelimit"; constexpr char region[] = "region"; + constexpr char description[] = "description"; + constexpr char cardDescription[] = "card_description"; + constexpr char features[] = "features"; + constexpr char availableCountries[] = "available_countries"; constexpr char storeEndpoint[] = "store_endpoint"; @@ -65,11 +70,9 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const case CardDescriptionRole: { auto speed = apiServiceData.serviceInfo.speed; if (serviceType == serviceType::amneziaPremium) { - return tr("Amnezia Premium is classic VPN for seamless work, downloading large files, and watching videos. " - "Access all websites and online resources. Speeds up to %1 Mbps.") - .arg(speed); + return apiServiceData.serviceInfo.cardDescription.arg(speed); } else if (serviceType == serviceType::amneziaFree) { - QString description = tr("Amnezia Free provides unlimited, free access to a basic set of websites and apps, including Facebook, Instagram, Twitter (X), Discord, Telegram, and more. YouTube is not included in the free plan."); + QString description = apiServiceData.serviceInfo.cardDescription; if (!isServiceAvailable) { description += tr("

    Not available in your region. If you have VPN enabled, disable it, " "return to the previous screen, and try again."); @@ -78,12 +81,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const } } case ServiceDescriptionRole: { - if (serviceType == serviceType::amneziaPremium) { - return tr("Amnezia Premium is classic VPN for for seamless work, downloading large files, and watching videos. " - "Access all websites and online resources."); - } else { - return tr("Amnezia Free provides unlimited, free access to a basic set of websites and apps, including Facebook, Instagram, Twitter (X), Discord, Telegram, and more. YouTube is not included in the free plan."); - } + return apiServiceData.serviceInfo.description; } case IsServiceAvailableRole: { if (serviceType == serviceType::amneziaFree) { @@ -107,13 +105,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const return apiServiceData.serviceInfo.region; } case FeaturesRole: { - if (serviceType == serviceType::amneziaPremium) { - return tr(""); - } else { - return tr("VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. " - "Other sites will be opened from your real IP address, " - "more details on the website."); - } + return apiServiceData.serviceInfo.features; } case PriceRole: { auto price = apiServiceData.serviceInfo.price; @@ -234,6 +226,7 @@ ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJs auto serviceType = data.value(configKey::serviceType).toString(); auto serviceProtocol = data.value(configKey::serviceProtocol).toString(); auto availableCountries = data.value(configKey::availableCountries).toArray(); + auto serviceDescription = data.value(configKey::serviceDescription).toObject(); auto subscriptionObject = data.value(configKey::subscription).toObject(); @@ -244,6 +237,10 @@ ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJs serviceData.serviceInfo.speed = serviceInfo.value(configKey::speed).toString(); serviceData.serviceInfo.timeLimit = serviceInfo.value(configKey::timelimit).toString(); + serviceData.serviceInfo.cardDescription = serviceDescription.value(configKey::cardDescription).toString(); + serviceData.serviceInfo.description = serviceDescription.value(configKey::description).toString(); + serviceData.serviceInfo.features = serviceDescription.value(configKey::features).toString(); + serviceData.type = serviceType; serviceData.protocol = serviceProtocol; diff --git a/client/ui/models/api/apiServicesModel.h b/client/ui/models/api/apiServicesModel.h index c96a49ab..4bd870b3 100644 --- a/client/ui/models/api/apiServicesModel.h +++ b/client/ui/models/api/apiServicesModel.h @@ -58,6 +58,10 @@ private: QString region; QString price; + QString description; + QString features; + QString cardDescription; + QJsonObject object; }; From a412d911053fd388e75fa9dd081cadfe44cff819 Mon Sep 17 00:00:00 2001 From: vkamn Date: Tue, 26 Aug 2025 20:31:41 +0800 Subject: [PATCH 35/40] feat: subscription expiration processing (#1814) --- client/core/api/apiUtils.cpp | 2 +- client/core/defs.h | 1 + client/core/errorstrings.cpp | 1 + .../controllers/api/apiConfigsController.cpp | 43 ++++++++++++++++++- client/ui/models/api/apiAccountInfoModel.cpp | 2 +- .../ui/qml/Controls2/LabelWithImageType.qml | 12 ++++-- .../qml/Pages2/PageSettingsApiServerInfo.qml | 4 ++ 7 files changed, 58 insertions(+), 7 deletions(-) diff --git a/client/core/api/apiUtils.cpp b/client/core/api/apiUtils.cpp index 7f3e6db3..78d2e3cb 100644 --- a/client/core/api/apiUtils.cpp +++ b/client/core/api/apiUtils.cpp @@ -23,7 +23,7 @@ namespace bool apiUtils::isSubscriptionExpired(const QString &subscriptionEndDate) { - QDateTime now = QDateTime::currentDateTime(); + QDateTime now = QDateTime::currentDateTimeUtc(); QDateTime endDate = QDateTime::fromString(subscriptionEndDate, Qt::ISODateWithMs); return endDate < now; } diff --git a/client/core/defs.h b/client/core/defs.h index 64f52ce6..75dd26af 100644 --- a/client/core/defs.h +++ b/client/core/defs.h @@ -120,6 +120,7 @@ namespace amnezia ApiNotFoundError = 1109, ApiMigrationError = 1110, ApiUpdateRequestError = 1111, + ApiSubscriptionExpiredError = 1112, // QFile errors OpenError = 1200, diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp index bd5ccaba..c29187fb 100644 --- a/client/core/errorstrings.cpp +++ b/client/core/errorstrings.cpp @@ -77,6 +77,7 @@ QString errorString(ErrorCode code) { case (ErrorCode::ApiNotFoundError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break; case (ErrorCode::ApiMigrationError): errorMessage = QObject::tr("A migration error has occurred. Please contact our technical support"); break; case (ErrorCode::ApiUpdateRequestError): errorMessage = QObject::tr("Please update the application to use this feature"); break; + case (ErrorCode::ApiSubscriptionExpiredError): errorMessage = QObject::tr("Your Amnezia Premium subscription has expired.\n Please check your email for renewal instructions.\n If you haven't received an email, please contact our support."); break; // QFile errors case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break; diff --git a/client/ui/controllers/api/apiConfigsController.cpp b/client/ui/controllers/api/apiConfigsController.cpp index b1e3ad7a..e543edf1 100644 --- a/client/ui/controllers/api/apiConfigsController.cpp +++ b/client/ui/controllers/api/apiConfigsController.cpp @@ -44,6 +44,9 @@ namespace constexpr char authData[] = "auth_data"; constexpr char config[] = "config"; + + constexpr char subscription[] = "subscription"; + constexpr char endDate[] = "end_date"; } struct ProtocolData @@ -164,7 +167,7 @@ namespace auto clientProtocolConfig = QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object(); - //TODO looks like this block can be removed after v1 configs EOL + // TODO looks like this block can be removed after v1 configs EOL serverProtocolConfig[config_key::junkPacketCount] = clientProtocolConfig.value(config_key::junkPacketCount); serverProtocolConfig[config_key::junkPacketMinSize] = clientProtocolConfig.value(config_key::junkPacketMinSize); @@ -224,6 +227,19 @@ namespace return ErrorCode::NoError; } + + bool isSubscriptionExpired(const QJsonObject &apiConfig) + { + auto subscription = apiConfig.value(configKey::subscription).toObject(); + if (subscription.isEmpty()) { + return false; + } + auto subscriptionEndDate = subscription.value(configKey::endDate).toString(); + if (apiUtils::isSubscriptionExpired(subscriptionEndDate)) { + return true; + } + return false; + } } ApiConfigsController::ApiConfigsController(const QSharedPointer &serversModel, @@ -243,6 +259,11 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode, auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex()); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); + if (isSubscriptionExpired(apiConfigObject)) { + emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError); + return false; + } + GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString(APP_VERSION), m_settings->getInstallationUuid(true), @@ -278,6 +299,11 @@ bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode) auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex()); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); + if (isSubscriptionExpired(apiConfigObject)) { + emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError); + return false; + } + GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString(APP_VERSION), m_settings->getInstallationUuid(true), @@ -398,6 +424,11 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const auto serverConfig = m_serversModel->getServerConfig(serverIndex); auto apiConfig = serverConfig.value(configKey::apiConfig).toObject(); + if (isSubscriptionExpired(apiConfig)) { + emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError); + return false; + } + GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString(APP_VERSION), m_settings->getInstallationUuid(true), @@ -504,6 +535,11 @@ bool ApiConfigsController::deactivateDevice() return true; } + if (isSubscriptionExpired(apiConfigObject)) { + emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError); + return false; + } + GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString(APP_VERSION), m_settings->getInstallationUuid(true), @@ -538,6 +574,11 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q return true; } + if (isSubscriptionExpired(apiConfigObject)) { + emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError); + return false; + } + GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString(APP_VERSION), uuid, diff --git a/client/ui/models/api/apiAccountInfoModel.cpp b/client/ui/models/api/apiAccountInfoModel.cpp index bd3027a4..bdd7d68d 100644 --- a/client/ui/models/api/apiAccountInfoModel.cpp +++ b/client/ui/models/api/apiAccountInfoModel.cpp @@ -31,7 +31,7 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const return tr("Active"); } - return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate) ? tr("Inactive") : tr("Active"); + return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate) ? tr("

    Inactive") : tr("Active"); } case EndDateRole: { if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) { diff --git a/client/ui/qml/Controls2/LabelWithImageType.qml b/client/ui/qml/Controls2/LabelWithImageType.qml index 57d60d8f..9ad4168f 100644 --- a/client/ui/qml/Controls2/LabelWithImageType.qml +++ b/client/ui/qml/Controls2/LabelWithImageType.qml @@ -7,17 +7,20 @@ import Style 1.0 import "TextTypes" RowLayout { + id: root + property string imageSource property string leftText property var rightText property bool isRightTextUndefined: rightText === undefined + property int rightTextFormat: Text.PlainText visible: !isRightTextUndefined Image { Layout.preferredHeight: 18 Layout.preferredWidth: 18 - source: imageSource + source: root.imageSource } ListItemTitleType { @@ -25,14 +28,15 @@ RowLayout { Layout.rightMargin: 10 Layout.alignment: Qt.AlignRight - text: leftText + text: root.leftText } ParagraphTextType { - visible: rightText !== "" + visible: root.rightText !== "" Layout.alignment: Qt.AlignLeft - text: isRightTextUndefined ? "" : rightText + text: root.isRightTextUndefined ? "" : root.rightText + textFormat: root.rightTextFormat } } diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index 1e947bd2..3a7290a6 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -29,6 +29,7 @@ PageType { readonly property string title: qsTr("Subscription Status") readonly property string contentKey: "subscriptionStatus" readonly property string objectImageSource: "qrc:/images/controls/info.svg" + readonly property bool isRichText: true } QtObject { @@ -37,6 +38,7 @@ PageType { readonly property string title: qsTr("Valid Until") readonly property string contentKey: "endDate" readonly property string objectImageSource: "qrc:/images/controls/history.svg" + readonly property bool isRichText: false } QtObject { @@ -45,6 +47,7 @@ PageType { readonly property string title: qsTr("Active Connections") readonly property string contentKey: "connectedDevices" readonly property string objectImageSource: "qrc:/images/controls/monitor.svg" + readonly property bool isRichText: false } property var processedServer @@ -134,6 +137,7 @@ PageType { imageSource: objectImageSource leftText: title rightText: ApiAccountInfoModel.data(contentKey) + rightTextFormat: isRichText ? Text.RichText : Text.PlainText visible: rightText !== "" } From c568bf8c24eb388cc0e37ec710ed6bf286c12a9b Mon Sep 17 00:00:00 2001 From: MrMirDan <58086007+MrMirDan@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:32:00 +0300 Subject: [PATCH 36/40] chore: ru translation update (#1812) * ru translation update * fixes --- client/translations/amneziavpn_ru_RU.ts | 1677 ++++++++++++----------- 1 file changed, 851 insertions(+), 826 deletions(-) diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts index 6458d3ef..756eaa39 100644 --- a/client/translations/amneziavpn_ru_RU.ts +++ b/client/translations/amneziavpn_ru_RU.ts @@ -246,8 +246,8 @@ - VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> - Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, <a href="%1/free" style="color: #FBB26A;">подробности на сайте.</a> + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1" style="color: #FBB26A;">more details on the website.</a> + Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, <a href="%1" style="color: #FBB26A;">подробности на сайте.</a> @@ -294,45 +294,45 @@ ConnectionController - + Connecting... Подключение... - + Connected Подключено - + Preparing... Подготовка... - + Settings updated successfully, reconnnection... Настройки успешно обновлены, переподключение... - + Settings updated successfully Настройки успешно обновлены - + Reconnecting... Переподключение... - - - + + + Connect Подключиться - + Disconnecting... Отключение... @@ -381,7 +381,7 @@ HomeContainersListView - + Unable change protocol while there is an active connection Невозможно изменить протокол во время активного соединения @@ -407,8 +407,9 @@ Enabled Can't be disabled for current server - Включено -Невозможно отключить для текущего сервера + Включено +Невозможно отключить для текущего сервера + @@ -478,47 +479,47 @@ Already installed containers were found on the server. All installed containers На сервере обнаружены установленные протоколы и сервисы. Все они были добавлены в приложение - + Settings updated successfully Настройки успешно обновлены - + Server '%1' was rebooted Сервер '%1' был перезагружен - + Server '%1' was removed Сервер '%1' был удален - + All containers from server '%1' have been removed Все протоколы и сервисы были удалены с сервера '%1' - + %1 has been removed from the server '%2' %1 был удален с сервера '%2' - + Api config removed Конфигурация API удалена - + %1 cached profile cleared %1 закэшированный профиль очищен - + Please login as the user Пожалуйста, войдите в систему от имени пользователя - + Server added successfully Сервер успешно добавлен @@ -531,12 +532,12 @@ Already installed containers were found on the server. All installed containers Выберите приложение - + application name название приложения - + Add selected Добавить выбранные @@ -562,28 +563,28 @@ Already installed containers were found on the server. All installed containers NotificationHandler - - + + AmneziaVPN AmneziaVPN - + VPN Connected VPN подключен - + VPN Disconnected VPN выключен - + AmneziaVPN notification Уведомление AmneziaVPN - + Unsecured network detected: Обнаружена незащищенная сеть: @@ -609,12 +610,12 @@ Already installed containers were found on the server. All installed containers PageDeinstalling - + Removing services from %1 Удаление сервисов c %1 - + Usually it takes no more than 5 minutes Обычно это занимает не более 5 минут @@ -622,12 +623,12 @@ Already installed containers were found on the server. All installed containers PageDevMenu - + Gateway endpoint Gateway endpoint - + Dev gateway environment Dev gateway environment @@ -667,12 +668,12 @@ Thank you for staying with us! Раздельное туннелирование выключено - + VPN protocol VPN-протокол - + Servers Серверы @@ -680,37 +681,37 @@ Thank you for staying with us! PageProtocolAwgClientSettings - + AmneziaWG settings Настройки AmneziaWG - + MTU MTU - + I1 - First special junk packet I1 - First special junk packet - + I2 - Second special junk packet I2 - Second special junk packet - + I3 - Third special junk packet I3 - Third special junk packet - + I4 - Fourth special junk packet I4 - Fourth special junk packet - + I5 - Fifth special junk packet I5 - Fifth special junk packet @@ -720,57 +721,57 @@ Thank you for staying with us! J1 - First controlled junk packet - + J2 - Second controlled junk packet J2 - Second controlled junk packet - + J3 - Third controlled junk packet J3 - Third controlled junk packet - + Itime - Special handshake timeout Itime - Special handshake timeout - + Server settings Настройки сервера - + Port Порт - + Save Сохранить - + Save settings? Сохранить настройки? - + Only the settings for this device will be changed Будут изменены настройки только для этого устройства - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -778,102 +779,102 @@ Thank you for staying with us! PageProtocolAwgSettings - + AmneziaWG settings Настройки AmneziaWG - + Port Порт - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Save Сохранить - + VPN address subnet Подсеть VPN-адресов - + Jc - Junk packet count Jc - Junk packet count - + Jmin - Junk packet minimum size Jmin - Junk packet minimum size - + Jmax - Junk packet maximum size Jmax - Junk packet maximum size - + S1 - Init packet junk size S1 - Init packet junk size - + S2 - Response packet junk size S2 - Response packet junk size - + H1 - Init packet magic header H1 - Init packet magic header - + H2 - Response packet magic header H2 - Response packet magic header - + H4 - Transport packet magic header H4 - Transport packet magic header - + H3 - Underload packet magic header H3 - Underload packet magic header - + The values of the H1-H4 fields must be unique Значения в полях H1-H4 должны быть уникальными - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) Значение в поле S1 + размер инициации сообщения (148) не должно равняться значению в поле S2 + размер ответа на сообщение (92) - + Save settings? Сохранить настройки? - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -881,53 +882,53 @@ Thank you for staying with us! PageProtocolCloakSettings - + Cloak settings Настройки Cloak - + Disguised as traffic from Замаскировать трафик под - + Port Порт - - + + Cipher Шифрование - + Save Сохранить - + Save settings? Сохранить настройки? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -935,195 +936,195 @@ Thank you for staying with us! PageProtocolOpenVpnSettings - - OpenVPN settings + + OpenVPN Settings Настройки OpenVPN - + VPN address subnet Подсеть VPN-адресов - + Network protocol Сетевой протокол - + Port Порт - + Auto-negotiate encryption Шифрование с автоматическим согласованием - - + + Hash Хэш - + SHA512 SHA512 - + SHA384 SHA384 - + SHA256 SHA256 - + SHA3-512 SHA3-512 - + SHA3-384 SHA3-384 - + SHA3-256 SHA3-256 - + whirlpool whirlpool - + BLAKE2b512 BLAKE2b512 - + BLAKE2s256 BLAKE2s256 - + SHA1 SHA1 - - + + Cipher Шифрование - + AES-256-GCM AES-256-GCM - + AES-192-GCM AES-192-GCM - + AES-128-GCM AES-128-GCM - + AES-256-CBC AES-256-CBC - + AES-192-CBC AES-192-CBC - + AES-128-CBC AES-128-CBC - + ChaCha20-Poly1305 ChaCha20-Poly1305 - + ARIA-256-CBC ARIA-256-CBC - + CAMELLIA-256-CBC CAMELLIA-256-CBC - + none none - + TLS auth TLS авторизация - + Block DNS requests outside of VPN Блокировать DNS-запросы за пределами VPN - + Additional client configuration commands Дополнительные команды конфигурации клиента - - + + Commands: Команды: - + Additional server configuration commands Дополнительные команды конфигурации сервера - + Save settings? Сохранить настройки? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения - + Save Сохранить @@ -1131,32 +1132,32 @@ Thank you for staying with us! PageProtocolRaw - + settings настройки - + Show connection options Показать параметры подключения - + Connection options %1 Параметры подключения %1 - + Remove Удалить - + Remove %1 from server? Удалить %1 с сервера? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. @@ -1165,12 +1166,12 @@ Thank you for staying with us! Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться. - + Continue Продолжить - + Cancel Отменить @@ -1178,48 +1179,48 @@ Thank you for staying with us! PageProtocolShadowSocksSettings - + Shadowsocks settings Настройки Shadowsocks - + Port Порт - - + + Cipher Шифрование - + Save Сохранить - + Save settings? Сохранить настройки? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -1227,52 +1228,52 @@ Thank you for staying with us! PageProtocolWireGuardClientSettings - + WG settings Настройки WG - + MTU MTU - + Server settings Настройки сервера - + Port Порт - + Save Сохранить - + Save settings? Сохранить настройки? - + Only the settings for this device will be changed Будут изменены настройки только для этого устройства - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -1280,47 +1281,47 @@ Thank you for staying with us! PageProtocolWireGuardSettings - + WG settings Настройки WG - + VPN address subnet Подсеть VPN-адресов - + Port Порт - + Save settings? Сохранить настройки? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения - + Continue Продолжить - + Cancel Отменить - + Save Сохранить @@ -1328,47 +1329,47 @@ Thank you for staying with us! PageProtocolXraySettings - + XRay settings Настройки XRay - + Disguised as traffic from Замаскировать трафик под - + Port Порт - + Save Сохранить - + Save settings? Сохранить настройки? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -1383,39 +1384,39 @@ Thank you for staying with us! PageServiceDnsSettings - + A DNS service is installed on your server, and it is only accessible via VPN. На вашем сервере установлен DNS-сервис, доступ к нему возможен только через VPN. - + The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab. Адрес DNS совпадает с адресом вашего сервера. Настроить DNS можно во вкладке "Соединение" настроек приложения. - + Remove Удалить - + Remove %1 from server? Удалить %1 с сервера? - + Continue Продолжить - + Cancel Отменить - + Cannot remove AmneziaDNS from running server Невозможно удалить AmneziaDNS с работающего сервера @@ -1428,62 +1429,62 @@ Thank you for staying with us! Настройки успешно обновлены - + SFTP settings Настройки SFTP - + Host Хост - - - - + + + + Copied Скопировано - + Port Порт - + User name Имя пользователя - + Password Пароль - + Mount folder on device Смонтировать папку на устройстве - + In order to mount remote SFTP folder as local drive, perform following steps: <br> Чтобы смонтировать SFTP-папку как локальный диск, выполните следующие действия: <br> - - + + <br>1. Install the latest version of <br>1. Установите последнюю версию - - + + <br>2. Install the latest version of <br>2. Установите последнюю версию - + Detailed instructions Подробные инструкции @@ -1496,64 +1497,64 @@ Thank you for staying with us! Настройки успешно обновлены - - + + SOCKS5 settings Настройки SOCKS5 - + Host Хост - - - - + + + + Copied Скопировано - - + + Port Порт - + User name Имя пользователя - - + + Password Пароль - + Username Имя пользователя - - + + Change connection settings Изменить настройки соединения - + The port must be in the range of 1 to 65535 Порт должен быть в диапазоне от 1 до 65535 - + Password cannot be empty Пароль не может быть пустым - + Username cannot be empty Имя пользователя не может быть пустым @@ -1566,32 +1567,32 @@ Thank you for staying with us! Настройки успешно обновлены - + Tor website settings Настройки сайта в сети Тоr - + Website address Адрес сайта - + Copied Скопировано - + Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. Используйте <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> для открытия этой ссылки. - + After creating your onion site, it takes a few minutes for the Tor network to make it available for use. Через несколько минут после установки ваш onion-сайт станет доступен в сети Tor. - + When configuring WordPress set the this onion address as domain. При настройке WordPress укажите этот onion-адрес в качестве домена. @@ -1599,42 +1600,42 @@ Thank you for staying with us! PageSettings - + Settings Настройки - + Servers Серверы - + Connection Соединение - + Application Приложение - + Backup Резервное копирование - + About AmneziaVPN Об AmneziaVPN - + Dev console Dev console - + Close application Закрыть приложение @@ -1642,87 +1643,87 @@ Thank you for staying with us! PageSettingsAbout - + Support Amnezia Поддержите Amnezia - + Amnezia is a free and open-source application. You can support the developers if you like it. Amnezia — это бесплатное приложение с открытым исходным кодом. Поддержите разработчиков, если оно вам нравится. - + Contacts Контакты - + Telegram group Группа в Telegram - + To discuss features Для обсуждения возможностей - + https://t.me/amnezia_vpn_en https://t.me/amnezia_vpn - + support@amnezia.org support@amnezia.org - + For reviews and bug reports Для отзывов и сообщений об ошибках - + mailto:support@amnezia.org - + GitHub GitHub - + Discover the source code Посмотреть исходный код - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website Веб-сайт - + Visit official website Посетить официальный сайт - + Software version: %1 Версия ПО: %1 - + Check for updates Проверить обновления - + Privacy Policy Политика конфиденциальности @@ -1736,6 +1737,11 @@ Thank you for staying with us! + Unable change server location while trying to make an active connection + Невозможно изменить локацию во время попытки соединения + + + Unable change server location while there is an active connection Невозможно изменить локацию во время активного соединения @@ -1805,69 +1811,69 @@ Thank you for staying with us! Windows - - - https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#windows - - macOS - - - https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#macos - - Android - - - https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#android - - AndroidTV - - - https://docs.amnezia.org/ru/documentation/instructions/android_tv_connect/ - - iOS - - - https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#ios - - Linux - - - https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#linux - - Routers + + + documentation/instructions/connect-amnezia-premium#windows + + + + + documentation/instructions/connect-amnezia-premium#macos + + + + + documentation/instructions/connect-amnezia-premium#android + + + + + documentation/instructions/android_tv_connect/ + + + + + documentation/instructions/connect-amnezia-premium#ios + + + + + documentation/instructions/connect-amnezia-premium#linux + + - https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#routers + documentation/instructions/connect-amnezia-premium#routers @@ -1889,77 +1895,77 @@ Thank you for staying with us! Сохранить конфигурацию AmneziaVPN - + Configuration Files Файлы конфигурации - + For router setup or the AmneziaWG app Для настройки роутера или приложения AmneziaWG - + The configuration needs to be reissued Необходимо заново скачать конфигурацию и добавить ее в приложение - + configuration file файл конфигурации - + Generate a new configuration file Создать новый файл конфигурации - + The previously created one will stop working Ранее созданный файл перестанет работать - + Revoke the current configuration file Отозвать текущий файл конфигурации - + Config file saved Файл конфигурации сохранен - + The config has been revoked Конфигурация была отозвана - + Generate a new %1 configuration file? Создать новый %1 файл конфигурации? - + Revoke the current %1 configuration file? Отозвать текущий %1 файл конфигурации? - + Your previous configuration file will no longer work, and it will not be possible to connect using it Ваш предыдущий файл конфигурации не будет работать, и вы больше не сможете использовать его для подключения - + Download Скачать - + Continue Продолжить - + Cancel Отменить @@ -1967,22 +1973,12 @@ Thank you for staying with us! PageSettingsApiServerInfo - + Configurations have been updated for some countries. Download and install the updated configuration files Сетевые адреса одного или нескольких серверов были обновлены. Пожалуйста, удалите старые конфигурацию и загрузите новые файлы - - Amnezia Premium subscription key - Ключ подписки Amnezia Premium - - - - Copy VPN key - Скопировать VPN ключ - - - + Manage configuration files Управление файлами конфигурации @@ -2002,115 +1998,160 @@ Thank you for staying with us! Активные соединения - + Use VLESS protocol Использовать протокол VLESS - + Cannot change protocol during active connection Невозможно изменить протокол во время активного соединения - + Subscription Key Ключ для подключения - - Save VPN key as a file - Сохранить VPN-ключ в файл - - - + Configuration Files Файлы конфигурации - + Active Devices Активные устройства - + Manage currently connected devices Управление подключенными устройствами - + Support Поддержка - + How to connect on another device Как подключить другие устройства - + Reload API config Перезагрузить конфигурацию API - + Reload API config? Перезагрузить конфигурацию API? - - - + + + Continue Продолжить - - - + + + Cancel Отменить - + Cannot reload API config during active connection Невозможно перзагрузить API конфигурацию при активном соединении - + Unlink this device Отвязать это устройство - + Are you sure you want to unlink this device? Вы уверены, что хотите отвязать это устройство? - + This will unlink the device from your subscription. You can reconnect it anytime by pressing "Reload API config" in subscription settings on device. Это отключит устройство от вашей подписки. Вы можете повторно подключить его в любое время, нажав "Перезагрузить конфигурацию API" в настройках подписки на устройстве. - + Cannot unlink device during active connection Невозможно отвязать устройство во время активного соединения - + Remove from application Удалить из приложения - + Remove from application? Удалить из приложения? - + Cannot remove server during active connection Невозможно удалить сервер во время активного соединения + + PageSettingsApiSubscriptionKey + + + Amnezia Premium +subscription key + Amnezia Premium +ключ подключения + + + + Copy key + Скопировать ключ + + + + Copied + Скопировано + + + + Save key as a file + Сохранить ключ как файл + + + + Save AmneziaVPN config + Сохранить конфигурацию AmneziaVPN + + + + Config files (*.vpn) + Файлы конфигов (*.vpn) + + + + Show key text + Показать ключ + + + + To read the QR code in the Amnezia app, tap + in the main menu → 'QR code' + Для считывания QR-кода в приложении Amnezia выберите + в главном меню → 'QR-код' + + + + Amnezia Premium Subscription key + Ключ подключения Amnezia Premium + + PageSettingsApiSupport @@ -2167,47 +2208,47 @@ Thank you for staying with us! Только приложения из списка должны работать через VPN - + Apps from the list should not have access via VPN Приложения из списка не должны работать через VPN - + App split tunneling Раздельное туннелирование приложений - + Mode Режим - + Remove Удалить - + Continue Продолжить - + Cancel Отменить - + application name название приложения - + Open executable file Открыть исполняемый файл - + Executable files (*.*) Исполняемые файлы (*.*) @@ -2215,102 +2256,102 @@ Thank you for staying with us! PageSettingsApplication - + Application Приложение - + Allow application screenshots Разрешить скриншоты приложения - + Auto start Автозапуск - + Launch the application every time the device is starts Запускать приложение при загрузке устройства - + Auto connect Автоподключение - + Connect to VPN on app start Подключаться к VPN при запуске приложения - + Start minimized Запускать в свернутом виде - - Launch application minimized - Запускать приложение в свернутом виде - - - + Language Язык - + Enable notifications Включить уведомления - + Enable notifications to show the VPN state in the status bar Включить уведомления для отображения статуса VPN в строке состояния - + + Launch application minimized (works with autostart option turned on) + Запускает приложение свёрнутым (работает с включенной функцией автозапуска) + + + Logging Логирование - + Enabled Включено - + Disabled Отключено - + Reset settings and remove all data from the application Сбросить настройки и удалить все данные из приложения - + Reset settings and remove all data from the application? Сбросить настройки и удалить все данные из приложения? - + All settings will be reset to default. All installed AmneziaVPN services will still remain on the server. Все настройки будут сброшены до значений по умолчанию. Все установленные сервисы AmneziaVPN останутся на сервере. - + Continue Продолжить - + Cancel Отменить - + Cannot reset settings during active connection Невозможно сбросить настройки во время активного соединения @@ -2323,73 +2364,73 @@ Thank you for staying with us! Настройки восстановлены из файла резервной копии - + Back up your configuration Создать резервную копию конфигурации - + You can save your settings to a backup file to restore them the next time you install the application. Вы можете сохранить настройки в файл резервной копии, чтобы восстановить их при следующей установке приложения. - + The backup will contain your passwords and private keys for all servers added to AmneziaVPN. Keep this information in a secure place. Резервная копия будет содержать ваши пароли и закрытые ключи для всех серверов, добавленных в AmneziaVPN. Храните эту информацию в надежном месте. - + Make a backup Создать резервную копию - + Save backup file Сохранить резервную копию - - + + Backup files (*.backup) Файлы резервных копий (*.backup) - + Backup file saved Резервная копия сохранена - + Restore from backup Восстановить из резервной копии - + Open backup file Открыть резервную копию - + Import settings from a backup file? Импортировать настройки из резервной копии? - + All current settings will be reset Все текущие настройки будут сброшены - + Continue Продолжить - + Cancel Отменить - + Cannot restore backup settings during active connection Невозможно восстановить настройки из резервной копии во время активного соединения @@ -2397,57 +2438,57 @@ Thank you for staying with us! PageSettingsConnection - + Connection Соединение - + Use AmneziaDNS Использовать AmneziaDNS - + If AmneziaDNS is installed on the server Если AmneziaDNS установлен на сервере - + DNS servers DNS-серверы - + When AmneziaDNS is not used or installed Когда AmneziaDNS не используется или не установлен - + Allows you to use the VPN only for certain Apps Позволяет использовать VPN только для определенных приложений - + KillSwitch KillSwitch - + Blocks network connections without VPN Блокирует интернет-соединение без VPN - + Site-based split tunneling Раздельное туннелирование сайтов - + Allows you to select which sites you want to access through the VPN Позволяет выбирать, к каким сайтам подключаться через VPN - + App-based split tunneling Раздельное туннелирование приложений @@ -2455,62 +2496,62 @@ Thank you for staying with us! PageSettingsDns - + Default server does not support custom DNS Сервер по умолчанию не поддерживает пользовательские DNS - + DNS servers DNS-серверы - + If AmneziaDNS is not used or installed Если AmneziaDNS не используется или не установлен - + Primary DNS Первичный DNS - + Secondary DNS Вторичный DNS - + Restore default Восстановить по умолчанию - + Restore default DNS settings? Восстановить настройки DNS по умолчанию? - + Continue Продолжить - + Cancel Отменить - + Settings have been reset Настройки были сброшены - + Save Сохранить - + Settings saved Настройки сохранены @@ -2543,42 +2584,42 @@ Thank you for staying with us! Доступ в интернет блокируется при разрыве VPN-соединения - + Strict KillSwitch Strict KillSwitch - + Internet connection is blocked even when VPN is turned off manually or hasn't started Доступ в интернет блокируется, даже если VPN отключен вручную или не был запущен - + Just a little heads-up Небольшое предупреждение - + If the VPN disconnects or drops while Strict KillSwitch is enabled, internet access will be blocked. To restore access, reconnect VPN or disable/change the KillSwitch. Если VPN отключится или соединение прервётся при включённом Strict KillSwitch, доступ в интернет будет заблокирован. Чтобы восстановить доступ, снова подключитесь к VPN или отключите (измените) режим KillSwitch. - + Continue Продолжить - + Cancel Отменить - + DNS Exceptions Исключения для DNS - + DNS servers listed here will remain accessible when KillSwitch is active. DNS-серверы из этого списка останутся доступными при активном KillSwitch. @@ -2667,90 +2708,90 @@ Thank you for staying with us! PageSettingsLogging - + Logging Логирование - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. Включение этой функции позволяет сохранять логи на вашем устройстве. По умолчанию она отключена. Включите сохранение логов в случае сбоев в работе приложения. - - + + Save Сохранить - - + + Logs files (*.log) Файлы логов (*.log) - - + + Logs file saved Файл с логами сохранен - + Enable logs Включить запись логов - + Clear logs? Очистить логи? - + Continue Продолжить - + Cancel Отменить - + Logs have been cleaned up Логи очищены - + Client logs Логи приложения - + AmneziaVPN logs AmneziaVPN logs - + Open logs folder Открыть папку с логами - + Export logs Сохранить логи - + Service logs Логи службы - + AmneziaVPN-service logs AmneziaVPN-service logs - + Clear logs Очистить логи @@ -2758,118 +2799,118 @@ Thank you for staying with us! PageSettingsServerData - + All installed containers have been added to the application Все установленные протоколы и сервисы были добавлены в приложение - + No new installed containers found Новые установленные протоколы и сервисы не обнаружены - - - - + + + + Continue Продолжить - - - - + + + + Cancel Отменить - + Check the server for previously installed Amnezia services Проверить сервер на наличие ранее установленных сервисов Amnezia - + Add them to the application if they were not displayed Добавить их в приложение, если они не отображаются - + Reboot server Перезагрузить сервер - + Do you want to reboot the server? Вы уверены, что хотите перезагрузить сервер? - + The reboot process may take approximately 30 seconds. Are you sure you wish to proceed? Процесс перезагрузки может занять около 30 секунд. Вы уверены, что хотите продолжить? - + Cannot reboot server during active connection Невозможно перезагрузить сервер во время активного соединения - + Do you want to remove the server from application? Вы уверены, что хотите удалить сервер из приложения? - + Cannot remove server during active connection Невозможно удалить сервер во время активного соединения - + Do you want to clear server from Amnezia software? Вы хотите очистить сервер от всех сервисов Amnezia? - + All users whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Cannot clear server from Amnezia software during active connection Невозможно очистить сервер от сервисов Amnezia во время активного соединения - + Reset API config Сбросить конфигурацию API - + Do you want to reset API config? Вы хотите сбросить конфигурацию API? - + Cannot reset API config during active connection Невозможно сбросить конфигурацию API во время активного соединения - + Switch to the new Amnezia Premium subscription Перейти на новый тип подписки Amnezia Premium - + Remove server from application Удалить сервер из приложения - + All installed AmneziaVPN services will still remain on the server. Все установленные сервисы и протоколы Amnezia останутся на сервере. - + Clear server from Amnezia software Очистить сервер от протоколов и сервисов Amnezia @@ -2895,74 +2936,74 @@ Thank you for staying with us! PageSettingsServerProtocol - + settings настройки - + Clear %1 profile? Очистить профиль %1? - + connection settings настройки подключения - + Click the "connect" button to create a connection configuration Нажмите кнопку «Подключиться», чтобы создать конфигурацию - + server settings настройки сервера - + Clear profile Очистить профиль - + The connection configuration will be deleted for this device only Конфигурация подключения будет удалена только на этом устройстве - + Unable to clear %1 profile while there is an active connection Невозможно очистить профиль %1 во время активного соединения - + Remove Удалить - + Remove %1 from server? Удалить %1 с сервера? - + All users with whom you shared a connection will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Cannot remove active container Невозможно удалить активный контейнер - - + + Continue Продолжить - - + + Cancel Отменить @@ -2998,25 +3039,22 @@ Thank you for staying with us! Режим - + Remove Удалить - + + Continue Продолжить - + + Cancel Отменить - - - Import / Export Sites - Импорт/экспорт сайтов - Only the sites listed here will be accessed through the VPN @@ -3028,50 +3066,70 @@ Thank you for staying with us! Невозможно изменить настройки раздельного туннелирования во время активного соединения - + website or IP веб-сайт или IP - + + Additional options + Дополнительные настройки + + + Import Импорт - + Save site list Сохранить список сайтов - + Save sites Сохранить сайты - - - + + + Sites files (*.json) Файлы сайтов (*.json) - + + Clear site list + Очистить список сайтов + + + + Clear site list? + Очистить список сайтов? + + + + All sites will be removed from list. + Все сайты будут удалены из списка. + + + Import a list of sites Импортировать список с сайтами - + Replace site list Заменить список с сайтами - - + + Open sites file Открыть список с сайтами - + Add imported sites to existing ones Добавить импортированные сайты к существующим @@ -3079,32 +3137,32 @@ Thank you for staying with us! PageSetupWizardApiServiceInfo - + For the region Для региона - + Price Цена - + Work period Период работы - + Speed Скорость - + Features Особенности - + Connect Подключиться @@ -3112,12 +3170,12 @@ Thank you for staying with us! PageSetupWizardApiServicesList - + VPN by Amnezia VPN от Amnezia - + Choose a VPN service that suits your needs. Выберите VPN-сервис, который подходит именно вам. @@ -3125,140 +3183,140 @@ Thank you for staying with us! PageSetupWizardConfigSource - + File with connection settings Файл с настройками подключения - + Connection Соединение - + Settings Настройки - + Enable logs Включить запись логов - + Export client logs Экспорт логов клиента - + Save Сохранить - + Logs files (*.log) Файлы логов (*.log) - + Logs file saved Файл с логами сохранен - + Support tag Support tag - + Copied Скопировано - + Insert the key, add a configuration file or scan the QR-code Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код - + Insert key Вставьте ключ - + Insert Вставить - + Continue Продолжить - + Other connection options Другие варианты подключения - + Site Amnezia Сайт Amnezia - + VPN by Amnezia VPN от Amnezia - + Connect to classic paid and free VPN services from Amnezia Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia - + Self-hosted VPN Self-hosted VPN - + Configure Amnezia VPN on your own server Настроить VPN на собственном сервере - + Restore from backup Восстановить из резервной копии - - - - + + + + - + Open backup file Открыть резервную копию - + Backup files (*.backup) Файлы резервных копий (*.backup) - + Open config file Открыть файл с конфигурацией - + QR code QR-код - + I have nothing У меня ничего нет @@ -3266,67 +3324,67 @@ Thank you for staying with us! PageSetupWizardCredentials - + Server IP address [:port] IP-адрес[:порт] сервера - + Continue Продолжить - + Enter the address in the format 255.255.255.255:88 Введите адрес в формате 255.255.255.255:88 - + Configure your server Настроить ваш сервер - + 255.255.255.255:22 255.255.255.255:22 - + SSH Username Имя пользователя SSH - + Password or SSH private key Пароль или закрытый ключ SSH - + All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties Все данные, которые вы вводите, останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или каким-либо третьим лицам - + How to run your VPN server Как создать VPN на собственном сервере - + Where to get connection data, step-by-step instructions for buying a VPS Где взять данные для подключения, пошаговые инструкции по покупке VPS - + Ip address cannot be empty Поле с IP-адресом не может быть пустым - + Login cannot be empty Поле с логином не может быть пустым - + Password/private key cannot be empty Поле с паролем/закрытым ключом не может быть пустым @@ -3334,27 +3392,27 @@ Thank you for staying with us! PageSetupWizardEasy - + Choose Installation Type Выберите тип установки - + Manual Ручная - + Choose a VPN protocol Выбрать VPN-протокол - + Skip setup Пропустить настройку - + Continue Продолжить @@ -3382,12 +3440,12 @@ Thank you for staying with us! будет приостановлена до тех пор, пока сервер не завершит установку другого ПО - + Installing Установка - + Cancel installation Отменить установку @@ -3401,37 +3459,37 @@ Thank you for staying with us! PageSetupWizardProtocolSettings - + Installing %1 Устанавливается %1 - + More detailed Подробнее - + Close Закрыть - + Network protocol Сетевой протокол - + Port Порт - + Install Установить - + The port must be in the range of 1 to 65535 Порт должен быть в диапазоне от 1 до 65535 @@ -3439,12 +3497,12 @@ Thank you for staying with us! PageSetupWizardProtocols - + VPN protocol VPN-протокол - + Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP. Выберите протокол, который вам больше подходит. В дальнейшем можно установить другие протоколы и дополнительные сервисы, такие как DNS-прокси и SFTP. @@ -3468,27 +3526,27 @@ Thank you for staying with us! PageSetupWizardTextKey - + Connection key Ключ для подключения - + A line that starts with vpn://... Строка, которая начинается с vpn://... - + Key Ключ - + Insert Вставить - + Continue Продолжить @@ -3496,32 +3554,32 @@ Thank you for staying with us! PageSetupWizardViewConfig - + New connection Новое соединение - + Collapse content Свернуть - + Show content Показать - + Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider. Включить обфускацию WireGuard. Это может быть полезно, если WireGuard блокируется вашим провайдером. - + Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data. Используйте файлы конфигурации только из тех источников, которым вы доверяете. Файлы из общедоступных источников могли быть созданы с целью перехвата ваших личных данных. - + Connect Подключиться @@ -3529,271 +3587,273 @@ Thank you for staying with us! PageShare - + OpenVPN native format Оригинальный формат OpenVPN - + WireGuard native format Оригинальный формат WireGuard - + Connection Соединение - - + + Server Сервер - + Config revoked Конфигурация отозвана - - Connection to - Подключение к - - - - File with connection settings to - Файл с настройками подключения к - - - - Save OpenVPN config - Сохранить конфигурацию OpenVPN - - - - Save WireGuard config - Сохранить конфигурацию WireGuard - - - - Save AmneziaWG config - Сохранить конфигурацию AmneziaWG - - - - Save Shadowsocks config - Сохранить конфигурацию Shadowsocks - - - - Save Cloak config - Сохранить конфигурацию Cloak - - - - Save XRay config - Сохранить конфигурацию XRay - - - + For the AmneziaVPN app Для приложения AmneziaVPN - + AmneziaWG native format Оригинальный формат AmneziaWG - + Shadowsocks native format Оригинальный формат Shadowsocks - + Cloak native format Оригинальный формат Cloak - + XRay native format Оригинальный формат XRay - + Share VPN Access Поделиться VPN - + Share full access to the server and VPN Поделиться полным доступом к серверу и VPN - + Use for your own devices, or share with those you trust to manage the server. Используйте для собственных устройств или передайте управление сервером тем, кому вы доверяете. - - + + Users Пользователи - + User name Имя пользователя - + Search Поиск - + Creation date: %1 Дата создания: %1 - + Latest handshake: %1 Последнее рукопожатие: %1 - + Data received: %1 Получено данных: %1 - + Data sent: %1 Отправлено данных: %1 - + Allowed IPs: %1 Разрешенные подсети: %1 - + Rename Переименовать - + Client name Имя клиента - + Save Сохранить - + Revoke Отозвать - + Revoke the config for a user - %1? Отозвать конфигурацию для пользователя - %1? - + The user will no longer be able to connect to your server. Пользователь больше не сможет подключаться к вашему серверу. - + Continue Продолжить - + Cancel Отменить - + Share VPN access without the ability to manage the server Поделиться доступом к VPN без возможности управления сервером - - + + Protocol Протокол - - + + Connection format Формат подключения - - + + Share Поделиться + + PageShareConnection + + + + Connection to + Подключение к + + + + + File with connection settings to + Файл с настройками подключения к + + + + Share + Поделиться + + + + Copy + Скопировать + + + + + Save AmneziaVPN config + Сохранить конфигурацию AmneziaVPN + + + + Copy config string + Скопировать строку конфигурации + + + + Show connection settings + Показать настройки подключения + + + + + Copied + Скопировано + + + + To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" + Для считывания QR-кода в приложении Amnezia выберите "Добавить сервер" → "У меня есть данные для подключения" → "Открыть файл конфигурации, ключ или QR-код" + + PageShareFullAccess - + Full access to the server and VPN Полный доступ к серверу и VPN - + We recommend that you use full access to the server only for your own additional devices. Мы рекомендуем использовать полный доступ к серверу только для собственных устройств. - + If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. Если вы поделитесь полным доступом с другими людьми, то они смогут удалять и добавлять протоколы и сервисы на сервер, что приведет к некорректной работе VPN для всех пользователей. - - + + Server Сервер - + Accessing Доступ - + File with accessing settings to Файл с настройками доступа к - + Share Поделиться - + Access error! Ошибка доступа! - - - Connection to - Подключение к - - - - File with connection settings to - Файл с настройками подключения к - PageStart @@ -4188,6 +4248,13 @@ Thank you for staying with us! The config does not contain any containers and credentials for connecting to the server Конфигурация не содержит каких-либо контейнеров и учетных данных для подключения к серверу + + + VPN Protocols is not installed. + Please install VPN container at first + VPN-протоколы не установлены. +Пожалуйста, установите протокол + @@ -4269,13 +4336,6 @@ Thank you for staying with us! Unable to open config file Не удалось открыть файл конфигурации - - - VPN Protocols is not installed. - Please install VPN container at first - VPN-протоколы не установлены. - Пожалуйста, установите протокол - VPN connection error @@ -4366,55 +4426,6 @@ Thank you for staying with us! Create a file vault on your server to securely store and transfer files. Создайте на сервере файловое хранилище для безопасного хранения и передачи файлов. - - - AmneziaWG is a modern VPN protocol based on WireGuard, combining simplified architecture with high performance across all devices. It addresses WireGuard's main vulnerability (easy detection by DPI systems) through advanced obfuscation techniques, making VPN traffic indistinguishable from regular internet traffic. - -AmneziaWG is an excellent choice for those seeking a fast, stealthy VPN connection. - -Features: -* Available on all AmneziaVPN platforms -* Low battery consumption on mobile devices -* Minimal settings required -* Undetectable by traffic analysis systems (DPI) -* Operates over UDP protocol - AmneziaWG — современный VPN-протокол на основе WireGuard, сочетающий простую архитектуру и высокую производительность на всех устройствах. Он устраняет основной недостаток WireGuard (лёгкое обнаружение трафика системами DPI) за счёт эффективного маскирования VPN-трафика под обычный интернет-трафик. - -Таким образом, AmneziaWG идеально подойдёт тем, кто ищет быстрое и незаметное VPN-соединение. - -Особенности: -* Доступен во всех версиях AmneziaVPN -* Низкое энергопотребление на мобильных устройствах -* Минимум настроек -* Незаметен для систем анализа трафика (DPI) -* Работает по протоколу UDP - - - - - REALITY is an innovative protocol developed by the creators of XRay, designed specifically to combat high levels of internet censorship. REALITY identifies censorship systems during the TLS handshake, redirecting suspicious traffic seamlessly to legitimate websites like google.com while providing genuine TLS certificates. This allows VPN traffic to blend indistinguishably with regular web traffic without special configuration. -Unlike older protocols such as VMess, VLESS, and XTLS-Vision, REALITY incorporates an advanced built-in "friend-or-foe" detection mechanism, effectively protecting against DPI and other traffic analysis methods. - -Features: -* Resistant to active probing and DPI detection -* No special configuration required to disguise traffic -* Highly effective in heavily censored regions -* Minimal battery consumption on devices -* Operates over TCP protocol - REALITY — это инновационный протокол от разработчиков XRay, специально созданный для эффективного противодействия жесткой интернет-цензуре. - -REALITY распознаёт системы блокировки во время TLS-рукопожатия и незаметно перенаправляет подозрительные запросы на реальные сайты, такие как google.com, предъявляя подлинные TLS-сертификаты. Это позволяет маскировать VPN-трафик под обычный веб-трафик без дополнительных настроек. - -В отличие от протоколов старого поколения (VMess, VLESS и XTLS-Vision), REALITY использует встроенную технологию распознавания «свой-чужой», надёжно защищая от DPI и других методов сетевого анализа. - -Особенности: -* Устойчив к активному зондированию и DPI-системам -* Не требует специальной настройки для маскировки трафика -* Эффективен в регионах с жесткой цензурой -* Минимальное энергопотребление на устройствах -* Работает по протоколу TCP - - DNS Service @@ -4557,6 +4568,53 @@ Features: * Минимум настроек * Легко определяется DPI-системами (подвержен блокировкам) * Работает по протоколу UDP + + + + AmneziaWG is a modern VPN protocol based on WireGuard, combining simplified architecture with high performance across all devices. It addresses WireGuard's main vulnerability (easy detection by DPI systems) through advanced obfuscation techniques, making VPN traffic indistinguishable from regular internet traffic. + +AmneziaWG is an excellent choice for those seeking a fast, stealthy VPN connection. + +Features: +* Available on all AmneziaVPN platforms +* Low battery consumption on mobile devices +* Minimal settings required +* Undetectable by traffic analysis systems (DPI) +* Operates over UDP protocol + AmneziaWG — современный VPN-протокол на основе WireGuard, сочетающий простую архитектуру и высокую производительность на всех устройствах. Он устраняет основной недостаток WireGuard (лёгкое обнаружение трафика системами DPI) за счёт эффективного маскирования VPN-трафика под обычный интернет-трафик. + +Таким образом, AmneziaWG идеально подойдёт тем, кто ищет быстрое и незаметное VPN-соединение. + +Особенности: +* Доступен во всех версиях AmneziaVPN +* Низкое энергопотребление на мобильных устройствах +* Минимум настроек +* Незаметен для систем анализа трафика (DPI) +* Работает по протоколу UDP + + + + REALITY is an innovative protocol developed by the creators of XRay, designed specifically to combat high levels of internet censorship. REALITY identifies censorship systems during the TLS handshake, redirecting suspicious traffic seamlessly to legitimate websites like google.com while providing genuine TLS certificates. This allows VPN traffic to blend indistinguishably with regular web traffic without special configuration. +Unlike older protocols such as VMess, VLESS, and XTLS-Vision, REALITY incorporates an advanced built-in "friend-or-foe" detection mechanism, effectively protecting against DPI and other traffic analysis methods. + +Features: +* Resistant to active probing and DPI detection +* No special configuration required to disguise traffic +* Highly effective in heavily censored regions +* Minimal battery consumption on devices +* Operates over TCP protocol + REALITY — это инновационный протокол от разработчиков XRay, специально созданный для эффективного противодействия жесткой интернет-цензуре. + +REALITY распознаёт системы блокировки во время TLS-рукопожатия и незаметно перенаправляет подозрительные запросы на реальные сайты, такие как google.com, предъявляя подлинные TLS-сертификаты. Это позволяет маскировать VPN-трафик под обычный веб-трафик без дополнительных настроек. + +В отличие от протоколов старого поколения (VMess, VLESS и XTLS-Vision), REALITY использует встроенную технологию распознавания «свой-чужой», надёжно защищая от DPI и других методов сетевого анализа. + +Особенности: +* Устойчив к активному зондированию и DPI-системам +* Не требует специальной настройки для маскировки трафика +* Эффективен в регионах с жесткой цензурой +* Минимальное энергопотребление на устройствах +* Работает по протоколу TCP @@ -4577,41 +4635,6 @@ Features: * Распознаётся DPI-системами (легко блокируется) * Работает по UDP (порты 500 и 4500) - - - AmneziaWG is a modern VPN protocol based on WireGuard, combining simplified architecture with high performance across all devices. It addresses WireGuard’s main vulnerability (easy detection by DPI systems) through advanced obfuscation techniques, making VPN traffic indistinguishable from regular internet traffic. - - AmneziaWG is an excellent choice for those seeking a fast, stealthy VPN connection. - - Features: - - * Available on all AmneziaVPN platforms - * Low battery consumption on mobile devices - * Minimal settings required - * Undetectable by traffic analysis systems (DPI) - * Operates over UDP protocol - - AmneziaWG — современный VPN-протокол на основе WireGuard, сочетающий простую архитектуру и высокую производительность на всех устройствах. Он устраняет основной недостаток WireGuard (лёгкое обнаружение трафика системами DPI) за счёт эффективного маскирования VPN-трафика под обычный интернет-трафик. - -Таким образом, AmneziaWG идеально подойдёт тем, кто ищет быстрое и незаметное VPN-соединение. - -Особенности: -* Доступен во всех версиях AmneziaVPN -* Низкое энергопотребление на мобильных устройствах -* Минимум настроек -* Незаметен для систем анализа трафика (DPI) -* Работает по протоколу UDP - - - - Deploy a WordPress site on the Tor network in two clicks. - Разверните сайт на WordPress в сети Tor в два клика. - - - - Replace the current DNS server with your own. This will increase your privacy level. - Замените текущий DNS-сервер на свой собственный. Это повысит уровень вашей конфиденциальности. - After installation, Amnezia will create a @@ -4624,12 +4647,49 @@ For more detailed information, you can find it in the support section under "Create SFTP file storage." После установки Amnezia создаст - файловое хранилище на вашем сервере. Вы сможете получить к нему доступ, используя - FileZilla или другие SFTP-клиенты, а также смонтировать диск на вашем устройстве для доступа - непосредственно с вашего устройства. +файловое хранилище на вашем сервере. Вы сможете получить к нему доступ, используя +FileZilla или другие SFTP-клиенты, а также смонтировать диск на вашем устройстве для доступа +непосредственно с вашего устройства. Более подробную информацию вы можете -найти в разделе поддержки "Создание файлового хранилища SFTP." +найти в разделе поддержки "Создание файлового хранилища SFTP." + + + + AmneziaWG is a modern VPN protocol based on WireGuard, combining simplified architecture with high performance across all devices. It addresses WireGuard’s main vulnerability (easy detection by DPI systems) through advanced obfuscation techniques, making VPN traffic indistinguishable from regular internet traffic. + + AmneziaWG is an excellent choice for those seeking a fast, stealthy VPN connection. + + Features: + + * Available on all AmneziaVPN platforms + * Low battery consumption on mobile devices + * Minimal settings required + * Undetectable by traffic analysis systems (DPI) + * Operates over UDP protocol + + + AmneziaWG — современный VPN-протокол на основе WireGuard, сочетающий простую архитектуру и высокую производительность на всех устройствах. Он устраняет основной недостаток WireGuard (лёгкое обнаружение трафика системами DPI) за счёт эффективного маскирования VPN-трафика под обычный интернет-трафик. + + Таким образом, AmneziaWG идеально подойдёт тем, кто ищет быстрое и незаметное VPN-соединение. + + Особенности: + * Доступен во всех версиях AmneziaVPN + * Низкое энергопотребление на мобильных устройствах + * Минимум настроек + * Незаметен для систем анализа трафика (DPI) + * Работает по протоколу UDP + + + + + Deploy a WordPress site on the Tor network in two clicks. + Разверните сайт на WordPress в сети Tor в два клика. + + + + Replace the current DNS server with your own. This will increase your privacy level. + Замените текущий DNS-сервер на свой собственный. Это повысит уровень вашей конфиденциальности. @@ -4860,7 +4920,7 @@ For more detailed information, you can ServersListView - + Unable change server while there is an active connection Невозможно изменить сервер во время активного соединения @@ -4882,56 +4942,16 @@ For more detailed information, you can SettingsController - + All settings have been reset to default values Все настройки сброшены до значений по умолчанию - + Backup file is corrupted Файл резервной копии поврежден - - ShareConnectionDrawer - - - - Save AmneziaVPN config - Сохранить конфигурацию AmneziaVPN - - - - Share - Поделиться - - - - Copy - Скопировать - - - - - Copied - Скопировано - - - - Copy config string - Скопировать строку конфигурации - - - - Show connection settings - Показать настройки подключения - - - - To read the QR code in the Amnezia app, select "Add server" → "I have data to connect" → "QR code, key or settings file" - Для считывания QR-кода в приложении Amnezia выберите "Добавить сервер" → "У меня есть данные для подключения" → "Открыть файл конфигурации, ключ или QR-код" - - SitesController @@ -4951,26 +4971,31 @@ For more detailed information, you can + Site list cleared! + Список сайтов очищен! + + + Can't open file: %1 Невозможно открыть файл: %1 - + Failed to parse JSON data from file: %1 Не удалось разобрать JSON-данные из файла: %1 - + The JSON data is not an array in file: %1 JSON-данные не являются массивом в файле: %1 - + Import completed Импорт завершен - + Export completed Экспорт завершен @@ -4979,31 +5004,31 @@ For more detailed information, you can SystemTrayNotificationHandler - + Show Показать - + Connect Подключиться - + Disconnect Отключиться - + Visit Website Посетить сайт - - + + Quit Закрыть @@ -5011,7 +5036,7 @@ For more detailed information, you can TextFieldWithHeaderType - + The field can't be empty Поле не может быть пустым @@ -5019,7 +5044,7 @@ For more detailed information, you can VpnConnection - + Mbps Мбит/с @@ -5070,12 +5095,12 @@ For more detailed information, you can amnezia::ContainerProps - + Automatic Автоматическая - + AmneziaWG protocol will be installed. It provides high connection speed and ensures stable operation even in the most challenging network conditions. Будет установлен протокол AmneziaWG. Он обеспечивает высокую скорость соединения и гарантирует стабильную работу даже в самых сложных условиях. @@ -5083,12 +5108,12 @@ For more detailed information, you can main2 - + Private key passphrase Парольная фраза для закрытого ключа - + Save Сохранить From 4551659c2a097dda9b256b5be8e8830a27fbc88e Mon Sep 17 00:00:00 2001 From: vkamn Date: Wed, 27 Aug 2025 15:15:53 +0800 Subject: [PATCH 37/40] fix: minor ui fixes with services list --- client/ui/models/api/apiServicesModel.cpp | 8 ++++++++ client/ui/models/api/apiServicesModel.h | 3 ++- .../qml/Pages2/PageSetupWizardApiServiceInfo.qml | 2 ++ .../qml/Pages2/PageSetupWizardApiServicesList.qml | 14 ++++++++++++-- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/client/ui/models/api/apiServicesModel.cpp b/client/ui/models/api/apiServicesModel.cpp index 1bd1f280..d571346b 100644 --- a/client/ui/models/api/apiServicesModel.cpp +++ b/client/ui/models/api/apiServicesModel.cpp @@ -117,6 +117,13 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const case EndDateRole: { return QDateTime::fromString(apiServiceData.subscription.endDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy"); } + case OrderRole: { + if (serviceType == serviceType::amneziaPremium) { + return 0; + } else if (serviceType == serviceType::amneziaFree) { + return 1; + } + } } return QVariant(); @@ -216,6 +223,7 @@ QHash ApiServicesModel::roleNames() const roles[FeaturesRole] = "features"; roles[PriceRole] = "price"; roles[EndDateRole] = "endDate"; + roles[OrderRole] = "order"; return roles; } diff --git a/client/ui/models/api/apiServicesModel.h b/client/ui/models/api/apiServicesModel.h index 4bd870b3..cee405b3 100644 --- a/client/ui/models/api/apiServicesModel.h +++ b/client/ui/models/api/apiServicesModel.h @@ -20,7 +20,8 @@ public: RegionRole, FeaturesRole, PriceRole, - EndDateRole + EndDateRole, + OrderRole }; explicit ApiServicesModel(QObject *parent = nullptr); diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml index 1f76c97d..8668a1e2 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml @@ -66,6 +66,8 @@ PageType { imageSource: imagePath leftText: lText rightText: rText + + visible: isVisible } } diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml index 51fdee36..61b5cde8 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml @@ -3,6 +3,8 @@ import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs +import SortFilterProxyModel 0.2 + import PageEnum 1.0 import Style 1.0 @@ -54,7 +56,15 @@ PageType { spacing: 0 - model: ApiServicesModel + model: SortFilterProxyModel { + id: proxyApiServicesModel + + sourceModel: ApiServicesModel + sorters: RoleSorter { + roleName: "order" + sortOrder: Qt.AscendingOrder + } + } delegate: ColumnLayout { @@ -78,7 +88,7 @@ PageType { onClicked: { if (isServiceAvailable) { - ApiServicesModel.setServiceIndex(index) + ApiServicesModel.setServiceIndex(proxyApiServicesModel.mapToSource(index)) PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) } } From 1ea716a163be643b109e264e8bfb72d3cdfad351 Mon Sep 17 00:00:00 2001 From: vkamn Date: Wed, 27 Aug 2025 16:41:11 +0800 Subject: [PATCH 38/40] fix: fix page share connection headers and config description --- client/ui/controllers/pageController.h | 4 ++- .../qml/Pages2/PageSettingsApiServerInfo.qml | 3 -- .../Pages2/PageSettingsApiSubscriptionKey.qml | 10 +------ client/ui/qml/Pages2/PageShare.qml | 29 ++++++++++++++++++- client/ui/qml/Pages2/PageShareConnection.qml | 26 +++++++---------- client/ui/qml/Pages2/PageShareFullAccess.qml | 9 ++++-- client/ui/qml/Pages2/PageStart.qml | 13 +++++++++ 7 files changed, 61 insertions(+), 33 deletions(-) diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h index 1aee1ed7..12dc8c80 100644 --- a/client/ui/controllers/pageController.h +++ b/client/ui/controllers/pageController.h @@ -40,7 +40,7 @@ namespace PageLoader PageSettingsApiDevices, PageSettingsApiSubscriptionKey, PageSettingsKillSwitchExceptions, - + PageServiceSftpSettings, PageServiceTorWebsiteSettings, PageServiceDnsSettings, @@ -125,6 +125,8 @@ signals: void goToPageViewConfig(); void goToPageSettingsServerServices(); void goToPageSettingsBackup(); + void goToShareConnectionPage(QString headerText, QString configContentHeaderText, QString configCaption, QString configExtension, + QString configFileName); void closePage(); diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index 3a7290a6..f1290948 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -218,9 +218,6 @@ PageType { ApiConfigsController.prepareVpnKeyExport() PageController.showBusyIndicator(false) - - // Navigate to PageShareConnection page - //PageController.goToPage(PageEnum.PageShareConnection) } } diff --git a/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml b/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml index eace92ed..23f9706a 100644 --- a/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml +++ b/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml @@ -53,14 +53,6 @@ PageType { Layout.leftMargin: 16 Layout.rightMargin: 16 - defaultColor: AmneziaStyle.color.paleGray - hoveredColor: AmneziaStyle.color.sheerWhite - pressedColor: AmneziaStyle.color.translucentWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.black - leftImageColor: "black" - borderWidth: 1 - text: qsTr("Copy key") leftImageSource: "qrc:/images/controls/copy.svg" @@ -194,7 +186,7 @@ PageType { font.pixelSize: 16 font.weight: Font.Medium font.family: "PT Root UI VF" - text: ApiConfigsController.vpnKey //|| "" + text: ApiConfigsController.vpnKey wrapMode: Text.Wrap background: Rectangle { color: AmneziaStyle.color.transparent } } diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index d0d2a4de..dd2890e3 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -45,40 +45,67 @@ PageType { function onGenerateConfig(type) { PageController.showBusyIndicator(true) + var configCaption + var configExtension + var configFileName + switch (type) { case PageShare.ConfigType.AmneziaConnection: { ExportController.generateConnectionConfig(clientNameTextField.textField.text); + configCaption = qsTr("Save AmneziaVPN config") + configExtension = ".vpn" + configFileName = "amnezia_config" break; } case PageShare.ConfigType.OpenVpn: { ExportController.generateOpenVpnConfig(clientNameTextField.textField.text) + configCaption = qsTr("Save OpenVPN config") + configExtension = ".ovpn" + configFileName = "amnezia_for_openvpn" break } case PageShare.ConfigType.WireGuard: { ExportController.generateWireGuardConfig(clientNameTextField.textField.text) + configCaption = qsTr("Save WireGuard config") + configExtension = ".conf" + configFileName = "amnezia_for_wireguard" break } case PageShare.ConfigType.Awg: { ExportController.generateAwgConfig(clientNameTextField.textField.text) + configCaption = qsTr("Save AmneziaWG config") + configExtension = ".conf" + configFileName = "amnezia_for_awg" break } case PageShare.ConfigType.ShadowSocks: { ExportController.generateShadowSocksConfig() + configCaption = qsTr("Save Shadowsocks config") + configExtension = ".json" + configFileName = "amnezia_for_shadowsocks" break } case PageShare.ConfigType.Cloak: { ExportController.generateCloakConfig() + configCaption = qsTr("Save Cloak config") + configExtension = ".json" + configFileName = "amnezia_for_cloak" break } case PageShare.ConfigType.Xray: { ExportController.generateXrayConfig(clientNameTextField.textField.text) + configCaption = qsTr("Save XRay config") + configExtension = ".json" + configFileName = "amnezia_for_xray" break } } PageController.showBusyIndicator(false) - PageController.goToPage(PageEnum.PageShareConnection) + var headerText = qsTr("Connection to ") + serverSelector.text + var configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text + PageController.goToShareConnectionPage(headerText, configContentHeaderText, configCaption, configExtension, configFileName) } function onExportErrorOccurred(error) { diff --git a/client/ui/qml/Pages2/PageShareConnection.qml b/client/ui/qml/Pages2/PageShareConnection.qml index 9bc81ca3..efac6a8d 100644 --- a/client/ui/qml/Pages2/PageShareConnection.qml +++ b/client/ui/qml/Pages2/PageShareConnection.qml @@ -21,12 +21,6 @@ PageType { id: pageShareConnection property string headerText - - Component.onCompleted: { - var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server" - headerText = qsTr("Connection to ") + serverName - configContentHeaderText = qsTr("File with connection settings to ") + serverName - } property string configContentHeaderText property string shareButtonText: qsTr("Share") property string copyButtonText: qsTr("Copy") @@ -36,17 +30,17 @@ PageType { property string configCaption: qsTr("Save AmneziaVPN config") property string configFileName: "amnezia_config" - onVisibleChanged: { - configExtension = ".vpn" - configCaption = qsTr("Save AmneziaVPN config") - configFileName = "amnezia_config" + // onVisibleChanged: { + // configExtension = ".vpn" + // configCaption = qsTr("Save AmneziaVPN config") + // configFileName = "amnezia_config" - if (visible) { - var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server" - headerText = qsTr("Connection to ") + serverName - configContentHeaderText = qsTr("File with connection settings to ") + serverName - } - } + // if (visible) { + // var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server" + // headerText = qsTr("Connection to ") + serverName + // configContentHeaderText = qsTr("File with connection settings to ") + serverName + // } + // } BackButtonType { id: backButton diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 1465459f..9b3bbd6f 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -37,6 +37,9 @@ PageType { ListViewType { id: listView + property string headerText: "" + property string configContentHeaderText: "" + anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.right: parent.right @@ -108,8 +111,8 @@ PageType { serverSelector.currentIndex = serverSelectorListView.currentIndex } - shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text - shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text + listView.headerText = qsTr("Accessing ") + serverSelector.text + listView.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text serverSelector.closeTriggered() } @@ -156,7 +159,7 @@ PageType { PageController.showBusyIndicator(false) - PageController.goToPage(PageEnum.PageShareConnection) + PageController.goToShareConnectionPage(listView.headerText, listView.configContentHeaderText, "", "", "") } } } diff --git a/client/ui/qml/Pages2/PageStart.qml b/client/ui/qml/Pages2/PageStart.qml index 0a21497d..570c51f3 100644 --- a/client/ui/qml/Pages2/PageStart.qml +++ b/client/ui/qml/Pages2/PageStart.qml @@ -44,6 +44,19 @@ PageType { tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition) } + function onGoToShareConnectionPage(headerText, configContentHeaderText, configCaption, configExtension, configFileName) { + var pagePath = PageController.getPagePath(PageEnum.PageShareConnection) + tabBarStackView.push(pagePath, + { "objectName" : pagePath, + "headerText" : headerText, + "configContentHeaderText" : configContentHeaderText, + "configCaption" : configCaption, + "configExtension" : configExtension, + "configFileName" : configFileName + }, + StackView.PushTransition) + } + function onDisableControls(disabled) { isControlsDisabled = disabled } From 3ac5d7bd1f19582ad33ccd99483ce20b8fc9ea2a Mon Sep 17 00:00:00 2001 From: MrMirDan <58086007+MrMirDan@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:37:43 +0300 Subject: [PATCH 39/40] chore: ru translation update (#1815) --- client/translations/amneziavpn_ru_RU.ts | 143 +++++++++++------------- 1 file changed, 63 insertions(+), 80 deletions(-) diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts index 756eaa39..f9013f8e 100644 --- a/client/translations/amneziavpn_ru_RU.ts +++ b/client/translations/amneziavpn_ru_RU.ts @@ -67,7 +67,7 @@ - Inactive + <p><a style="color: #EB5757;">Inactive</a> Не активна @@ -89,17 +89,17 @@ ApiConfigsController - + %1 installed successfully. %1 успешно установлен. - + API config reloaded Конфигурация API перезагружена - + Successfully changed the country of connection to %1 Страна подключения изменена на %1 @@ -209,53 +209,27 @@ ApiServicesModel - + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> <p><a style="color: #EB5757;">Недоступно в вашем регионе. Если у вас включен VPN, отключите его, вернитесь на предыдущий экран и попробуйте снова.</a> - - - Amnezia Free provides unlimited, free access to a basic set of websites and apps, including Facebook, Instagram, Twitter (X), Discord, Telegram, and more. YouTube is not included in the free plan. - Amnezia Free позволяет бесплатно и без ограничений пользоваться базовым набором сайтов и приложений, включая Facebook, Instagram, Twitter (X), Discord, Telegram и другие. YouTube не входит в бесплатный тариф. - - - - Amnezia Premium is classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online resources. Speeds up to %1 Mbps. - Amnezia Premium - это классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Доступ ко всем сайтам и онлайн ресурсам. Скорость - до %1 Мбит/с. - - - - Amnezia Premium is classic VPN for for seamless work, downloading large files, and watching videos. Access all websites and online resources. - Amnezia Premium - это классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Доступ ко всем сайтам и онлайн ресурсам. - - - + %1 MBit/s %1 Мбит/с - + %1 days %1 дней - - - - - - VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1" style="color: #FBB26A;">more details on the website.</a> - Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, <a href="%1" style="color: #FBB26A;">подробности на сайте.</a> - - - Free Бесплатно - + %1 $/month %1 $/месяц @@ -1973,12 +1947,12 @@ Thank you for staying with us! PageSettingsApiServerInfo - + Configurations have been updated for some countries. Download and install the updated configuration files Сетевые адреса одного или нескольких серверов были обновлены. Пожалуйста, удалите старые конфигурацию и загрузите новые файлы - + Manage configuration files Управление файлами конфигурации @@ -1988,116 +1962,116 @@ Thank you for staying with us! Статус подписки - + Valid Until Действительна до - + Active Connections Активные соединения - + Use VLESS protocol Использовать протокол VLESS - + Cannot change protocol during active connection Невозможно изменить протокол во время активного соединения - + Subscription Key Ключ для подключения - + Configuration Files Файлы конфигурации - + Active Devices Активные устройства - + Manage currently connected devices Управление подключенными устройствами - + Support Поддержка - + How to connect on another device Как подключить другие устройства - + Reload API config Перезагрузить конфигурацию API - + Reload API config? Перезагрузить конфигурацию API? - - - + + + Continue Продолжить - - - + + + Cancel Отменить - + Cannot reload API config during active connection Невозможно перзагрузить API конфигурацию при активном соединении - + Unlink this device Отвязать это устройство - + Are you sure you want to unlink this device? Вы уверены, что хотите отвязать это устройство? - + This will unlink the device from your subscription. You can reconnect it anytime by pressing "Reload API config" in subscription settings on device. Это отключит устройство от вашей подписки. Вы можете повторно подключить его в любое время, нажав "Перезагрузить конфигурацию API" в настройках подписки на устройстве. - + Cannot unlink device during active connection Невозможно отвязать устройство во время активного соединения - + Remove from application Удалить из приложения - + Remove from application? Удалить из приложения? - + Cannot remove server during active connection Невозможно удалить сервер во время активного соединения @@ -2718,20 +2692,20 @@ subscription key Включение этой функции позволяет сохранять логи на вашем устройстве. По умолчанию она отключена. Включите сохранение логов в случае сбоев в работе приложения. - - + + Save Сохранить - - + + Logs files (*.log) Файлы логов (*.log) - - + + Logs file saved Файл с логами сохранен @@ -2761,12 +2735,12 @@ subscription key Логи очищены - + Client logs Логи приложения - + AmneziaVPN logs AmneziaVPN logs @@ -2781,12 +2755,12 @@ subscription key Сохранить логи - + Service logs Логи службы - + AmneziaVPN-service logs AmneziaVPN-service logs @@ -4277,7 +4251,16 @@ subscription key Пожалуйста, обновите приложение, чтобы использовать эту функцию - + + Your Amnezia Premium subscription has expired. + Please check your email for renewal instructions. + If you haven't received an email, please contact our support. + Ваша подписка Amnezia Premium истекла. +Проверьте свою почту для инструкций по продлению. +Если вы не получили письмо, пожалуйста, свяжитесь с нашей службой поддержки. + + + ErrorCode: %1. Код ошибки: %1. @@ -4377,37 +4360,37 @@ subscription key Превышен лимит разрешенных конфигураций для одной подписки - + QFile error: The file could not be opened Ошибка QFile: не удалось открыть файл - + QFile error: An error occurred when reading from the file Ошибка QFile: произошла ошибка при чтении из файла - + QFile error: The file could not be accessed Ошибка QFile: не удалось получить доступ к файлу - + QFile error: An unspecified error occurred Ошибка QFile: произошла неизвестная ошибка - + QFile error: A fatal error occurred Ошибка QFile: произошла фатальная ошибка - + QFile error: The operation was aborted Ошибка QFile: операция была прервана - + Internal error Внутренняя ошибка From e88f7c5e46a8d6236f4d2606ec272e0708f7b32d Mon Sep 17 00:00:00 2001 From: MrMirDan <58086007+MrMirDan@users.noreply.github.com> Date: Tue, 2 Sep 2025 08:03:05 +0300 Subject: [PATCH 40/40] fix: index assignment (#1821) --- client/ui/qml/Pages2/PageShareFullAccess.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 9b3bbd6f..37f89f1c 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -107,8 +107,9 @@ PageType { clickedFunction: function() { handler() - if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) { - serverSelector.currentIndex = serverSelectorListView.currentIndex + if (serverSelector.currentIndex !== serverSelectorListView.selectedIndex) { + serverSelector.currentIndex = serverSelectorListView.selectedIndex + serverSelector.severSelectorIndexChanged() } listView.headerText = qsTr("Accessing ") + serverSelector.text @@ -124,7 +125,7 @@ PageType { function handler() { serverSelector.text = selectedText - ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex) + ServersModel.processedIndex = proxyServersModel.mapToSource(selectedIndex) } } }

    O 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°>@P)w6*0zr4vB}kSXYXpPDe$Zs_-I2#Ic4 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 z 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%0D=#8G}H74 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