Compare commits

..

26 Commits

Author SHA1 Message Date
vladimir.kuznetsov ab4f454c19 Merge branch 'fix/ui-fixes-after-merge-with-d20ed4a' of github.com:amnezia-vpn/amnezia-client into fix/ui-fixes-after-merge-with-d20ed4a 2025-08-09 22:21:38 +08:00
vladimir.kuznetsov e96dfe5800 chore: page settings dns margins 2025-08-09 22:20:48 +08:00
Cyril Anisimov 768c51dbbe update OpenVPN settings page 2025-08-09 14:19:11 +02:00
vladimir.kuznetsov 5acbdd7af6 fix: ui fixes after merge with d20ed4a 2025-08-08 11:45:20 +08:00
serj95reg a6e6de33c8 feat: updated xray version in dockerfile to 25.8.3 (#1771) 2025-08-08 10:34:51 +08:00
Mitternacht822 53c7fd4d81 fix: android build (#1768)
* added signal-slot connection between corecontroller and systemtraynofificationhandler updating websiteurl

* cleared up the commented lines

* fixed andorid includes for systemtraynotificationhandler
2025-08-07 11:12:09 +08:00
Nethius 2608ea4367 chore: fix typo (#1769) 2025-08-06 11:00:43 +08:00
Cyril Anisimov d20ed4ad01 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 <nethiuswork@gmail.com>
2025-08-06 10:35:51 +08:00
KsZnak eae2936449 Update README links.md [no ci]
Update README links.md
2025-08-04 19:35:45 +01:00
KsZnak da8ad1f6ba UTM added.md [no ci]
Update README_RU.md
2025-08-04 19:34:12 +01:00
Mitternacht822 5472347969 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
2025-08-04 14:13:22 +08:00
Mitternacht822 a43f7a6926 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
2025-08-01 21:02:12 +08:00
Cyril Anisimov 47f917de0b refactoring: change logs time to UTC (#1578)
* update logger to show utc

* add logger to `FocusController`

* add utc timestamps to android logs
2025-08-01 11:56:16 +08:00
Cyril Anisimov dbeb7edd7a 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
2025-08-01 11:56:02 +08:00
Mitternacht822 6cede712f5 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
2025-08-01 11:54:58 +08:00
Mitternacht822 d328739192 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
2025-08-01 11:52:11 +08:00
Mitternacht822 d15c0bd962 fix: fixed system tray open site link (#1686)
* added signal-slot connection between corecontroller and systemtraynofificationhandler updating websiteurl

* cleared up the commented lines
2025-08-01 11:50:31 +08:00
Mitternacht822 d53c794936 fix: fixed language load after settings reset (#1735) 2025-08-01 11:47:43 +08:00
Mitternacht822 e5dcb25a4a fix: removed the ability to change location while making connection (#1736) 2025-08-01 11:45:19 +08:00
Mitternacht822 f9002b4f43 refactoring: made start-minimized-option available only when autostart-option is truned on (#1740) 2025-08-01 11:38:36 +08:00
Nethius 0531508a75 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>
2025-08-01 11:37:56 +08:00
Mitternacht822 174e85a20a 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
2025-08-01 11:36:52 +08:00
MrMirDan e9abb6f1e2 fix: mirror links (#1760)
* Instructions links

* amnezia free feature link

* trying fix api instructions page issue

* androidTV link fix

* tv link fix 2
2025-08-01 11:36:30 +08:00
Nethius 5be44f9596 chore: bump version (#1757)
* chore: update link to submodule

* chore: bump version
2025-07-29 12:20:43 +08:00
vladimir.kuznetsov 90efaaff92 chore: bump version 2025-07-29 12:19:54 +08:00
vladimir.kuznetsov 99b554e7c3 chore: update link to submodule 2025-07-29 12:19:27 +08:00
97 changed files with 7008 additions and 6912 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
set(AMNEZIAVPN_VERSION 4.8.9.1)
set(AMNEZIAVPN_VERSION 4.8.9.2)
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 2091)
set(APP_ANDROID_VERSION_CODE 2092)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
+5 -5
View File
@@ -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).
<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
<a href="https://amnezia.org/en/downloads?utm_source=github&utm_campaign=amnezia_button-readme-en"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/en/downloads&utm_source=github&utm_campaign=amnezia_button-readme-en-mirrow"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
+4 -4
View File
@@ -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).
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/ru/downloads&utm_source=github&utm_campaign=amnezia_button-readme-ru-mirror"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
+4 -2
View File
@@ -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"
}
@@ -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());
@@ -242,6 +245,9 @@ void CoreController::initNotificationHandler()
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
&ConnectionController::closeConnection);
connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
auto* trayHandler = qobject_cast<SystemTrayNotificationHandler*>(m_notificationHandler.get());
connect(this, &CoreController::websiteUrlChanged, trayHandler, &SystemTrayNotificationHandler::updateWebsiteUrl);
#endif
}
@@ -279,6 +285,7 @@ void CoreController::updateTranslator(const QLocale &locale)
m_engine->retranslate();
emit translationsUpdated();
emit websiteUrlChanged(m_languageModel->getCurrentSiteUrl());
}
void CoreController::initErrorMessagesHandler()
+5
View File
@@ -5,6 +5,10 @@
#include <QQmlContext>
#include <QThread>
#ifndef Q_OS_ANDROID
#include "ui/systemtray_notificationhandler.h"
#endif
#include "ui/controllers/api/apiConfigsController.h"
#include "ui/controllers/api/apiSettingsController.h"
#include "ui/controllers/api/apiPremV1MigrationController.h"
@@ -61,6 +65,7 @@ public:
signals:
void translationsUpdated();
void websiteUrlChanged(const QString &newUrl);
private:
void initModels();
+3 -19
View File
@@ -10,7 +10,6 @@
#include <QLoggingCategory>
#include <QPointer>
#include <QTemporaryFile>
#include <QtGlobal>
#include <QThread>
#include <QTimer>
#include <QtConcurrent>
@@ -198,24 +197,9 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
return error;
}
// Create a unique temporary file for upload and write data to it
#ifdef Q_OS_MAC
const QString tmpBase = QStringLiteral("/tmp");
#else
const QString tmpBase = QDir::tempPath();
#endif
const QString tmpTemplate = tmpBase + QDir::separator() + QStringLiteral("amnezia-upload-XXXXXX");
QTemporaryFile localFile(tmpTemplate);
if (!localFile.open()) {
qCritical() << "ServerController: failed to open temporary file for upload";
return ErrorCode::OpenError;
}
const qint64 bytesWritten = localFile.write(data);
if (bytesWritten != data.size()) {
qCritical() << "ServerController: failed to write data to temporary file, wrote" << bytesWritten << "of" << data.size();
return ErrorCode::UnspecifiedError;
}
localFile.flush();
QTemporaryFile localFile;
localFile.open();
localFile.write(data);
localFile.close();
error = m_sshClient.scpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
+3 -1
View File
@@ -127,7 +127,7 @@
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
<file>ui/qml/Components/ServersListView.qml</file>
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
<file>ui/qml/Components/TransportProtoSelector.qml</file>
<file>ui/qml/Components/AddSitePanel.qml</file>
<file>ui/qml/Config/GlobalConfig.qml</file>
@@ -228,6 +228,7 @@
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
<file>ui/qml/Pages2/PageShare.qml</file>
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>ui/qml/Pages2/PageShareConnection.qml</file>
<file>ui/qml/Pages2/PageStart.qml</file>
<file>ui/qml/Components/RenameServerDrawer.qml</file>
<file>ui/qml/Controls2/ListViewType.qml</file>
@@ -240,6 +241,7 @@
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
<file>ui/qml/Components/AwgTextField.qml</file>
<file>ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml</file>
</qresource>
<qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file>
+1 -1
View File
@@ -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
+11 -5
View File
@@ -4,6 +4,12 @@
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#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<QQuickItem *>(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;
}
+96 -1
View File
@@ -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<QString, QString> 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));
}
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()) {
@@ -721,6 +814,8 @@ void InstallController::clearCachedProfile(QSharedPointer<ServerController> 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()
@@ -83,6 +83,8 @@ signals:
void noInstalledContainers();
void profileCleared(const QJsonObject &config);
private:
void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
const ServerCredentials &serverCredentials, const QSharedPointer<ServerController> &serverController,
@@ -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: {
+2
View File
@@ -38,6 +38,7 @@ namespace PageLoader
PageSettingsApiInstructions,
PageSettingsApiNativeConfigs,
PageSettingsApiDevices,
PageSettingsApiSubscriptionKey,
PageSettingsKillSwitchExceptions,
PageServiceSftpSettings,
@@ -71,6 +72,7 @@ namespace PageLoader
PageProtocolAwgClientSettings,
PageShareFullAccess,
PageShareConnection,
PageDevMenu
};
+43 -4
View File
@@ -35,6 +35,23 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &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<LanguageSettings::AvailableLanguageEnum>(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<int>(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"));
@@ -185,8 +225,7 @@ void SettingsController::clearSettings()
{
m_settings->clearSettings();
m_serversModel->resetModel();
m_languageModel->changeLanguage(
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
m_languageModel->changeLanguage(m_languageModel->getSystemLanguageEnum());
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
m_sitesModel->toggleSplitTunneling(false);
@@ -136,6 +136,8 @@ private:
QString m_appVersion;
QString getPlatform();
QDateTime m_loggingDisableDate;
bool m_isDevModeEnabled = false;
@@ -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;
+1
View File
@@ -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);
+1 -1
View File
@@ -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, "
"<a href=\"%1/free\" style=\"color: #FBB26A;\">more details on the website.</a>");
"<a href=\"%1\" style=\"color: #FBB26A;\">more details on the website.</a>");
}
}
case PriceRole: {
@@ -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;
@@ -29,6 +29,7 @@ public:
public slots:
bool addApp(const InstalledAppInfo &appInfo);
void removeApp(QModelIndex index);
void clearAppsList();
int getRouteMode();
void setRouteMode(int routeMode);
+27
View File
@@ -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<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
@@ -110,3 +127,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<LanguageSettings::AvailableLanguageEnum>(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)));
}
}
+2
View File
@@ -46,6 +46,7 @@ public:
};
LanguageModel(std::shared_ptr<Settings> 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;
@@ -60,6 +61,7 @@ public slots:
int getLineHeightAppend();
QString getCurrentLanguageName();
QString getCurrentSiteUrl(const QString &path = "");
QString getCurrentDocsUrl(const QString &path = "");
signals:
void updateTranslations(const QLocale &locale);
+10
View File
@@ -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;
+1
View File
@@ -28,6 +28,7 @@ public slots:
bool addSite(const QString &hostname, const QString &ip);
void addSites(const QMap<QString, QString> &sites, bool replaceExisting);
void removeSite(QModelIndex index);
void removeSites();
int getRouteMode();
void setRouteMode(int routeMode);
@@ -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
}
@@ -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,20 +76,12 @@ DrawerType2 {
}
}
ScrollBar.vertical: ScrollBarType {}
ButtonGroup {
id: buttonGroup
}
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
delegate: ColumnLayout {
width: listView.width
RowLayout {
CheckBoxType {
@@ -121,7 +108,6 @@ DrawerType2 {
}
}
}
}
TextFieldWithHeaderType {
id: searchField
@@ -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 {
+1 -8
View File
@@ -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"
@@ -13,29 +13,16 @@ import "../Controls2"
import "../Controls2/TextTypes"
ListView {
ListViewType {
id: root
width: parent.width
height: root.contentItem.height
clip: true
reuseItems: true
property bool isFocusable: false
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
delegate: ColumnLayout {
width: root.width
LabelWithButtonType {
id: containerRadioButton
implicitWidth: parent.width
Layout.fillWidth: true
text: name
descriptionText: description
@@ -86,5 +73,4 @@ ListView {
DividerType {}
}
}
}
@@ -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\"")
}
}
}
}
}
@@ -29,8 +29,6 @@ Button {
property bool squareLeftSide: false
property FlickableType parentFlickable
property var clickedFunc
property alias buttonTextLabel: buttonText
@@ -65,14 +63,6 @@ Button {
hoverEnabled: true
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(this)
}
}
}
background: Rectangle {
id: focusBorder
@@ -27,8 +27,6 @@ Button {
property alias focusItem: rightImage
property FlickableType parentFlickable
hoverEnabled: true
background: Rectangle {
@@ -44,22 +42,6 @@ Button {
}
}
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
+22 -5
View File
@@ -34,13 +34,30 @@ CheckBox {
property string imageSource: "qrc:/images/controls/check.svg"
property var parentFlickable
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
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
@@ -27,6 +27,5 @@ Flickable {
ScrollBar.vertical: ScrollBarType {
id: scrollBar
policy: fl.height >= fl.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
}
@@ -9,6 +9,7 @@ import "TextTypes"
Item {
id: root
// property alias focusObjectName: eyeImage.objectName
property string text
property int textMaximumLineCount: 2
property int textElide: Qt.ElideRight
@@ -25,7 +26,6 @@ Item {
property alias rightButton: rightImage
property alias eyeButton: eyeImage
property FlickableType parentFlickable
property string textColor: AmneziaStyle.color.paleGray
property string textDisabledColor: AmneziaStyle.color.mutedGray
@@ -70,25 +70,6 @@ Item {
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
+8 -25
View File
@@ -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;
}
}
@@ -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
}
+1 -1
View File
@@ -7,5 +7,5 @@ import "../Controls2"
ScrollBar {
id: root
policy: parent.height >= parent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
policy: ScrollBar.AsNeeded
}
-10
View File
@@ -64,16 +64,6 @@ Switch {
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
+26 -9
View File
@@ -21,15 +21,6 @@ Rectangle {
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
@@ -54,6 +45,32 @@ Rectangle {
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
@@ -31,15 +31,6 @@ Rectangle {
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
@@ -37,19 +37,6 @@ Item {
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
+13 -23
View File
@@ -20,7 +20,9 @@ PageType {
SortFilterProxyModel {
id: proxyServersModel
sourceModel: ServersModel
filters: [
ValueFilter {
roleName: "isCurrentlyProcessed"
@@ -29,36 +31,23 @@ PageType {
]
}
FlickableType {
id: fl
ListViewType {
id: listView
anchors.fill: parent
contentHeight: content.height
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 16
Repeater {
model: proxyServersModel
delegate: Item {
implicitWidth: parent.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
delegate: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Removing services from %1").arg(name)
}
@@ -68,6 +57,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
Timer {
id: timer
@@ -84,12 +75,11 @@ PageType {
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Usually it takes no more than 5 minutes")
}
}
}
}
}
}
}
+3 -13
View File
@@ -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
+9 -6
View File
@@ -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
@@ -16,91 +16,60 @@ 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.top: backButton.bottom
anchors.bottom: saveButton.top
anchors.right: parent.right
anchors.left: parent.left
width: parent.width
header: ColumnLayout {
width: listView.width
clip: true
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
headerText: qsTr("AmneziaWG settings")
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
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
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("AmneziaWG settings")
}
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("MTU")
textField.text: clientMtu
@@ -112,11 +81,14 @@ PageType {
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
AwgTextField {
id: junkPacketCountTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jc - Junk packet count"
textField.text: clientJunkPacketCount
@@ -125,12 +97,14 @@ PageType {
clientJunkPacketCount = textField.text
}
}
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
AwgTextField {
id: junkPacketMinSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jmin - Junk packet minimum size"
textField.text: clientJunkPacketMinSize
@@ -139,12 +113,14 @@ PageType {
clientJunkPacketMinSize = textField.text
}
}
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
AwgTextField {
id: junkPacketMaxSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jmax - Junk packet maximum size"
textField.text: clientJunkPacketMaxSize
@@ -157,6 +133,10 @@ PageType {
AwgTextField {
id: specialJunk1TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("I1 - First special junk packet")
textField.text: clientSpecialJunk1
textField.validator: null
@@ -171,6 +151,10 @@ PageType {
AwgTextField {
id: specialJunk2TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("I2 - Second special junk packet")
textField.text: clientSpecialJunk2
textField.validator: null
@@ -185,6 +169,10 @@ PageType {
AwgTextField {
id: specialJunk3TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("I3 - Third special junk packet")
textField.text: clientSpecialJunk3
textField.validator: null
@@ -199,6 +187,10 @@ PageType {
AwgTextField {
id: specialJunk4TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("I4 - Fourth special junk packet")
textField.text: clientSpecialJunk4
textField.validator: null
@@ -213,6 +205,10 @@ PageType {
AwgTextField {
id: specialJunk5TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("I5 - Fifth special junk packet")
textField.text: clientSpecialJunk5
textField.validator: null
@@ -227,6 +223,10 @@ PageType {
AwgTextField {
id: controlledJunk1TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("J1 - First controlled junk packet")
textField.text: clientControlledJunk1
textField.validator: null
@@ -241,6 +241,10 @@ PageType {
AwgTextField {
id: controlledJunk2TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("J2 - Second controlled junk packet")
textField.text: clientControlledJunk2
textField.validator: null
@@ -255,6 +259,10 @@ PageType {
AwgTextField {
id: controlledJunk3TextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("J3 - Third controlled junk packet")
textField.text: clientControlledJunk3
textField.validator: null
@@ -269,6 +277,10 @@ PageType {
AwgTextField {
id: iTimeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Itime - Special handshake timeout")
textField.text: clientSpecialHandshakeTimeout
checkEmptyText: false
@@ -283,12 +295,18 @@ PageType {
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Server settings")
}
AwgTextField {
id: portTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
headerText: qsTr("Port")
@@ -297,6 +315,10 @@ PageType {
AwgTextField {
id: initPacketJunkSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
headerText: "S1 - Init packet junk size"
@@ -305,6 +327,10 @@ PageType {
AwgTextField {
id: responsePacketJunkSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
headerText: "S2 - Response packet junk size"
@@ -313,6 +339,10 @@ PageType {
// AwgTextField {
// id: cookieReplyPacketJunkSizeTextField
// Layout.leftMargin: 16
// Layout.rightMargin: 16
// enabled: false
// headerText: "S3 - Cookie Reply packet junk size"
@@ -321,6 +351,10 @@ PageType {
// AwgTextField {
// id: transportPacketJunkSizeTextField
// Layout.leftMargin: 16
// Layout.rightMargin: 16
// enabled: false
// headerText: "S4 - Transport packet junk size"
@@ -329,6 +363,10 @@ PageType {
AwgTextField {
id: initPacketMagicHeaderTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
headerText: "H1 - Init packet magic header"
@@ -337,6 +375,10 @@ PageType {
AwgTextField {
id: responsePacketMagicHeaderTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
headerText: "H2 - Response packet magic header"
@@ -345,6 +387,10 @@ PageType {
AwgTextField {
id: underloadPacketMagicHeaderTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
headerText: "H3 - Underload packet magic header"
@@ -353,13 +399,15 @@ PageType {
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)
}
}
@@ -19,80 +19,45 @@ 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
property bool isFocusable: true
anchors.top: backButtonLayout.bottom
anchors.top: backButton.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
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("AmneziaWG settings")
}
@@ -102,6 +67,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
@@ -121,6 +88,8 @@ PageType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
@@ -140,6 +109,10 @@ PageType {
AwgTextField {
id: junkPacketCountTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jc - Junk packet count")
textField.text: serverJunkPacketCount
@@ -152,6 +125,10 @@ PageType {
AwgTextField {
id: junkPacketMinSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jmin - Junk packet minimum size")
textField.text: serverJunkPacketMinSize
@@ -164,6 +141,10 @@ PageType {
AwgTextField {
id: junkPacketMaxSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jmax - Junk packet maximum size")
textField.text: serverJunkPacketMaxSize
@@ -176,6 +157,10 @@ PageType {
AwgTextField {
id: initPacketJunkSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("S1 - Init packet junk size")
textField.text: serverInitPacketJunkSize
@@ -188,6 +173,10 @@ PageType {
AwgTextField {
id: responsePacketJunkSizeTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("S2 - Response packet junk size")
textField.text: serverResponsePacketJunkSize
@@ -200,6 +189,10 @@ PageType {
// AwgTextField {
// id: cookieReplyPacketJunkSizeTextField
// Layout.leftMargin: 16
// Layout.rightMargin: 16
// headerText: qsTr("S3 - Cookie reply packet junk size")
// textField.text: serverCookieReplyPacketJunkSize
@@ -212,6 +205,10 @@ PageType {
// AwgTextField {
// id: transportPacketJunkSizeTextField
// Layout.leftMargin: 16
// Layout.rightMargin: 16
// headerText: qsTr("S4 - Transport packet junk size")
// textField.text: serverTransportPacketJunkSize
@@ -224,6 +221,10 @@ PageType {
AwgTextField {
id: initPacketMagicHeaderTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H1 - Init packet magic header")
textField.text: serverInitPacketMagicHeader
@@ -236,6 +237,10 @@ PageType {
AwgTextField {
id: responsePacketMagicHeaderTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H2 - Response packet magic header")
textField.text: serverResponsePacketMagicHeader
@@ -248,6 +253,10 @@ PageType {
AwgTextField {
id: underloadPacketMagicHeaderTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H3 - Underload packet magic header")
textField.text: serverUnderloadPacketMagicHeader
@@ -260,6 +269,10 @@ PageType {
AwgTextField {
id: transportPacketMagicHeaderTextField
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H4 - Transport packet magic header")
textField.text: serverTransportPacketMagicHeader
@@ -270,13 +283,14 @@ PageType {
}
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
transportPacketMagicHeaderTextField.errorText === "" &&
@@ -296,13 +310,11 @@ PageType {
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
listView.positionViewAtEnd()
}
}
clickedFunc: function() {
forceActiveFocus()
if (delegateItem.isEnabled) {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
transportPacketMagicHeaderTextField.textField.text,
@@ -340,15 +352,12 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveRestartButton.forceActiveFocus()
}
}
var noButtonFunction = function() {}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
}
}
}
@@ -16,81 +16,61 @@ import "../Components"
PageType {
id: root
ColumnLayout {
id: backButtonLayout
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
anchors.topMargin: 20
enabled: ServersModel.isProcessedServerHasWriteAccess()
onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListView {
id: listview
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
property int selectedIndex: 0
width: parent.width
height: listview.contentItem.height
enabled: ServersModel.isProcessedServerHasWriteAccess()
clip: true
reuseItems: true
model: CloakConfigModel
delegate: Item {
id: delegateItem
property alias trafficFromField: trafficFromField
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
header: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Cloak settings")
}
}
model: CloakConfigModel
delegate: ColumnLayout {
width: listView.width
property alias trafficFromField: trafficFromField
spacing: 0
TextFieldWithHeaderType {
id: trafficFromField
Layout.fillWidth: true
Layout.topMargin: 32
enabled: delegateItem.isEnabled
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Disguised as traffic from")
textField.text: site
@@ -117,8 +97,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Port")
textField.text: port
@@ -136,10 +116,11 @@ PageType {
DropDownType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
Layout.leftMargin: 16
Layout.rightMargin: 16
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
@@ -183,6 +164,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: trafficFromField.errorText === "" &&
portTextField.errorText === ""
@@ -221,7 +204,4 @@ PageType {
}
}
}
}
}
}
}
@@ -17,85 +17,65 @@ import "../Components"
PageType {
id: root
ColumnLayout {
id: backButtonLayout
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
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
enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
header: ColumnLayout {
width: listView.width
width: parent.width
height: listview.contentItem.height
BaseHeaderType {
id: header
clip: true
interactive: false
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("OpenVPN Settings")
}
}
model: OpenVpnConfigModel
delegate: Item {
id: delegateItem
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
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
delegate: ColumnLayout {
width: listView.width
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
headerText: qsTr("OpenVPN settings")
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
enabled: listView.enabled
headerText: qsTr("VPN address subnet")
textField.text: subnetAddress
parentFlickable: fl
textField.onEditingFinished: {
if (textField.text !== subnetAddress) {
subnetAddress = textField.text
@@ -108,6 +88,8 @@ PageType {
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Network protocol")
}
@@ -116,6 +98,9 @@ PageType {
id: transportProtoSelector
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
rootWidth: root.width
enabled: isTransportProtoEditable
@@ -138,9 +123,10 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 40
parentFlickable: fl
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
enabled: listView.enabled
headerText: qsTr("Port")
textField.text: port
@@ -161,7 +147,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 24
parentFlickable: fl
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Auto-negotiate encryption")
checked: autoNegotiateEncryprion
@@ -177,6 +164,8 @@ PageType {
id: hashDropDown
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked
@@ -225,6 +214,8 @@ PageType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked
@@ -273,25 +264,18 @@ PageType {
id: contentRect
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
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
@@ -329,7 +313,8 @@ PageType {
id: additionalClientCommandsSwitcher
Layout.fillWidth: true
Layout.topMargin: 32
parentFlickable: fl
Layout.leftMargin: 16
Layout.rightMargin: 16
checked: additionalClientCommands !== ""
@@ -346,11 +331,11 @@ PageType {
id: additionalClientCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalClientCommandsSwitcher.checked
parentFlickable: fl
textAreaText: additionalClientCommands
placeholderText: qsTr("Commands:")
@@ -365,7 +350,8 @@ PageType {
id: additionalServerCommandsSwitcher
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
Layout.leftMargin: 16
Layout.rightMargin: 16
checked: additionalServerCommands !== ""
@@ -382,12 +368,14 @@ PageType {
id: additionalServerCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalServerCommandsSwitcher.checked
textAreaText: additionalServerCommands
placeholderText: qsTr("Commands:")
parentFlickable: fl
textArea.onEditingFinished: {
if (additionalServerCommands !== textAreaText) {
additionalServerCommands = textAreaText
@@ -401,12 +389,13 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: vpnAddressSubnetTextField.errorText === "" &&
portTextField.errorText === ""
text: qsTr("Save")
parentFlickable: fl
onClicked: function() {
forceActiveFocus()
@@ -438,7 +427,4 @@ PageType {
}
}
}
}
}
}
}
+46 -60
View File
@@ -19,69 +19,53 @@ 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
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.bottomMargin: 16
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
}
}
FlickableType {
id: fl
anchors.top: header.bottom
anchors.left: parent.left
anchors.right: parent.right
contentHeight: content.height
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
ListView {
id: listView
width: parent.width
height: contentItem.height
clip: true
interactive: false
model: ProtocolsModel
activeFocusOnTab: true
focus: true
delegate: Item {
implicitWidth: parent.width
implicitHeight: delegateContent.implicitHeight
property alias focusItem: button
ColumnLayout {
id: delegateContent
anchors.fill: parent
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType {
id: button
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Show connection options")
@@ -110,7 +94,7 @@ PageType {
implicitHeight: configContentDrawer.expandedHeight
BackButtonType {
id: backButton1
id: drawerBackButton
anchors.top: parent.top
anchors.left: parent.left
@@ -122,36 +106,41 @@ PageType {
}
}
FlickableType {
anchors.top: backButton1.bottom
anchors.left: parent.left
anchors.right: parent.right
ListViewType {
id: drawerListView
anchors.top: drawerBackButton.bottom
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
anchors.right: parent.right
anchors.left: parent.left
ColumnLayout {
id: configContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
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)
}
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: drawerListView.width
TextArea {
id: configText
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
padding: 0
leftPadding: 0
height: 24
color: AmneziaStyle.color.paleGray
@@ -175,8 +164,9 @@ PageType {
}
}
}
}
}
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)
}
@@ -16,68 +16,43 @@ import "../Components"
PageType {
id: root
ColumnLayout {
id: backButtonLayout
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
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
enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: ShadowSocksConfigModel
delegate: Item {
id: delegateItem
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
delegate: ColumnLayout {
width: listView.width
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Shadowsocks settings")
}
@@ -86,8 +61,10 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
enabled: listView.enabled
headerText: qsTr("Port")
textField.text: port
@@ -105,10 +82,13 @@ PageType {
DropDownType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
enabled: listView.enabled
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
@@ -153,6 +133,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: portTextField.errorText === ""
@@ -188,7 +170,4 @@ PageType {
}
}
}
}
}
}
}
@@ -16,77 +16,43 @@ import "../Components"
PageType {
id: root
Item {
id: focusItem
onFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.mtuTextField.textField
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
ListView {
id: listview
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
width: parent.width
height: listview.contentItem.height
ListViewType {
id: listView
clip: true
interactive: false
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
model: WireGuardConfigModel
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
delegate: ColumnLayout {
width: listView.width
property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === ""
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
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("WG settings")
}
@@ -95,6 +61,8 @@ PageType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("MTU")
textField.text: clientMtu
@@ -106,12 +74,13 @@ PageType {
}
}
checkEmptyText: true
KeyNavigation.tab: saveButton
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Server settings")
}
@@ -120,6 +89,8 @@ PageType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
@@ -127,29 +98,24 @@ PageType {
textField.text: port
}
}
}
}
}
}
footer: ColumnLayout {
width: listView.width
BasicButtonType {
id: saveButton
anchors.right: root.right
anchors.left: root.left
anchors.bottom: root.bottom
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
anchors.topMargin: 24
anchors.bottomMargin: 24
anchors.rightMargin: 16
anchors.leftMargin: 16
enabled: listview.currentItem.isSaveButtonEnabled
enabled: listView.currentItem.isSaveButtonEnabled
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")
@@ -164,12 +130,10 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(WireGuardConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveButton.forceActiveFocus()
}
}
var noButtonFunction = function() {}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
}
}
@@ -16,78 +16,55 @@ import "../Components"
PageType {
id: root
ColumnLayout {
id: backButtonLayout
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
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
enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: WireGuardConfigModel
delegate: Item {
id: delegateItem
delegate: ColumnLayout {
width: listView.width
property alias focusItemId: vpnAddressSubnetTextField
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
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("WG settings")
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 40
enabled: delegateItem.isEnabled
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("VPN address subnet")
textField.text: subnetAddress
@@ -105,8 +82,8 @@ PageType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Port")
textField.text: port
@@ -124,9 +101,12 @@ PageType {
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === ""
@@ -163,7 +143,4 @@ PageType {
}
}
}
}
}
}
}
@@ -17,78 +17,55 @@ 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
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
delegate: ColumnLayout {
width: listView.width
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
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: delegateItem.isEnabled
enabled: listView.enabled
headerText: qsTr("Disguised as traffic from")
textField.text: site
@@ -112,10 +89,13 @@ PageType {
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
enabled: listView.enabled
headerText: qsTr("Port")
textField.text: port
@@ -133,9 +113,12 @@ PageType {
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: portTextField.errorText === ""
@@ -157,7 +140,6 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(XrayConfigModel.getConfig())
//focusItem.forceActiveFocus()
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
@@ -172,8 +154,4 @@ PageType {
}
}
}
}
}
}
}
+31 -33
View File
@@ -16,50 +16,53 @@ import "../Components"
PageType {
id: root
ColumnLayout {
id: backButtonLayout
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
ColumnLayout {
id: content
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 {
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
@@ -73,17 +76,12 @@ PageType {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
&& 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)
}
@@ -24,64 +24,35 @@ PageType {
}
}
ColumnLayout {
id: backButtonLayout
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
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
enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: SftpConfigModel
onFocusChanged: {
if (focus) {
listview.currentItem.listViewFocusItem.forceActiveFocus()
}
}
delegate: Item {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias listViewFocusItem: hostLabel.rightButton
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
delegate: ColumnLayout {
width: listView.width
spacing: 0
@@ -95,10 +66,11 @@ PageType {
LabelWithButtonType {
id: hostLabel
Layout.fillWidth: true
Layout.topMargin: 32
parentFlickable: fl
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
@@ -111,69 +83,63 @@ PageType {
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
LabelWithButtonType {
id: portLabel
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
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
Layout.leftMargin: 16
Layout.rightMargin: 16
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
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Password")
descriptionText: password
descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -182,14 +148,12 @@ PageType {
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
BasicButtonType {
id: mountButton
visible: !GC.isMobile()
Layout.fillWidth: true
@@ -205,8 +169,6 @@ PageType {
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
parentFlickable: fl
text: qsTr("Mount folder on device")
clickedFunc: function() {
@@ -246,7 +208,6 @@ PageType {
return str
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
@@ -256,6 +217,7 @@ PageType {
BasicButtonType {
id: detailedInstructionsButton
Layout.topMargin: 16
Layout.bottomMargin: 16
Layout.leftMargin: 8
@@ -269,13 +231,8 @@ PageType {
text: qsTr("Detailed instructions")
parentFlickable: fl
clickedFunc: function() {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
}
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
}
@@ -25,55 +25,33 @@ 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
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
anchors.right: parent.right
anchors.left: parent.left
model: Socks5ProxyConfigModel
onFocusChanged: {
if (focus) {
listview.currentItem.focusItemId.forceActiveFocus()
}
}
delegate: Item {
implicitWidth: listview.width
implicitHeight: content.implicitHeight
property alias focusItemId: hostLabel.rightButton
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
delegate: ColumnLayout {
width: listView.width
spacing: 0
@@ -86,11 +64,10 @@ PageType {
}
LabelWithButtonType {
id: hostLabel
Layout.fillWidth: true
Layout.topMargin: 32
parentFlickable: fl
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
@@ -103,69 +80,57 @@ PageType {
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
LabelWithButtonType {
id: portLabel
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
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
Layout.rightMargin: 16
Layout.bottomMargin: 16
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
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("Password")
descriptionText: password
descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -174,9 +139,6 @@ PageType {
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
@@ -219,6 +181,8 @@ PageType {
BaseHeaderType {
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("SOCKS5 settings")
}
@@ -228,7 +192,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 40
parentFlickable: fl
Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Port")
textField.text: port
@@ -248,7 +213,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Username")
textField.placeholderText: "username"
@@ -270,7 +236,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Password")
textField.placeholderText: "password"
@@ -299,12 +266,11 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.rightMargin: 16
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
@@ -340,12 +306,9 @@ PageType {
text: qsTr("Change connection settings")
clickedFunc: function() {
forceActiveFocus()
changeSettingsDrawer.openTriggered()
}
}
}
}
}
}
}
@@ -25,34 +25,31 @@ PageType {
}
}
ColumnLayout {
id: backButtonLayout
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
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
spacing: 0
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
@@ -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
+104 -97
View File
@@ -14,130 +14,58 @@ import "../Config"
PageType {
id: root
FlickableType {
id: fl
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ListViewType {
id: listView
ColumnLayout {
id: content
anchors.fill: parent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
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 {
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")
visible: isVisible
text: title
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/radio.svg"
leftImageSource: leftImagePath
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)
}
clickedFunction: clickedHandler
}
DividerType {
visible: SettingsController.isDevModeEnabled
visible: isVisible
}
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType {
id: close
visible: GC.isDesktop()
Layout.fillWidth: true
Layout.preferredHeight: about.height
text: qsTr("Close application")
leftImageSource: "qrc:/images/controls/x-circle.svg"
@@ -149,8 +77,87 @@ PageType {
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: GC.isDesktop()
}
}
}
property list<QtObject> 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)
}
}
}
+54 -85
View File
@@ -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<QtObject> 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<QtObject> 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())
}
}
}
@@ -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
@@ -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<QtObject> instructionsModel: [
@@ -114,7 +114,7 @@ PageType {
rightImageSource: "qrc:/images/controls/external-link.svg"
clickedFunction: function() {
Qt.openUrlExternally(link)
Qt.openUrlExternally(LanguageModel.getCurrentDocsUrl(link))
}
}
@@ -22,22 +22,34 @@ PageType {
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.fill: parent
anchors.topMargin: 20
anchors.bottomMargin: 24
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
model: ApiCountryModel
header: ColumnLayout {
width: listView.width
BackButtonType {
id: backButton
}
BaseHeaderType {
id: header
@@ -59,6 +71,7 @@ PageType {
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"
@@ -104,30 +117,34 @@ PageType {
}
}
FlickableType {
ListViewType {
id: drawerListView
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
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")
@@ -138,9 +155,16 @@ PageType {
}
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() {
@@ -212,8 +236,7 @@ PageType {
}
moreOptionsDrawer.closeTriggered()
}
var noButtonFunction = function() {
}
var noButtonFunction = function() {}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
@@ -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 {
@@ -198,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 {
@@ -207,35 +202,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 +410,12 @@ PageType {
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
RenameServerDrawer {
id: serverNameEditDrawer
anchors.fill: parent
expandedHeight: parent.height * 0.35
serverNameText: root.processedServer.name
}
}
@@ -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 }
}
}
}
}
}
@@ -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,24 +147,14 @@ PageType {
}
}
FlickableType {
ListViewType {
id: listView
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight + addAppButton.implicitHeight + addAppButton.anchors.bottomMargin + addAppButton.anchors.topMargin
enabled: root.pageEnabled
Column {
id: col
anchors.top: parent.top
anchors.bottom: addAppButton.top
anchors.left: parent.left
anchors.right: parent.right
ListView {
id: apps
width: parent.width
height: apps.contentItem.height
model: SortFilterProxyModel {
id: proxyAppSplitTunnelingModel
sourceModel: AppSplitTunnelingModel
@@ -177,23 +168,15 @@ PageType {
]
}
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
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: appPath
rightImageSource: "qrc:/images/controls/trash.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -216,9 +199,6 @@ PageType {
DividerType {}
}
}
}
}
}
Rectangle {
anchors.fill: addAppButton
@@ -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
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,15 +145,17 @@ PageType {
SwitcherType {
id: switcherStartMinimized
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.margins: 16
text: qsTr("Start minimized")
descriptionText: qsTr("Launch application minimized")
descriptionText: qsTr("Launch application minimized (works with autostart option turned on)")
parentFlickable: fl
enabled: switcherAutoStart.checked
opacity: enabled ? 1.0 : 0.5
checked: SettingsController.isStartMinimizedEnabled()
onCheckedChanged: {
@@ -162,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()
}
@@ -182,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)
}
@@ -199,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.")
+33 -15
View File
@@ -41,35 +41,51 @@ 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
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
header: ColumnLayout {
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.")
@@ -79,13 +95,14 @@ PageType {
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)"))
+30 -16
View File
@@ -21,21 +21,26 @@ 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
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
header: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
@@ -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)
}
+36 -13
View File
@@ -21,13 +21,21 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
FlickableType {
id: fl
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
anchors.right: parent.right
anchors.left: parent.left
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
@@ -39,32 +47,40 @@ PageType {
}
}
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
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")
}
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
spacing: 16
TextFieldWithHeaderType {
id: primaryDns
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Primary DNS")
textField.text: SettingsController.primaryDns
@@ -77,6 +93,9 @@ PageType {
id: secondaryDns
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Secondary DNS")
textField.text: SettingsController.secondaryDns
@@ -87,7 +106,11 @@ PageType {
BasicButtonType {
id: restoreDefaultButton
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
@@ -121,6 +144,7 @@ PageType {
id: saveButton
Layout.fillWidth: true
Layout.margins: 16
text: qsTr("Save")
@@ -136,5 +160,4 @@ PageType {
}
}
}
}
@@ -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 {
@@ -64,7 +64,7 @@ PageType {
displayMarginBeginning: 40
displayMarginEnd: 40
ScrollBar.vertical: ScrollBarType { }
ScrollBar.vertical: ScrollBarType {}
footer: Item {
width: listView.width
+8 -7
View File
@@ -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 {
+79 -107
View File
@@ -18,9 +18,7 @@ PageType {
signal lastItemTabClickedSignal()
onFocusChanged: content.isServerWithWriteAccess ?
labelWithButton.forceActiveFocus() :
labelWithButton3.forceActiveFocus()
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
Connections {
target: InstallController
@@ -63,53 +61,71 @@ PageType {
target: ServersModel
function onProcessedServerIndexChanged() {
content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
root.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
}
}
FlickableType {
id: fl
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ListViewType {
id: listView
ColumnLayout {
id: content
anchors.fill: parent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
model: serverActions
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
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<QtObject> serverActions: [
check,
reboot,
remove,
clear,
reset,
switch_to_premium,
]
QtObject {
id: check
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
readonly property var clickedHandler: function() {
PageController.showBusyIndicator(true)
InstallController.scanServerForInstalledContainers()
PageController.showBusyIndicator(false)
}
}
DividerType {
visible: content.isServerWithWriteAccess
}
QtObject {
id: reboot
LabelWithButtonType {
id: labelWithButton2
visible: content.isServerWithWriteAccess
Layout.fillWidth: true
text: qsTr("Reboot server")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
property bool isVisible: root.isServerWithWriteAccess
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")
@@ -123,32 +139,23 @@ PageType {
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)
}
}
DividerType {
visible: content.isServerWithWriteAccess
}
QtObject {
id: remove
LabelWithButtonType {
id: labelWithButton3
Layout.fillWidth: true
text: qsTr("Remove server from application")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
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")
@@ -162,31 +169,23 @@ PageType {
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)
}
}
DividerType {}
QtObject {
id: clear
LabelWithButtonType {
id: labelWithButton4
visible: content.isServerWithWriteAccess
Layout.fillWidth: true
text: qsTr("Clear server from Amnezia software")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
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
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")
@@ -199,33 +198,23 @@ PageType {
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)
}
}
DividerType {
visible: content.isServerWithWriteAccess
}
QtObject {
id: reset
LabelWithButtonType {
id: labelWithButton5
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
Layout.fillWidth: true
text: qsTr("Reset API config")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
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")
@@ -239,42 +228,25 @@ PageType {
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")
}
QtObject {
id: switch_to_premium
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() {
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
readonly property var clickedHandler: function() {
PageController.goToPageHome()
ApiPremV1MigrationController.showMigrationDrawer()
}
}
DividerType {
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
}
}
}
}
@@ -21,18 +21,31 @@ 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()
}
}
}
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
@@ -42,52 +55,16 @@ PageType {
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
}
ListView {
id: protocols
Layout.fillWidth: true
height: protocols.contentItem.height
clip: true
interactive: 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()
}
model: ProtocolsModel
delegate: Item {
implicitWidth: protocols.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
delegate: ColumnLayout {
id: delegateContent
anchors.fill: parent
width: listView.width
property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg
property bool isClientSettingsVisible: (protocolIndex === ProtocolEnum.WireGuard) || (protocolIndex === ProtocolEnum.Awg)
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
LabelWithButtonType {
@@ -157,10 +134,10 @@ PageType {
visible: delegateContent.isServerSettingsVisible
}
}
}
footer: ColumnLayout {
width: header.width
width: listView.width
LabelWithButtonType {
id: clearCacheButton
@@ -188,10 +165,8 @@ PageType {
InstallController.clearCachedProfile()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
// if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
// }
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@@ -205,10 +180,6 @@ PageType {
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: root.isClearCacheVisible
}
@@ -239,9 +210,7 @@ PageType {
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@@ -255,15 +224,8 @@ PageType {
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ServersModel.isProcessedServerHasWriteAccess()
}
}
}
}
}
@@ -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
@@ -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
@@ -308,7 +299,7 @@ PageType {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import / Export Sites")
headerText: qsTr("Additional options")
}
LabelWithButtonType {
@@ -351,6 +342,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 {}
}
}
@@ -374,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
@@ -397,34 +418,58 @@ 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")
property list<QtObject> importOptions: [
replaceOption,
addOption,
]
clickedFunction: function() {
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 !== "") {
importSitesDrawerContent.importSites(fileName, false)
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)
}
}
}
@@ -436,10 +481,4 @@ PageType {
importSitesDrawer.closeTriggered()
moreActionsDrawer.closeTriggered()
}
DividerType {}
}
}
}
}
}
@@ -15,25 +15,31 @@ 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
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
spacing: 0
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
@@ -45,53 +51,28 @@ PageType {
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: "qrc:/images/controls/map-pin.svg"
leftText: qsTr("For the region")
rightText: ApiServicesModel.getSelectedServiceData("region")
imageSource: imagePath
leftText: lText
rightText: rText
}
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
footer: ColumnLayout {
width: listView.width
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: ""
}
spacing: 0
ParagraphTextType {
Layout.fillWidth: true
@@ -104,7 +85,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 {
@@ -113,20 +94,15 @@ PageType {
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
Layout.fillWidth: true
Layout.topMargin: 32
Layout.bottomMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Connect")
@@ -143,4 +119,59 @@ PageType {
}
}
}
}
}
property list<QtObject> 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
}
}
@@ -14,62 +14,54 @@ import "../Config"
PageType {
id: root
ColumnLayout {
id: header
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
BackButtonType {
id: backButton
Layout.topMargin: 20
onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.topMargin: 16
header: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
Layout.bottomMargin: 24
headerText: qsTr("VPN by Amnezia")
descriptionText: qsTr("Choose a VPN service that suits your needs.")
}
}
ListView {
id: servicesListView
anchors.top: header.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
model: ApiServicesModel
ScrollBar.vertical: ScrollBarType {}
delegate: ColumnLayout {
delegate: Item {
implicitWidth: servicesListView.width
implicitHeight: delegateContent.implicitHeight
width: listView.width
enabled: isServiceAvailable
ColumnLayout {
id: delegateContent
anchors.fill: parent
CardWithIconsType {
id: card
@@ -96,5 +88,4 @@ PageType {
}
}
}
}
}
@@ -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
@@ -234,6 +226,9 @@ PageType {
leftImageSource: imageSource
onClicked: { handler() }
Keys.onEnterPressed: this.clicked()
Keys.onReturnPressed: this.clicked()
}
}
@@ -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
@@ -177,6 +148,9 @@ PageType {
onClicked: {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("starter-guide"))
}
Keys.onEnterPressed: this.clicked()
Keys.onReturnPressed: this.clicked()
}
}
}
+81 -73
View File
@@ -20,6 +20,7 @@ PageType {
SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
filters: [
ValueFilter {
@@ -40,70 +41,64 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) {
listView.positionViewAtBeginning()
}
}
FlickableType {
id: fl
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + setupLaterButton.anchors.bottomMargin
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 16
BaseHeaderType {
id: header
implicitWidth: parent.width
headerTextMaximumLineCount: 10
headerText: qsTr("Choose Installation Type")
}
ButtonGroup {
id: buttonGroup
}
ListView {
id: containers
width: parent.width
height: containers.contentItem.height
spacing: 16
currentIndex: 0
clip: true
interactive: false
model: proxyContainersModel
ListViewType {
id: listView
property int dockerContainer
property int containerDefaultPort
property int containerDefaultTransportProto
property bool isFocusable: true
delegate: Item {
implicitWidth: containers.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
spacing: 16
header: ColumnLayout {
width: listView.width
spacing: 16
BaseHeaderType {
id: header
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerTextMaximumLineCount: 10
headerText: qsTr("Choose Installation Type")
}
}
model: proxyContainersModel
currentIndex: 0
delegate: ColumnLayout {
width: listView.width
CardType {
id: card
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: easySetupHeader
bodyText: easySetupDescription
@@ -114,30 +109,30 @@ PageType {
isEasySetup = true
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
containers.dockerContainer = dockerContainer
containers.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
containers.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
}
listView.dockerContainer = dockerContainer
listView.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
listView.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
}
Keys.onReturnPressed: this.clicked()
Keys.onEnterPressed: this.clicked()
}
}
Component.onCompleted: {
var item = containers.itemAtIndex(containers.currentIndex)
if (item !== null) {
var button = item.children[0].children[0]
button.checked = true
button.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")
@@ -146,25 +141,29 @@ PageType {
onClicked: function() {
isEasySetup = false
checked = true
}
Keys.onEnterPressed: this.clicked()
Keys.onReturnPressed: this.clicked()
}
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)
}
@@ -174,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
@@ -185,9 +186,6 @@ PageType {
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
Keys.onTabPressed: lastItemTabClicked(focusItem)
parentFlickable: fl
visible: {
if (PageController.isTriggeredByConnectButton()) {
PageController.setTriggeredByConnectButton(false)
@@ -205,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()
}
}
}
}
@@ -85,42 +85,23 @@ PageType {
]
}
FlickableType {
ListViewType {
id: listView
anchors.fill: parent
contentHeight: content.height
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 16
ListView {
id: container
width: parent.width
height: container.contentItem.height
currentIndex: -1
clip: true
interactive: false
model: proxyContainersModel
delegate: Item {
implicitWidth: container.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
delegate: ColumnLayout {
width: listView.width
BaseHeaderType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Installing")
descriptionText: name
@@ -131,6 +112,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
Timer {
id: timer
@@ -149,6 +132,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
text: root.progressBarText
}
@@ -158,6 +143,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: root.isCancelButtonVisible
@@ -170,7 +157,4 @@ PageType {
}
}
}
}
}
}
}
@@ -29,77 +29,42 @@ PageType {
]
}
FlickableType {
anchors.fill: parent
contentHeight: content.height
Column {
id: content
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
ListView {
id: processedContainerListView
width: parent.width
height: contentItem.height
currentIndex: -1
clip: true
interactive: false
model: proxyContainersModel
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()
}
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
}
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
@@ -109,7 +74,8 @@ PageType {
id: showDetailsButton
Layout.topMargin: 16
Layout.leftMargin: -8
Layout.rightMargin: 16
Layout.leftMargin: 16
implicitHeight: 32
@@ -120,7 +86,6 @@ PageType {
textColor: AmneziaStyle.color.goldenApricot
text: qsTr("More detailed")
KeyNavigation.tab: transportProtoSelector
clickedFunc: function() {
showDetailsDrawer.openTriggered()
@@ -149,39 +114,40 @@ PageType {
}
}
FlickableType {
id: fl
ListViewType {
id: showDetailsListView
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
}
ColumnLayout {
id: showDetailsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
header: ColumnLayout {
width: showDetailsListView.width
Header2Type {
id: showDetailsDrawerHeader
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: name
}
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: showDetailsListView.width
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: detailedDescription
textFormat: Text.MarkdownText
@@ -189,14 +155,22 @@ PageType {
Rectangle {
Layout.fillHeight: true
Layout.leftMargin: 16
Layout.rightMargin: 16
color: AmneziaStyle.color.transparent
}
}
footer: ColumnLayout {
width: showDetailsListView.width
BasicButtonType {
id: showDetailsCloseButton
Layout.fillWidth: true
Layout.bottomMargin: 32
parentFlickable: fl
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Close")
@@ -213,6 +187,8 @@ PageType {
id: transportProtoHeader
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: qsTr("Network protocol")
}
@@ -221,6 +197,9 @@ PageType {
id: transportProtoSelector
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
rootWidth: root.width
}
@@ -229,6 +208,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Port")
textField.maximumLength: 5
@@ -237,6 +218,9 @@ PageType {
Rectangle {
Layout.fillHeight: true
Layout.rightMargin: 16
Layout.leftMargin: 16
color: AmneziaStyle.color.transparent
}
@@ -245,6 +229,8 @@ PageType {
Layout.fillWidth: true
Layout.bottomMargin: 32
Layout.rightMargin: 16
Layout.leftMargin: 16
text: qsTr("Install")
@@ -278,7 +264,4 @@ PageType {
}
}
}
}
}
}
}
@@ -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);
}
}
+36 -20
View File
@@ -13,25 +13,31 @@ import "../Config"
PageType {
id: root
FlickableType {
id: fl
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
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,17 +73,18 @@ PageType {
}
}
}
}
footer: ColumnLayout {
width: listView.width
BasicButtonType {
id: continueButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.bottomMargin: 32
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.topMargin: 16
Layout.bottomMargin: 32
text: qsTr("Continue")
@@ -80,4 +94,6 @@ PageType {
}
}
}
}
}
}
@@ -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
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.left: parent.left
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,35 +186,39 @@ PageType {
}
}
}
}
Rectangle {
anchors.fill: columnContent
anchors.bottomMargin: -24
color: AmneziaStyle.color.midnightBlack
opacity: 0.8
}
ColumnLayout {
id: columnContent
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
footer: ColumnLayout {
width: listView.width
BasicButtonType {
id: connectButton
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 32
Layout.rightMargin: 16
Layout.leftMargin: 16
text: qsTr("Connect")
clickedFunc: function() {
if (cloakingCheckBox.checked) {
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()
}
}
}
}
}
+9 -35
View File
@@ -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)
}
}
@@ -256,6 +235,9 @@ PageType {
onClicked: {
accessTypeSelector.currentIndex = 0
}
Keys.onEnterPressed: this.clicked()
Keys.onReturnPressed: this.clicked()
}
HorizontalRadioButton {
@@ -272,6 +254,9 @@ PageType {
ServersModel.getProcessedServerCredentials())
PageController.showBusyIndicator(false)
}
Keys.onEnterPressed: this.clicked()
Keys.onReturnPressed: this.clicked()
}
}
}
@@ -525,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)
@@ -826,9 +808,6 @@ PageType {
root.revokeConfig(index)
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
// focusItem1.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@@ -842,9 +821,4 @@ PageType {
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
}
}
@@ -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\"")
}
}
}
}
+36 -28
View File
@@ -15,6 +15,7 @@ import "../Controls2/TextTypes"
import "../Components"
import "../Config"
PageType {
id: root
@@ -25,27 +26,29 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
FlickableType {
ListViewType {
id: listView
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.left: parent.left
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
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")
@@ -53,6 +56,8 @@ PageType {
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 24
Layout.bottomMargin: 24
@@ -63,11 +68,14 @@ PageType {
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
@@ -100,8 +108,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()
}
@@ -117,11 +125,20 @@ PageType {
}
}
}
}
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: 40
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg"
@@ -137,20 +154,11 @@ 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)
}
}
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
PageController.goToPage(PageEnum.PageShareConnection)
}
}
}
}
}
+6 -1
View File
@@ -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));
@@ -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
+64 -39
View File
@@ -9,8 +9,6 @@
#include <QStandardPaths>
#include <QUrl>
#include <iostream>
#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) \
#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));
+22 -20
View File
@@ -39,28 +39,32 @@ public:
{
m_className = className;
}
Logger(Logger const &) = delete;
Logger &operator=(Logger const &) = delete;
const QString &className() const
{
return m_className;
}
class Log
class LogStreamer
{
public:
Log(Logger *logger, LogLevel level);
~Log();
LogStreamer(Logger *logger, LogLevel level);
~LogStreamer();
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);
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 T> typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, Log &>::type operator<<(T t)
template<typename T> typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, LogStreamer &>::type operator<<(T t)
{
const QMetaObject *meta = qt_getEnumMetaObject(t);
const char *name = qt_getEnumName(t);
@@ -87,16 +91,14 @@ public:
Data *m_data;
};
Log error();
Log warning();
Log info();
Log debug();
LogStreamer error();
LogStreamer warning();
LogStreamer info();
LogStreamer debug();
QString sensitive(const QString &input);
private:
Logger() {};
Logger(Logger const &) = delete;
Logger &operator=(Logger const &) = delete;
Logger() = default;
static QString userLogsDir();
@@ -105,7 +107,7 @@ private:
static QString m_logFileName;
static QString m_serviceLogFileName;
friend void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
friend void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
// compat with Mozilla logger
QString m_className;