mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-24 02:00:24 +07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 20989ea832 |
@@ -255,20 +255,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
||||||
QT_VERSION: 6.4.3
|
QT_VERSION: 6.4.3
|
||||||
|
|
||||||
MAC_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
|
||||||
|
|
||||||
MAC_APP_CERT_CERT: ${{ secrets.MAC_APP_CERT_CERT }}
|
|
||||||
MAC_SIGNER_ID: ${{ secrets.MAC_SIGNER_ID }}
|
|
||||||
MAC_APP_CERT_PW: ${{ secrets.MAC_APP_CERT_PW }}
|
|
||||||
|
|
||||||
MAC_INSTALLER_SIGNER_CERT: ${{ secrets.MAC_INSTALLER_SIGNER_CERT }}
|
|
||||||
MAC_INSTALLER_SIGNER_ID: ${{ secrets.MAC_INSTALLER_SIGNER_ID }}
|
|
||||||
MAC_INSTALL_CERT_PW: ${{ secrets.MAC_INSTALL_CERT_PW }}
|
|
||||||
|
|
||||||
APPLE_DEV_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
|
||||||
APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
|
||||||
|
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
@@ -309,7 +295,7 @@ jobs:
|
|||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
run: |
|
run: |
|
||||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||||
bash deploy/build_macos.sh -n
|
bash deploy/build_macos.sh
|
||||||
|
|
||||||
- name: 'Upload installer artifact'
|
- name: 'Upload installer artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -332,20 +318,6 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 6.8.0
|
QT_VERSION: 6.8.0
|
||||||
|
|
||||||
MAC_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
|
||||||
|
|
||||||
MAC_APP_CERT_CERT: ${{ secrets.MAC_APP_CERT_CERT }}
|
|
||||||
MAC_SIGNER_ID: ${{ secrets.MAC_SIGNER_ID }}
|
|
||||||
MAC_APP_CERT_PW: ${{ secrets.MAC_APP_CERT_PW }}
|
|
||||||
|
|
||||||
MAC_INSTALLER_SIGNER_CERT: ${{ secrets.MAC_INSTALLER_SIGNER_CERT }}
|
|
||||||
MAC_INSTALLER_SIGNER_ID: ${{ secrets.MAC_INSTALLER_SIGNER_ID }}
|
|
||||||
MAC_INSTALL_CERT_PW: ${{ secrets.MAC_INSTALL_CERT_PW }}
|
|
||||||
|
|
||||||
APPLE_DEV_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
|
||||||
APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
|
||||||
|
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
@@ -386,7 +358,7 @@ jobs:
|
|||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
run: |
|
run: |
|
||||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||||
bash deploy/build_macos.sh -n
|
bash deploy/build_macos.sh
|
||||||
|
|
||||||
- name: 'Upload installer artifact'
|
- name: 'Upload installer artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|||||||
@@ -138,4 +138,3 @@ CMakeFiles/
|
|||||||
ios-ne-build.sh
|
ios-ne-build.sh
|
||||||
macos-ne-build.sh
|
macos-ne-build.sh
|
||||||
macos-signed-build.sh
|
macos-signed-build.sh
|
||||||
macos-with-sign-build.sh
|
|
||||||
|
|||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
set(AMNEZIAVPN_VERSION 4.8.9.2)
|
|
||||||
|
|
||||||
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
project(${PROJECT} VERSION 4.8.8.1
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
@@ -12,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
|||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 2092)
|
set(APP_ANDROID_VERSION_CODE 2087)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
|
|||||||
@@ -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)
|
### [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?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.
|
[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.
|
||||||
|
|
||||||
[](https://amnezia.org)
|
[](https://amnezia.org)
|
||||||
|
|
||||||
### [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)
|
### [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)
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> 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).
|
> 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 ).
|
||||||
|
|
||||||
<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://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/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>
|
<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>
|
||||||
|
|
||||||
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
|
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -6,16 +6,16 @@
|
|||||||
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
||||||
|
|
||||||
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
|
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
|
||||||
[AmneziaVPN](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
[AmneziaVPN](https://amnezia.org) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
||||||
|
|
||||||
[](https://amnezia.org)
|
[](https://amnezia.org)
|
||||||
|
|
||||||
### [Сайт](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)
|
### [Сайт](https://amnezia.org) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Если [сайт 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).
|
> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org).
|
||||||
|
|
||||||
<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>
|
<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>
|
||||||
|
|
||||||
|
|
||||||
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
|
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
|
||||||
|
|||||||
+1
-1
Submodule client/3rd-prebuilt updated: 522e8d33a9...840b7b070e
@@ -10,8 +10,6 @@ import java.nio.channels.FileChannel
|
|||||||
import java.nio.channels.FileLock
|
import java.nio.channels.FileLock
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.time.ZonedDateTime
|
|
||||||
import java.time.ZoneOffset
|
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import org.amnezia.vpn.util.Log.Priority.D
|
import org.amnezia.vpn.util.Log.Priority.D
|
||||||
import org.amnezia.vpn.util.Log.Priority.E
|
import org.amnezia.vpn.util.Log.Priority.E
|
||||||
@@ -137,8 +135,8 @@ object Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
|
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
|
||||||
val utcDate = ZonedDateTime.now(ZoneOffset.UTC).format(dateTimeFormat)
|
val date = LocalDateTime.now().format(dateTimeFormat)
|
||||||
return "${utcDate}Z ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
||||||
"$tag: $msg\n"
|
"$tag: $msg\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ include(${CLIENT_ROOT_DIR}/3rd/qrcodegen/qrcodegen.cmake)
|
|||||||
|
|
||||||
set(LIBSSH_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/")
|
set(LIBSSH_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/")
|
||||||
set(OPENSSL_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/")
|
set(OPENSSL_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/")
|
||||||
|
set(LIBXRAY_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libxray")
|
||||||
|
|
||||||
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
||||||
|
|
||||||
@@ -27,6 +28,9 @@ if(WIN32)
|
|||||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
||||||
endif()
|
endif()
|
||||||
elseif(APPLE AND NOT IOS)
|
elseif(APPLE AND NOT IOS)
|
||||||
|
set(LIBS ${LIBS} "resolv")
|
||||||
|
set(LIBXRAY_LIB_PATH "${LIBXRAY_ROOT_DIR}/macos/x86_64/libxray.a")
|
||||||
|
set(LIBXRAY_INCLUDE_DIR "${LIBXRAY_ROOT_DIR}/macos/x86_64")
|
||||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a")
|
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a")
|
||||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a")
|
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a")
|
||||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64")
|
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64")
|
||||||
@@ -72,6 +76,8 @@ set(LIBS ${LIBS}
|
|||||||
${OPENSSL_LIB_CRYPTO_PATH}
|
${OPENSSL_LIB_CRYPTO_PATH}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(LIBS ${LIBS} ${LIBXRAY_LIB_PATH})
|
||||||
|
|
||||||
add_compile_definitions(_WINSOCKAPI_)
|
add_compile_definitions(_WINSOCKAPI_)
|
||||||
|
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
@@ -88,4 +94,5 @@ include_directories(
|
|||||||
${CLIENT_ROOT_DIR}/3rd/qtkeychain/qtkeychain
|
${CLIENT_ROOT_DIR}/3rd/qtkeychain/qtkeychain
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
|
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/libssh/include
|
${CMAKE_CURRENT_BINARY_DIR}/3rd/libssh/include
|
||||||
|
${LIBXRAY_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,11 +18,7 @@ set(LIBS ${LIBS}
|
|||||||
${FW_NETWORK_EXTENSION}
|
${FW_NETWORK_EXTENSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${PROJECT} PROPERTIES
|
set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE)
|
||||||
MACOSX_BUNDLE TRUE
|
|
||||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}"
|
|
||||||
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
|
||||||
)
|
|
||||||
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||||
|
|
||||||
|
|||||||
@@ -120,9 +120,6 @@ void CoreController::initControllers()
|
|||||||
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
|
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
|
||||||
&ConnectionController::onCurrentContainerUpdated); // TODO remove this
|
&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_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
|
||||||
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
|
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
|
||||||
|
|
||||||
@@ -245,9 +242,6 @@ void CoreController::initNotificationHandler()
|
|||||||
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
||||||
&ConnectionController::closeConnection);
|
&ConnectionController::closeConnection);
|
||||||
connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +279,6 @@ void CoreController::updateTranslator(const QLocale &locale)
|
|||||||
m_engine->retranslate();
|
m_engine->retranslate();
|
||||||
|
|
||||||
emit translationsUpdated();
|
emit translationsUpdated();
|
||||||
emit websiteUrlChanged(m_languageModel->getCurrentSiteUrl());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::initErrorMessagesHandler()
|
void CoreController::initErrorMessagesHandler()
|
||||||
@@ -306,10 +299,13 @@ void CoreController::setQmlRoot()
|
|||||||
|
|
||||||
void CoreController::initApiCountryModelUpdateHandler()
|
void CoreController::initApiCountryModelUpdateHandler()
|
||||||
{
|
{
|
||||||
|
// TODO
|
||||||
connect(m_serversModel.get(), &ServersModel::updateApiCountryModel, this, [this]() {
|
connect(m_serversModel.get(), &ServersModel::updateApiCountryModel, this, [this]() {
|
||||||
m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
|
m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
|
||||||
m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
|
m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
|
||||||
});
|
});
|
||||||
|
connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this,
|
||||||
|
[this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreController::initContainerModelUpdateHandler()
|
void CoreController::initContainerModelUpdateHandler()
|
||||||
|
|||||||
@@ -5,10 +5,6 @@
|
|||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#ifndef Q_OS_ANDROID
|
|
||||||
#include "ui/systemtray_notificationhandler.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ui/controllers/api/apiConfigsController.h"
|
#include "ui/controllers/api/apiConfigsController.h"
|
||||||
#include "ui/controllers/api/apiSettingsController.h"
|
#include "ui/controllers/api/apiSettingsController.h"
|
||||||
#include "ui/controllers/api/apiPremV1MigrationController.h"
|
#include "ui/controllers/api/apiPremV1MigrationController.h"
|
||||||
@@ -65,7 +61,6 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void translationsUpdated();
|
void translationsUpdated();
|
||||||
void websiteUrlChanged(const QString &newUrl);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initModels();
|
void initModels();
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
|
||||||
|
<key>CFBundleAllowMixedLocalizations</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(MARKETING_VERSION)</string>
|
||||||
|
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false/>
|
||||||
|
|
||||||
|
<key>LSApplicationCategoryType</key>
|
||||||
|
<string>public.app-category.utilities</string>
|
||||||
|
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||||
|
|
||||||
|
<key>LSMultipleInstancesProhibited</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
|
||||||
|
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -1,12 +1,28 @@
|
|||||||
#include "xrayprotocol.h"
|
#include "xrayprotocol.h"
|
||||||
|
|
||||||
|
#include "core/defs.h"
|
||||||
|
#include "core/networkUtilities.h"
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
#include <QtCore/qcontainerfwd.h>
|
||||||
|
#include <QtCore/qdebug.h>
|
||||||
|
#include <QtCore/qlogging.h>
|
||||||
|
#include <QtCore/qobject.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "core/networkUtilities.h"
|
#include "core/ipcclient.h"
|
||||||
#include "utilities.h"
|
#include "libxray.h"
|
||||||
|
|
||||||
XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) : VpnProtocol(configuration, parent)
|
XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) : VpnProtocol(configuration, parent)
|
||||||
{
|
{
|
||||||
@@ -15,6 +31,9 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) :
|
|||||||
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
||||||
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
||||||
m_t2sProcess = IpcClient::InterfaceTun2Socks();
|
m_t2sProcess = IpcClient::InterfaceTun2Socks();
|
||||||
|
|
||||||
|
amnezia_xray_setloghandler(&XrayProtocol::ctxLogHandler, this);
|
||||||
|
amnezia_xray_setsockcallback(&XrayProtocol::ctxSockCallback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
XrayProtocol::~XrayProtocol()
|
XrayProtocol::~XrayProtocol()
|
||||||
@@ -25,61 +44,20 @@ XrayProtocol::~XrayProtocol()
|
|||||||
|
|
||||||
ErrorCode XrayProtocol::start()
|
ErrorCode XrayProtocol::start()
|
||||||
{
|
{
|
||||||
qDebug().noquote() << "XrayProtocol xrayExecPath():" << xrayExecPath();
|
qDebug() << "XrayProtocol::start()";
|
||||||
|
|
||||||
if (!QFileInfo::exists(xrayExecPath())) {
|
auto cfg = QJsonDocument(m_xrayConfig).toJson().toStdString();
|
||||||
setLastError(ErrorCode::XrayExecutableMissing);
|
if (auto err = amnezia_xray_configure(cfg.data()); err != 0) {
|
||||||
return lastError();
|
return ErrorCode::InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
if (auto err = amnezia_xray_start(); err != 0) {
|
||||||
m_xrayCfgFile.setAutoRemove(false);
|
return ErrorCode::NotImplementedError;
|
||||||
#endif
|
|
||||||
m_xrayCfgFile.open();
|
|
||||||
QString config = QJsonDocument(m_xrayConfig).toJson();
|
|
||||||
config.replace(m_remoteHost, m_remoteAddress);
|
|
||||||
m_xrayCfgFile.write(config.toUtf8());
|
|
||||||
m_xrayCfgFile.close();
|
|
||||||
|
|
||||||
QStringList args = QStringList() << "-c" << m_xrayCfgFile.fileName() << "-format=json";
|
|
||||||
|
|
||||||
qDebug().noquote() << "XrayProtocol::start()" << xrayExecPath() << args.join(" ");
|
|
||||||
|
|
||||||
m_xrayProcess.setProcessChannelMode(QProcess::MergedChannels);
|
|
||||||
m_xrayProcess.setProgram(xrayExecPath());
|
|
||||||
|
|
||||||
if (Utils::processIsRunning(Utils::executable("xray", false))) {
|
|
||||||
qDebug().noquote() << "kill previos xray";
|
|
||||||
Utils::killProcessByName(Utils::executable("xray", false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_xrayProcess.setArguments(args);
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
|
|
||||||
connect(&m_xrayProcess, &QProcess::readyReadStandardOutput, this, [this]() {
|
return startTun2Sock();
|
||||||
#ifdef QT_DEBUG
|
|
||||||
qDebug().noquote() << "xray:" << m_xrayProcess.readAllStandardOutput();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(&m_xrayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this,
|
|
||||||
[this](int exitCode, QProcess::ExitStatus exitStatus) {
|
|
||||||
qDebug().noquote() << "XrayProtocol finished, exitCode, exitStatus" << exitCode << exitStatus;
|
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
||||||
if ((exitStatus != QProcess::NormalExit) || (exitCode != 0)) {
|
|
||||||
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
|
|
||||||
emit setConnectionState(Vpn::ConnectionState::Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m_xrayProcess.start();
|
|
||||||
m_xrayProcess.waitForStarted();
|
|
||||||
|
|
||||||
if (m_xrayProcess.state() == QProcess::ProcessState::Running) {
|
|
||||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
|
||||||
QThread::msleep(1000);
|
|
||||||
return startTun2Sock();
|
|
||||||
} else
|
|
||||||
return ErrorCode::XrayExecutableMissing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode XrayProtocol::startTun2Sock()
|
ErrorCode XrayProtocol::startTun2Sock()
|
||||||
@@ -126,9 +104,7 @@ ErrorCode XrayProtocol::startTun2Sock()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
|
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
|
||||||
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1");
|
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "1.0.0.0/8" << "2.0.0.0/7" << "4.0.0.0/6" << "8.0.0.0/5" << "16.0.0.0/4" << "32.0.0.0/3" << "64.0.0.0/2" << "128.0.0.0/1");
|
||||||
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1");
|
|
||||||
IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress);
|
|
||||||
}
|
}
|
||||||
IpcClient::Interface()->StopRoutingIpv6();
|
IpcClient::Interface()->StopRoutingIpv6();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -171,9 +147,9 @@ void XrayProtocol::stop()
|
|||||||
IpcClient::Interface()->StartRoutingIpv6();
|
IpcClient::Interface()->StartRoutingIpv6();
|
||||||
#endif
|
#endif
|
||||||
qDebug() << "XrayProtocol::stop()";
|
qDebug() << "XrayProtocol::stop()";
|
||||||
m_xrayProcess.disconnect();
|
|
||||||
m_xrayProcess.kill();
|
amnezia_xray_stop();
|
||||||
m_xrayProcess.waitForFinished(3000);
|
|
||||||
if (m_t2sProcess) {
|
if (m_t2sProcess) {
|
||||||
m_t2sProcess->stop();
|
m_t2sProcess->stop();
|
||||||
}
|
}
|
||||||
@@ -181,15 +157,6 @@ void XrayProtocol::stop()
|
|||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString XrayProtocol::xrayExecPath()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
return Utils::executable(QString("xray/xray"), true);
|
|
||||||
#else
|
|
||||||
return Utils::executable(QString("xray"), true);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
|
void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
|
||||||
{
|
{
|
||||||
m_configData = configuration;
|
m_configData = configuration;
|
||||||
@@ -205,3 +172,20 @@ void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
|
|||||||
m_primaryDNS = configuration.value(amnezia::config_key::dns1).toString();
|
m_primaryDNS = configuration.value(amnezia::config_key::dns1).toString();
|
||||||
m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString();
|
m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XrayProtocol::sockCallback(uintptr_t fd)
|
||||||
|
{
|
||||||
|
// #ifdef Q_OS_DARWIN
|
||||||
|
// const int iface = if_nametoindex("en0");
|
||||||
|
// if (iface > 0)
|
||||||
|
// {
|
||||||
|
// setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface, sizeof(iface));
|
||||||
|
// setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface, sizeof(iface));
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void XrayProtocol::logHandler(char* str)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
#include "QProcess"
|
#include "QProcess"
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "protocols/vpnprotocol.h"
|
||||||
#include "openvpnprotocol.h"
|
#include "rep_ipc_process_tun2socks_replica.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
class XrayProtocol : public VpnProtocol
|
class XrayProtocol : public VpnProtocol
|
||||||
{
|
{
|
||||||
@@ -24,10 +25,16 @@ protected:
|
|||||||
QJsonObject m_xrayConfig;
|
QJsonObject m_xrayConfig;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QString xrayExecPath();
|
static void ctxSockCallback(uintptr_t fd, void* ctx) {
|
||||||
static QString tun2SocksExecPath();
|
reinterpret_cast<XrayProtocol*>(ctx)->sockCallback(fd);
|
||||||
|
}
|
||||||
|
static void ctxLogHandler(char* str, void* ctx) {
|
||||||
|
reinterpret_cast<XrayProtocol*>(ctx)->logHandler(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sockCallback(uintptr_t fd);
|
||||||
|
void logHandler(char* str);
|
||||||
|
|
||||||
private:
|
|
||||||
int m_localPort;
|
int m_localPort;
|
||||||
QString m_remoteHost;
|
QString m_remoteHost;
|
||||||
QString m_remoteAddress;
|
QString m_remoteAddress;
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
|
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
|
||||||
<file>ui/qml/Components/ServersListView.qml</file>
|
<file>ui/qml/Components/ServersListView.qml</file>
|
||||||
<file>ui/qml/Components/SettingsContainersListView.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/TransportProtoSelector.qml</file>
|
||||||
<file>ui/qml/Components/AddSitePanel.qml</file>
|
<file>ui/qml/Components/AddSitePanel.qml</file>
|
||||||
<file>ui/qml/Config/GlobalConfig.qml</file>
|
<file>ui/qml/Config/GlobalConfig.qml</file>
|
||||||
@@ -228,7 +228,6 @@
|
|||||||
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
|
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
|
||||||
<file>ui/qml/Pages2/PageShare.qml</file>
|
<file>ui/qml/Pages2/PageShare.qml</file>
|
||||||
<file>ui/qml/Pages2/PageShareFullAccess.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/Pages2/PageStart.qml</file>
|
||||||
<file>ui/qml/Components/RenameServerDrawer.qml</file>
|
<file>ui/qml/Components/RenameServerDrawer.qml</file>
|
||||||
<file>ui/qml/Controls2/ListViewType.qml</file>
|
<file>ui/qml/Controls2/ListViewType.qml</file>
|
||||||
@@ -241,7 +240,6 @@
|
|||||||
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
|
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
|
||||||
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
|
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
|
||||||
<file>ui/qml/Components/AwgTextField.qml</file>
|
<file>ui/qml/Components/AwgTextField.qml</file>
|
||||||
<file>ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/countriesFlags">
|
<qresource prefix="/countriesFlags">
|
||||||
<file>images/flagKit/ZW.svg</file>
|
<file>images/flagKit/ZW.svg</file>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.15
|
||||||
LABEL maintainer="AmneziaVPN"
|
LABEL maintainer="AmneziaVPN"
|
||||||
|
|
||||||
ARG XRAY_RELEASE="v25.8.3"
|
ARG XRAY_RELEASE="v1.8.6"
|
||||||
|
|
||||||
RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz
|
RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz
|
||||||
RUN apk --update upgrade --no-cache
|
RUN apk --update upgrade --no-cache
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -248,10 +248,10 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
|||||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
apiConfigObject.value(configKey::userCountryCode).toString(),
|
||||||
serverCountryCode,
|
serverCountryCode,
|
||||||
apiConfigObject.value(configKey::serviceType).toString(),
|
apiConfigObject.value(configKey::serviceType).toString(),
|
||||||
configKey::awg, // apiConfigObject.value(configKey::serviceProtocol).toString(),
|
m_apiServicesModel->getSelectedServiceProtocol(),
|
||||||
serverConfigObject.value(configKey::authData).toObject() };
|
serverConfigObject.value(configKey::authData).toObject() };
|
||||||
|
|
||||||
QString protocol = gatewayRequestData.serviceProtocol;
|
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||||
ProtocolData protocolData = generateProtocolData(protocol);
|
ProtocolData protocolData = generateProtocolData(protocol);
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||||
@@ -283,7 +283,7 @@ bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
|
|||||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
apiConfigObject.value(configKey::userCountryCode).toString(),
|
||||||
serverCountryCode,
|
serverCountryCode,
|
||||||
apiConfigObject.value(configKey::serviceType).toString(),
|
apiConfigObject.value(configKey::serviceType).toString(),
|
||||||
configKey::awg, // apiConfigObject.value(configKey::serviceProtocol).toString(),
|
m_apiServicesModel->getSelectedServiceProtocol(),
|
||||||
serverConfigObject.value(configKey::authData).toObject() };
|
serverConfigObject.value(configKey::authData).toObject() };
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
Logger logger("FocusController");
|
|
||||||
}
|
|
||||||
|
|
||||||
FocusController::FocusController(QQmlApplicationEngine *engine, QObject *parent)
|
FocusController::FocusController(QQmlApplicationEngine *engine, QObject *parent)
|
||||||
: QObject { parent },
|
: QObject { parent },
|
||||||
m_engine { engine },
|
m_engine { engine },
|
||||||
@@ -91,7 +85,7 @@ void FocusController::dropRootObject(QObject *object)
|
|||||||
dropListView();
|
dropListView();
|
||||||
setFocusOnDefaultItem();
|
setFocusOnDefaultItem();
|
||||||
} else {
|
} else {
|
||||||
logger.warning() << "TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
|
qWarning() << "===>> TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +101,7 @@ void FocusController::reload(Direction direction)
|
|||||||
QObject *rootObject = (m_rootObjects.empty() ? m_engine->rootObjects().value(0) : m_rootObjects.top());
|
QObject *rootObject = (m_rootObjects.empty() ? m_engine->rootObjects().value(0) : m_rootObjects.top());
|
||||||
|
|
||||||
if (!rootObject) {
|
if (!rootObject) {
|
||||||
logger.error() << "No ROOT OBJECT found!";
|
qCritical() << "No ROOT OBJECT found!";
|
||||||
resetRootObject();
|
resetRootObject();
|
||||||
dropListView();
|
dropListView();
|
||||||
return;
|
return;
|
||||||
@@ -119,7 +113,7 @@ void FocusController::reload(Direction direction)
|
|||||||
direction == Direction::Forward ? FocusControl::isLess : FocusControl::isMore);
|
direction == Direction::Forward ? FocusControl::isLess : FocusControl::isMore);
|
||||||
|
|
||||||
if (m_focusChain.empty()) {
|
if (m_focusChain.empty()) {
|
||||||
logger.warning() << "Focus chain is empty!";
|
qWarning() << "Focus chain is empty!";
|
||||||
resetRootObject();
|
resetRootObject();
|
||||||
dropListView();
|
dropListView();
|
||||||
return;
|
return;
|
||||||
@@ -137,7 +131,7 @@ void FocusController::nextItem(Direction direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_focusChain.empty()) {
|
if (m_focusChain.empty()) {
|
||||||
logger.warning() << "There are no items to navigate";
|
qWarning() << "There are no items to navigate";
|
||||||
setFocusOnDefaultItem();
|
setFocusOnDefaultItem();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -155,7 +149,7 @@ void FocusController::nextItem(Direction direction)
|
|||||||
const auto focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(focusedItemIndex));
|
const auto focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(focusedItemIndex));
|
||||||
|
|
||||||
if (focusedItem == nullptr) {
|
if (focusedItem == nullptr) {
|
||||||
logger.warning() << "Failed to get item to focus on. Setting focus on default";
|
qWarning() << "Failed to get item to focus on. Setting focus on default";
|
||||||
setFocusOnDefaultItem();
|
setFocusOnDefaultItem();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,19 +403,9 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
|||||||
QJsonObject config;
|
QJsonObject config;
|
||||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||||
const auto &protocols = ContainerProps::protocolsForContainer(container);
|
const auto &protocols = ContainerProps::protocolsForContainer(container);
|
||||||
|
|
||||||
for (const auto &protocol : protocols) {
|
for (const auto &protocol : protocols) {
|
||||||
QJsonObject containerConfig;
|
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::port, port);
|
||||||
containerConfig.insert(config_key::transport_proto, transportProto);
|
containerConfig.insert(config_key::transport_proto, transportProto);
|
||||||
|
|
||||||
@@ -560,97 +550,14 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
|||||||
qDebug() << siteName;
|
qDebug() << siteName;
|
||||||
|
|
||||||
containerConfig.insert(config_key::site, 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));
|
config.insert(config_key::container, ContainerProps::containerToString(container));
|
||||||
}
|
}
|
||||||
if (shouldProcessProtocol) {
|
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
|
||||||
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
installedContainers.insert(container, config);
|
installedContainers.insert(container, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
const static QRegularExpression torOrDnsRegExp("(amnezia-(?:torwebsite|dns)).*?([0-9]*)/(udp|tcp).*");
|
const static QRegularExpression torOrDnsRegExp("(amnezia-(?:torwebsite|dns)).*?([0-9]*)/(udp|tcp).*");
|
||||||
QRegularExpressionMatch torOrDnsRegMatch = torOrDnsRegExp.match(containerInfo);
|
QRegularExpressionMatch torOrDnsRegMatch = torOrDnsRegExp.match(containerInfo);
|
||||||
if (torOrDnsRegMatch.hasMatch()) {
|
if (torOrDnsRegMatch.hasMatch()) {
|
||||||
@@ -814,8 +721,6 @@ void InstallController::clearCachedProfile(QSharedPointer<ServerController> serv
|
|||||||
m_clientManagementModel->revokeClient(containerConfig, container, serverCredentials, serverIndex, serverController);
|
m_clientManagementModel->revokeClient(containerConfig, container, serverCredentials, serverIndex, serverController);
|
||||||
|
|
||||||
emit cachedProfileCleared(tr("%1 cached profile cleared").arg(ContainerProps::containerHumanNames().value(container)));
|
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()
|
QRegularExpression InstallController::ipAddressPortRegExp()
|
||||||
|
|||||||
@@ -83,8 +83,6 @@ signals:
|
|||||||
|
|
||||||
void noInstalledContainers();
|
void noInstalledContainers();
|
||||||
|
|
||||||
void profileCleared(const QJsonObject &config);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
|
void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
|
||||||
const ServerCredentials &serverCredentials, const QSharedPointer<ServerController> &serverController,
|
const ServerCredentials &serverCredentials, const QSharedPointer<ServerController> &serverController,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ void ListViewFocusController::viewAtCurrentIndex() const
|
|||||||
}
|
}
|
||||||
case Section::Delegate: {
|
case Section::Delegate: {
|
||||||
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index
|
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index
|
||||||
Q_ARG(int, 6)); // PositionMode (0 = Beginning; 1 = Center; 2 = End; 3 = Visible; 4 = Contain; 5 = SnapPosition)
|
Q_ARG(int, 2)); // PositionMode (0 = Visible)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Section::Footer: {
|
case Section::Footer: {
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ namespace PageLoader
|
|||||||
PageSettingsApiInstructions,
|
PageSettingsApiInstructions,
|
||||||
PageSettingsApiNativeConfigs,
|
PageSettingsApiNativeConfigs,
|
||||||
PageSettingsApiDevices,
|
PageSettingsApiDevices,
|
||||||
PageSettingsApiSubscriptionKey,
|
|
||||||
PageSettingsKillSwitchExceptions,
|
PageSettingsKillSwitchExceptions,
|
||||||
|
|
||||||
PageServiceSftpSettings,
|
PageServiceSftpSettings,
|
||||||
@@ -72,7 +71,6 @@ namespace PageLoader
|
|||||||
PageProtocolAwgClientSettings,
|
PageProtocolAwgClientSettings,
|
||||||
|
|
||||||
PageShareFullAccess,
|
PageShareFullAccess,
|
||||||
PageShareConnection,
|
|
||||||
|
|
||||||
PageDevMenu
|
PageDevMenu
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,23 +35,6 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
|
|||||||
#endif
|
#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)
|
void SettingsController::toggleAmneziaDns(bool enable)
|
||||||
{
|
{
|
||||||
m_settings->setUseAmneziaDns(enable);
|
m_settings->setUseAmneziaDns(enable);
|
||||||
@@ -147,10 +130,7 @@ void SettingsController::backupAppConfig(const QString &fileName)
|
|||||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||||
QJsonObject config = doc.object();
|
QJsonObject config = doc.object();
|
||||||
|
|
||||||
config["AppPlatform"] = getPlatformName();
|
|
||||||
config["Conf/autoStart"] = Autostart::isAutostart();
|
config["Conf/autoStart"] = Autostart::isAutostart();
|
||||||
config["Conf/killSwitchEnabled"] = isKillSwitchEnabled();
|
|
||||||
config["Conf/strictKillSwitchEnabled"] = isStrictKillSwitchEnabled();
|
|
||||||
|
|
||||||
SystemController::saveFile(fileName, QJsonDocument(config).toJson());
|
SystemController::saveFile(fileName, QJsonDocument(config).toJson());
|
||||||
}
|
}
|
||||||
@@ -175,41 +155,21 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
|||||||
}
|
}
|
||||||
toggleAutoStart(autoStart);
|
toggleAutoStart(autoStart);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_serversModel->resetModel();
|
m_serversModel->resetModel();
|
||||||
m_languageModel->changeLanguage(
|
m_languageModel->changeLanguage(
|
||||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||||
|
|
||||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
|
#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
|
||||||
int appSplitTunnelingRouteMode = newConfigData.value("Conf/appsRouteMode").toInt();
|
int appSplitTunnelingRouteMode = newConfigData.value("Conf/appsRouteMode").toInt();
|
||||||
bool appSplittunnelingEnabled = newConfigData.value("Conf/appsSplitTunnelingEnabled").toString().toLower() == "true";
|
bool appSplittunnelingEnabled = newConfigData.value("Conf/appsSplitTunnelingEnabled").toBool();
|
||||||
m_appSplitTunnelingModel->setRouteMode(appSplitTunnelingRouteMode);
|
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);
|
m_appSplitTunnelingModel->toggleSplitTunneling(appSplittunnelingEnabled);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int siteSplitTunnelingRouteMode = newConfigData.value("Conf/routeMode").toInt();
|
int siteSplitTunnelingRouteMode = newConfigData.value("Conf/routeMode").toInt();
|
||||||
bool siteSplittunnelingEnabled = newConfigData.value("Conf/sitesSplitTunnelingEnabled").toString().toLower() == "true";
|
bool siteSplittunnelingEnabled = newConfigData.value("Conf/sitesSplitTunnelingEnabled").toBool();
|
||||||
m_sitesModel->setRouteMode(siteSplitTunnelingRouteMode);
|
m_sitesModel->setRouteMode(siteSplitTunnelingRouteMode);
|
||||||
m_sitesModel->toggleSplitTunneling(siteSplittunnelingEnabled);
|
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();
|
emit restoreBackupFinished();
|
||||||
} else {
|
} else {
|
||||||
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
|
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
|
||||||
@@ -225,7 +185,8 @@ void SettingsController::clearSettings()
|
|||||||
{
|
{
|
||||||
m_settings->clearSettings();
|
m_settings->clearSettings();
|
||||||
m_serversModel->resetModel();
|
m_serversModel->resetModel();
|
||||||
m_languageModel->changeLanguage(m_languageModel->getSystemLanguageEnum());
|
m_languageModel->changeLanguage(
|
||||||
|
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||||
|
|
||||||
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
|
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
|
||||||
m_sitesModel->toggleSplitTunneling(false);
|
m_sitesModel->toggleSplitTunneling(false);
|
||||||
|
|||||||
@@ -136,8 +136,6 @@ private:
|
|||||||
|
|
||||||
QString m_appVersion;
|
QString m_appVersion;
|
||||||
|
|
||||||
QString getPlatform();
|
|
||||||
|
|
||||||
QDateTime m_loggingDisableDate;
|
QDateTime m_loggingDisableDate;
|
||||||
|
|
||||||
bool m_isDevModeEnabled = false;
|
bool m_isDevModeEnabled = false;
|
||||||
|
|||||||
@@ -78,13 +78,6 @@ void SitesController::removeSite(int index)
|
|||||||
emit finished(tr("Site removed: %1").arg(hostname));
|
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)
|
void SitesController::importSites(const QString &fileName, bool replaceExisting)
|
||||||
{
|
{
|
||||||
QByteArray jsonData;
|
QByteArray jsonData;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ public slots:
|
|||||||
void addSite(QString hostname);
|
void addSite(QString hostname);
|
||||||
void removeSite(int index);
|
void removeSite(int index);
|
||||||
|
|
||||||
void removeSites();
|
|
||||||
void importSites(const QString &fileName, bool replaceExisting);
|
void importSites(const QString &fileName, bool replaceExisting);
|
||||||
void exportSites(const QString &fileName);
|
void exportSites(const QString &fileName);
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
|||||||
} else {
|
} else {
|
||||||
return tr("VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. "
|
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, "
|
"Other sites will be opened from your real IP address, "
|
||||||
"<a href=\"%1\" style=\"color: #FBB26A;\">more details on the website.</a>");
|
"<a href=\"%1/free\" style=\"color: #FBB26A;\">more details on the website.</a>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case PriceRole: {
|
case PriceRole: {
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ QVariant AppSplitTunnelingModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case AppPathRole: {
|
case AppPathRole: {
|
||||||
return m_apps.at(index.row()).appName;
|
return m_apps.at(index.row()).appName;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@@ -59,13 +59,6 @@ void AppSplitTunnelingModel::removeApp(QModelIndex index)
|
|||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppSplitTunnelingModel::clearAppsList() {
|
|
||||||
beginResetModel();
|
|
||||||
m_apps.clear();
|
|
||||||
m_settings->setVpnApps(m_currentRouteMode, m_apps);
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
int AppSplitTunnelingModel::getRouteMode()
|
int AppSplitTunnelingModel::getRouteMode()
|
||||||
{
|
{
|
||||||
return m_currentRouteMode;
|
return m_currentRouteMode;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
bool addApp(const InstalledAppInfo &appInfo);
|
bool addApp(const InstalledAppInfo &appInfo);
|
||||||
void removeApp(QModelIndex index);
|
void removeApp(QModelIndex index);
|
||||||
void clearAppsList();
|
|
||||||
|
|
||||||
int getRouteMode();
|
int getRouteMode();
|
||||||
void setRouteMode(int routeMode);
|
void setRouteMode(int routeMode);
|
||||||
|
|||||||
@@ -101,23 +101,6 @@ QString LanguageModel::getCurrentLanguageName()
|
|||||||
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
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)
|
QString LanguageModel::getCurrentSiteUrl(const QString &path)
|
||||||
{
|
{
|
||||||
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
||||||
@@ -127,13 +110,3 @@ QString LanguageModel::getCurrentSiteUrl(const QString &path)
|
|||||||
default: return QString("https://amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
LanguageModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
LanguageModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||||
LanguageSettings::AvailableLanguageEnum getSystemLanguageEnum();
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
@@ -61,7 +60,6 @@ public slots:
|
|||||||
int getLineHeightAppend();
|
int getLineHeightAppend();
|
||||||
QString getCurrentLanguageName();
|
QString getCurrentLanguageName();
|
||||||
QString getCurrentSiteUrl(const QString &path = "");
|
QString getCurrentSiteUrl(const QString &path = "");
|
||||||
QString getCurrentDocsUrl(const QString &path = "");
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateTranslations(const QLocale &locale);
|
void updateTranslations(const QLocale &locale);
|
||||||
|
|||||||
@@ -83,16 +83,6 @@ void SitesModel::removeSite(QModelIndex index)
|
|||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SitesModel::removeSites()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
|
|
||||||
m_settings->removeAllVpnSites(m_currentRouteMode);
|
|
||||||
fillSites();
|
|
||||||
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SitesModel::getRouteMode()
|
int SitesModel::getRouteMode()
|
||||||
{
|
{
|
||||||
return m_currentRouteMode;
|
return m_currentRouteMode;
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ public slots:
|
|||||||
bool addSite(const QString &hostname, const QString &ip);
|
bool addSite(const QString &hostname, const QString &ip);
|
||||||
void addSites(const QMap<QString, QString> &sites, bool replaceExisting);
|
void addSites(const QMap<QString, QString> &sites, bool replaceExisting);
|
||||||
void removeSite(QModelIndex index);
|
void removeSite(QModelIndex index);
|
||||||
void removeSites();
|
|
||||||
|
|
||||||
int getRouteMode();
|
int getRouteMode();
|
||||||
void setRouteMode(int routeMode);
|
void setRouteMode(int routeMode);
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import ProtocolEnum 1.0
|
|||||||
import "../Controls2"
|
import "../Controls2"
|
||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
|
|
||||||
ListViewType {
|
|
||||||
|
ListView {
|
||||||
id: menuContent
|
id: menuContent
|
||||||
|
|
||||||
property var rootWidth
|
property var rootWidth
|
||||||
@@ -20,6 +21,13 @@ ListViewType {
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
snapMode: ListView.SnapToItem
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: containersRadioButtonGroup
|
id: containersRadioButtonGroup
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ DrawerType2 {
|
|||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||||
root.closeTriggered()
|
root.closeTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ DrawerType2 {
|
|||||||
headerText: qsTr("Choose application")
|
headerText: qsTr("Choose application")
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -66,6 +66,11 @@ DrawerType2 {
|
|||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
interactive: true
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
model: SortFilterProxyModel {
|
model: SortFilterProxyModel {
|
||||||
id: proxyInstalledAppsModel
|
id: proxyInstalledAppsModel
|
||||||
sourceModel: installedAppsModel
|
sourceModel: installedAppsModel
|
||||||
@@ -76,35 +81,44 @@ DrawerType2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: buttonGroup
|
id: buttonGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: Item {
|
||||||
width: listView.width
|
implicitWidth: root.width
|
||||||
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
RowLayout {
|
ColumnLayout {
|
||||||
CheckBoxType {
|
id: delegateContent
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: appName
|
anchors.fill: parent
|
||||||
checked: isAppSelected
|
|
||||||
onCheckedChanged: {
|
RowLayout {
|
||||||
installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked)
|
CheckBoxType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: appName
|
||||||
|
checked: isAppSelected
|
||||||
|
onCheckedChanged: {
|
||||||
|
installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
source: "image://installedAppImage/" + appIcon
|
||||||
|
|
||||||
|
sourceSize.width: 24
|
||||||
|
sourceSize.height: 24
|
||||||
|
|
||||||
|
Layout.rightMargin: 48
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
DividerType {}
|
||||||
source: "image://installedAppImage/" + appIcon
|
|
||||||
|
|
||||||
sourceSize.width: 24
|
|
||||||
sourceSize.height: 24
|
|
||||||
|
|
||||||
Layout.rightMargin: 48
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ DrawerType2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButtonLayout.bottom
|
anchors.top: backButtonLayout.bottom
|
||||||
@@ -57,8 +57,14 @@ DrawerType2 {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
property int selectedIndex: LanguageModel.currentLanguageIndex
|
property int selectedIndex: LanguageModel.currentLanguageIndex
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
model: LanguageModel
|
model: LanguageModel
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import "../Controls2"
|
|||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
import "../Config"
|
import "../Config"
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property int selectedIndex: ServersModel.defaultIndex
|
property int selectedIndex: ServersModel.defaultIndex
|
||||||
@@ -28,6 +28,10 @@ ListViewType {
|
|||||||
|
|
||||||
model: ServersModel
|
model: ServersModel
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ServersModel
|
target: ServersModel
|
||||||
function onDefaultServerIndexChanged(serverIndex) {
|
function onDefaultServerIndexChanged(serverIndex) {
|
||||||
@@ -35,6 +39,9 @@ ListViewType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
id: menuContentDelegate
|
id: menuContentDelegate
|
||||||
objectName: "menuContentDelegate"
|
objectName: "menuContentDelegate"
|
||||||
|
|||||||
@@ -13,64 +13,78 @@ import "../Controls2"
|
|||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
|
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
anchors.fill: parent
|
width: parent.width
|
||||||
|
height: root.contentItem.height
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
clip: true
|
||||||
width: root.width
|
reuseItems: true
|
||||||
|
|
||||||
LabelWithButtonType {
|
property bool isFocusable: false
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: name
|
delegate: Item {
|
||||||
descriptionText: description
|
implicitWidth: root.width
|
||||||
rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg"
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
clickedFunction: function() {
|
ColumnLayout {
|
||||||
if (isInstalled) {
|
id: delegateContent
|
||||||
var containerIndex = root.model.mapToSource(index)
|
|
||||||
ContainersModel.setProcessedContainerIndex(containerIndex)
|
|
||||||
|
|
||||||
if (serviceType !== ProtocolEnum.Other) {
|
anchors.fill: parent
|
||||||
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: containerRadioButton
|
||||||
|
implicitWidth: parent.width
|
||||||
|
|
||||||
|
text: name
|
||||||
|
descriptionText: description
|
||||||
|
rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
if (isInstalled) {
|
||||||
|
var containerIndex = root.model.mapToSource(index)
|
||||||
|
ContainersModel.setProcessedContainerIndex(containerIndex)
|
||||||
|
|
||||||
|
if (serviceType !== ProtocolEnum.Other) {
|
||||||
|
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
|
||||||
|
ProtocolsModel.updateModel(config)
|
||||||
|
PageController.goToPage(PageEnum.PageProtocolRaw)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (containerIndex) {
|
||||||
|
case ContainerEnum.Ipsec: {
|
||||||
ProtocolsModel.updateModel(config)
|
ProtocolsModel.updateModel(config)
|
||||||
PageController.goToPage(PageEnum.PageProtocolRaw)
|
PageController.goToPage(PageEnum.PageProtocolRaw)
|
||||||
return
|
break
|
||||||
|
}
|
||||||
|
case ContainerEnum.Dns: {
|
||||||
|
PageController.goToPage(PageEnum.PageServiceDnsSettings)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
ProtocolsModel.updateModel(config)
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsServerProtocol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch (containerIndex) {
|
} else {
|
||||||
case ContainerEnum.Ipsec: {
|
ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
|
||||||
ProtocolsModel.updateModel(config)
|
InstallController.setShouldCreateServer(false)
|
||||||
PageController.goToPage(PageEnum.PageProtocolRaw)
|
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
||||||
break
|
|
||||||
}
|
|
||||||
case ContainerEnum.Dns: {
|
|
||||||
PageController.goToPage(PageEnum.PageServiceDnsSettings)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
ProtocolsModel.updateModel(config)
|
|
||||||
PageController.goToPage(PageEnum.PageSettingsServerProtocol)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
MouseArea {
|
||||||
ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
|
anchors.fill: parent
|
||||||
InstallController.setShouldCreateServer(false)
|
cursorShape: Qt.PointingHandCursor
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
enabled: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
DividerType {}
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,375 @@
|
|||||||
|
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,6 +29,8 @@ Button {
|
|||||||
|
|
||||||
property bool squareLeftSide: false
|
property bool squareLeftSide: false
|
||||||
|
|
||||||
|
property FlickableType parentFlickable
|
||||||
|
|
||||||
property var clickedFunc
|
property var clickedFunc
|
||||||
|
|
||||||
property alias buttonTextLabel: buttonText
|
property alias buttonTextLabel: buttonText
|
||||||
@@ -63,6 +65,14 @@ Button {
|
|||||||
|
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
if (root.activeFocus) {
|
||||||
|
if (root.parentFlickable) {
|
||||||
|
root.parentFlickable.ensureVisible(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
id: focusBorder
|
id: focusBorder
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ Button {
|
|||||||
|
|
||||||
property alias focusItem: rightImage
|
property alias focusItem: rightImage
|
||||||
|
|
||||||
|
property FlickableType parentFlickable
|
||||||
|
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
@@ -42,6 +44,22 @@ Button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureVisible(item) {
|
||||||
|
if (item.activeFocus) {
|
||||||
|
if (root.parentFlickable) {
|
||||||
|
root.parentFlickable.ensureVisible(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
ensureVisible(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
focusItem.onFocusChanged: {
|
||||||
|
root.ensureVisible(focusItem)
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|||||||
@@ -34,30 +34,13 @@ CheckBox {
|
|||||||
|
|
||||||
property string imageSource: "qrc:/images/controls/check.svg"
|
property string imageSource: "qrc:/images/controls/check.svg"
|
||||||
|
|
||||||
property bool isFocusable: true
|
property var parentFlickable
|
||||||
|
onFocusChanged: {
|
||||||
Keys.onTabPressed: {
|
if (root.activeFocus) {
|
||||||
FocusController.nextKeyTabItem()
|
if (root.parentFlickable) {
|
||||||
}
|
root.parentFlickable.ensureVisible(root)
|
||||||
|
}
|
||||||
Keys.onBacktabPressed: {
|
}
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hoverEnabled: enabled ? true : false
|
hoverEnabled: enabled ? true : false
|
||||||
|
|||||||
@@ -27,5 +27,6 @@ Flickable {
|
|||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {
|
ScrollBar.vertical: ScrollBarType {
|
||||||
id: scrollBar
|
id: scrollBar
|
||||||
|
policy: fl.height >= fl.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import "TextTypes"
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// property alias focusObjectName: eyeImage.objectName
|
|
||||||
property string text
|
property string text
|
||||||
property int textMaximumLineCount: 2
|
property int textMaximumLineCount: 2
|
||||||
property int textElide: Qt.ElideRight
|
property int textElide: Qt.ElideRight
|
||||||
@@ -26,6 +25,7 @@ Item {
|
|||||||
|
|
||||||
property alias rightButton: rightImage
|
property alias rightButton: rightImage
|
||||||
property alias eyeButton: eyeImage
|
property alias eyeButton: eyeImage
|
||||||
|
property FlickableType parentFlickable
|
||||||
|
|
||||||
property string textColor: AmneziaStyle.color.paleGray
|
property string textColor: AmneziaStyle.color.paleGray
|
||||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||||
@@ -70,6 +70,25 @@ Item {
|
|||||||
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
||||||
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
|
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 {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|||||||
@@ -6,16 +6,33 @@ ListView {
|
|||||||
|
|
||||||
property bool isFocusable: 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()
|
||||||
|
}
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
reuseItems: 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"
|
import "TextTypes"
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var rootWidth
|
property var rootWidth
|
||||||
@@ -25,6 +25,13 @@ ListViewType {
|
|||||||
width: rootWidth
|
width: rootWidth
|
||||||
height: root.contentItem.height
|
height: root.contentItem.height
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: buttonGroup
|
id: buttonGroup
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ import "../Controls2"
|
|||||||
ScrollBar {
|
ScrollBar {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
policy: ScrollBar.AsNeeded
|
policy: parent.height >= parent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ Switch {
|
|||||||
hoverEnabled: enabled ? true : false
|
hoverEnabled: enabled ? true : false
|
||||||
focusPolicy: Qt.TabFocus
|
focusPolicy: Qt.TabFocus
|
||||||
|
|
||||||
|
property FlickableType parentFlickable: null
|
||||||
|
|
||||||
|
onFocusChanged: {
|
||||||
|
if (root.activeFocus) {
|
||||||
|
if (root.parentFlickable) {
|
||||||
|
root.parentFlickable.ensureVisible(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
indicator: Rectangle {
|
indicator: Rectangle {
|
||||||
id: switcher
|
id: switcher
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,15 @@ Rectangle {
|
|||||||
border.color: getBorderColor(borderNormalColor)
|
border.color: getBorderColor(borderNormalColor)
|
||||||
radius: 16
|
radius: 16
|
||||||
|
|
||||||
|
property FlickableType parentFlickable: null
|
||||||
|
onFocusChanged: {
|
||||||
|
if (root.activeFocus) {
|
||||||
|
if (root.parentFlickable) {
|
||||||
|
root.parentFlickable.ensureVisible(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: parentMouse
|
id: parentMouse
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -45,32 +54,6 @@ Rectangle {
|
|||||||
anchors.topMargin: 16
|
anchors.topMargin: 16
|
||||||
anchors.bottomMargin: 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
|
color: AmneziaStyle.color.paleGray
|
||||||
selectionColor: AmneziaStyle.color.richBrown
|
selectionColor: AmneziaStyle.color.richBrown
|
||||||
selectedTextColor: AmneziaStyle.color.paleGray
|
selectedTextColor: AmneziaStyle.color.paleGray
|
||||||
|
|||||||
@@ -31,6 +31,15 @@ Rectangle {
|
|||||||
border.color: getBorderColor(borderNormalColor)
|
border.color: getBorderColor(borderNormalColor)
|
||||||
radius: 16
|
radius: 16
|
||||||
|
|
||||||
|
property FlickableType parentFlickable: null
|
||||||
|
onFocusChanged: {
|
||||||
|
if (root.activeFocus) {
|
||||||
|
if (root.parentFlickable) {
|
||||||
|
root.parentFlickable.ensureVisible(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: parentMouse
|
id: parentMouse
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -37,6 +37,19 @@ Item {
|
|||||||
implicitWidth: content.implicitWidth
|
implicitWidth: content.implicitWidth
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
|
|
||||||
|
property FlickableType parentFlickable
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: textField
|
||||||
|
function onFocusChanged() {
|
||||||
|
if (textField.activeFocus) {
|
||||||
|
if (root.parentFlickable) {
|
||||||
|
root.parentFlickable.ensureVisible(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: content
|
id: content
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ PageType {
|
|||||||
|
|
||||||
SortFilterProxyModel {
|
SortFilterProxyModel {
|
||||||
id: proxyServersModel
|
id: proxyServersModel
|
||||||
|
|
||||||
sourceModel: ServersModel
|
sourceModel: ServersModel
|
||||||
|
|
||||||
filters: [
|
filters: [
|
||||||
ValueFilter {
|
ValueFilter {
|
||||||
roleName: "isCurrentlyProcessed"
|
roleName: "isCurrentlyProcessed"
|
||||||
@@ -31,55 +29,67 @@ PageType {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
spacing: 16
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
model: proxyServersModel
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
spacing: 16
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
BaseHeaderType {
|
Repeater {
|
||||||
Layout.fillWidth: true
|
model: proxyServersModel
|
||||||
Layout.topMargin: 20
|
delegate: Item {
|
||||||
Layout.leftMargin: 16
|
implicitWidth: parent.width
|
||||||
Layout.rightMargin: 16
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
headerText: qsTr("Removing services from %1").arg(name)
|
ColumnLayout {
|
||||||
}
|
id: delegateContent
|
||||||
|
|
||||||
ProgressBarType {
|
anchors.fill: parent
|
||||||
id: progressBar
|
anchors.rightMargin: 16
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
Layout.fillWidth: true
|
BaseHeaderType {
|
||||||
Layout.topMargin: 32
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
Layout.topMargin: 20
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
Timer {
|
headerText: qsTr("Removing services from %1").arg(name)
|
||||||
id: timer
|
}
|
||||||
|
|
||||||
interval: 300
|
ProgressBarType {
|
||||||
repeat: true
|
id: progressBar
|
||||||
running: true
|
|
||||||
onTriggered: {
|
Layout.fillWidth: true
|
||||||
progressBar.value += 0.003
|
Layout.topMargin: 32
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: timer
|
||||||
|
|
||||||
|
interval: 300
|
||||||
|
repeat: true
|
||||||
|
running: true
|
||||||
|
onTriggered: {
|
||||||
|
progressBar.value += 0.003
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
|
||||||
|
text: qsTr("Usually it takes no more than 5 minutes")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParagraphTextType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 8
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Usually it takes no more than 5 minutes")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,17 +25,23 @@ PageType {
|
|||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
|
id: header
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
@@ -44,14 +50,16 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model: 1 // fake model to force the ListView to be created without a model
|
model: 1
|
||||||
|
clip: true
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
TextFieldWithHeaderType {
|
||||||
|
id: passwordTextField
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
@@ -79,6 +87,8 @@ PageType {
|
|||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
|
id: switcher
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ PageType {
|
|||||||
visible: isLoggingEnabled ? true : false
|
visible: isLoggingEnabled ? true : false
|
||||||
text: qsTr("Logging enabled")
|
text: qsTr("Logging enabled")
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
Keys.onEnterPressed: loggingButton.clicked()
|
||||||
Keys.onReturnPressed: this.clicked()
|
Keys.onReturnPressed: loggingButton.clicked()
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PageController.goToPage(PageEnum.PageSettingsLogging)
|
PageController.goToPage(PageEnum.PageSettingsLogging)
|
||||||
@@ -147,8 +147,8 @@ PageType {
|
|||||||
leftImageColor: ""
|
leftImageColor: ""
|
||||||
rightImageSource: "qrc:/images/controls/chevron-down.svg"
|
rightImageSource: "qrc:/images/controls/chevron-down.svg"
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
Keys.onEnterPressed: splitTunnelingButton.clicked()
|
||||||
Keys.onReturnPressed: this.clicked()
|
Keys.onReturnPressed: splitTunnelingButton.clicked()
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
homeSplitTunnelingDrawer.openTriggered()
|
homeSplitTunnelingDrawer.openTriggered()
|
||||||
@@ -276,8 +276,8 @@ PageType {
|
|||||||
topPadding: 4
|
topPadding: 4
|
||||||
bottomPadding: 3
|
bottomPadding: 3
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
Keys.onEnterPressed: collapsedButtonChevron.clicked()
|
||||||
Keys.onReturnPressed: this.clicked()
|
Keys.onReturnPressed: collapsedButtonChevron.clicked()
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (drawer.isCollapsedStateActive()) {
|
if (drawer.isCollapsedStateActive()) {
|
||||||
@@ -320,9 +320,6 @@ PageType {
|
|||||||
|
|
||||||
rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : ""
|
rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : ""
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
ServersModel.processedIndex = ServersModel.defaultIndex
|
ServersModel.processedIndex = ServersModel.defaultIndex
|
||||||
|
|
||||||
|
|||||||
@@ -16,397 +16,349 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
BackButtonType {
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listview
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.bottom: saveButton.top
|
anchors.bottom: saveButton.top
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
width: parent.width
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
BaseHeaderType {
|
clip: true
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("AmneziaWG settings")
|
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: AwgConfigModel
|
model: AwgConfigModel
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: Item {
|
||||||
width: listView.width
|
id: delegateItem
|
||||||
|
implicitWidth: listview.width
|
||||||
|
implicitHeight: col.implicitHeight
|
||||||
|
|
||||||
|
property alias mtuTextField: mtuTextField
|
||||||
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
|
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
|
||||||
junkPacketMaxSizeTextField.errorText === "" &&
|
junkPacketMaxSizeTextField.errorText === "" &&
|
||||||
junkPacketMinSizeTextField.errorText === "" &&
|
junkPacketMinSizeTextField.errorText === "" &&
|
||||||
junkPacketCountTextField.errorText === ""
|
junkPacketCountTextField.errorText === ""
|
||||||
|
|
||||||
spacing: 0
|
ColumnLayout {
|
||||||
|
id: col
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
anchors.top: parent.top
|
||||||
id: mtuTextField
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.leftMargin: 16
|
||||||
Layout.topMargin: 40
|
anchors.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("MTU")
|
spacing: 0
|
||||||
textField.text: clientMtu
|
|
||||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
BaseHeaderType {
|
||||||
if (textField.text !== clientMtu) {
|
Layout.fillWidth: true
|
||||||
clientMtu = textField.text
|
|
||||||
|
headerText: qsTr("AmneziaWG settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: mtuTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 40
|
||||||
|
|
||||||
|
headerText: qsTr("MTU")
|
||||||
|
textField.text: clientMtu
|
||||||
|
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== clientMtu) {
|
||||||
|
clientMtu = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkEmptyText: true
|
||||||
|
KeyNavigation.tab: junkPacketCountTextField.textField
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: junkPacketCountTextField
|
||||||
|
headerText: "Jc - Junk packet count"
|
||||||
|
textField.text: clientJunkPacketCount
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== clientJunkPacketCount) {
|
||||||
|
clientJunkPacketCount = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyNavigation.tab: junkPacketMinSizeTextField.textField
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: junkPacketMinSizeTextField
|
||||||
|
headerText: "Jmin - Junk packet minimum size"
|
||||||
|
textField.text: clientJunkPacketMinSize
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== clientJunkPacketMinSize) {
|
||||||
|
clientJunkPacketMinSize = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: junkPacketMaxSizeTextField
|
||||||
|
headerText: "Jmax - Junk packet maximum size"
|
||||||
|
textField.text: clientJunkPacketMaxSize
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== clientJunkPacketMaxSize) {
|
||||||
|
clientJunkPacketMaxSize = textField.text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: junkPacketCountTextField
|
id: specialJunk1TextField
|
||||||
|
headerText: qsTr("I1 - First special junk packet")
|
||||||
|
textField.text: clientSpecialJunk1
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientSpecialJunk1) {
|
||||||
|
clientSpecialJunk1 = textField.text
|
||||||
headerText: "Jc - Junk packet count"
|
}
|
||||||
textField.text: clientJunkPacketCount
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientJunkPacketCount) {
|
|
||||||
clientJunkPacketCount = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: junkPacketMinSizeTextField
|
id: specialJunk2TextField
|
||||||
|
headerText: qsTr("I2 - Second special junk packet")
|
||||||
|
textField.text: clientSpecialJunk2
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientSpecialJunk2) {
|
||||||
|
clientSpecialJunk2 = textField.text
|
||||||
headerText: "Jmin - Junk packet minimum size"
|
}
|
||||||
textField.text: clientJunkPacketMinSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientJunkPacketMinSize) {
|
|
||||||
clientJunkPacketMinSize = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: junkPacketMaxSizeTextField
|
id: specialJunk3TextField
|
||||||
|
headerText: qsTr("I3 - Third special junk packet")
|
||||||
|
textField.text: clientSpecialJunk3
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientSpecialJunk3) {
|
||||||
|
clientSpecialJunk3 = textField.text
|
||||||
headerText: "Jmax - Junk packet maximum size"
|
}
|
||||||
textField.text: clientJunkPacketMaxSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientJunkPacketMaxSize) {
|
|
||||||
clientJunkPacketMaxSize = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: specialJunk1TextField
|
id: specialJunk4TextField
|
||||||
|
headerText: qsTr("I4 - Fourth special junk packet")
|
||||||
|
textField.text: clientSpecialJunk4
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientSpecialJunk4) {
|
||||||
|
clientSpecialJunk4 = textField.text
|
||||||
headerText: qsTr("I1 - First special junk packet")
|
}
|
||||||
textField.text: clientSpecialJunk1
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientSpecialJunk1) {
|
|
||||||
clientSpecialJunk1 = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: specialJunk2TextField
|
id: specialJunk5TextField
|
||||||
|
headerText: qsTr("I5 - Fifth special junk packet")
|
||||||
|
textField.text: clientSpecialJunk5
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientSpecialJunk5 ) {
|
||||||
|
clientSpecialJunk5 = textField.text
|
||||||
headerText: qsTr("I2 - Second special junk packet")
|
}
|
||||||
textField.text: clientSpecialJunk2
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientSpecialJunk2) {
|
|
||||||
clientSpecialJunk2 = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: specialJunk3TextField
|
id: controlledJunk1TextField
|
||||||
|
headerText: qsTr("J1 - First controlled junk packet")
|
||||||
|
textField.text: clientControlledJunk1
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientControlledJunk1) {
|
||||||
|
clientControlledJunk1 = textField.text
|
||||||
headerText: qsTr("I3 - Third special junk packet")
|
}
|
||||||
textField.text: clientSpecialJunk3
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientSpecialJunk3) {
|
|
||||||
clientSpecialJunk3 = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: specialJunk4TextField
|
id: controlledJunk2TextField
|
||||||
|
headerText: qsTr("J2 - Second controlled junk packet")
|
||||||
|
textField.text: clientControlledJunk2
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientControlledJunk2) {
|
||||||
|
clientControlledJunk2 = textField.text
|
||||||
headerText: qsTr("I4 - Fourth special junk packet")
|
}
|
||||||
textField.text: clientSpecialJunk4
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientSpecialJunk4) {
|
|
||||||
clientSpecialJunk4 = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: specialJunk5TextField
|
id: controlledJunk3TextField
|
||||||
|
headerText: qsTr("J3 - Third controlled junk packet")
|
||||||
|
textField.text: clientControlledJunk3
|
||||||
|
textField.validator: null
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientControlledJunk3) {
|
||||||
|
clientControlledJunk3 = textField.text
|
||||||
headerText: qsTr("I5 - Fifth special junk packet")
|
}
|
||||||
textField.text: clientSpecialJunk5
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientSpecialJunk5 ) {
|
|
||||||
clientSpecialJunk5 = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: controlledJunk1TextField
|
id: iTimeTextField
|
||||||
|
headerText: qsTr("Itime - Special handshake timeout")
|
||||||
|
textField.text: clientSpecialHandshakeTimeout
|
||||||
|
checkEmptyText: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
textField.onEditingFinished: {
|
||||||
Layout.rightMargin: 16
|
if (textField.text !== clientSpecialHandshakeTimeout) {
|
||||||
|
clientSpecialHandshakeTimeout = textField.text
|
||||||
headerText: qsTr("J1 - First controlled junk packet")
|
}
|
||||||
textField.text: clientControlledJunk1
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientControlledJunk1) {
|
|
||||||
clientControlledJunk1 = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
Header2TextType {
|
||||||
id: controlledJunk2TextField
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
text: qsTr("Server settings")
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("J2 - Second controlled junk packet")
|
|
||||||
textField.text: clientControlledJunk2
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientControlledJunk2) {
|
|
||||||
clientControlledJunk2 = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: controlledJunk3TextField
|
id: portTextField
|
||||||
|
enabled: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
headerText: qsTr("Port")
|
||||||
Layout.rightMargin: 16
|
textField.text: port
|
||||||
|
|
||||||
headerText: qsTr("J3 - Third controlled junk packet")
|
|
||||||
textField.text: clientControlledJunk3
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientControlledJunk3) {
|
|
||||||
clientControlledJunk3 = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: iTimeTextField
|
id: initPacketJunkSizeTextField
|
||||||
|
enabled: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
headerText: "S1 - Init packet junk size"
|
||||||
Layout.rightMargin: 16
|
textField.text: serverInitPacketJunkSize
|
||||||
|
|
||||||
headerText: qsTr("Itime - Special handshake timeout")
|
|
||||||
textField.text: clientSpecialHandshakeTimeout
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientSpecialHandshakeTimeout) {
|
|
||||||
clientSpecialHandshakeTimeout = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Header2TextType {
|
AwgTextField {
|
||||||
Layout.fillWidth: true
|
id: responsePacketJunkSizeTextField
|
||||||
Layout.topMargin: 16
|
enabled: false
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Server settings")
|
headerText: "S2 - Response packet junk size"
|
||||||
}
|
textField.text: serverResponsePacketJunkSize
|
||||||
|
}
|
||||||
|
|
||||||
AwgTextField {
|
// AwgTextField {
|
||||||
id: portTextField
|
// id: cookieReplyPacketJunkSizeTextField
|
||||||
|
// enabled: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
// headerText: "S3 - Cookie Reply packet junk size"
|
||||||
Layout.rightMargin: 16
|
// textField.text: serverCookieReplyPacketJunkSize
|
||||||
|
// }
|
||||||
|
|
||||||
enabled: false
|
// AwgTextField {
|
||||||
|
// id: transportPacketJunkSizeTextField
|
||||||
|
// enabled: false
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
// headerText: "S4 - Transport packet junk size"
|
||||||
textField.text: port
|
// textField.text: serverTransportPacketJunkSize
|
||||||
}
|
// }
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: initPacketJunkSizeTextField
|
id: initPacketMagicHeaderTextField
|
||||||
|
enabled: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
headerText: "H1 - Init packet magic header"
|
||||||
Layout.rightMargin: 16
|
textField.text: serverInitPacketMagicHeader
|
||||||
|
}
|
||||||
|
|
||||||
enabled: false
|
AwgTextField {
|
||||||
|
id: responsePacketMagicHeaderTextField
|
||||||
|
enabled: false
|
||||||
|
|
||||||
headerText: "S1 - Init packet junk size"
|
headerText: "H2 - Response packet magic header"
|
||||||
textField.text: serverInitPacketJunkSize
|
textField.text: serverResponsePacketMagicHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
AwgTextField {
|
||||||
id: responsePacketJunkSizeTextField
|
id: underloadPacketMagicHeaderTextField
|
||||||
|
enabled: false
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
headerText: "H3 - Underload packet magic header"
|
||||||
Layout.rightMargin: 16
|
textField.text: serverUnderloadPacketMagicHeader
|
||||||
|
}
|
||||||
|
|
||||||
enabled: false
|
AwgTextField {
|
||||||
|
id: transportPacketMagicHeaderTextField
|
||||||
|
enabled: false
|
||||||
|
|
||||||
headerText: "S2 - Response packet junk size"
|
headerText: "H4 - Transport packet magic header"
|
||||||
textField.text: serverResponsePacketJunkSize
|
textField.text: serverTransportPacketMagicHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// AwgTextField {
|
|
||||||
// id: cookieReplyPacketJunkSizeTextField
|
|
||||||
|
|
||||||
// Layout.leftMargin: 16
|
|
||||||
// Layout.rightMargin: 16
|
|
||||||
|
|
||||||
// enabled: false
|
|
||||||
|
|
||||||
// headerText: "S3 - Cookie Reply packet junk size"
|
|
||||||
// textField.text: serverCookieReplyPacketJunkSize
|
|
||||||
// }
|
|
||||||
|
|
||||||
// AwgTextField {
|
|
||||||
// id: transportPacketJunkSizeTextField
|
|
||||||
|
|
||||||
// Layout.leftMargin: 16
|
|
||||||
// Layout.rightMargin: 16
|
|
||||||
|
|
||||||
// enabled: false
|
|
||||||
|
|
||||||
// headerText: "S4 - Transport packet junk size"
|
|
||||||
// textField.text: serverTransportPacketJunkSize
|
|
||||||
// }
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: initPacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H1 - Init packet magic header"
|
|
||||||
textField.text: serverInitPacketMagicHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: responsePacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H2 - Response packet magic header"
|
|
||||||
textField.text: serverResponsePacketMagicHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: underloadPacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H3 - Underload packet magic header"
|
|
||||||
textField.text: serverUnderloadPacketMagicHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: transportPacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H4 - Transport packet magic header"
|
|
||||||
textField.text: serverTransportPacketMagicHeader
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,17 +375,18 @@ PageType {
|
|||||||
anchors.rightMargin: 16
|
anchors.rightMargin: 16
|
||||||
anchors.leftMargin: 16
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
enabled: listView.currentItem.isSaveButtonEnabled
|
enabled: listview.currentItem.isSaveButtonEnabled
|
||||||
|
|
||||||
text: qsTr("Save")
|
text: qsTr("Save")
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
onActiveFocusChanged: {
|
||||||
if(activeFocus) {
|
if(activeFocus) {
|
||||||
listView.positionViewAtEnd()
|
listview.positionViewAtEnd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
|
forceActiveFocus()
|
||||||
var headerText = qsTr("Save settings?")
|
var headerText = qsTr("Save settings?")
|
||||||
var descriptionText = qsTr("Only the settings for this device will be changed")
|
var descriptionText = qsTr("Only the settings for this device will be changed")
|
||||||
var yesButtonText = qsTr("Continue")
|
var yesButtonText = qsTr("Continue")
|
||||||
@@ -448,9 +401,11 @@ PageType {
|
|||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
InstallController.updateContainer(AwgConfigModel.getConfig())
|
InstallController.updateContainer(AwgConfigModel.getConfig())
|
||||||
}
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
var noButtonFunction = function() {}
|
if (!GC.isMobile()) {
|
||||||
|
saveButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,343 +19,334 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
BackButtonType {
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listview
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
property bool isFocusable: true
|
||||||
|
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
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
|
||||||
|
|
||||||
model: AwgConfigModel
|
model: AwgConfigModel
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: Item {
|
||||||
id: delegateItem
|
id: delegateItem
|
||||||
|
implicitWidth: listview.width
|
||||||
width: listView.width
|
implicitHeight: col.implicitHeight
|
||||||
|
|
||||||
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
spacing: 0
|
ColumnLayout {
|
||||||
|
id: col
|
||||||
|
|
||||||
BaseHeaderType {
|
anchors.top: parent.top
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.leftMargin: 16
|
anchors.right: parent.right
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("AmneziaWG settings")
|
anchors.leftMargin: 16
|
||||||
}
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
spacing: 0
|
||||||
id: vpnAddressSubnetTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
BaseHeaderType {
|
||||||
Layout.topMargin: 40
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
headerText: qsTr("AmneziaWG settings")
|
||||||
|
}
|
||||||
|
|
||||||
headerText: qsTr("VPN address subnet")
|
TextFieldWithHeaderType {
|
||||||
textField.text: subnetAddress
|
id: vpnAddressSubnetTextField
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
Layout.fillWidth: true
|
||||||
if (textField.text !== subnetAddress) {
|
Layout.topMargin: 40
|
||||||
subnetAddress = textField.text
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("VPN address subnet")
|
||||||
|
textField.text: subnetAddress
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== subnetAddress) {
|
||||||
|
subnetAddress = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: junkPacketCountTextField
|
||||||
|
headerText: qsTr("Jc - Junk packet count")
|
||||||
|
textField.text: serverJunkPacketCount
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverJunkPacketCount) {
|
||||||
|
serverJunkPacketCount = textField.text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEmptyText: true
|
AwgTextField {
|
||||||
}
|
id: junkPacketMinSizeTextField
|
||||||
|
headerText: qsTr("Jmin - Junk packet minimum size")
|
||||||
|
textField.text: serverJunkPacketMinSize
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
textField.onEditingFinished: {
|
||||||
id: portTextField
|
if (textField.text !== serverJunkPacketMinSize) {
|
||||||
Layout.fillWidth: true
|
serverJunkPacketMinSize = textField.text
|
||||||
Layout.topMargin: 16
|
}
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEmptyText: true
|
AwgTextField {
|
||||||
}
|
id: junkPacketMaxSizeTextField
|
||||||
|
headerText: qsTr("Jmax - Junk packet maximum size")
|
||||||
|
textField.text: serverJunkPacketMaxSize
|
||||||
|
|
||||||
AwgTextField {
|
textField.onEditingFinished: {
|
||||||
id: junkPacketCountTextField
|
if (textField.text !== serverJunkPacketMaxSize) {
|
||||||
|
serverJunkPacketMaxSize = textField.text
|
||||||
Layout.leftMargin: 16
|
}
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Jc - Junk packet count")
|
|
||||||
textField.text: serverJunkPacketCount
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverJunkPacketCount) {
|
|
||||||
serverJunkPacketCount = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: junkPacketMinSizeTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Jmin - Junk packet minimum size")
|
|
||||||
textField.text: serverJunkPacketMinSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverJunkPacketMinSize) {
|
|
||||||
serverJunkPacketMinSize = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: junkPacketMaxSizeTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Jmax - Junk packet maximum size")
|
|
||||||
textField.text: serverJunkPacketMaxSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverJunkPacketMaxSize) {
|
|
||||||
serverJunkPacketMaxSize = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: initPacketJunkSizeTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("S1 - Init packet junk size")
|
|
||||||
textField.text: serverInitPacketJunkSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverInitPacketJunkSize) {
|
|
||||||
serverInitPacketJunkSize = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: responsePacketJunkSizeTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("S2 - Response packet junk size")
|
|
||||||
textField.text: serverResponsePacketJunkSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverResponsePacketJunkSize) {
|
|
||||||
serverResponsePacketJunkSize = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AwgTextField {
|
|
||||||
// id: cookieReplyPacketJunkSizeTextField
|
|
||||||
|
|
||||||
// Layout.leftMargin: 16
|
|
||||||
// Layout.rightMargin: 16
|
|
||||||
|
|
||||||
// headerText: qsTr("S3 - Cookie reply packet junk size")
|
|
||||||
// textField.text: serverCookieReplyPacketJunkSize
|
|
||||||
|
|
||||||
// textField.onEditingFinished: {
|
|
||||||
// if (textField.text !== serverCookieReplyPacketJunkSize) {
|
|
||||||
// serverCookieReplyPacketJunkSize = textField.text
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// AwgTextField {
|
|
||||||
// id: transportPacketJunkSizeTextField
|
|
||||||
|
|
||||||
// Layout.leftMargin: 16
|
|
||||||
// Layout.rightMargin: 16
|
|
||||||
|
|
||||||
// headerText: qsTr("S4 - Transport packet junk size")
|
|
||||||
// textField.text: serverTransportPacketJunkSize
|
|
||||||
|
|
||||||
// textField.onEditingFinished: {
|
|
||||||
// if (textField.text !== serverTransportPacketJunkSize) {
|
|
||||||
// serverTransportPacketJunkSize = textField.text
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: initPacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("H1 - Init packet magic header")
|
|
||||||
textField.text: serverInitPacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverInitPacketMagicHeader) {
|
|
||||||
serverInitPacketMagicHeader = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: responsePacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("H2 - Response packet magic header")
|
|
||||||
textField.text: serverResponsePacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverResponsePacketMagicHeader) {
|
|
||||||
serverResponsePacketMagicHeader = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: underloadPacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("H3 - Underload packet magic header")
|
|
||||||
textField.text: serverUnderloadPacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverUnderloadPacketMagicHeader) {
|
|
||||||
serverUnderloadPacketMagicHeader = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: transportPacketMagicHeaderTextField
|
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("H4 - Transport packet magic header")
|
|
||||||
textField.text: serverTransportPacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverTransportPacketMagicHeader) {
|
|
||||||
serverTransportPacketMagicHeader = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveRestartButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
|
|
||||||
transportPacketMagicHeaderTextField.errorText === "" &&
|
|
||||||
responsePacketMagicHeaderTextField.errorText === "" &&
|
|
||||||
initPacketMagicHeaderTextField.errorText === "" &&
|
|
||||||
responsePacketJunkSizeTextField.errorText === "" &&
|
|
||||||
// cookieReplyHeaderJunkTextField.errorText === "" &&
|
|
||||||
// transportHeaderJunkTextField.errorText === "" &&
|
|
||||||
initPacketJunkSizeTextField.errorText === "" &&
|
|
||||||
junkPacketMaxSizeTextField.errorText === "" &&
|
|
||||||
junkPacketMinSizeTextField.errorText === "" &&
|
|
||||||
junkPacketCountTextField.errorText === "" &&
|
|
||||||
portTextField.errorText === "" &&
|
|
||||||
vpnAddressSubnetTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(activeFocus) {
|
|
||||||
listView.positionViewAtEnd()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clickedFunc: function() {
|
AwgTextField {
|
||||||
if (delegateItem.isEnabled) {
|
id: initPacketJunkSizeTextField
|
||||||
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
|
headerText: qsTr("S1 - Init packet junk size")
|
||||||
transportPacketMagicHeaderTextField.textField.text,
|
textField.text: serverInitPacketJunkSize
|
||||||
responsePacketMagicHeaderTextField.textField.text,
|
|
||||||
initPacketMagicHeaderTextField.textField.text)) {
|
textField.onEditingFinished: {
|
||||||
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
|
if (textField.text !== serverInitPacketJunkSize) {
|
||||||
return
|
serverInitPacketJunkSize = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: responsePacketJunkSizeTextField
|
||||||
|
headerText: qsTr("S2 - Response packet junk size")
|
||||||
|
textField.text: serverResponsePacketJunkSize
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverResponsePacketJunkSize) {
|
||||||
|
serverResponsePacketJunkSize = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AwgTextField {
|
||||||
|
// id: cookieReplyPacketJunkSizeTextField
|
||||||
|
// headerText: qsTr("S3 - Cookie reply packet junk size")
|
||||||
|
// textField.text: serverCookieReplyPacketJunkSize
|
||||||
|
|
||||||
|
// textField.onEditingFinished: {
|
||||||
|
// if (textField.text !== serverCookieReplyPacketJunkSize) {
|
||||||
|
// serverCookieReplyPacketJunkSize = textField.text
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// AwgTextField {
|
||||||
|
// id: transportPacketJunkSizeTextField
|
||||||
|
// headerText: qsTr("S4 - Transport packet junk size")
|
||||||
|
// textField.text: serverTransportPacketJunkSize
|
||||||
|
|
||||||
|
// textField.onEditingFinished: {
|
||||||
|
// if (textField.text !== serverTransportPacketJunkSize) {
|
||||||
|
// serverTransportPacketJunkSize = textField.text
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: initPacketMagicHeaderTextField
|
||||||
|
headerText: qsTr("H1 - Init packet magic header")
|
||||||
|
textField.text: serverInitPacketMagicHeader
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverInitPacketMagicHeader) {
|
||||||
|
serverInitPacketMagicHeader = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: responsePacketMagicHeaderTextField
|
||||||
|
headerText: qsTr("H2 - Response packet magic header")
|
||||||
|
textField.text: serverResponsePacketMagicHeader
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverResponsePacketMagicHeader) {
|
||||||
|
serverResponsePacketMagicHeader = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: underloadPacketMagicHeaderTextField
|
||||||
|
headerText: qsTr("H3 - Underload packet magic header")
|
||||||
|
textField.text: serverUnderloadPacketMagicHeader
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverUnderloadPacketMagicHeader) {
|
||||||
|
serverUnderloadPacketMagicHeader = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AwgTextField {
|
||||||
|
id: transportPacketMagicHeaderTextField
|
||||||
|
headerText: qsTr("H4 - Transport packet magic header")
|
||||||
|
textField.text: serverTransportPacketMagicHeader
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverTransportPacketMagicHeader) {
|
||||||
|
serverTransportPacketMagicHeader = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveRestartButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
|
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
transportPacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
responsePacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
initPacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
responsePacketJunkSizeTextField.errorText === "" &&
|
||||||
|
// cookieReplyHeaderJunkTextField.errorText === "" &&
|
||||||
|
// transportHeaderJunkTextField.errorText === "" &&
|
||||||
|
initPacketJunkSizeTextField.errorText === "" &&
|
||||||
|
junkPacketMaxSizeTextField.errorText === "" &&
|
||||||
|
junkPacketMinSizeTextField.errorText === "" &&
|
||||||
|
junkPacketCountTextField.errorText === "" &&
|
||||||
|
portTextField.errorText === "" &&
|
||||||
|
vpnAddressSubnetTextField.errorText === ""
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
onActiveFocusChanged: {
|
||||||
|
if(activeFocus) {
|
||||||
|
listview.positionViewAtEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
forceActiveFocus()
|
||||||
|
|
||||||
|
if (delegateItem.isEnabled) {
|
||||||
|
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
|
||||||
|
transportPacketMagicHeaderTextField.textField.text,
|
||||||
|
responsePacketMagicHeaderTextField.textField.text,
|
||||||
|
initPacketMagicHeaderTextField.textField.text)) {
|
||||||
|
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
||||||
|
parseInt(responsePacketJunkSizeTextField.textField.text))) {
|
||||||
|
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
||||||
|
// parseInt(responsePacketJunkSizeTextField.textField.text),
|
||||||
|
// parseInt(cookieReplyPacketJunkSizeTextField.textField.text),
|
||||||
|
// parseInt(transportPacketJunkSizeTextField.textField.text))) {
|
||||||
|
// PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) + S3 + cookie reply size (64) + S4 + transport packet size (32)"))
|
||||||
|
// return
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
var headerText = qsTr("Save settings?")
|
||||||
parseInt(responsePacketJunkSizeTextField.textField.text))) {
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
|
var yesButtonText = qsTr("Continue")
|
||||||
return
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(AwgConfigModel.getConfig())
|
||||||
}
|
}
|
||||||
// if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
var noButtonFunction = function() {
|
||||||
// parseInt(responsePacketJunkSizeTextField.textField.text),
|
if (!GC.isMobile()) {
|
||||||
// parseInt(cookieReplyPacketJunkSizeTextField.textField.text),
|
saveRestartButton.forceActiveFocus()
|
||||||
// parseInt(transportPacketJunkSizeTextField.textField.text))) {
|
}
|
||||||
// PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) + S3 + cookie reply size (64) + S4 + transport packet size (32)"))
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(AwgConfigModel.getConfig())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var noButtonFunction = function() {}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,191 +16,211 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
BackButtonType {
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
contentHeight: content.implicitHeight
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
property int selectedIndex: 0
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
header: ColumnLayout {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
BaseHeaderType {
|
ListView {
|
||||||
Layout.fillWidth: true
|
id: listview
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Cloak settings")
|
property int selectedIndex: 0
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model: CloakConfigModel
|
width: parent.width
|
||||||
|
height: listview.contentItem.height
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
clip: true
|
||||||
width: listView.width
|
reuseItems: true
|
||||||
|
|
||||||
property alias trafficFromField: trafficFromField
|
model: CloakConfigModel
|
||||||
|
|
||||||
spacing: 0
|
delegate: Item {
|
||||||
|
id: delegateItem
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
property alias trafficFromField: trafficFromField
|
||||||
id: trafficFromField
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
implicitWidth: listview.width
|
||||||
Layout.topMargin: 32
|
implicitHeight: col.implicitHeight
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Disguised as traffic from")
|
ColumnLayout {
|
||||||
textField.text: site
|
id: col
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
anchors.top: parent.top
|
||||||
if (textField.text !== site) {
|
anchors.left: parent.left
|
||||||
var tmpText = textField.text
|
anchors.right: parent.right
|
||||||
tmpText = tmpText.toLocaleLowerCase()
|
|
||||||
|
|
||||||
var indexHttps = tmpText.indexOf("https://")
|
anchors.leftMargin: 16
|
||||||
if (indexHttps === 0) {
|
anchors.rightMargin: 16
|
||||||
tmpText = textField.text.substring(8)
|
|
||||||
} else {
|
spacing: 0
|
||||||
site = textField.text
|
|
||||||
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
headerText: qsTr("Cloak settings")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
TextFieldWithHeaderType {
|
||||||
}
|
id: trafficFromField
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
Layout.fillWidth: true
|
||||||
id: portTextField
|
Layout.topMargin: 32
|
||||||
|
|
||||||
Layout.fillWidth: true
|
enabled: delegateItem.isEnabled
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
headerText: qsTr("Disguised as traffic from")
|
||||||
textField.text: port
|
textField.text: site
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
textField.onEditingFinished: {
|
||||||
if (textField.text !== port) {
|
if (textField.text !== site) {
|
||||||
port = textField.text
|
var tmpText = textField.text
|
||||||
}
|
tmpText = tmpText.toLocaleLowerCase()
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
var indexHttps = tmpText.indexOf("https://")
|
||||||
}
|
if (indexHttps === 0) {
|
||||||
|
tmpText = textField.text.substring(8)
|
||||||
|
} else {
|
||||||
|
site = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DropDownType {
|
checkEmptyText: true
|
||||||
id: cipherDropDown
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
TextFieldWithHeaderType {
|
||||||
Layout.topMargin: 16
|
id: portTextField
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
descriptionText: qsTr("Cipher")
|
Layout.fillWidth: true
|
||||||
headerText: qsTr("Cipher")
|
Layout.topMargin: 16
|
||||||
|
|
||||||
drawerParent: root
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
headerText: qsTr("Port")
|
||||||
id: cipherListView
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
rootWidth: root.width
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
model: ListModel {
|
checkEmptyText: true
|
||||||
ListElement { name : "chacha20-ietf-poly1305" }
|
}
|
||||||
ListElement { name : "xchacha20-ietf-poly1305" }
|
|
||||||
ListElement { name : "aes-256-gcm" }
|
|
||||||
ListElement { name : "aes-192-gcm" }
|
|
||||||
ListElement { name : "aes-128-gcm" }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
DropDownType {
|
||||||
cipherDropDown.text = selectedText
|
id: cipherDropDown
|
||||||
cipher = cipherDropDown.text
|
Layout.fillWidth: true
|
||||||
cipherDropDown.closeTriggered()
|
Layout.topMargin: 16
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
enabled: delegateItem.isEnabled
|
||||||
cipherDropDown.text = cipher
|
|
||||||
|
|
||||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
descriptionText: qsTr("Cipher")
|
||||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
headerText: qsTr("Cipher")
|
||||||
selectedIndex = i
|
|
||||||
|
drawerParent: root
|
||||||
|
|
||||||
|
listView: ListViewWithRadioButtonType {
|
||||||
|
id: cipherListView
|
||||||
|
|
||||||
|
rootWidth: root.width
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { name : "chacha20-ietf-poly1305" }
|
||||||
|
ListElement { name : "xchacha20-ietf-poly1305" }
|
||||||
|
ListElement { name : "aes-256-gcm" }
|
||||||
|
ListElement { name : "aes-192-gcm" }
|
||||||
|
ListElement { name : "aes-128-gcm" }
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
cipherDropDown.text = selectedText
|
||||||
|
cipher = cipherDropDown.text
|
||||||
|
cipherDropDown.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
cipherDropDown.text = cipher
|
||||||
|
|
||||||
|
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||||
|
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||||
|
selectedIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: saveButton
|
id: saveButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.bottomMargin: 24
|
Layout.bottomMargin: 24
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: trafficFromField.errorText === "" &&
|
enabled: trafficFromField.errorText === "" &&
|
||||||
portTextField.errorText === ""
|
portTextField.errorText === ""
|
||||||
|
|
||||||
text: qsTr("Save")
|
text: qsTr("Save")
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
forceActiveFocus()
|
forceActiveFocus()
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
var headerText = qsTr("Save settings?")
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
var yesButtonText = qsTr("Continue")
|
var yesButtonText = qsTr("Continue")
|
||||||
var noButtonText = qsTr("Cancel")
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||||
InstallController.updateContainer(CloakConfigModel.getConfig())
|
InstallController.updateContainer(CloakConfigModel.getConfig())
|
||||||
}
|
}
|
||||||
|
|
||||||
var noButtonFunction = function() {
|
var noButtonFunction = function() {
|
||||||
if (!GC.isMobile()) {
|
if (!GC.isMobile()) {
|
||||||
saveButton.forceActiveFocus()
|
saveButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: saveButton.clicked()
|
||||||
|
Keys.onReturnPressed: saveButton.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,413 +17,427 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
BackButtonType {
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
header: ColumnLayout {
|
anchors.top: parent.top
|
||||||
width: listView.width
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
BaseHeaderType {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: header
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
ListView {
|
||||||
Layout.rightMargin: 16
|
id: listview
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("OpenVPN Settings")
|
width: parent.width
|
||||||
}
|
height: listview.contentItem.height
|
||||||
}
|
|
||||||
|
|
||||||
model: OpenVpnConfigModel
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
model: OpenVpnConfigModel
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
spacing: 0
|
delegate: Item {
|
||||||
|
id: delegateItem
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
||||||
id: vpnAddressSubnetTextField
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
implicitWidth: listview.width
|
||||||
Layout.topMargin: 32
|
implicitHeight: col.implicitHeight
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: listView.enabled
|
ColumnLayout {
|
||||||
|
id: col
|
||||||
|
|
||||||
headerText: qsTr("VPN address subnet")
|
anchors.top: parent.top
|
||||||
textField.text: subnetAddress
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
anchors.leftMargin: 16
|
||||||
if (textField.text !== subnetAddress) {
|
anchors.rightMargin: 16
|
||||||
subnetAddress = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
spacing: 0
|
||||||
}
|
|
||||||
|
|
||||||
ParagraphTextType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
headerText: qsTr("OpenVPN settings")
|
||||||
Layout.leftMargin: 16
|
}
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Network protocol")
|
TextFieldWithHeaderType {
|
||||||
}
|
id: vpnAddressSubnetTextField
|
||||||
|
|
||||||
TransportProtoSelector {
|
Layout.fillWidth: true
|
||||||
id: transportProtoSelector
|
Layout.topMargin: 32
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
rootWidth: root.width
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
enabled: isTransportProtoEditable
|
headerText: qsTr("VPN address subnet")
|
||||||
|
textField.text: subnetAddress
|
||||||
|
|
||||||
currentIndex: {
|
parentFlickable: fl
|
||||||
return transportProto === "tcp" ? 1 : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
textField.onEditingFinished: {
|
||||||
if (transportProto === "tcp" && currentIndex === 0) {
|
if (textField.text !== subnetAddress) {
|
||||||
transportProto = "udp"
|
subnetAddress = textField.text
|
||||||
} else if (transportProto === "udp" && currentIndex === 1) {
|
}
|
||||||
transportProto = "tcp"
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
checkEmptyText: true
|
||||||
id: portTextField
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
ParagraphTextType {
|
||||||
Layout.topMargin: 40
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
Layout.topMargin: 32
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: listView.enabled
|
text: qsTr("Network protocol")
|
||||||
|
}
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
TransportProtoSelector {
|
||||||
textField.text: port
|
id: transportProtoSelector
|
||||||
textField.maximumLength: 5
|
Layout.fillWidth: true
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
Layout.topMargin: 16
|
||||||
|
rootWidth: root.width
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
enabled: isTransportProtoEditable
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
currentIndex: {
|
||||||
}
|
return transportProto === "tcp" ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
SwitcherType {
|
onCurrentIndexChanged: {
|
||||||
id: autoNegotiateEncryprionSwitcher
|
if (transportProto === "tcp" && currentIndex === 0) {
|
||||||
|
transportProto = "udp"
|
||||||
Layout.fillWidth: true
|
} else if (transportProto === "udp" && currentIndex === 1) {
|
||||||
Layout.topMargin: 24
|
transportProto = "tcp"
|
||||||
Layout.leftMargin: 16
|
}
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Auto-negotiate encryption")
|
|
||||||
checked: autoNegotiateEncryprion
|
|
||||||
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked !== autoNegotiateEncryprion) {
|
|
||||||
autoNegotiateEncryprion = checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DropDownType {
|
|
||||||
id: hashDropDown
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 20
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
|
||||||
|
|
||||||
descriptionText: qsTr("Hash")
|
|
||||||
headerText: qsTr("Hash")
|
|
||||||
|
|
||||||
drawerParent: root
|
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
|
||||||
id: hashListView
|
|
||||||
|
|
||||||
rootWidth: root.width
|
|
||||||
|
|
||||||
model: ListModel {
|
|
||||||
ListElement { name : qsTr("SHA512") }
|
|
||||||
ListElement { name : qsTr("SHA384") }
|
|
||||||
ListElement { name : qsTr("SHA256") }
|
|
||||||
ListElement { name : qsTr("SHA3-512") }
|
|
||||||
ListElement { name : qsTr("SHA3-384") }
|
|
||||||
ListElement { name : qsTr("SHA3-256") }
|
|
||||||
ListElement { name : qsTr("whirlpool") }
|
|
||||||
ListElement { name : qsTr("BLAKE2b512") }
|
|
||||||
ListElement { name : qsTr("BLAKE2s256") }
|
|
||||||
ListElement { name : qsTr("SHA1") }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
hashDropDown.text = selectedText
|
|
||||||
hash = hashDropDown.text
|
|
||||||
hashDropDown.closeTriggered()
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
hashDropDown.text = hash
|
|
||||||
|
|
||||||
for (var i = 0; i < hashListView.model.count; i++) {
|
|
||||||
if (hashListView.model.get(i).name === hashDropDown.text) {
|
|
||||||
currentIndex = i
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DropDownType {
|
TextFieldWithHeaderType {
|
||||||
id: cipherDropDown
|
id: portTextField
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 40
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
descriptionText: qsTr("Cipher")
|
enabled: delegateItem.isEnabled
|
||||||
headerText: qsTr("Cipher")
|
|
||||||
|
|
||||||
drawerParent: root
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
textField.onEditingFinished: {
|
||||||
id: cipherListView
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rootWidth: root.width
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
model: ListModel {
|
SwitcherType {
|
||||||
ListElement { name : qsTr("AES-256-GCM") }
|
id: autoNegotiateEncryprionSwitcher
|
||||||
ListElement { name : qsTr("AES-192-GCM") }
|
|
||||||
ListElement { name : qsTr("AES-128-GCM") }
|
|
||||||
ListElement { name : qsTr("AES-256-CBC") }
|
|
||||||
ListElement { name : qsTr("AES-192-CBC") }
|
|
||||||
ListElement { name : qsTr("AES-128-CBC") }
|
|
||||||
ListElement { name : qsTr("ChaCha20-Poly1305") }
|
|
||||||
ListElement { name : qsTr("ARIA-256-CBC") }
|
|
||||||
ListElement { name : qsTr("CAMELLIA-256-CBC") }
|
|
||||||
ListElement { name : qsTr("none") }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
Layout.fillWidth: true
|
||||||
cipherDropDown.text = selectedText
|
Layout.topMargin: 24
|
||||||
cipher = cipherDropDown.text
|
parentFlickable: fl
|
||||||
cipherDropDown.closeTriggered()
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
text: qsTr("Auto-negotiate encryption")
|
||||||
cipherDropDown.text = cipher
|
checked: autoNegotiateEncryprion
|
||||||
|
|
||||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
onCheckedChanged: {
|
||||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
if (checked !== autoNegotiateEncryprion) {
|
||||||
currentIndex = i
|
autoNegotiateEncryprion = checked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
DropDownType {
|
||||||
id: contentRect
|
id: hashDropDown
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 20
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
Layout.preferredHeight: checkboxLayout.implicitHeight
|
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||||
color: AmneziaStyle.color.onyxBlack
|
|
||||||
radius: 16
|
|
||||||
|
|
||||||
ColumnLayout {
|
descriptionText: qsTr("Hash")
|
||||||
id: checkboxLayout
|
headerText: qsTr("Hash")
|
||||||
|
|
||||||
anchors.fill: parent
|
drawerParent: root
|
||||||
|
|
||||||
CheckBoxType {
|
listView: ListViewWithRadioButtonType {
|
||||||
id: tlsAuthCheckBox
|
id: hashListView
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("TLS auth")
|
rootWidth: root.width
|
||||||
checked: tlsAuth
|
|
||||||
|
|
||||||
onCheckedChanged: {
|
model: ListModel {
|
||||||
if (checked !== tlsAuth) {
|
ListElement { name : qsTr("SHA512") }
|
||||||
console.log("tlsAuth changed to: " + checked)
|
ListElement { name : qsTr("SHA384") }
|
||||||
tlsAuth = checked
|
ListElement { name : qsTr("SHA256") }
|
||||||
|
ListElement { name : qsTr("SHA3-512") }
|
||||||
|
ListElement { name : qsTr("SHA3-384") }
|
||||||
|
ListElement { name : qsTr("SHA3-256") }
|
||||||
|
ListElement { name : qsTr("whirlpool") }
|
||||||
|
ListElement { name : qsTr("BLAKE2b512") }
|
||||||
|
ListElement { name : qsTr("BLAKE2s256") }
|
||||||
|
ListElement { name : qsTr("SHA1") }
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
hashDropDown.text = selectedText
|
||||||
|
hash = hashDropDown.text
|
||||||
|
hashDropDown.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
hashDropDown.text = hash
|
||||||
|
|
||||||
|
for (var i = 0; i < hashListView.model.count; i++) {
|
||||||
|
if (hashListView.model.get(i).name === hashDropDown.text) {
|
||||||
|
currentIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {}
|
DropDownType {
|
||||||
|
id: cipherDropDown
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
CheckBoxType {
|
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||||
id: blockDnsCheckBox
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Block DNS requests outside of VPN")
|
descriptionText: qsTr("Cipher")
|
||||||
checked: blockDns
|
headerText: qsTr("Cipher")
|
||||||
|
|
||||||
onCheckedChanged: {
|
drawerParent: root
|
||||||
if (checked !== blockDns) {
|
|
||||||
blockDns = checked
|
listView: ListViewWithRadioButtonType {
|
||||||
|
id: cipherListView
|
||||||
|
|
||||||
|
rootWidth: root.width
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { name : qsTr("AES-256-GCM") }
|
||||||
|
ListElement { name : qsTr("AES-192-GCM") }
|
||||||
|
ListElement { name : qsTr("AES-128-GCM") }
|
||||||
|
ListElement { name : qsTr("AES-256-CBC") }
|
||||||
|
ListElement { name : qsTr("AES-192-CBC") }
|
||||||
|
ListElement { name : qsTr("AES-128-CBC") }
|
||||||
|
ListElement { name : qsTr("ChaCha20-Poly1305") }
|
||||||
|
ListElement { name : qsTr("ARIA-256-CBC") }
|
||||||
|
ListElement { name : qsTr("CAMELLIA-256-CBC") }
|
||||||
|
ListElement { name : qsTr("none") }
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
cipherDropDown.text = selectedText
|
||||||
|
cipher = cipherDropDown.text
|
||||||
|
cipherDropDown.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
cipherDropDown.text = cipher
|
||||||
|
|
||||||
|
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||||
|
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||||
|
currentIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SwitcherType {
|
Rectangle {
|
||||||
id: additionalClientCommandsSwitcher
|
id: contentRect
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 32
|
||||||
Layout.leftMargin: 16
|
Layout.preferredHeight: checkboxLayout.implicitHeight
|
||||||
Layout.rightMargin: 16
|
color: AmneziaStyle.color.onyxBlack
|
||||||
|
radius: 16
|
||||||
|
|
||||||
checked: additionalClientCommands !== ""
|
Connections {
|
||||||
|
target: tlsAuthCheckBox
|
||||||
|
enabled: !GC.isMobile()
|
||||||
|
|
||||||
text: qsTr("Additional client configuration commands")
|
function onFocusChanged() {
|
||||||
|
if (tlsAuthCheckBox.activeFocus) {
|
||||||
|
fl.ensureVisible(contentRect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onCheckedChanged: {
|
ColumnLayout {
|
||||||
if (!checked) {
|
id: checkboxLayout
|
||||||
additionalClientCommands = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextAreaType {
|
anchors.fill: parent
|
||||||
id: additionalClientCommandsTextArea
|
CheckBoxType {
|
||||||
Layout.fillWidth: true
|
id: tlsAuthCheckBox
|
||||||
Layout.topMargin: 16
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
visible: additionalClientCommandsSwitcher.checked
|
text: qsTr("TLS auth")
|
||||||
|
checked: tlsAuth
|
||||||
|
|
||||||
textAreaText: additionalClientCommands
|
onCheckedChanged: {
|
||||||
placeholderText: qsTr("Commands:")
|
if (checked !== tlsAuth) {
|
||||||
|
console.log("tlsAuth changed to: " + checked)
|
||||||
|
tlsAuth = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
textArea.onEditingFinished: {
|
DividerType {}
|
||||||
if (additionalClientCommands !== textAreaText) {
|
|
||||||
additionalClientCommands = textAreaText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SwitcherType {
|
CheckBoxType {
|
||||||
id: additionalServerCommandsSwitcher
|
id: blockDnsCheckBox
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
checked: additionalServerCommands !== ""
|
text: qsTr("Block DNS requests outside of VPN")
|
||||||
|
checked: blockDns
|
||||||
|
|
||||||
text: qsTr("Additional server configuration commands")
|
onCheckedChanged: {
|
||||||
|
if (checked !== blockDns) {
|
||||||
onCheckedChanged: {
|
blockDns = checked
|
||||||
if (!checked) {
|
}
|
||||||
additionalServerCommands = ""
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TextAreaType {
|
|
||||||
id: additionalServerCommandsTextArea
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
visible: additionalServerCommandsSwitcher.checked
|
|
||||||
|
|
||||||
textAreaText: additionalServerCommands
|
|
||||||
placeholderText: qsTr("Commands:")
|
|
||||||
|
|
||||||
textArea.onEditingFinished: {
|
|
||||||
if (additionalServerCommands !== textAreaText) {
|
|
||||||
additionalServerCommands = textAreaText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: vpnAddressSubnetTextField.errorText === "" &&
|
|
||||||
portTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
onClicked: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
SwitcherType {
|
||||||
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
|
id: additionalClientCommandsSwitcher
|
||||||
}
|
Layout.fillWidth: true
|
||||||
var noButtonFunction = function() {
|
Layout.topMargin: 32
|
||||||
if (!GC.isMobile()) {
|
parentFlickable: fl
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
|
checked: additionalClientCommands !== ""
|
||||||
|
|
||||||
|
text: qsTr("Additional client configuration commands")
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (!checked) {
|
||||||
|
additionalClientCommands = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAreaType {
|
||||||
|
id: additionalClientCommandsTextArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
visible: additionalClientCommandsSwitcher.checked
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
textAreaText: additionalClientCommands
|
||||||
|
placeholderText: qsTr("Commands:")
|
||||||
|
|
||||||
|
textArea.onEditingFinished: {
|
||||||
|
if (additionalClientCommands !== textAreaText) {
|
||||||
|
additionalClientCommands = textAreaText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitcherType {
|
||||||
|
id: additionalServerCommandsSwitcher
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
checked: additionalServerCommands !== ""
|
||||||
|
|
||||||
|
text: qsTr("Additional server configuration commands")
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (!checked) {
|
||||||
|
additionalServerCommands = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAreaType {
|
||||||
|
id: additionalServerCommandsTextArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
visible: additionalServerCommandsSwitcher.checked
|
||||||
|
|
||||||
|
textAreaText: additionalServerCommands
|
||||||
|
placeholderText: qsTr("Commands:")
|
||||||
|
parentFlickable: fl
|
||||||
|
textArea.onEditingFinished: {
|
||||||
|
if (additionalServerCommands !== textAreaText) {
|
||||||
|
additionalServerCommands = textAreaText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
|
enabled: vpnAddressSubnetTextField.errorText === "" &&
|
||||||
|
portTextField.errorText === ""
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
onClicked: function() {
|
||||||
|
forceActiveFocus()
|
||||||
|
|
||||||
|
var headerText = qsTr("Save settings?")
|
||||||
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
saveButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: saveButton.clicked()
|
||||||
|
Keys.onReturnPressed: saveButton.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,154 +19,164 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: header
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
}
|
||||||
}
|
|
||||||
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: header.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
header: ColumnLayout {
|
Column {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
BaseHeaderType {
|
anchors.top: parent.top
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.leftMargin: 16
|
anchors.right: parent.right
|
||||||
Layout.rightMargin: 16
|
anchors.topMargin: 32
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
ListView {
|
||||||
}
|
id: listView
|
||||||
}
|
width: parent.width
|
||||||
|
height: contentItem.height
|
||||||
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
model: ProtocolsModel
|
||||||
|
|
||||||
model: ProtocolsModel
|
activeFocusOnTab: true
|
||||||
|
focus: true
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: Item {
|
||||||
width: listView.width
|
implicitWidth: parent.width
|
||||||
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
LabelWithButtonType {
|
property alias focusItem: button
|
||||||
id: button
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
ColumnLayout {
|
||||||
Layout.leftMargin: 16
|
id: delegateContent
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Show connection options")
|
anchors.fill: parent
|
||||||
|
|
||||||
clickedFunction: function() {
|
LabelWithButtonType {
|
||||||
configContentDrawer.openTriggered()
|
id: button
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
Layout.fillWidth: true
|
||||||
anchors.fill: button
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {}
|
text: qsTr("Show connection options")
|
||||||
|
|
||||||
DrawerType2 {
|
clickedFunction: function() {
|
||||||
id: configContentDrawer
|
configContentDrawer.openTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
expandedHeight: root.height * 0.9
|
MouseArea {
|
||||||
|
anchors.fill: button
|
||||||
parent: root
|
cursorShape: Qt.PointingHandCursor
|
||||||
anchors.fill: parent
|
enabled: false
|
||||||
|
|
||||||
expandedStateContent: Item {
|
|
||||||
implicitHeight: configContentDrawer.expandedHeight
|
|
||||||
|
|
||||||
BackButtonType {
|
|
||||||
id: drawerBackButton
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.topMargin: 16
|
|
||||||
|
|
||||||
backButtonFunction: function() {
|
|
||||||
configContentDrawer.closeTriggered()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ListViewType {
|
|
||||||
id: drawerListView
|
|
||||||
|
|
||||||
anchors.top: drawerBackButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
|
||||||
width: drawerListView.width
|
|
||||||
|
|
||||||
Header2Type {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Connection options %1").arg(protocolName)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model: 1 // fake model to force the ListView to be created without a model
|
DividerType {}
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
DrawerType2 {
|
||||||
width: drawerListView.width
|
id: configContentDrawer
|
||||||
|
|
||||||
TextArea {
|
expandedHeight: root.height * 0.9
|
||||||
id: configText
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
parent: root
|
||||||
Layout.topMargin: 16
|
anchors.fill: parent
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
padding: 0
|
expandedStateContent: Item {
|
||||||
height: 24
|
implicitHeight: configContentDrawer.expandedHeight
|
||||||
|
|
||||||
color: AmneziaStyle.color.paleGray
|
BackButtonType {
|
||||||
selectionColor: AmneziaStyle.color.richBrown
|
id: backButton1
|
||||||
selectedTextColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
font.pixelSize: 16
|
anchors.top: parent.top
|
||||||
font.weight: Font.Medium
|
anchors.left: parent.left
|
||||||
font.family: "PT Root UI VF"
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 16
|
||||||
|
|
||||||
text: rawConfig
|
backButtonFunction: function() {
|
||||||
|
configContentDrawer.closeTriggered()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wrapMode: Text.Wrap
|
FlickableType {
|
||||||
|
anchors.top: backButton1.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
|
||||||
|
|
||||||
background: Rectangle {
|
ColumnLayout {
|
||||||
color: AmneziaStyle.color.transparent
|
id: configContent
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
|
Header2Type {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("Connection options %1").arg(protocolName)
|
||||||
|
}
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: configText
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
|
padding: 0
|
||||||
|
leftPadding: 0
|
||||||
|
height: 24
|
||||||
|
|
||||||
|
color: AmneziaStyle.color.paleGray
|
||||||
|
selectionColor: AmneziaStyle.color.richBrown
|
||||||
|
selectedTextColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
font.pixelSize: 16
|
||||||
|
font.weight: Font.Medium
|
||||||
|
font.family: "PT Root UI VF"
|
||||||
|
|
||||||
|
text: rawConfig
|
||||||
|
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: AmneziaStyle.color.transparent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: removeButton
|
id: removeButton
|
||||||
@@ -188,7 +198,11 @@ PageType {
|
|||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
InstallController.removeProcessedContainer()
|
InstallController.removeProcessedContainer()
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {}
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
focusItem.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,157 +16,178 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
model: ShadowSocksConfigModel
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
spacing: 0
|
ListView {
|
||||||
|
id: listview
|
||||||
|
|
||||||
BaseHeaderType {
|
width: parent.width
|
||||||
Layout.fillWidth: true
|
height: listview.contentItem.height
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Shadowsocks settings")
|
clip: true
|
||||||
}
|
interactive: false
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
model: ShadowSocksConfigModel
|
||||||
id: portTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
delegate: Item {
|
||||||
Layout.topMargin: 40
|
id: delegateItem
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: listView.enabled
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
implicitWidth: listview.width
|
||||||
textField.text: port
|
implicitHeight: col.implicitHeight
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
ColumnLayout {
|
||||||
if (textField.text !== port) {
|
id: col
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
anchors.top: parent.top
|
||||||
}
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
DropDownType {
|
anchors.leftMargin: 16
|
||||||
id: cipherDropDown
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
Layout.fillWidth: true
|
spacing: 0
|
||||||
Layout.topMargin: 20
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: listView.enabled
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
headerText: qsTr("Shadowsocks settings")
|
||||||
|
}
|
||||||
|
|
||||||
descriptionText: qsTr("Cipher")
|
TextFieldWithHeaderType {
|
||||||
headerText: qsTr("Cipher")
|
id: portTextField
|
||||||
|
|
||||||
drawerParent: root
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 40
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
id: cipherListView
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
rootWidth: root.width
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
model: ListModel {
|
checkEmptyText: true
|
||||||
ListElement { name : "chacha20-ietf-poly1305" }
|
}
|
||||||
ListElement { name : "xchacha20-ietf-poly1305" }
|
|
||||||
ListElement { name : "aes-256-gcm" }
|
|
||||||
ListElement { name : "aes-192-gcm" }
|
|
||||||
ListElement { name : "aes-128-gcm" }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
DropDownType {
|
||||||
cipherDropDown.text = selectedText
|
id: cipherDropDown
|
||||||
cipher = cipherDropDown.text
|
Layout.fillWidth: true
|
||||||
cipherDropDown.closeTriggered()
|
Layout.topMargin: 20
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
enabled: delegateItem.isEnabled
|
||||||
cipherDropDown.text = cipher
|
|
||||||
|
|
||||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
descriptionText: qsTr("Cipher")
|
||||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
headerText: qsTr("Cipher")
|
||||||
currentIndex = i
|
|
||||||
|
drawerParent: root
|
||||||
|
|
||||||
|
listView: ListViewWithRadioButtonType {
|
||||||
|
|
||||||
|
id: cipherListView
|
||||||
|
|
||||||
|
rootWidth: root.width
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { name : "chacha20-ietf-poly1305" }
|
||||||
|
ListElement { name : "xchacha20-ietf-poly1305" }
|
||||||
|
ListElement { name : "aes-256-gcm" }
|
||||||
|
ListElement { name : "aes-192-gcm" }
|
||||||
|
ListElement { name : "aes-128-gcm" }
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
cipherDropDown.text = selectedText
|
||||||
|
cipher = cipherDropDown.text
|
||||||
|
cipherDropDown.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
cipherDropDown.text = cipher
|
||||||
|
|
||||||
|
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||||
|
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||||
|
currentIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: saveButton
|
id: saveButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.bottomMargin: 24
|
Layout.bottomMargin: 24
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: portTextField.errorText === ""
|
enabled: portTextField.errorText === ""
|
||||||
|
|
||||||
text: qsTr("Save")
|
text: qsTr("Save")
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
forceActiveFocus()
|
forceActiveFocus()
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
var headerText = qsTr("Save settings?")
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
var yesButtonText = qsTr("Continue")
|
var yesButtonText = qsTr("Continue")
|
||||||
var noButtonText = qsTr("Cancel")
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
|
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
var noButtonFunction = function() {
|
||||||
if (!GC.isMobile()) {
|
if (!GC.isMobile()) {
|
||||||
saveButton.forceActiveFocus()
|
saveButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: saveButton.clicked()
|
||||||
|
Keys.onReturnPressed: saveButton.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,124 +16,160 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
Item {
|
||||||
id: backButton
|
id: focusItem
|
||||||
|
onFocusChanged: {
|
||||||
|
if (activeFocus) {
|
||||||
|
fl.ensureVisible(focusItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyNavigation.tab: backButton
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
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
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listview
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: listview.contentItem.height
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
model: WireGuardConfigModel
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: delegateItem
|
||||||
|
implicitWidth: listview.width
|
||||||
|
implicitHeight: col.implicitHeight
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
headerText: qsTr("WG settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: mtuTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 40
|
||||||
|
|
||||||
|
headerText: qsTr("MTU")
|
||||||
|
textField.text: clientMtu
|
||||||
|
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== clientMtu) {
|
||||||
|
clientMtu = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkEmptyText: true
|
||||||
|
KeyNavigation.tab: saveButton
|
||||||
|
}
|
||||||
|
|
||||||
|
Header2TextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Server settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
BasicButtonType {
|
||||||
id: listView
|
id: saveButton
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.right: root.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.left: root.left
|
||||||
anchors.right: parent.right
|
anchors.bottom: root.bottom
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
model: WireGuardConfigModel
|
anchors.topMargin: 24
|
||||||
|
anchors.bottomMargin: 24
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
enabled: listview.currentItem.isSaveButtonEnabled
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
property alias mtuTextField: mtuTextField
|
text: qsTr("Save")
|
||||||
property bool isSaveButtonEnabled: mtuTextField.errorText === ""
|
|
||||||
|
|
||||||
spacing: 0
|
clickedFunc: function() {
|
||||||
|
forceActiveFocus()
|
||||||
|
var headerText = qsTr("Save settings?")
|
||||||
|
var descriptionText = qsTr("Only the settings for this device will be changed")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
BaseHeaderType {
|
var yesButtonFunction = function() {
|
||||||
Layout.fillWidth: true
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
Layout.leftMargin: 16
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
Layout.rightMargin: 16
|
return
|
||||||
|
|
||||||
headerText: qsTr("WG settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: mtuTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 40
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("MTU")
|
|
||||||
textField.text: clientMtu
|
|
||||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientMtu) {
|
|
||||||
clientMtu = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checkEmptyText: true
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
||||||
}
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
Header2TextType {
|
if (!GC.isMobile()) {
|
||||||
Layout.fillWidth: true
|
saveButton.forceActiveFocus()
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Server settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 8
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
enabled: listView.currentItem.isSaveButtonEnabled
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("Only the settings for this device will be changed")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,130 +16,153 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
model: WireGuardConfigModel
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
ListView {
|
||||||
|
id: listview
|
||||||
|
|
||||||
spacing: 0
|
width: parent.width
|
||||||
|
height: listview.contentItem.height
|
||||||
|
|
||||||
BaseHeaderType {
|
clip: true
|
||||||
Layout.fillWidth: true
|
interactive: false
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("WG settings")
|
model: WireGuardConfigModel
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
delegate: Item {
|
||||||
id: vpnAddressSubnetTextField
|
id: delegateItem
|
||||||
|
|
||||||
Layout.fillWidth: true
|
property alias focusItemId: vpnAddressSubnetTextField
|
||||||
Layout.topMargin: 40
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("VPN address subnet")
|
implicitWidth: listview.width
|
||||||
textField.text: subnetAddress
|
implicitHeight: col.implicitHeight
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
ColumnLayout {
|
||||||
if (textField.text !== subnetAddress) {
|
id: col
|
||||||
subnetAddress = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
anchors.top: parent.top
|
||||||
}
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
anchors.leftMargin: 16
|
||||||
id: portTextField
|
anchors.rightMargin: 16
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
spacing: 0
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
BaseHeaderType {
|
||||||
if (textField.text !== port) {
|
Layout.fillWidth: true
|
||||||
port = textField.text
|
headerText: qsTr("WG settings")
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: portTextField.errorText === "" &&
|
|
||||||
vpnAddressSubnetTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
onClicked: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
TextFieldWithHeaderType {
|
||||||
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
id: vpnAddressSubnetTextField
|
||||||
}
|
Layout.fillWidth: true
|
||||||
var noButtonFunction = function() {
|
Layout.topMargin: 40
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveButton.forceActiveFocus()
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("VPN address subnet")
|
||||||
|
textField.text: subnetAddress
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== subnetAddress) {
|
||||||
|
subnetAddress = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
|
enabled: portTextField.errorText === "" &&
|
||||||
|
vpnAddressSubnetTextField.errorText === ""
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
onClicked: function() {
|
||||||
|
forceActiveFocus()
|
||||||
|
|
||||||
|
var headerText = qsTr("Save settings?")
|
||||||
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
saveButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: saveButton.clicked()
|
||||||
|
Keys.onReturnPressed: saveButton.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,141 +17,163 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
contentHeight: content.implicitHeight
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
Column {
|
||||||
model: XrayConfigModel
|
id: content
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
anchors.top: parent.top
|
||||||
width: listView.width
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
property alias focusItemId: textFieldWithHeaderType.textField
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
spacing: 0
|
ListView {
|
||||||
|
id: listview
|
||||||
|
|
||||||
BaseHeaderType {
|
width: parent.width
|
||||||
Layout.fillWidth: true
|
height: listview.contentItem.height
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
headerText: qsTr("XRay settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
clip: true
|
||||||
id: textFieldWithHeaderType
|
interactive: false
|
||||||
|
|
||||||
Layout.fillWidth: true
|
model: XrayConfigModel
|
||||||
Layout.topMargin: 32
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: listView.enabled
|
delegate: Item {
|
||||||
|
id: delegateItem
|
||||||
|
|
||||||
headerText: qsTr("Disguised as traffic from")
|
property alias focusItemId: textFieldWithHeaderType.textField
|
||||||
textField.text: site
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
implicitWidth: listview.width
|
||||||
if (textField.text !== site) {
|
implicitHeight: col.implicitHeight
|
||||||
var tmpText = textField.text
|
|
||||||
tmpText = tmpText.toLocaleLowerCase()
|
|
||||||
|
|
||||||
if (tmpText.startsWith("https://")) {
|
ColumnLayout {
|
||||||
tmpText = textField.text.substring(8)
|
id: col
|
||||||
site = tmpText
|
|
||||||
} else {
|
anchors.top: parent.top
|
||||||
site = textField.text
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
headerText: qsTr("XRay settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: textFieldWithHeaderType
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 32
|
||||||
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("Disguised as traffic from")
|
||||||
|
textField.text: site
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== site) {
|
||||||
|
var tmpText = textField.text
|
||||||
|
tmpText = tmpText.toLocaleLowerCase()
|
||||||
|
|
||||||
|
if (tmpText.startsWith("https://")) {
|
||||||
|
tmpText = textField.text.substring(8)
|
||||||
|
site = tmpText
|
||||||
|
} else {
|
||||||
|
site = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
|
enabled: portTextField.errorText === ""
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
onClicked: function() {
|
||||||
|
forceActiveFocus()
|
||||||
|
|
||||||
|
var headerText = qsTr("Save settings?")
|
||||||
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(XrayConfigModel.getConfig())
|
||||||
|
//focusItem.forceActiveFocus()
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
saveButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: saveButton.clicked()
|
||||||
|
Keys.onReturnPressed: saveButton.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: listView.enabled
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
enabled: portTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
onClicked: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(XrayConfigModel.getConfig())
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,53 +16,50 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
|
id: header
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
headerText: "AmneziaDNS"
|
headerText: "AmneziaDNS"
|
||||||
descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") +
|
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.")
|
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 {
|
LabelWithButtonType {
|
||||||
Layout.fillWidth: true
|
id: removeButton
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
Layout.topMargin: 24
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
@@ -74,14 +71,19 @@ PageType {
|
|||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
||||||
&& SettingsController.isAmneziaDnsEnabled()) {
|
&& SettingsController.isAmneziaDnsEnabled()) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server"))
|
PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server"))
|
||||||
} else {
|
} else
|
||||||
|
{
|
||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
InstallController.removeProcessedContainer()
|
InstallController.removeProcessedContainer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {}
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
removeButton.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,215 +24,258 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
model: SftpConfigModel
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
spacing: 0
|
ListView {
|
||||||
|
id: listview
|
||||||
|
|
||||||
BaseHeaderType {
|
width: parent.width
|
||||||
Layout.fillWidth: true
|
height: listview.contentItem.height
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("SFTP settings")
|
clip: true
|
||||||
}
|
interactive: false
|
||||||
|
|
||||||
LabelWithButtonType {
|
model: SftpConfigModel
|
||||||
id: hostLabel
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
onFocusChanged: {
|
||||||
Layout.topMargin: 32
|
if (focus) {
|
||||||
Layout.leftMargin: 16
|
listview.currentItem.listViewFocusItem.forceActiveFocus()
|
||||||
Layout.rightMargin: 16
|
}
|
||||||
|
|
||||||
text: qsTr("Host")
|
|
||||||
descriptionText: ServersModel.getProcessedServerData("hostName")
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: portLabel
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Port")
|
|
||||||
descriptionText: port
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: usernameLabel
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("User name")
|
|
||||||
descriptionText: username
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: passwordLabel
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Password")
|
|
||||||
descriptionText: password
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: mountButton
|
|
||||||
|
|
||||||
visible: !GC.isMobile()
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
|
||||||
pressedColor: AmneziaStyle.color.sheerWhite
|
|
||||||
disabledColor: AmneziaStyle.color.mutedGray
|
|
||||||
textColor: AmneziaStyle.color.paleGray
|
|
||||||
borderWidth: 1
|
|
||||||
|
|
||||||
text: qsTr("Mount folder on device")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
InstallController.mountSftpDrive(port, password, username)
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParagraphTextType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
readonly property string windowsFirstLink: "<a href=\"https://github.com/billziss-gh/winfsp/releases/latest\" style=\"color: #FBB26A;\">WinFsp</a>"
|
|
||||||
readonly property string windowsSecondLink: "<a href=\"https://github.com/billziss-gh/sshfs-win/releases\" style=\"color: #FBB26A;\">SSHFS-Win</a>"
|
|
||||||
|
|
||||||
readonly property string macosFirstLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">macFUSE</a>"
|
|
||||||
readonly property string macosSecondLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">SSHFS</a>"
|
|
||||||
|
|
||||||
onLinkActivated: function(link) {
|
|
||||||
Qt.openUrlExternally(link)
|
|
||||||
}
|
|
||||||
textFormat: Text.RichText
|
|
||||||
text: {
|
|
||||||
var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps: <br>")
|
|
||||||
if (Qt.platform.os === "windows") {
|
|
||||||
str += qsTr("<br>1. Install the latest version of ") + windowsFirstLink + "\n"
|
|
||||||
str += qsTr("<br>2. Install the latest version of ") + windowsSecondLink + "\n"
|
|
||||||
} else if (Qt.platform.os === "osx") {
|
|
||||||
str += qsTr("<br>1. Install the latest version of ") + macosFirstLink + "\n"
|
|
||||||
str += qsTr("<br>2. Install the latest version of ") + macosSecondLink + "\n"
|
|
||||||
} else if (Qt.platform.os === "linux") {
|
|
||||||
return ""
|
|
||||||
} else return ""
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
delegate: Item {
|
||||||
anchors.fill: parent
|
implicitWidth: listview.width
|
||||||
acceptedButtons: Qt.NoButton
|
implicitHeight: col.implicitHeight
|
||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
property alias listViewFocusItem: hostLabel.rightButton
|
||||||
id: detailedInstructionsButton
|
|
||||||
|
|
||||||
Layout.topMargin: 16
|
ColumnLayout {
|
||||||
Layout.bottomMargin: 16
|
id: col
|
||||||
Layout.leftMargin: 8
|
|
||||||
implicitHeight: 32
|
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
anchors.top: parent.top
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
anchors.left: parent.left
|
||||||
pressedColor: AmneziaStyle.color.sheerWhite
|
anchors.right: parent.right
|
||||||
disabledColor: AmneziaStyle.color.mutedGray
|
|
||||||
textColor: AmneziaStyle.color.goldenApricot
|
|
||||||
|
|
||||||
text: qsTr("Detailed instructions")
|
spacing: 0
|
||||||
|
|
||||||
clickedFunc: function() {
|
BaseHeaderType {
|
||||||
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("SFTP settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: hostLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 32
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
text: qsTr("Host")
|
||||||
|
descriptionText: ServersModel.getProcessedServerData("hostName")
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: portLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Port")
|
||||||
|
descriptionText: port
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: usernameLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("User name")
|
||||||
|
descriptionText: username
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: passwordLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Password")
|
||||||
|
descriptionText: password
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: mountButton
|
||||||
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
|
disabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
textColor: AmneziaStyle.color.paleGray
|
||||||
|
borderWidth: 1
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
text: qsTr("Mount folder on device")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.mountSftpDrive(port, password, username)
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
readonly property string windowsFirstLink: "<a href=\"https://github.com/billziss-gh/winfsp/releases/latest\" style=\"color: #FBB26A;\">WinFsp</a>"
|
||||||
|
readonly property string windowsSecondLink: "<a href=\"https://github.com/billziss-gh/sshfs-win/releases\" style=\"color: #FBB26A;\">SSHFS-Win</a>"
|
||||||
|
|
||||||
|
readonly property string macosFirstLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">macFUSE</a>"
|
||||||
|
readonly property string macosSecondLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">SSHFS</a>"
|
||||||
|
|
||||||
|
onLinkActivated: function(link) {
|
||||||
|
Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
textFormat: Text.RichText
|
||||||
|
text: {
|
||||||
|
var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps: <br>")
|
||||||
|
if (Qt.platform.os === "windows") {
|
||||||
|
str += qsTr("<br>1. Install the latest version of ") + windowsFirstLink + "\n"
|
||||||
|
str += qsTr("<br>2. Install the latest version of ") + windowsSecondLink + "\n"
|
||||||
|
} else if (Qt.platform.os === "osx") {
|
||||||
|
str += qsTr("<br>1. Install the latest version of ") + macosFirstLink + "\n"
|
||||||
|
str += qsTr("<br>2. Install the latest version of ") + macosSecondLink + "\n"
|
||||||
|
} else if (Qt.platform.os === "linux") {
|
||||||
|
return ""
|
||||||
|
} else return ""
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: detailedInstructionsButton
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
Layout.leftMargin: 8
|
||||||
|
implicitHeight: 32
|
||||||
|
|
||||||
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
|
disabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
textColor: AmneziaStyle.color.goldenApricot
|
||||||
|
|
||||||
|
text: qsTr("Detailed instructions")
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,290 +25,327 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: listview.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
model: Socks5ProxyConfigModel
|
ListView {
|
||||||
|
id: listview
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
width: parent.width
|
||||||
width: listView.width
|
height: listview.contentItem.height
|
||||||
|
|
||||||
spacing: 0
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
|
||||||
BaseHeaderType {
|
model: Socks5ProxyConfigModel
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("SOCKS5 settings")
|
onFocusChanged: {
|
||||||
}
|
if (focus) {
|
||||||
|
listview.currentItem.focusItemId.forceActiveFocus()
|
||||||
LabelWithButtonType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 32
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Host")
|
|
||||||
descriptionText: ServersModel.getProcessedServerData("hostName")
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
delegate: Item {
|
||||||
Layout.fillWidth: true
|
implicitWidth: listview.width
|
||||||
Layout.rightMargin: 16
|
implicitHeight: content.implicitHeight
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Port")
|
property alias focusItemId: hostLabel.rightButton
|
||||||
descriptionText: port
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("User name")
|
|
||||||
descriptionText: username
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Password")
|
|
||||||
descriptionText: password
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawerType2 {
|
|
||||||
id: changeSettingsDrawer
|
|
||||||
parent: root
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
expandedHeight: root.height * 0.9
|
|
||||||
|
|
||||||
expandedStateContent: ColumnLayout {
|
|
||||||
property string tempPort: port
|
|
||||||
property string tempUsername: username
|
|
||||||
property string tempPassword: password
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 32
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Connections {
|
spacing: 0
|
||||||
target: changeSettingsDrawer
|
|
||||||
function onOpened() {
|
|
||||||
tempPort = port
|
|
||||||
tempUsername = username
|
|
||||||
tempPassword = password
|
|
||||||
}
|
|
||||||
function onClosed() {
|
|
||||||
port = tempPort
|
|
||||||
username = tempUsername
|
|
||||||
password = tempPassword
|
|
||||||
portTextField.textField.text = port
|
|
||||||
usernameTextField.textField.text = username
|
|
||||||
passwordTextField.textField.text = password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("SOCKS5 settings")
|
headerText: qsTr("SOCKS5 settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
LabelWithButtonType {
|
||||||
id: portTextField
|
id: hostLabel
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 40
|
Layout.topMargin: 32
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
parentFlickable: fl
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
text: qsTr("Host")
|
||||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
descriptionText: ServersModel.getProcessedServerData("hostName")
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
LabelWithButtonType {
|
||||||
id: usernameTextField
|
id: portLabel
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Username")
|
text: qsTr("Port")
|
||||||
textField.placeholderText: "username"
|
descriptionText: port
|
||||||
textField.text: username
|
|
||||||
textField.maximumLength: 32
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
descriptionOnTop: true
|
||||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
|
||||||
if (textField.text !== username) {
|
parentFlickable: fl
|
||||||
username = textField.text
|
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
LabelWithButtonType {
|
||||||
id: passwordTextField
|
id: usernameLabel
|
||||||
|
|
||||||
property bool hidePassword: true
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Password")
|
text: qsTr("User name")
|
||||||
textField.placeholderText: "password"
|
descriptionText: username
|
||||||
textField.text: password
|
|
||||||
textField.maximumLength: 32
|
|
||||||
|
|
||||||
textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
|
descriptionOnTop: true
|
||||||
buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
|
|
||||||
: ""
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
parentFlickable: fl
|
||||||
hidePassword = !hidePassword
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
textField.onFocusChanged: {
|
LabelWithButtonType {
|
||||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
id: passwordLabel
|
||||||
if (textField.text !== password) {
|
Layout.fillWidth: true
|
||||||
password = textField.text
|
|
||||||
|
text: qsTr("Password")
|
||||||
|
descriptionText: password
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawerType2 {
|
||||||
|
id: changeSettingsDrawer
|
||||||
|
parent: root
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
expandedHeight: root.height * 0.9
|
||||||
|
|
||||||
|
expandedStateContent: ColumnLayout {
|
||||||
|
property string tempPort: port
|
||||||
|
property string tempUsername: username
|
||||||
|
property string tempPassword: password
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 32
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: changeSettingsDrawer
|
||||||
|
function onOpened() {
|
||||||
|
tempPort = port
|
||||||
|
tempUsername = username
|
||||||
|
tempPassword = password
|
||||||
|
}
|
||||||
|
function onClosed() {
|
||||||
|
port = tempPort
|
||||||
|
username = tempUsername
|
||||||
|
password = tempPassword
|
||||||
|
portTextField.textField.text = port
|
||||||
|
usernameTextField.textField.text = username
|
||||||
|
passwordTextField.textField.text = password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
headerText: qsTr("SOCKS5 settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 40
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: usernameTextField
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
headerText: qsTr("Username")
|
||||||
|
textField.placeholderText: "username"
|
||||||
|
textField.text: username
|
||||||
|
textField.maximumLength: 32
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||||
|
if (textField.text !== username) {
|
||||||
|
username = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: passwordTextField
|
||||||
|
|
||||||
|
property bool hidePassword: true
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
headerText: qsTr("Password")
|
||||||
|
textField.placeholderText: "password"
|
||||||
|
textField.text: password
|
||||||
|
textField.maximumLength: 32
|
||||||
|
|
||||||
|
textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
|
||||||
|
buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
|
||||||
|
: ""
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
hidePassword = !hidePassword
|
||||||
|
}
|
||||||
|
|
||||||
|
textField.onFocusChanged: {
|
||||||
|
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||||
|
if (textField.text !== password) {
|
||||||
|
password = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
|
text: qsTr("Change connection settings")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
forceActiveFocus()
|
||||||
|
|
||||||
|
if (!portTextField.textField.acceptableInput) {
|
||||||
|
portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (usernameTextField.textField.text && passwordTextField.textField.text === "") {
|
||||||
|
passwordTextField.errorText = qsTr("Password cannot be empty")
|
||||||
|
return
|
||||||
|
} else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) {
|
||||||
|
usernameTextField.errorText = qsTr("Username cannot be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||||
|
InstallController.updateContainer(Socks5ProxyConfigModel.getConfig())
|
||||||
|
tempPort = portTextField.textField.text
|
||||||
|
tempUsername = usernameTextField.textField.text
|
||||||
|
tempPassword = passwordTextField.textField.text
|
||||||
|
changeSettingsDrawer.closeTriggered()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: saveButton
|
id: changeSettingsButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.bottomMargin: 24
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Change connection settings")
|
text: qsTr("Change connection settings")
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
if (!portTextField.textField.acceptableInput) {
|
forceActiveFocus()
|
||||||
portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
|
changeSettingsDrawer.openTriggered()
|
||||||
return
|
|
||||||
}
|
|
||||||
if (usernameTextField.textField.text && passwordTextField.textField.text === "") {
|
|
||||||
passwordTextField.errorText = qsTr("Password cannot be empty")
|
|
||||||
return
|
|
||||||
} else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) {
|
|
||||||
usernameTextField.errorText = qsTr("Username cannot be empty")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
|
||||||
InstallController.updateContainer(Socks5ProxyConfigModel.getConfig())
|
|
||||||
tempPort = portTextField.textField.text
|
|
||||||
tempUsername = usernameTextField.textField.text
|
|
||||||
tempPassword = passwordTextField.textField.text
|
|
||||||
changeSettingsDrawer.closeTriggered()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: changeSettingsButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Change connection settings")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
changeSettingsDrawer.openTriggered()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,31 +25,34 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: backButtonLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.top: backButton.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -58,19 +61,11 @@ PageType {
|
|||||||
|
|
||||||
headerText: qsTr("Tor website settings")
|
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 {
|
LabelWithButtonType {
|
||||||
id: websiteName
|
id: websiteName
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 32
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
text: qsTr("Website address")
|
text: qsTr("Website address")
|
||||||
descriptionText: {
|
descriptionText: {
|
||||||
@@ -88,16 +83,15 @@ PageType {
|
|||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
GC.copyToClipBoard(descriptionText)
|
GC.copyToClipBoard(descriptionText)
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
this.rightButton.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
ParagraphTextType {
|
ParagraphTextType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 40
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
|||||||
@@ -14,58 +14,130 @@ import "../Config"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
anchors.fill: parent
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
|
|
||||||
header: ColumnLayout {
|
anchors.top: parent.top
|
||||||
width: listView.width
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
id: header
|
id: header
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.bottomMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Settings")
|
headerText: qsTr("Settings")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
model: settingsEntries
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
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
|
Layout.fillWidth: true
|
||||||
|
|
||||||
visible: isVisible
|
text: qsTr("Connection")
|
||||||
|
|
||||||
text: title
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
leftImageSource: leftImagePath
|
leftImageSource: "qrc:/images/controls/radio.svg"
|
||||||
|
|
||||||
clickedFunction: clickedHandler
|
clickedFunction: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsConnection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: application
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Application")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
leftImageSource: "qrc:/images/controls/app.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsApplication)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: backup
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Backup")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
leftImageSource: "qrc:/images/controls/save.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsBackup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: about
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("About AmneziaVPN")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
leftImageSource: "qrc:/images/controls/amnezia.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsAbout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: devConsole
|
||||||
|
visible: SettingsController.isDevModeEnabled
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Dev console")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
leftImageSource: "qrc:/images/controls/bug.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageDevMenu)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: isVisible
|
visible: SettingsController.isDevModeEnabled
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: close
|
id: close
|
||||||
|
|
||||||
visible: GC.isDesktop()
|
visible: GC.isDesktop()
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: about.height
|
||||||
|
|
||||||
text: qsTr("Close application")
|
text: qsTr("Close application")
|
||||||
leftImageSource: "qrc:/images/controls/x-circle.svg"
|
leftImageSource: "qrc:/images/controls/x-circle.svg"
|
||||||
@@ -77,87 +149,8 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
visible: GC.isDesktop()
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,58 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
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 {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
@@ -37,6 +88,38 @@ PageType {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
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 {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
@@ -87,12 +170,11 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model: contacts
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
|
id: telegramButton
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 6
|
Layout.topMargin: 6
|
||||||
|
|
||||||
@@ -175,55 +257,4 @@ 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,10 +119,6 @@ PageType {
|
|||||||
checkable: !ConnectionController.isConnected
|
checkable: !ConnectionController.isConnected
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (ConnectionController.isConnectionInProgress) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change server location while trying to make an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (ConnectionController.isConnected) {
|
if (ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection"))
|
PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -20,49 +20,49 @@ PageType {
|
|||||||
id: windows
|
id: windows
|
||||||
|
|
||||||
readonly property string title: qsTr("Windows")
|
readonly property string title: qsTr("Windows")
|
||||||
readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#windows")
|
readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#windows")
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: macos
|
id: macos
|
||||||
|
|
||||||
readonly property string title: qsTr("macOS")
|
readonly property string title: qsTr("macOS")
|
||||||
readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#macos")
|
readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#macos")
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: android
|
id: android
|
||||||
|
|
||||||
readonly property string title: qsTr("Android")
|
readonly property string title: qsTr("Android")
|
||||||
readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#android")
|
readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#android")
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: androidTv
|
id: androidTv
|
||||||
|
|
||||||
readonly property string title: qsTr("AndroidTV")
|
readonly property string title: qsTr("AndroidTV")
|
||||||
readonly property string link: qsTr("documentation/instructions/android_tv_connect/")
|
readonly property string link: qsTr("https://docs.amnezia.org/ru/documentation/instructions/android_tv_connect/")
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: ios
|
id: ios
|
||||||
|
|
||||||
readonly property string title: qsTr("iOS")
|
readonly property string title: qsTr("iOS")
|
||||||
readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#ios")
|
readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#ios")
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: linux
|
id: linux
|
||||||
|
|
||||||
readonly property string title: qsTr("Linux")
|
readonly property string title: qsTr("Linux")
|
||||||
readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#linux")
|
readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#linux")
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: routers
|
id: routers
|
||||||
|
|
||||||
readonly property string title: qsTr("Routers")
|
readonly property string title: qsTr("Routers")
|
||||||
readonly property string link: qsTr("documentation/instructions/connect-amnezia-premium#routers")
|
readonly property string link: qsTr("https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#routers")
|
||||||
}
|
}
|
||||||
|
|
||||||
property list<QtObject> instructionsModel: [
|
property list<QtObject> instructionsModel: [
|
||||||
@@ -114,7 +114,7 @@ PageType {
|
|||||||
rightImageSource: "qrc:/images/controls/external-link.svg"
|
rightImageSource: "qrc:/images/controls/external-link.svg"
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
Qt.openUrlExternally(LanguageModel.getCurrentDocsUrl(link))
|
Qt.openUrlExternally(link)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,34 +22,22 @@ PageType {
|
|||||||
property string configExtension: ".conf"
|
property string configExtension: ".conf"
|
||||||
property string configCaption: qsTr("Save AmneziaVPN config")
|
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 {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.fill: parent
|
||||||
anchors.bottom: parent.bottom
|
anchors.topMargin: 20
|
||||||
anchors.right: parent.right
|
anchors.bottomMargin: 24
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
model: ApiCountryModel
|
model: ApiCountryModel
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
|
BackButtonType {
|
||||||
|
id: backButton
|
||||||
|
}
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
id: header
|
id: header
|
||||||
|
|
||||||
@@ -71,7 +59,6 @@ PageType {
|
|||||||
|
|
||||||
text: countryName
|
text: countryName
|
||||||
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
|
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
|
||||||
hideDescription: isWorkerExpired ? true : false
|
|
||||||
descriptionColor: AmneziaStyle.color.vibrantRed
|
descriptionColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
|
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
|
||||||
@@ -117,16 +104,20 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: drawerListView
|
|
||||||
|
|
||||||
anchors.top: moreOptionsDrawerBackButton.bottom
|
anchors.top: moreOptionsDrawerBackButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
header: ColumnLayout {
|
contentHeight: moreOptionsDrawerContent.height
|
||||||
width: drawerListView.width
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: moreOptionsDrawerContent
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
Header2Type {
|
Header2Type {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -134,17 +125,9 @@ PageType {
|
|||||||
|
|
||||||
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
|
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 {
|
LabelWithButtonType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Generate a new configuration file")
|
text: qsTr("Generate a new configuration file")
|
||||||
descriptionText: qsTr("The previously created one will stop working")
|
descriptionText: qsTr("The previously created one will stop working")
|
||||||
@@ -155,16 +138,9 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
DividerType {}
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
|
||||||
width: drawerListView.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Revoke the current configuration file")
|
text: qsTr("Revoke the current configuration file")
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
@@ -236,7 +212,8 @@ PageType {
|
|||||||
}
|
}
|
||||||
moreOptionsDrawer.closeTriggered()
|
moreOptionsDrawer.closeTriggered()
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {}
|
var noButtonFunction = function() {
|
||||||
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,17 @@ PageType {
|
|||||||
serverNameEditDrawer.openTriggered()
|
serverNameEditDrawer.openTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RenameServerDrawer {
|
||||||
|
id: serverNameEditDrawer
|
||||||
|
|
||||||
|
parent: root
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
expandedHeight: root.height * 0.35
|
||||||
|
|
||||||
|
serverNameText: root.processedServer.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
@@ -187,13 +198,7 @@ PageType {
|
|||||||
|
|
||||||
iconPath: "qrc:/images/controls/alert-circle.svg"
|
iconPath: "qrc:/images/controls/alert-circle.svg"
|
||||||
|
|
||||||
visible: {
|
visible: ApiAccountInfoModel.data("hasExpiredWorker")
|
||||||
for (let i = 0; i < ApiCountryModel.count; ++i) {
|
|
||||||
if (ApiCountryModel.get(i).isWorkerExpired)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
@@ -202,30 +207,35 @@ PageType {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: warning.visible ? 16 : 32
|
Layout.topMargin: warning.visible ? 16 : 32
|
||||||
|
|
||||||
visible: footer.isVisibleForAmneziaFree
|
visible: false //footer.isVisibleForAmneziaFree
|
||||||
|
|
||||||
text: qsTr("Subscription Key")
|
text: qsTr("Subscription Key")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsApiSubscriptionKey)
|
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.showBusyIndicator(true)
|
PageController.showBusyIndicator(true)
|
||||||
|
|
||||||
ApiConfigsController.prepareVpnKeyExport()
|
ApiConfigsController.prepareVpnKeyExport()
|
||||||
|
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
|
|
||||||
// Navigate to PageShareConnection page
|
|
||||||
//PageController.goToPage(PageEnum.PageShareConnection)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: footer.isVisibleForAmneziaFree
|
visible: false //footer.isVisibleForAmneziaFree
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: warning.visible ? 16 : 32
|
||||||
|
|
||||||
visible: footer.isVisibleForAmneziaFree
|
visible: footer.isVisibleForAmneziaFree
|
||||||
|
|
||||||
@@ -410,12 +420,9 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RenameServerDrawer {
|
ShareConnectionDrawer {
|
||||||
id: serverNameEditDrawer
|
id: shareConnectionDrawer
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
expandedHeight: parent.height * 0.35
|
|
||||||
|
|
||||||
serverNameText: root.processedServer.name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
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,7 +50,6 @@ PageType {
|
|||||||
readonly property string name: qsTr("Only the apps from the list should have access via VPN")
|
readonly property string name: qsTr("Only the apps from the list should have access via VPN")
|
||||||
readonly property int type: routeMode.onlyForwardApps
|
readonly property int type: routeMode.onlyForwardApps
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: allExceptApps
|
id: allExceptApps
|
||||||
|
|
||||||
@@ -112,7 +111,7 @@ PageType {
|
|||||||
|
|
||||||
headerText: qsTr("Mode")
|
headerText: qsTr("Mode")
|
||||||
|
|
||||||
enabled: (Qt.platform.os === "android") && root.pageEnabled
|
enabled: Qt.platform.os === "android" && root.pageEnabled
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
listView: ListViewWithRadioButtonType {
|
||||||
rootWidth: root.width
|
rootWidth: root.width
|
||||||
@@ -147,56 +146,77 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
|
||||||
|
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
anchors.bottom: addAppButton.top
|
anchors.topMargin: 16
|
||||||
anchors.left: parent.left
|
contentHeight: col.implicitHeight + addAppButton.implicitHeight + addAppButton.anchors.bottomMargin + addAppButton.anchors.topMargin
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
model: SortFilterProxyModel {
|
enabled: root.pageEnabled
|
||||||
id: proxyAppSplitTunnelingModel
|
|
||||||
sourceModel: AppSplitTunnelingModel
|
|
||||||
filters: RegExpFilter {
|
|
||||||
roleName: "appPath"
|
|
||||||
pattern: ".*" + searchField.textField.text + ".*"
|
|
||||||
caseSensitivity: Qt.CaseInsensitive
|
|
||||||
}
|
|
||||||
sorters: [
|
|
||||||
RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
Column {
|
||||||
width: listView.width
|
id: col
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
LabelWithButtonType {
|
ListView {
|
||||||
Layout.fillWidth: true
|
id: apps
|
||||||
|
width: parent.width
|
||||||
|
height: apps.contentItem.height
|
||||||
|
|
||||||
Layout.leftMargin: 16
|
model: SortFilterProxyModel {
|
||||||
Layout.rightMargin: 16
|
id: proxyAppSplitTunnelingModel
|
||||||
|
sourceModel: AppSplitTunnelingModel
|
||||||
text: appPath
|
filters: RegExpFilter {
|
||||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
roleName: "appPath"
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
pattern: ".*" + searchField.textField.text + ".*"
|
||||||
|
caseSensitivity: Qt.CaseInsensitive
|
||||||
clickedFunction: function() {
|
|
||||||
var headerText = qsTr("Remove ") + appPath + "?"
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index))
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
}
|
}
|
||||||
|
sorters: [
|
||||||
|
RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
implicitWidth: apps.width
|
||||||
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: delegateContent
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: appPath
|
||||||
|
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var headerText = qsTr("Remove ") + appPath + "?"
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index))
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,24 +21,22 @@ PageType {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
contentHeight: content.height
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -47,17 +45,9 @@ PageType {
|
|||||||
|
|
||||||
headerText: qsTr("Application")
|
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 {
|
SwitcherType {
|
||||||
id: switcherAllowScreenshots
|
id: switcher
|
||||||
|
|
||||||
visible: GC.isMobile()
|
visible: GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -71,6 +61,10 @@ PageType {
|
|||||||
SettingsController.toggleScreenshotsEnabled(checked)
|
SettingsController.toggleScreenshotsEnabled(checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
|
||||||
|
// labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
|
||||||
|
parentFlickable: fl
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
@@ -79,15 +73,15 @@ PageType {
|
|||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonNotification
|
id: labelWithButtonNotification
|
||||||
|
|
||||||
visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted
|
visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Enable notifications")
|
text: qsTr("Enable notifications")
|
||||||
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
|
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
SettingsController.requestNotificationPermission()
|
SettingsController.requestNotificationPermission()
|
||||||
}
|
}
|
||||||
@@ -99,7 +93,6 @@ PageType {
|
|||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcherAutoStart
|
id: switcherAutoStart
|
||||||
|
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -108,6 +101,8 @@ PageType {
|
|||||||
text: qsTr("Auto start")
|
text: qsTr("Auto start")
|
||||||
descriptionText: qsTr("Launch the application every time the device is starts")
|
descriptionText: qsTr("Launch the application every time the device is starts")
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
checked: SettingsController.isAutoStartEnabled()
|
checked: SettingsController.isAutoStartEnabled()
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (checked !== SettingsController.isAutoStartEnabled()) {
|
if (checked !== SettingsController.isAutoStartEnabled()) {
|
||||||
@@ -122,7 +117,6 @@ PageType {
|
|||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcherAutoConnect
|
id: switcherAutoConnect
|
||||||
|
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -131,6 +125,8 @@ PageType {
|
|||||||
text: qsTr("Auto connect")
|
text: qsTr("Auto connect")
|
||||||
descriptionText: qsTr("Connect to VPN on app start")
|
descriptionText: qsTr("Connect to VPN on app start")
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
checked: SettingsController.isAutoConnectEnabled()
|
checked: SettingsController.isAutoConnectEnabled()
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (checked !== SettingsController.isAutoConnectEnabled()) {
|
if (checked !== SettingsController.isAutoConnectEnabled()) {
|
||||||
@@ -145,17 +141,15 @@ PageType {
|
|||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcherStartMinimized
|
id: switcherStartMinimized
|
||||||
|
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: 16
|
Layout.margins: 16
|
||||||
|
|
||||||
text: qsTr("Start minimized")
|
text: qsTr("Start minimized")
|
||||||
descriptionText: qsTr("Launch application minimized (works with autostart option turned on)")
|
descriptionText: qsTr("Launch application minimized")
|
||||||
|
|
||||||
enabled: switcherAutoStart.checked
|
parentFlickable: fl
|
||||||
opacity: enabled ? 1.0 : 0.5
|
|
||||||
|
|
||||||
checked: SettingsController.isStartMinimizedEnabled()
|
checked: SettingsController.isStartMinimizedEnabled()
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
@@ -168,21 +162,17 @@ PageType {
|
|||||||
DividerType {
|
DividerType {
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
|
||||||
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonLanguage
|
id: labelWithButtonLanguage
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Language")
|
text: qsTr("Language")
|
||||||
descriptionText: LanguageModel.currentLanguageName
|
descriptionText: LanguageModel.currentLanguageName
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
selectLanguageDrawer.openTriggered()
|
selectLanguageDrawer.openTriggered()
|
||||||
}
|
}
|
||||||
@@ -192,13 +182,14 @@ PageType {
|
|||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonLogging
|
id: labelWithButtonLogging
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Logging")
|
text: qsTr("Logging")
|
||||||
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsLogging)
|
PageController.goToPage(PageEnum.PageSettingsLogging)
|
||||||
}
|
}
|
||||||
@@ -208,13 +199,14 @@ PageType {
|
|||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonReset
|
id: labelWithButtonReset
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Reset settings and remove all data from the application")
|
text: qsTr("Reset settings and remove all data from the application")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
var headerText = qsTr("Reset settings and remove all data from the application?")
|
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.")
|
var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
|
||||||
|
|||||||
@@ -41,68 +41,51 @@ PageType {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
contentHeight: content.height
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
|
|
||||||
width: listView.width
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Back up your configuration")
|
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.")
|
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 {
|
WarningType {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
textString: qsTr("The backup will contain your passwords and private keys for all servers added " +
|
textString: qsTr("The backup will contain your passwords and private keys for all servers added " +
|
||||||
"to AmneziaVPN. Keep this information in a secure place.")
|
"to AmneziaVPN. Keep this information in a secure place.")
|
||||||
|
|
||||||
iconPath: "qrc:/images/controls/alert-circle.svg"
|
iconPath: "qrc:/images/controls/alert-circle.svg"
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: makeBackupButton
|
id: makeBackupButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 14
|
Layout.topMargin: 14
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Make a backup")
|
text: qsTr("Make a backup")
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
var fileName = ""
|
var fileName = ""
|
||||||
if (GC.isMobile()) {
|
if (GC.isMobile()) {
|
||||||
@@ -125,11 +108,8 @@ PageType {
|
|||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: restoreBackupButton
|
id: restoreBackupButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: -8
|
Layout.topMargin: -8
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
@@ -140,6 +120,8 @@ PageType {
|
|||||||
|
|
||||||
text: qsTr("Restore from backup")
|
text: qsTr("Restore from backup")
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
var filePath = SystemController.getFileName(qsTr("Open backup file"),
|
var filePath = SystemController.getFileName(qsTr("Open backup file"),
|
||||||
qsTr("Backup files (*.backup)"))
|
qsTr("Backup files (*.backup)"))
|
||||||
|
|||||||
@@ -21,25 +21,20 @@ PageType {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
contentHeight: content.height
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
|
|
||||||
width: listView.width
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -48,17 +43,9 @@ PageType {
|
|||||||
|
|
||||||
headerText: qsTr("Connection")
|
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 {
|
SwitcherType {
|
||||||
id: amneziaDnsSwitch
|
id: amneziaDnsSwitch
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: 16
|
Layout.margins: 16
|
||||||
|
|
||||||
@@ -77,13 +64,14 @@ PageType {
|
|||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: dnsServersButton
|
id: dnsServersButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("DNS servers")
|
text: qsTr("DNS servers")
|
||||||
descriptionText: qsTr("When AmneziaDNS is not used or installed")
|
descriptionText: qsTr("When AmneziaDNS is not used or installed")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsDns)
|
PageController.goToPage(PageEnum.PageSettingsDns)
|
||||||
}
|
}
|
||||||
@@ -93,13 +81,14 @@ PageType {
|
|||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: splitTunnelingButton
|
id: splitTunnelingButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Site-based split tunneling")
|
text: qsTr("Site-based split tunneling")
|
||||||
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
|
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||||
}
|
}
|
||||||
@@ -107,15 +96,8 @@ PageType {
|
|||||||
|
|
||||||
DividerType {}
|
DividerType {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout { // TODO(CyAn84): move to delegate,add DelegateChooser when have migrated to 6.9
|
|
||||||
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: splitTunnelingButton2
|
id: splitTunnelingButton2
|
||||||
|
|
||||||
visible: root.isAppSplitTinnelingEnabled
|
visible: root.isAppSplitTinnelingEnabled
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -124,6 +106,8 @@ PageType {
|
|||||||
descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
|
descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||||
}
|
}
|
||||||
@@ -143,6 +127,8 @@ PageType {
|
|||||||
descriptionText: qsTr("Blocks network connections without VPN")
|
descriptionText: qsTr("Blocks network connections without VPN")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsKillSwitch)
|
PageController.goToPage(PageEnum.PageSettingsKillSwitch)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,21 +21,13 @@ PageType {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
|
||||||
if (this.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.height
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
|
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
|
||||||
|
|
||||||
@@ -47,40 +39,32 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("DNS servers")
|
headerText: qsTr("DNS servers")
|
||||||
}
|
}
|
||||||
|
|
||||||
ParagraphTextType {
|
ParagraphTextType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("If AmneziaDNS is not used or installed")
|
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 {
|
TextFieldWithHeaderType {
|
||||||
id: primaryDns
|
id: primaryDns
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Primary DNS")
|
headerText: qsTr("Primary DNS")
|
||||||
|
|
||||||
textField.text: SettingsController.primaryDns
|
textField.text: SettingsController.primaryDns
|
||||||
@@ -93,9 +77,6 @@ PageType {
|
|||||||
id: secondaryDns
|
id: secondaryDns
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Secondary DNS")
|
headerText: qsTr("Secondary DNS")
|
||||||
|
|
||||||
textField.text: SettingsController.secondaryDns
|
textField.text: SettingsController.secondaryDns
|
||||||
@@ -106,11 +87,7 @@ PageType {
|
|||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: restoreDefaultButton
|
id: restoreDefaultButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
@@ -144,7 +121,6 @@ PageType {
|
|||||||
id: saveButton
|
id: saveButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: 16
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
text: qsTr("Save")
|
||||||
|
|
||||||
@@ -160,4 +136,5 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,9 +71,6 @@ PageType {
|
|||||||
onClicked: function() {
|
onClicked: function() {
|
||||||
SettingsController.strictKillSwitchEnabled = false
|
SettingsController.strictKillSwitchEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
DividerType {}
|
||||||
@@ -106,9 +103,6 @@ PageType {
|
|||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ PageType {
|
|||||||
displayMarginBeginning: 40
|
displayMarginBeginning: 40
|
||||||
displayMarginEnd: 40
|
displayMarginEnd: 40
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
ScrollBar.vertical: ScrollBarType { }
|
||||||
|
|
||||||
footer: Item {
|
footer: Item {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|||||||
@@ -23,15 +23,9 @@ PageType {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
|
||||||
if (this.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
@@ -39,6 +33,10 @@ PageType {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
@@ -103,7 +101,8 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model: logTypes
|
model: logTypes
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
snapMode: ListView.SnapOneItem
|
snapMode: ListView.SnapOneItem
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ PageType {
|
|||||||
|
|
||||||
signal lastItemTabClickedSignal()
|
signal lastItemTabClickedSignal()
|
||||||
|
|
||||||
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
|
onFocusChanged: content.isServerWithWriteAccess ?
|
||||||
|
labelWithButton.forceActiveFocus() :
|
||||||
|
labelWithButton3.forceActiveFocus()
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: InstallController
|
target: InstallController
|
||||||
@@ -61,192 +63,218 @@ PageType {
|
|||||||
target: ServersModel
|
target: ServersModel
|
||||||
|
|
||||||
function onProcessedServerIndexChanged() {
|
function onProcessedServerIndexChanged() {
|
||||||
root.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
|
content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
anchors.fill: parent
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
|
|
||||||
model: serverActions
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
|
id: labelWithButton
|
||||||
|
visible: content.isServerWithWriteAccess
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
visible: isVisible
|
text: qsTr("Check the server for previously installed Amnezia services")
|
||||||
|
descriptionText: qsTr("Add them to the application if they were not displayed")
|
||||||
text: title
|
|
||||||
descriptionText: description
|
|
||||||
textColor: tColor
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
clickedHandler()
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.scanServerForInstalledContainers()
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: isVisible
|
visible: content.isServerWithWriteAccess
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property list<QtObject> serverActions: [
|
LabelWithButtonType {
|
||||||
check,
|
id: labelWithButton2
|
||||||
reboot,
|
visible: content.isServerWithWriteAccess
|
||||||
remove,
|
Layout.fillWidth: true
|
||||||
clear,
|
|
||||||
reset,
|
|
||||||
switch_to_premium,
|
|
||||||
]
|
|
||||||
|
|
||||||
QtObject {
|
text: qsTr("Reboot server")
|
||||||
id: check
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
property bool isVisible: root.isServerWithWriteAccess
|
clickedFunction: function() {
|
||||||
readonly property string title: qsTr("Check the server for previously installed Amnezia services")
|
var headerText = qsTr("Do you want to reboot the server?")
|
||||||
readonly property string description: qsTr("Add them to the application if they were not displayed")
|
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
|
||||||
readonly property var tColor: AmneziaStyle.color.paleGray
|
var yesButtonText = qsTr("Continue")
|
||||||
readonly property var clickedHandler: function() {
|
var noButtonText = qsTr("Cancel")
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
InstallController.scanServerForInstalledContainers()
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
var yesButtonFunction = function() {
|
||||||
id: reboot
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection"))
|
||||||
|
} else {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.rebootProcessedServer()
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton5.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton2.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property bool isVisible: root.isServerWithWriteAccess
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
readonly property string title: qsTr("Reboot server")
|
|
||||||
readonly property string description: ""
|
|
||||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
|
||||||
readonly property var clickedHandler: function() {
|
|
||||||
var headerText = qsTr("Do you want to reboot the server?")
|
|
||||||
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection"))
|
|
||||||
} else {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
InstallController.rebootProcessedServer()
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: content.isServerWithWriteAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
LabelWithButtonType {
|
||||||
}
|
id: labelWithButton3
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
|
||||||
QtObject {
|
text: qsTr("Remove server from application")
|
||||||
id: remove
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
property bool isVisible: true
|
clickedFunction: function() {
|
||||||
readonly property string title: qsTr("Remove server from application")
|
var headerText = qsTr("Do you want to remove the server from application?")
|
||||||
readonly property string description: ""
|
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
|
||||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
var yesButtonText = qsTr("Continue")
|
||||||
readonly property var clickedHandler: function() {
|
var noButtonText = qsTr("Cancel")
|
||||||
var headerText = qsTr("Do you want to remove the server from application?")
|
|
||||||
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
||||||
} else {
|
} else {
|
||||||
PageController.showBusyIndicator(true)
|
PageController.showBusyIndicator(true)
|
||||||
InstallController.removeProcessedServer()
|
InstallController.removeProcessedServer()
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton5.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton3.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
|
||||||
|
|
||||||
}
|
DividerType {}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
LabelWithButtonType {
|
||||||
}
|
id: labelWithButton4
|
||||||
}
|
visible: content.isServerWithWriteAccess
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
QtObject {
|
text: qsTr("Clear server from Amnezia software")
|
||||||
id: clear
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
property bool isVisible: root.isServerWithWriteAccess
|
clickedFunction: function() {
|
||||||
readonly property string title: qsTr("Clear server from Amnezia software")
|
var headerText = qsTr("Do you want to clear server from Amnezia software?")
|
||||||
readonly property string description: ""
|
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
|
||||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
var yesButtonText = qsTr("Continue")
|
||||||
readonly property var clickedHandler: function() {
|
var noButtonText = qsTr("Cancel")
|
||||||
var headerText = qsTr("Do you want to clear server from Amnezia software?")
|
|
||||||
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection"))
|
PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection"))
|
||||||
} else {
|
} else {
|
||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
InstallController.removeAllContainers()
|
InstallController.removeAllContainers()
|
||||||
|
}
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton5.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton4.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: content.isServerWithWriteAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
LabelWithButtonType {
|
||||||
}
|
id: labelWithButton5
|
||||||
}
|
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
QtObject {
|
text: qsTr("Reset API config")
|
||||||
id: reset
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
clickedFunction: function() {
|
||||||
readonly property string title: qsTr("Reset API config")
|
var headerText = qsTr("Do you want to reset API config?")
|
||||||
readonly property string description: ""
|
var descriptionText = ""
|
||||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
var yesButtonText = qsTr("Continue")
|
||||||
readonly property var clickedHandler: function() {
|
var noButtonText = qsTr("Cancel")
|
||||||
var headerText = qsTr("Do you want to reset API config?")
|
|
||||||
var descriptionText = ""
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection"))
|
PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection"))
|
||||||
} else {
|
} else {
|
||||||
PageController.showBusyIndicator(true)
|
PageController.showBusyIndicator(true)
|
||||||
InstallController.removeApiConfig(ServersModel.processedIndex)
|
InstallController.removeApiConfig(ServersModel.processedIndex)
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton5.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
labelWithButton5.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||||
}
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
LabelWithButtonType {
|
||||||
}
|
id: labelWithButton6
|
||||||
}
|
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
QtObject {
|
text: qsTr("Switch to the new Amnezia Premium subscription")
|
||||||
id: switch_to_premium
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
|
clickedFunction: function() {
|
||||||
readonly property string title: qsTr("Switch to the new Amnezia Premium subscription")
|
PageController.goToPageHome()
|
||||||
readonly property string description: ""
|
ApiPremV1MigrationController.showMigrationDrawer()
|
||||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
}
|
||||||
readonly property var clickedHandler: function() {
|
}
|
||||||
PageController.goToPageHome()
|
|
||||||
ApiPremV1MigrationController.showMigrationDrawer()
|
DividerType {
|
||||||
|
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,211 +21,249 @@ PageType {
|
|||||||
|
|
||||||
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
|
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: header
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onFocusChanged: {
|
BackButtonType {
|
||||||
if (this.activeFocus) {
|
id: backButton
|
||||||
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: 32
|
|
||||||
|
|
||||||
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model: ProtocolsModel
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 32
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
||||||
id: delegateContent
|
|
||||||
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
property bool isClientSettingsVisible: (protocolIndex === ProtocolEnum.WireGuard) || (protocolIndex === ProtocolEnum.Awg)
|
|
||||||
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: clientSettings
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: protocolName + qsTr(" connection settings")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
|
||||||
visible: delegateContent.isClientSettingsVisible
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
if (isClientProtocolExists) {
|
|
||||||
switch (protocolIndex) {
|
|
||||||
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
}
|
|
||||||
PageController.goToPage(clientProtocolPage);
|
|
||||||
} else {
|
|
||||||
PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: clientSettings
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: delegateContent.isClientSettingsVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: serverSettings
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: protocolName + qsTr(" server settings")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
|
||||||
visible: delegateContent.isServerSettingsVisible
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
switch (protocolIndex) {
|
|
||||||
case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
}
|
|
||||||
PageController.goToPage(serverProtocolPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: serverSettings
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: delegateContent.isServerSettingsVisible
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
footer: ColumnLayout {
|
ListView {
|
||||||
|
id: protocols
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: protocols.contentItem.height
|
||||||
|
clip: true
|
||||||
|
interactive: true
|
||||||
|
|
||||||
width: listView.width
|
property bool isFocusable: true
|
||||||
|
|
||||||
LabelWithButtonType {
|
Keys.onTabPressed: {
|
||||||
id: clearCacheButton
|
FocusController.nextKeyTabItem()
|
||||||
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Keys.onBacktabPressed: {
|
||||||
|
FocusController.previousKeyTabItem()
|
||||||
|
}
|
||||||
|
|
||||||
visible: root.isClearCacheVisible
|
Keys.onUpPressed: {
|
||||||
|
FocusController.nextKeyUpItem()
|
||||||
|
}
|
||||||
|
|
||||||
text: qsTr("Clear profile")
|
Keys.onDownPressed: {
|
||||||
|
FocusController.nextKeyDownItem()
|
||||||
|
}
|
||||||
|
|
||||||
clickedFunction: function() {
|
Keys.onLeftPressed: {
|
||||||
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
|
FocusController.nextKeyLeftItem()
|
||||||
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
|
}
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
Keys.onRightPressed: {
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
FocusController.nextKeyRightItem()
|
||||||
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
|
}
|
||||||
PageController.showNotificationMessage(message)
|
|
||||||
return
|
model: ProtocolsModel
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
implicitWidth: protocols.width
|
||||||
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: delegateContent
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg
|
||||||
|
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: clientSettings
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: protocolName + qsTr(" connection settings")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
visible: delegateContent.isClientSettingsVisible
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
if (isClientProtocolExists) {
|
||||||
|
switch (protocolIndex) {
|
||||||
|
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
}
|
||||||
|
PageController.goToPage(clientProtocolPage);
|
||||||
|
} else {
|
||||||
|
PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PageController.showBusyIndicator(true)
|
MouseArea {
|
||||||
InstallController.clearCachedProfile()
|
anchors.fill: clientSettings
|
||||||
PageController.showBusyIndicator(false)
|
cursorShape: Qt.PointingHandCursor
|
||||||
}
|
enabled: false
|
||||||
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: clearCacheButton
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: root.isClearCacheVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: removeButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
|
||||||
|
|
||||||
text: qsTr("Remove ")
|
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
|
||||||
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
|
||||||
InstallController.removeProcessedContainer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: delegateContent.isClientSettingsVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
LabelWithButtonType {
|
||||||
}
|
id: serverSettings
|
||||||
|
|
||||||
MouseArea {
|
Layout.fillWidth: true
|
||||||
anchors.fill: removeButton
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
text: protocolName + qsTr(" server settings")
|
||||||
enabled: false
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
visible: delegateContent.isServerSettingsVisible
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
switch (protocolIndex) {
|
||||||
|
case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
}
|
||||||
|
PageController.goToPage(serverProtocolPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: serverSettings
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: delegateContent.isServerSettingsVisible
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
footer: ColumnLayout {
|
||||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
width: header.width
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: clearCacheButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: root.isClearCacheVisible
|
||||||
|
|
||||||
|
text: qsTr("Clear profile")
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
|
||||||
|
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
|
||||||
|
PageController.showNotificationMessage(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.clearCachedProfile()
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
// if (!GC.isMobile()) {
|
||||||
|
// focusItem.forceActiveFocus()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: clearCacheButton
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
visible: root.isClearCacheVisible
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: removeButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
|
text: qsTr("Remove ")
|
||||||
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||||
|
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
||||||
|
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
|
InstallController.removeProcessedContainer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
focusItem.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: removeButton
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,20 +40,25 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: servers
|
id: servers
|
||||||
objectName: "servers"
|
objectName: "servers"
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
anchors.topMargin: 16
|
anchors.topMargin: 16
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
height: 500
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
model: ServersModel
|
model: ServersModel
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
implicitWidth: servers.width
|
implicitWidth: servers.width
|
||||||
implicitHeight: delegateContent.implicitHeight
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
@@ -172,6 +172,8 @@ PageType {
|
|||||||
|
|
||||||
enabled: root.pageEnabled
|
enabled: root.pageEnabled
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
model: SortFilterProxyModel {
|
model: SortFilterProxyModel {
|
||||||
id: proxySitesModel
|
id: proxySitesModel
|
||||||
sourceModel: SitesModel
|
sourceModel: SitesModel
|
||||||
@@ -191,7 +193,13 @@ PageType {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
|
id: delegateContent
|
||||||
|
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
@@ -228,6 +236,7 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: addSiteButton
|
anchors.fill: addSiteButton
|
||||||
anchors.bottomMargin: -24
|
anchors.bottomMargin: -24
|
||||||
@@ -299,7 +308,7 @@ PageType {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: 16
|
Layout.margins: 16
|
||||||
|
|
||||||
headerText: qsTr("Additional options")
|
headerText: qsTr("Import / Export Sites")
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
@@ -342,34 +351,6 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
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 {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,24 +374,22 @@ PageType {
|
|||||||
backButtonFunction: function() {
|
backButtonFunction: function() {
|
||||||
importSitesDrawer.closeTriggered()
|
importSitesDrawer.closeTriggered()
|
||||||
}
|
}
|
||||||
|
|
||||||
onFocusChanged: {
|
|
||||||
if (this.activeFocus) {
|
|
||||||
importSitesDrawerListView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: importSitesDrawerListView
|
|
||||||
|
|
||||||
anchors.top: importSitesDrawerBackButton.bottom
|
anchors.top: importSitesDrawerBackButton.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
header: ColumnLayout {
|
contentHeight: importSitesDrawerContent.height
|
||||||
width: importSitesDrawerListView.width
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: importSitesDrawerContent
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
Header2Type {
|
Header2Type {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -418,67 +397,49 @@ PageType {
|
|||||||
|
|
||||||
headerText: qsTr("Import a list of sites")
|
headerText: qsTr("Import a list of sites")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
model: importOptions
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
|
||||||
width: importSitesDrawerListView.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
|
id: importSitesButton2
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: title
|
text: qsTr("Replace site list")
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
clickedHandler()
|
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
||||||
|
qsTr("Sites files (*.json)"))
|
||||||
|
if (fileName !== "") {
|
||||||
|
importSitesDrawerContent.importSites(fileName, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: importSitesButton3
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("Add imported sites to existing ones")
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
||||||
|
qsTr("Sites files (*.json)"))
|
||||||
|
if (fileName !== "") {
|
||||||
|
importSitesDrawerContent.importSites(fileName, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function importSites(fileName, replaceExistingSites) {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
SitesController.importSites(fileName, replaceExistingSites)
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
importSitesDrawer.closeTriggered()
|
||||||
|
moreActionsDrawer.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property list<QtObject> importOptions: [
|
|
||||||
replaceOption,
|
|
||||||
addOption,
|
|
||||||
]
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: replaceOption
|
|
||||||
|
|
||||||
readonly property string title: qsTr("Replace site list")
|
|
||||||
readonly property var clickedHandler: function() {
|
|
||||||
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
|
||||||
qsTr("Sites files (*.json)"))
|
|
||||||
if (fileName !== "") {
|
|
||||||
root.importSites(fileName, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: addOption
|
|
||||||
|
|
||||||
readonly property string title: qsTr("Add imported sites to existing ones")
|
|
||||||
readonly property var clickedHandler: function() {
|
|
||||||
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
|
||||||
qsTr("Sites files (*.json)"))
|
|
||||||
if (fileName !== "") {
|
|
||||||
root.importSites(fileName, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function importSites(fileName, replaceExistingSites) {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
SitesController.importSites(fileName, replaceExistingSites)
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
importSitesDrawer.closeTriggered()
|
|
||||||
moreActionsDrawer.closeTriggered()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,31 +15,25 @@ import "../Components"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
FlickableType {
|
||||||
id: backButton
|
id: fl
|
||||||
|
|
||||||
anchors.top: parent.top
|
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.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
BackButtonType {
|
||||||
|
id: backButton
|
||||||
|
Layout.topMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -51,28 +45,53 @@ PageType {
|
|||||||
headerText: ApiServicesModel.getSelectedServiceData("name")
|
headerText: ApiServicesModel.getSelectedServiceData("name")
|
||||||
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
|
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
model: inputFields
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
LabelWithImageType {
|
LabelWithImageType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: 16
|
Layout.margins: 16
|
||||||
|
|
||||||
imageSource: imagePath
|
imageSource: "qrc:/images/controls/map-pin.svg"
|
||||||
leftText: lText
|
leftText: qsTr("For the region")
|
||||||
rightText: rText
|
rightText: ApiServicesModel.getSelectedServiceData("region")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
LabelWithImageType {
|
||||||
width: listView.width
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 16
|
||||||
|
|
||||||
spacing: 0
|
imageSource: "qrc:/images/controls/tag.svg"
|
||||||
|
leftText: qsTr("Price")
|
||||||
|
rightText: ApiServicesModel.getSelectedServiceData("price")
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithImageType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 16
|
||||||
|
|
||||||
|
imageSource: "qrc:/images/controls/history.svg"
|
||||||
|
leftText: qsTr("Work period")
|
||||||
|
rightText: ApiServicesModel.getSelectedServiceData("timeLimit")
|
||||||
|
|
||||||
|
visible: rightText !== ""
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithImageType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 16
|
||||||
|
|
||||||
|
imageSource: "qrc:/images/controls/gauge.svg"
|
||||||
|
leftText: qsTr("Speed")
|
||||||
|
rightText: ApiServicesModel.getSelectedServiceData("speed")
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithImageType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 16
|
||||||
|
|
||||||
|
imageSource: "qrc:/images/controls/info.svg"
|
||||||
|
leftText: qsTr("Features")
|
||||||
|
rightText: ""
|
||||||
|
}
|
||||||
|
|
||||||
ParagraphTextType {
|
ParagraphTextType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -85,7 +104,7 @@ PageType {
|
|||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
text: {
|
text: {
|
||||||
var text = ApiServicesModel.getSelectedServiceData("features")
|
var text = ApiServicesModel.getSelectedServiceData("features")
|
||||||
return text.replace("%1", LanguageModel.getCurrentSiteUrl("free"))
|
return text.replace("%1", LanguageModel.getCurrentSiteUrl())
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -94,84 +113,34 @@ PageType {
|
|||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: continueButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 32
|
|
||||||
Layout.bottomMargin: 32
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Connect")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
var endpoint = ApiServicesModel.getStoreEndpoint()
|
|
||||||
if (endpoint !== undefined && endpoint !== "") {
|
|
||||||
Qt.openUrlExternally(endpoint)
|
|
||||||
PageController.closePage()
|
|
||||||
PageController.closePage()
|
|
||||||
} else {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
ApiConfigsController.importServiceFromGateway()
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property list<QtObject> inputFields: [
|
BasicButtonType {
|
||||||
region,
|
id: continueButton
|
||||||
price,
|
|
||||||
timeLimit,
|
|
||||||
speed,
|
|
||||||
features
|
|
||||||
]
|
|
||||||
|
|
||||||
QtObject {
|
anchors.right: parent.right
|
||||||
id: region
|
anchors.left: parent.left
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
readonly property string imagePath: "qrc:/images/controls/map-pin.svg"
|
anchors.topMargin: 32
|
||||||
readonly property string lText: qsTr("For the region")
|
anchors.rightMargin: 16
|
||||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("region")
|
anchors.leftMargin: 16
|
||||||
property bool isVisible: true
|
anchors.bottomMargin: 32
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
text: qsTr("Connect")
|
||||||
id: price
|
|
||||||
|
|
||||||
readonly property string imagePath: "qrc:/images/controls/tag.svg"
|
clickedFunc: function() {
|
||||||
readonly property string lText: qsTr("Price")
|
var endpoint = ApiServicesModel.getStoreEndpoint()
|
||||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("price")
|
if (endpoint !== undefined && endpoint !== "") {
|
||||||
property bool isVisible: true
|
Qt.openUrlExternally(endpoint)
|
||||||
}
|
PageController.closePage()
|
||||||
|
PageController.closePage()
|
||||||
QtObject {
|
} else {
|
||||||
id: timeLimit
|
PageController.showBusyIndicator(true)
|
||||||
|
ApiConfigsController.importServiceFromGateway()
|
||||||
readonly property string imagePath: "qrc:/images/controls/history.svg"
|
PageController.showBusyIndicator(false)
|
||||||
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,77 +14,86 @@ import "../Config"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
ColumnLayout {
|
||||||
id: backButton
|
id: header
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
Layout.topMargin: 20
|
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
spacing: 0
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
BackButtonType {
|
||||||
}
|
id: backButton
|
||||||
|
Layout.topMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("VPN by Amnezia")
|
||||||
|
descriptionText: qsTr("Choose a VPN service that suits your needs.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: servicesListView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: header.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.topMargin: 16
|
anchors.topMargin: 16
|
||||||
|
|
||||||
header: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
headerText: qsTr("VPN by Amnezia")
|
|
||||||
descriptionText: qsTr("Choose a VPN service that suits your needs.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
model: ApiServicesModel
|
model: ApiServicesModel
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
width: listView.width
|
delegate: Item {
|
||||||
|
implicitWidth: servicesListView.width
|
||||||
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
enabled: isServiceAvailable
|
enabled: isServiceAvailable
|
||||||
|
|
||||||
CardWithIconsType {
|
ColumnLayout {
|
||||||
id: card
|
id: delegateContent
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.fill: parent
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerText: name
|
CardWithIconsType {
|
||||||
bodyText: cardDescription
|
id: card
|
||||||
footerText: price
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
onClicked: {
|
headerText: name
|
||||||
if (isServiceAvailable) {
|
bodyText: cardDescription
|
||||||
ApiServicesModel.setServiceIndex(index)
|
footerText: price
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
|
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (isServiceAvailable) {
|
||||||
|
ApiServicesModel.setServiceIndex(index)
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: clicked()
|
Keys.onEnterPressed: clicked()
|
||||||
Keys.onReturnPressed: clicked()
|
Keys.onReturnPressed: clicked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,21 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
|
model: variants
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
@@ -206,8 +216,6 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model: variants
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
@@ -226,9 +234,6 @@ PageType {
|
|||||||
leftImageSource: imageSource
|
leftImageSource: imageSource
|
||||||
|
|
||||||
onClicked: { handler() }
|
onClicked: { handler() }
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,41 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
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 {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
@@ -51,6 +78,8 @@ PageType {
|
|||||||
|
|
||||||
model: inputFields
|
model: inputFields
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
clip: true
|
||||||
|
reuseItems: true
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
@@ -148,9 +177,6 @@ PageType {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("starter-guide"))
|
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("starter-guide"))
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ PageType {
|
|||||||
|
|
||||||
SortFilterProxyModel {
|
SortFilterProxyModel {
|
||||||
id: proxyContainersModel
|
id: proxyContainersModel
|
||||||
|
|
||||||
sourceModel: ContainersModel
|
sourceModel: ContainersModel
|
||||||
filters: [
|
filters: [
|
||||||
ValueFilter {
|
ValueFilter {
|
||||||
@@ -41,98 +40,104 @@ PageType {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ButtonGroup {
|
FlickableType {
|
||||||
id: buttonGroup
|
id: fl
|
||||||
}
|
|
||||||
|
|
||||||
ListViewType {
|
|
||||||
id: listView
|
|
||||||
|
|
||||||
property int dockerContainer
|
|
||||||
property int containerDefaultPort
|
|
||||||
property int containerDefaultTransportProto
|
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
contentHeight: content.implicitHeight + setupLaterButton.anchors.bottomMargin
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
spacing: 16
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
header: ColumnLayout {
|
anchors.top: parent.top
|
||||||
width: listView.width
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
id: header
|
id: header
|
||||||
|
|
||||||
Layout.fillWidth: true
|
implicitWidth: parent.width
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerTextMaximumLineCount: 10
|
headerTextMaximumLineCount: 10
|
||||||
|
|
||||||
headerText: qsTr("Choose Installation Type")
|
headerText: qsTr("Choose Installation Type")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
model: proxyContainersModel
|
ButtonGroup {
|
||||||
currentIndex: 0
|
id: buttonGroup
|
||||||
|
}
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
ListView {
|
||||||
width: listView.width
|
id: containers
|
||||||
|
width: parent.width
|
||||||
|
height: containers.contentItem.height
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
CardType {
|
currentIndex: 0
|
||||||
id: card
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
model: proxyContainersModel
|
||||||
|
|
||||||
Layout.fillWidth: true
|
property int dockerContainer
|
||||||
Layout.rightMargin: 16
|
property int containerDefaultPort
|
||||||
Layout.leftMargin: 16
|
property int containerDefaultTransportProto
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
headerText: easySetupHeader
|
property bool isFocusable: true
|
||||||
bodyText: easySetupDescription
|
|
||||||
|
|
||||||
ButtonGroup.group: buttonGroup
|
delegate: Item {
|
||||||
|
implicitWidth: containers.width
|
||||||
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
onClicked: function() {
|
ColumnLayout {
|
||||||
isEasySetup = true
|
id: delegateContent
|
||||||
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
|
|
||||||
|
|
||||||
listView.dockerContainer = dockerContainer
|
anchors.top: parent.top
|
||||||
listView.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
|
anchors.left: parent.left
|
||||||
listView.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
CardType {
|
||||||
|
id: card
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
headerText: easySetupHeader
|
||||||
|
bodyText: easySetupDescription
|
||||||
|
|
||||||
|
ButtonGroup.group: buttonGroup
|
||||||
|
|
||||||
|
onClicked: function() {
|
||||||
|
isEasySetup = true
|
||||||
|
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
|
||||||
|
|
||||||
|
containers.dockerContainer = dockerContainer
|
||||||
|
containers.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
|
||||||
|
containers.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
Component.onCompleted: {
|
||||||
Keys.onEnterPressed: this.clicked()
|
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 {
|
DividerType {
|
||||||
Layout.fillWidth: true
|
implicitWidth: parent.width
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CardType {
|
CardType {
|
||||||
Layout.fillWidth: true
|
implicitWidth: parent.width
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Manual")
|
headerText: qsTr("Manual")
|
||||||
bodyText: qsTr("Choose a VPN protocol")
|
bodyText: qsTr("Choose a VPN protocol")
|
||||||
@@ -141,29 +146,25 @@ PageType {
|
|||||||
|
|
||||||
onClicked: function() {
|
onClicked: function() {
|
||||||
isEasySetup = false
|
isEasySetup = false
|
||||||
checked = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: continueButton
|
id: continueButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
implicitWidth: parent.width
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Continue")
|
text: qsTr("Continue")
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
if (root.isEasySetup) {
|
if (root.isEasySetup) {
|
||||||
ContainersModel.setProcessedContainerIndex(listView.dockerContainer)
|
ContainersModel.setProcessedContainerIndex(containers.dockerContainer)
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||||
InstallController.install(listView.dockerContainer,
|
InstallController.install(containers.dockerContainer,
|
||||||
listView.containerDefaultPort,
|
containers.containerDefaultPort,
|
||||||
listView.containerDefaultTransportProto)
|
containers.containerDefaultTransportProto)
|
||||||
} else {
|
} else {
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardProtocols)
|
PageController.goToPage(PageEnum.PageSetupWizardProtocols)
|
||||||
}
|
}
|
||||||
@@ -173,11 +174,9 @@ PageType {
|
|||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: setupLaterButton
|
id: setupLaterButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
implicitWidth: parent.width
|
||||||
Layout.topMargin: 8
|
anchors.topMargin: 8
|
||||||
Layout.bottomMargin: 24
|
anchors.bottomMargin: 24
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
@@ -186,6 +185,9 @@ PageType {
|
|||||||
textColor: AmneziaStyle.color.paleGray
|
textColor: AmneziaStyle.color.paleGray
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
|
|
||||||
|
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
visible: {
|
visible: {
|
||||||
if (PageController.isTriggeredByConnectButton()) {
|
if (PageController.isTriggeredByConnectButton()) {
|
||||||
PageController.setTriggeredByConnectButton(false)
|
PageController.setTriggeredByConnectButton(false)
|
||||||
@@ -203,15 +205,5 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
var item = listView.itemAtIndex(listView.currentIndex)
|
|
||||||
if (item !== null) {
|
|
||||||
var button = item.children[0]
|
|
||||||
button.checked = true
|
|
||||||
button.clicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,76 +85,92 @@ PageType {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
currentIndex: -1
|
Column {
|
||||||
|
id: content
|
||||||
|
|
||||||
model: proxyContainersModel
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
spacing: 16
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
BaseHeaderType {
|
ListView {
|
||||||
Layout.fillWidth: true
|
id: container
|
||||||
Layout.topMargin: 20
|
width: parent.width
|
||||||
Layout.leftMargin: 16
|
height: container.contentItem.height
|
||||||
Layout.rightMargin: 16
|
currentIndex: -1
|
||||||
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
model: proxyContainersModel
|
||||||
|
|
||||||
headerText: qsTr("Installing")
|
delegate: Item {
|
||||||
descriptionText: name
|
implicitWidth: container.width
|
||||||
}
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
||||||
ProgressBarType {
|
ColumnLayout {
|
||||||
id: progressBar
|
id: delegateContent
|
||||||
|
|
||||||
Layout.fillWidth: true
|
anchors.fill: parent
|
||||||
Layout.topMargin: 32
|
anchors.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
anchors.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
Timer {
|
BaseHeaderType {
|
||||||
id: timer
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 20
|
||||||
|
|
||||||
interval: 300
|
headerText: qsTr("Installing")
|
||||||
repeat: true
|
descriptionText: name
|
||||||
running: root.isTimerRunning
|
}
|
||||||
onTriggered: {
|
|
||||||
progressBar.value += 0.003
|
ProgressBarType {
|
||||||
|
id: progressBar
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 32
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: timer
|
||||||
|
|
||||||
|
interval: 300
|
||||||
|
repeat: true
|
||||||
|
running: root.isTimerRunning
|
||||||
|
onTriggered: {
|
||||||
|
progressBar.value += 0.003
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
id: progressText
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
|
||||||
|
text: root.progressBarText
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: cancelIntallationButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
|
||||||
|
visible: root.isCancelButtonVisible
|
||||||
|
|
||||||
|
text: qsTr("Cancel installation")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
InstallController.cancelInstallation()
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParagraphTextType {
|
|
||||||
id: progressText
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 8
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: root.progressBarText
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: cancelIntallationButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
visible: root.isCancelButtonVisible
|
|
||||||
|
|
||||||
text: qsTr("Cancel installation")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
InstallController.cancelInstallation()
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,239 +29,256 @@ PageType {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
BackButtonType {
|
FlickableType {
|
||||||
id: backButton
|
anchors.fill: parent
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
anchors.top: parent.top
|
Column {
|
||||||
anchors.left: parent.left
|
id: content
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.topMargin: 20
|
|
||||||
|
|
||||||
onFocusChanged: {
|
anchors.top: parent.top
|
||||||
if (this.activeFocus) {
|
anchors.left: parent.left
|
||||||
listView.positionViewAtBeginning()
|
anchors.right: parent.right
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: processedContainerListView
|
||||||
|
width: parent.width
|
||||||
|
height: contentItem.height
|
||||||
|
currentIndex: -1
|
||||||
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
model: proxyContainersModel
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
property bool isFocusable: true
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
currentIndex: -1
|
Keys.onTabPressed: {
|
||||||
|
FocusController.nextKeyTabItem()
|
||||||
model: proxyContainersModel
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
|
||||||
width: listView.width
|
|
||||||
|
|
||||||
BaseHeaderType {
|
|
||||||
id: header
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Installing %1").arg(name)
|
|
||||||
descriptionText: description
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: showDetailsButton
|
|
||||||
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
implicitHeight: 32
|
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
|
||||||
pressedColor: AmneziaStyle.color.sheerWhite
|
|
||||||
disabledColor: AmneziaStyle.color.mutedGray
|
|
||||||
textColor: AmneziaStyle.color.goldenApricot
|
|
||||||
|
|
||||||
text: qsTr("More detailed")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
showDetailsDrawer.openTriggered()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DrawerType2 {
|
Keys.onBacktabPressed: {
|
||||||
id: showDetailsDrawer
|
FocusController.previousKeyTabItem()
|
||||||
parent: root
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
Keys.onUpPressed: {
|
||||||
expandedHeight: parent.height * 0.9
|
FocusController.nextKeyUpItem()
|
||||||
expandedStateContent: Item {
|
}
|
||||||
implicitHeight: showDetailsDrawer.expandedHeight
|
|
||||||
|
|
||||||
BackButtonType {
|
Keys.onDownPressed: {
|
||||||
id: showDetailsBackButton
|
FocusController.nextKeyDownItem()
|
||||||
|
}
|
||||||
|
|
||||||
anchors.top: parent.top
|
Keys.onLeftPressed: {
|
||||||
anchors.left: parent.left
|
FocusController.nextKeyLeftItem()
|
||||||
anchors.right: parent.right
|
}
|
||||||
anchors.topMargin: 16
|
|
||||||
|
|
||||||
backButtonFunction: function() {
|
Keys.onRightPressed: {
|
||||||
showDetailsDrawer.closeTriggered()
|
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
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ListViewType {
|
BaseHeaderType {
|
||||||
id: showDetailsListView
|
id: header
|
||||||
|
|
||||||
anchors.top: showDetailsBackButton.bottom
|
Layout.fillWidth: true
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
headerText: qsTr("Installing %1").arg(name)
|
||||||
width: showDetailsListView.width
|
descriptionText: description
|
||||||
|
}
|
||||||
|
|
||||||
Header2Type {
|
BasicButtonType {
|
||||||
id: showDetailsDrawerHeader
|
id: showDetailsButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.topMargin: 16
|
||||||
Layout.topMargin: 16
|
Layout.leftMargin: -8
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
headerText: name
|
implicitHeight: 32
|
||||||
|
|
||||||
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
|
disabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
textColor: AmneziaStyle.color.goldenApricot
|
||||||
|
|
||||||
|
text: qsTr("More detailed")
|
||||||
|
KeyNavigation.tab: transportProtoSelector
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
showDetailsDrawer.openTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model: 1 // fake model to force the ListView to be created without a model
|
DrawerType2 {
|
||||||
|
id: showDetailsDrawer
|
||||||
|
parent: root
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
anchors.fill: parent
|
||||||
width: showDetailsListView.width
|
expandedHeight: parent.height * 0.9
|
||||||
|
expandedStateContent: Item {
|
||||||
|
implicitHeight: showDetailsDrawer.expandedHeight
|
||||||
|
|
||||||
ParagraphTextType {
|
BackButtonType {
|
||||||
Layout.fillWidth: true
|
id: showDetailsBackButton
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: detailedDescription
|
anchors.top: parent.top
|
||||||
textFormat: Text.MarkdownText
|
anchors.left: parent.left
|
||||||
}
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 16
|
||||||
|
|
||||||
Rectangle {
|
backButtonFunction: function() {
|
||||||
Layout.fillHeight: true
|
showDetailsDrawer.closeTriggered()
|
||||||
Layout.leftMargin: 16
|
}
|
||||||
Layout.rightMargin: 16
|
}
|
||||||
|
|
||||||
color: AmneziaStyle.color.transparent
|
FlickableType {
|
||||||
}
|
id: fl
|
||||||
}
|
anchors.top: showDetailsBackButton.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
contentHeight: {
|
||||||
|
var emptySpaceHeight = parent.height - showDetailsBackButton.implicitHeight - showDetailsBackButton.anchors.topMargin
|
||||||
|
return (showDetailsDrawerContent.height > emptySpaceHeight) ?
|
||||||
|
showDetailsDrawerContent.height : emptySpaceHeight
|
||||||
|
}
|
||||||
|
|
||||||
footer: ColumnLayout {
|
ColumnLayout {
|
||||||
width: showDetailsListView.width
|
id: showDetailsDrawerContent
|
||||||
|
|
||||||
BasicButtonType {
|
anchors.top: parent.top
|
||||||
id: showDetailsCloseButton
|
anchors.left: parent.left
|
||||||
Layout.fillWidth: true
|
anchors.right: parent.right
|
||||||
Layout.bottomMargin: 32
|
anchors.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
anchors.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Close")
|
Header2Type {
|
||||||
|
id: showDetailsDrawerHeader
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
clickedFunc: function() {
|
headerText: name
|
||||||
showDetailsDrawer.closeTriggered()
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
|
text: detailedDescription
|
||||||
|
textFormat: Text.MarkdownText
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
color: AmneziaStyle.color.transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: showDetailsCloseButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.bottomMargin: 32
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
|
text: qsTr("Close")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
showDetailsDrawer.closeTriggered()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
id: transportProtoHeader
|
||||||
|
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Network protocol")
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportProtoSelector {
|
||||||
|
id: transportProtoSelector
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
rootWidth: root.width
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: port
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
color: AmneziaStyle.color.transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: installButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.bottomMargin: 32
|
||||||
|
|
||||||
|
text: qsTr("Install")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
if (!port.textField.acceptableInput &&
|
||||||
|
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" &&
|
||||||
|
ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") {
|
||||||
|
port.errorText = qsTr("The port must be in the range of 1 to 65535")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.install(dockerContainer, port.textField.text, transportProtoSelector.currentIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
|
||||||
|
|
||||||
|
if (ProtocolProps.defaultPort(defaultContainerProto) < 0) {
|
||||||
|
port.visible = false
|
||||||
|
} else {
|
||||||
|
port.textField.text = ProtocolProps.getPortForInstall(defaultContainerProto)
|
||||||
|
}
|
||||||
|
transportProtoSelector.currentIndex = ProtocolProps.defaultTransportProto(defaultContainerProto)
|
||||||
|
|
||||||
|
port.enabled = ProtocolProps.defaultPortChangeable(defaultContainerProto)
|
||||||
|
var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto)
|
||||||
|
transportProtoSelector.visible = protocolSelectorVisible
|
||||||
|
transportProtoHeader.visible = protocolSelectorVisible
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParagraphTextType {
|
|
||||||
id: transportProtoHeader
|
|
||||||
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Network protocol")
|
|
||||||
}
|
|
||||||
|
|
||||||
TransportProtoSelector {
|
|
||||||
id: transportProtoSelector
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
rootWidth: root.width
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: port
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
color: AmneziaStyle.color.transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: installButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.bottomMargin: 32
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Install")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
if (!port.textField.acceptableInput &&
|
|
||||||
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" &&
|
|
||||||
ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") {
|
|
||||||
port.errorText = qsTr("The port must be in the range of 1 to 65535")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.install(dockerContainer, port.textField.text, transportProtoSelector.currentIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
|
|
||||||
|
|
||||||
if (ProtocolProps.defaultPort(defaultContainerProto) < 0) {
|
|
||||||
port.visible = false
|
|
||||||
} else {
|
|
||||||
port.textField.text = ProtocolProps.getPortForInstall(defaultContainerProto)
|
|
||||||
}
|
|
||||||
transportProtoSelector.currentIndex = ProtocolProps.defaultTransportProto(defaultContainerProto)
|
|
||||||
|
|
||||||
port.enabled = ProtocolProps.defaultPortChangeable(defaultContainerProto)
|
|
||||||
var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto)
|
|
||||||
transportProtoSelector.visible = protocolSelectorVisible
|
|
||||||
transportProtoHeader.visible = protocolSelectorVisible
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,21 +42,19 @@ PageType {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
property bool isFocusable: true
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
@@ -74,8 +72,9 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model: proxyContainersModel
|
model: proxyContainersModel
|
||||||
|
clip: true
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
reuseItems: true
|
||||||
snapMode: ListView.SnapToItem
|
snapMode: ListView.SnapToItem
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
@@ -88,9 +87,9 @@ PageType {
|
|||||||
descriptionText: description
|
descriptionText: description
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
clickedFunction: function () {
|
clickedFunction: function() {
|
||||||
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index));
|
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index))
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings);
|
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,31 +13,25 @@ import "../Config"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
BackButtonType {
|
FlickableType {
|
||||||
id: backButton
|
id: fl
|
||||||
|
|
||||||
anchors.top: parent.top
|
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.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.height
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
|
BackButtonType {
|
||||||
|
id: backButton
|
||||||
|
Layout.topMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -47,13 +41,6 @@ PageType {
|
|||||||
headerText: qsTr("Connection key")
|
headerText: qsTr("Connection key")
|
||||||
descriptionText: qsTr("A line that starts with vpn://...")
|
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 {
|
TextFieldWithHeaderType {
|
||||||
id: textKey
|
id: textKey
|
||||||
@@ -73,26 +60,23 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
footer: ColumnLayout {
|
BasicButtonType {
|
||||||
width: listView.width
|
id: continueButton
|
||||||
|
|
||||||
BasicButtonType {
|
anchors.bottom: parent.bottom
|
||||||
id: continueButton
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.bottomMargin: 32
|
||||||
|
|
||||||
Layout.fillWidth: true
|
text: qsTr("Continue")
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.bottomMargin: 32
|
|
||||||
|
|
||||||
text: qsTr("Continue")
|
clickedFunc: function() {
|
||||||
|
if (ImportController.extractConfigFromData(textKey.textField.text)) {
|
||||||
clickedFunc: function() {
|
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||||
if (ImportController.extractConfigFromData(textKey.textField.text)) {
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,6 @@ PageType {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(backButton.enabled && backButton.activeFocus) {
|
|
||||||
listView.positionViewAtBeginning()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -52,29 +46,27 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewType {
|
FlickableType {
|
||||||
id: listView
|
id: fl
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
contentHeight: content.implicitHeight + connectButton.implicitHeight
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
ColumnLayout {
|
||||||
width: listView.width
|
id: content
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("New connection")
|
headerText: qsTr("New connection")
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 32
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
visible: fileName.text !== ""
|
visible: fileName.text !== ""
|
||||||
@@ -96,9 +88,7 @@ PageType {
|
|||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: showContentButton
|
id: showContentButton
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: -8
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
implicitHeight: 32
|
implicitHeight: 32
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
@@ -109,6 +99,8 @@ PageType {
|
|||||||
|
|
||||||
text: showContent ? qsTr("Collapse content") : qsTr("Show content")
|
text: showContent ? qsTr("Collapse content") : qsTr("Show content")
|
||||||
|
|
||||||
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
showContent = !showContent
|
showContent = !showContent
|
||||||
}
|
}
|
||||||
@@ -116,28 +108,16 @@ PageType {
|
|||||||
|
|
||||||
CheckBoxType {
|
CheckBoxType {
|
||||||
id: cloakingCheckBox
|
id: cloakingCheckBox
|
||||||
objectName: "cloakingCheckBox"
|
|
||||||
|
|
||||||
visible: ImportController.isNativeWireGuardConfig()
|
visible: ImportController.isNativeWireGuardConfig()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
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.")
|
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 {
|
WarningType {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
textString: ImportController.getMaliciousWarningText()
|
textString: ImportController.getMaliciousWarningText()
|
||||||
textFormat: Qt.RichText
|
textFormat: Qt.RichText
|
||||||
@@ -150,10 +130,8 @@ PageType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WarningType {
|
WarningType {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.fillWidth: true
|
||||||
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.")
|
textString: qsTr("Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data.")
|
||||||
|
|
||||||
@@ -162,10 +140,7 @@ PageType {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.bottomMargin: 48
|
Layout.bottomMargin: 48
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
implicitHeight: configContent.implicitHeight
|
implicitHeight: configContent.implicitHeight
|
||||||
|
|
||||||
@@ -186,38 +161,34 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
footer: ColumnLayout {
|
Rectangle {
|
||||||
width: listView.width
|
anchors.fill: columnContent
|
||||||
|
anchors.bottomMargin: -24
|
||||||
|
color: AmneziaStyle.color.midnightBlack
|
||||||
|
opacity: 0.8
|
||||||
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
ColumnLayout {
|
||||||
id: connectButton
|
id: columnContent
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
Layout.fillWidth: true
|
BasicButtonType {
|
||||||
Layout.topMargin: 16
|
id: connectButton
|
||||||
Layout.bottomMargin: 32
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
Layout.bottomMargin: 32
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Connect")
|
text: qsTr("Connect")
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
const headerItem = listView.headerItem;
|
if (cloakingCheckBox.checked) {
|
||||||
if (!headerItem) {
|
ImportController.processNativeWireGuardConfig()
|
||||||
console.error("Header item not found in ListView")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const cloakingCheckBoxItem = listView.findChildWithObjectName(headerItem.children, "cloakingCheckBox");
|
|
||||||
if (!cloakingCheckBoxItem) {
|
|
||||||
console.error("cloakingCheckBox not found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cloakingCheckBoxItem.checked) {
|
|
||||||
ImportController.processNativeWireGuardConfig()
|
|
||||||
}
|
|
||||||
ImportController.importConfig()
|
|
||||||
}
|
}
|
||||||
|
ImportController.importConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import "../Controls2/TextTypes"
|
|||||||
import "../Components"
|
import "../Components"
|
||||||
import "../Config"
|
import "../Config"
|
||||||
|
|
||||||
|
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -43,6 +42,10 @@ PageType {
|
|||||||
target: ExportController
|
target: ExportController
|
||||||
|
|
||||||
function onGenerateConfig(type) {
|
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)
|
PageController.showBusyIndicator(true)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -52,36 +55,54 @@ PageType {
|
|||||||
}
|
}
|
||||||
case PageShare.ConfigType.OpenVpn: {
|
case PageShare.ConfigType.OpenVpn: {
|
||||||
ExportController.generateOpenVpnConfig(clientNameTextField.textField.text)
|
ExportController.generateOpenVpnConfig(clientNameTextField.textField.text)
|
||||||
|
shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config")
|
||||||
|
shareConnectionDrawer.configExtension = ".ovpn"
|
||||||
|
shareConnectionDrawer.configFileName = "amnezia_for_openvpn"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case PageShare.ConfigType.WireGuard: {
|
case PageShare.ConfigType.WireGuard: {
|
||||||
ExportController.generateWireGuardConfig(clientNameTextField.textField.text)
|
ExportController.generateWireGuardConfig(clientNameTextField.textField.text)
|
||||||
|
shareConnectionDrawer.configCaption = qsTr("Save WireGuard config")
|
||||||
|
shareConnectionDrawer.configExtension = ".conf"
|
||||||
|
shareConnectionDrawer.configFileName = "amnezia_for_wireguard"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case PageShare.ConfigType.Awg: {
|
case PageShare.ConfigType.Awg: {
|
||||||
ExportController.generateAwgConfig(clientNameTextField.textField.text)
|
ExportController.generateAwgConfig(clientNameTextField.textField.text)
|
||||||
|
shareConnectionDrawer.configCaption = qsTr("Save AmneziaWG config")
|
||||||
|
shareConnectionDrawer.configExtension = ".conf"
|
||||||
|
shareConnectionDrawer.configFileName = "amnezia_for_awg"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case PageShare.ConfigType.ShadowSocks: {
|
case PageShare.ConfigType.ShadowSocks: {
|
||||||
ExportController.generateShadowSocksConfig()
|
ExportController.generateShadowSocksConfig()
|
||||||
|
shareConnectionDrawer.configCaption = qsTr("Save Shadowsocks config")
|
||||||
|
shareConnectionDrawer.configExtension = ".json"
|
||||||
|
shareConnectionDrawer.configFileName = "amnezia_for_shadowsocks"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case PageShare.ConfigType.Cloak: {
|
case PageShare.ConfigType.Cloak: {
|
||||||
ExportController.generateCloakConfig()
|
ExportController.generateCloakConfig()
|
||||||
|
shareConnectionDrawer.configCaption = qsTr("Save Cloak config")
|
||||||
|
shareConnectionDrawer.configExtension = ".json"
|
||||||
|
shareConnectionDrawer.configFileName = "amnezia_for_cloak"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case PageShare.ConfigType.Xray: {
|
case PageShare.ConfigType.Xray: {
|
||||||
ExportController.generateXrayConfig(clientNameTextField.textField.text)
|
ExportController.generateXrayConfig(clientNameTextField.textField.text)
|
||||||
|
shareConnectionDrawer.configCaption = qsTr("Save XRay config")
|
||||||
|
shareConnectionDrawer.configExtension = ".json"
|
||||||
|
shareConnectionDrawer.configFileName = "amnezia_for_xray"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageShareConnection)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onExportErrorOccurred(error) {
|
function onExportErrorOccurred(error) {
|
||||||
|
shareConnectionDrawer.closeTriggered()
|
||||||
|
|
||||||
PageController.showErrorMessage(error)
|
PageController.showErrorMessage(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,9 +256,6 @@ PageType {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
accessTypeSelector.currentIndex = 0
|
accessTypeSelector.currentIndex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HorizontalRadioButton {
|
HorizontalRadioButton {
|
||||||
@@ -254,9 +272,6 @@ PageType {
|
|||||||
ServersModel.getProcessedServerCredentials())
|
ServersModel.getProcessedServerCredentials())
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: this.clicked()
|
|
||||||
Keys.onReturnPressed: this.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,6 +525,9 @@ PageType {
|
|||||||
text: qsTr("Share")
|
text: qsTr("Share")
|
||||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||||
|
|
||||||
|
|
||||||
|
parentFlickable: a
|
||||||
|
|
||||||
clickedFunc: function(){
|
clickedFunc: function(){
|
||||||
if (clientNameTextField.textField.text !== "") {
|
if (clientNameTextField.textField.text !== "") {
|
||||||
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
|
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
|
||||||
@@ -808,6 +826,9 @@ PageType {
|
|||||||
root.revokeConfig(index)
|
root.revokeConfig(index)
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
// focusItem1.forceActiveFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
@@ -821,4 +842,9 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShareConnectionDrawer {
|
||||||
|
id: shareConnectionDrawer
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,329 +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"
|
|
||||||
|
|
||||||
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\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user