Compare commits

...

54 Commits

Author SHA1 Message Date
KsZnak 7c560d709b Update amneziavpn_fa_IR.ts 2024-02-24 22:16:18 +02:00
pokamest ac234b77e2 Merge pull request #638 from amnezia-vpn/update/update_ts
Update all translations
2024-02-24 06:59:50 -08:00
pokamest d34cb8898f Update all translations 2024-02-24 11:51:22 +00:00
pokamest 13aadbda64 Merge pull request #637 from amnezia-vpn/bugfix/connection-drawer-close-button
fixed connection drawer close button
2024-02-23 09:56:52 -08:00
agalehaga c7c7c8eb01 added export awg native format (#635)
add export awg native format
2024-02-23 17:55:59 +00:00
vladimir.kuznetsov b1e5bba33f fixed connection drawer close button 2024-02-23 22:51:46 +05:00
pokamest 474e7c6d62 Merge pull request #634 from amnezia-vpn/update/gh_actions_qt_update
Update Qt in deploy.yml
2024-02-22 06:02:04 -08:00
pokamest 794ec921b8 Update Qt in deploy.yml 2024-02-22 13:28:37 +00:00
pokamest b674240362 Merge pull request #632 from amnezia-vpn/refactoring/changing-settings-item-location
moving settings item to other settings page
2024-02-22 05:02:13 -08:00
pokamest a768c7c451 Merge pull request #633 from rodionos/patch-1
MacOS build: increase image size to 256Mb
2024-02-22 04:58:21 -08:00
Sergei Rodionov 28d2a4ec2c MacOS build: increase image size to 256Mb
In my case, using Qt 6.6.2, the size of the AmneziaVPN.dmg file is 226Mb so a higher image size is needed for the hdiutil command.
2024-02-22 13:57:58 +03:00
Shehab Ahmed 9f1210d18f changed the location of Auto connect item from settings connections page to settings application page 2024-02-22 02:31:51 +02:00
pokamest 3012559627 Merge pull request #630 from amnezia-vpn/feature/api-containers-listview
for api servers, removed the ability to select a container
2024-02-21 11:03:18 -08:00
vladimir.kuznetsov b3ed57aee7 for api servers, removed the ability to select a container 2024-02-21 23:41:47 +05:00
pokamest 89d0a8107d Merge pull request #620 from amnezia-vpn/translations/fix-for-pr618
Fix translation for #618
2024-02-21 06:03:12 -08:00
Andrey Zaharow 6c0b71bd1b Fix translation on About Page (#618)
Fix About Page
2024-02-21 14:01:53 +00:00
Nethius 61abf74b2d feature/page-home-split-tunneling (#540)
Added split tunneling button on home page
2024-02-21 11:27:27 +00:00
pokamest 21fdf02921 Merge pull request #625 from amnezia-vpn/bugfix/default-server-default-container-update
fixed the use of defaultServerDefaultContainerChanged
2024-02-21 03:22:09 -08:00
vladimir.kuznetsov 7a245d80ee fixed the use of defaultServerDefaultContainerChanged 2024-02-21 13:06:39 +05:00
KsZnak da85922f23 Update amneziavpn_zh_CN.ts (#617)
Update amneziavpn_zh_CN.ts
2024-02-20 20:49:26 +00:00
pokamest a5356b6319 Merge pull request #623 from amnezia-vpn/update/Arabic-translation
updated the Arabic translation for fixing some sentences
2024-02-20 12:47:41 -08:00
KsZnak 3828891b9b Update amneziavpn_fa_IR.ts (#622)
Update amneziavpn_fa_IR.ts
2024-02-20 20:46:23 +00:00
pokamest 15d866ce04 WG/AWG ipv6 fix (#621)
WG/AWG ipv6 fix
2024-02-20 19:05:36 +00:00
Shehab Ahmed 560eb3d620 updated the Arabic translation for fixing some sentences 2024-02-20 20:37:19 +02:00
Andrey Zaharow ac894254cc Fix translation for #618 2024-02-20 00:23:20 +01:00
pokamest 17e3fbde25 Merge pull request #616 from amnezia-vpn/bugfix/cursor-changing-fix
Fix cursor change when hover over elements
2024-02-19 12:20:46 -08:00
Andrey Zaharow ee11a8410c Fix cursor change when hover over elements 2024-02-19 18:28:29 +01:00
pokamest ff5c51cfd9 Merge pull request #615 from amnezia-vpn/KsZnak-patch-1
Update amneziavpn_ru.ts
2024-02-19 07:10:49 -08:00
Nethius b3943ae5e3 serversModel cleanup (#599) 2024-02-19 14:54:15 +00:00
pokamest a32952fde6 Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText for
all TextFields
2024-02-19 14:06:18 +00:00
isamnezia 9c4ee4014d Fix for Codacy: variable name should be between 3 and 40 characters long (#608)
Tiny fixes for iOS
2024-02-19 13:13:10 +00:00
KsZnak dc9069f1f4 Update_2_amneziavpn_ru.ts
Add new change
2024-02-19 13:37:40 +02:00
pokamest e402cacc05 Merge pull request #614 from amnezia-vpn/bugfix/translations
returned translation files to commit fab167bb34a9f7199359e3d8589a1cd1…
2024-02-19 02:23:39 -08:00
vladimir.kuznetsov a98cd248d6 returned translation files to commit fab167bb34 2024-02-19 09:31:31 +05:00
pokamest 00fbfb6a01 Merge pull request #611 from amnezia-vpn/refactoring/show-installed-containers-first
show installed protocols first
2024-02-18 11:10:37 -08:00
vladimir.kuznetsov 86c31c3766 show installed protocols first in services tab and page home containers listview 2024-02-18 13:24:21 +05:00
agalehaga 698cfe910c add navigation using enter + buttons will be clicked if enter (if but… (#556)
Enter navigation
2024-02-17 21:09:05 +00:00
pokamest 16db23c159 Rewrite sftp file copy to Qt way (#562)
Rewrite sftp file copy to Qt way
2024-02-17 21:07:17 +00:00
Andrey Zaharow b05a5ee1c6 fix connection button behavior (#595)
Fix connection button behavior
2024-02-17 19:57:31 +00:00
pokamest 8cb298937f Merge pull request #604 from amnezia-vpn/KsZnak-ru_translate
Update amneziavpn_ru.ts
2024-02-17 11:52:18 -08:00
Andrey Zaharow 68fe20ddf6 UI fixes (#596)
UI fixes
2024-02-17 19:48:41 +00:00
KsZnak fab167bb34 Update amneziavpn_ru.ts 2024-02-17 20:29:25 +02:00
isamnezia f640d4b5f5 Remove config string dependency (#577)
Remove WG/AWG config string dependency
2024-02-16 10:30:00 +00:00
Nethius 074562b141 feature/custom-drawer (#563)
Replaced all the DrawerType with DrawerType2
2024-02-16 10:24:06 +00:00
Shehab Ahmed fd030a5fd4 Arabic translation (#594)
added Arabic translation
2024-02-16 10:19:47 +00:00
albexk 82fa6b13c6 Fix foreground service type (#592)
Fix foreground service type
2024-02-14 16:35:40 +00:00
pokamest bf16298c40 Version bump - 4.4.0.0 2024-02-13 21:10:47 +00:00
pokamest bcebb0a2b5 Merge pull request #580 from amnezia-vpn/feature/update-cloak-binary
Update AWG and Cloak libraries
2024-02-13 12:03:02 -08:00
pokamest b27442cf74 Merge pull request #583 from amnezia-vpn/bugfix/double_clear_server_from_amnezia
fixed bug with double button clear server from amnezia software
2024-02-13 07:50:35 -08:00
Nethius 92fbbd4812 bugfix/default-container-index (#578)
fixed get/set DefaultContainer
2024-02-13 15:20:13 +00:00
agalehaga 321ed810e3 fixed bug with double button clear server from amnezia software 2024-02-13 15:16:04 +02:00
albexk 17ff530683 Merge branch 'fix/android' into feature/update-cloak-binary 2024-02-13 12:32:36 +03:00
albexk 2b413736a4 Build with new version of awg lib. Move GoBackend to org.amnezia.vpn.protocol.wireguard package. 2024-02-13 12:30:55 +03:00
Mykola Baibuz 0b8f3c9d9d Update Cloak binary to v2.8.0 2024-02-12 21:01:44 +02:00
94 changed files with 6945 additions and 2782 deletions
+7 -7
View File
@@ -14,8 +14,8 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
env: env:
QT_VERSION: 6.5.1 QT_VERSION: 6.6.2
QIF_VERSION: 4.6 QIF_VERSION: 4.7
steps: steps:
- name: 'Install Qt' - name: 'Install Qt'
@@ -72,8 +72,8 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
env: env:
QT_VERSION: 6.5.1 QT_VERSION: 6.6.2
QIF_VERSION: 4.6 QIF_VERSION: 4.7
BUILD_ARCH: 64 BUILD_ARCH: 64
steps: steps:
@@ -134,7 +134,7 @@ jobs:
runs-on: macos-13 runs-on: macos-13
env: env:
QT_VERSION: 6.5.2 QT_VERSION: 6.6.2
CC: cc CC: cc
CXX: c++ CXX: c++
@@ -227,7 +227,7 @@ 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
QIF_VERSION: 4.6 QIF_VERSION: 4.7
steps: steps:
- name: 'Setup xcode' - name: 'Setup xcode'
@@ -286,7 +286,7 @@ jobs:
env: env:
ANDROID_BUILD_PLATFORM: android-34 ANDROID_BUILD_PLATFORM: android-34
QT_VERSION: 6.6.1 QT_VERSION: 6.6.2
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools' QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
steps: steps:
+3
View File
@@ -131,3 +131,6 @@ client/3rd/ShadowSocks/ss_ios.xcconfig
# UML generated pics # UML generated pics
out/ out/
# CMake files
CMakeFiles/
+2 -2
View File
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN) set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.3.0.0 project(${PROJECT} VERSION 4.4.0.0
DESCRIPTION "AmneziaVPN" DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/" HOMEPAGE_URL "https://amnezia.org/"
) )
@@ -11,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 44) set(APP_ANDROID_VERSION_CODE 46)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux") set(MZ_PLATFORM_NAME "linux")
+10
View File
@@ -15,6 +15,15 @@ set(PACKAGES
Core5Compat Concurrent LinguistTools Core5Compat Concurrent LinguistTools
) )
execute_process(
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMAND git rev-parse --short HEAD
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
if(IOS) if(IOS)
set(PACKAGES ${PACKAGES} Multimedia) set(PACKAGES ${PACKAGES} Multimedia)
endif() endif()
@@ -57,6 +66,7 @@ set(AMNEZIAVPN_TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts ${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts ${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_fa_IR.ts ${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_fa_IR.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ar.ts
) )
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui) file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)
+16 -7
View File
@@ -286,13 +286,16 @@ void AmneziaApplication::initModels()
m_containersModel.reset(new ContainersModel(this)); m_containersModel.reset(new ContainersModel(this));
m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get()); m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get());
m_defaultServerContainersModel.reset(new ContainersModel(this));
m_engine->rootContext()->setContextProperty("DefaultServerContainersModel", m_defaultServerContainersModel.get());
m_serversModel.reset(new ServersModel(m_settings, this)); m_serversModel.reset(new ServersModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get()); m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
connect(m_serversModel.get(), &ServersModel::containersUpdated, m_containersModel.get(), connect(m_serversModel.get(), &ServersModel::containersUpdated, m_containersModel.get(),
&ContainersModel::updateModel); &ContainersModel::updateModel);
connect(m_serversModel.get(), &ServersModel::defaultContainerChanged, m_containersModel.get(), connect(m_serversModel.get(), &ServersModel::defaultServerContainersUpdated, m_defaultServerContainersModel.get(),
&ContainersModel::setDefaultContainer); &ContainersModel::updateModel);
m_containersModel->setDefaultContainer(m_serversModel->getDefaultContainer()); // make better? m_serversModel->resetModel();
m_languageModel.reset(new LanguageModel(m_settings, this)); m_languageModel.reset(new LanguageModel(m_settings, this));
m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get()); m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
@@ -336,7 +339,7 @@ void AmneziaApplication::initModels()
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, this, connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, this,
[this](const QString &clientId, const QString &clientName, const DockerContainer container, [this](const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials) { ServerCredentials credentials) {
m_serversModel->reloadContainerConfig(); m_serversModel->reloadDefaultServerContainerConfig();
m_clientManagementModel->appendClient(clientId, clientName, container, credentials); m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
emit m_configurator->clientModelUpdated(); emit m_configurator->clientModelUpdated();
}); });
@@ -388,7 +391,13 @@ void AmneziaApplication::initControllers()
m_engine->rootContext()->setContextProperty("ApiController", m_apiController.get()); m_engine->rootContext()->setContextProperty("ApiController", m_apiController.get());
connect(m_apiController.get(), &ApiController::updateStarted, this, connect(m_apiController.get(), &ApiController::updateStarted, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Connecting); }); [this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Connecting); });
connect(m_apiController.get(), &ApiController::errorOccurred, this, connect(m_apiController.get(), &ApiController::errorOccurred, this, [this](const QString &errorMessage) {
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); }); if (m_connectionController->isConnectionInProgress()) {
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(), &ConnectionController::toggleConnection); emit m_pageController->showErrorMessage(errorMessage);
}
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(),
&ConnectionController::toggleConnection);
} }
+1
View File
@@ -92,6 +92,7 @@ private:
QCommandLineParser m_parser; QCommandLineParser m_parser;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ContainersModel> m_defaultServerContainersModel;
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<LanguageModel> m_languageModel; QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<ProtocolsModel> m_protocolsModel; QSharedPointer<ProtocolsModel> m_protocolsModel;
+4 -5
View File
@@ -22,7 +22,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Enable when VPN-per-app mode will be implemented --> <!-- Enable when VPN-per-app mode will be implemented -->
@@ -137,14 +137,13 @@
android:name=".AmneziaVpnService" android:name=".AmneziaVpnService"
android:process=":amneziaVpnService" android:process=":amneziaVpnService"
android:permission="android.permission.BIND_VPN_SERVICE" android:permission="android.permission.BIND_VPN_SERVICE"
android:foregroundServiceType="specialUse" android:foregroundServiceType="systemExempted"
android:exported="false"> android:exported="false"
tools:ignore="ForegroundServicePermission">
<intent-filter> <intent-filter>
<action android:name="android.net.VpnService" /> <action android:name="android.net.VpnService" />
</intent-filter> </intent-filter>
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="vpn" />
</service> </service>
<provider <provider
@@ -4,7 +4,7 @@ import android.app.Notification
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Intent import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
import android.net.VpnService import android.net.VpnService
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
@@ -156,7 +156,7 @@ class AmneziaVpnService : VpnService() {
*/ */
private val foregroundServiceTypeCompat private val foregroundServiceTypeCompat
get() = when { get() = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SPECIAL_USE Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> FOREGROUND_SERVICE_TYPE_MANIFEST Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> FOREGROUND_SERVICE_TYPE_MANIFEST
else -> 0 else -> 0
} }
@@ -1,7 +1,5 @@
package com.wireguard.android.backend package org.amnezia.vpn.protocol.wireguard
// TODO: Refactor Amnezia wireguard project by changing the JNI method names
// to move this object to 'org.amnezia.vpn.protocol.wireguard.backend' package
object GoBackend { object GoBackend {
external fun wgGetConfig(handle: Int): String? external fun wgGetConfig(handle: Int): String?
external fun wgGetSocketV4(handle: Int): Int external fun wgGetSocketV4(handle: Int): Int
@@ -3,7 +3,6 @@ package org.amnezia.vpn.protocol.wireguard
import android.content.Context import android.content.Context
import android.net.VpnService.Builder import android.net.VpnService.Builder
import java.util.TreeMap import java.util.TreeMap
import com.wireguard.android.backend.GoBackend
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import org.amnezia.vpn.protocol.Protocol import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState import org.amnezia.vpn.protocol.ProtocolState
+3 -3
View File
@@ -42,9 +42,9 @@ set(SOURCES ${SOURCES}
foreach(abi IN ITEMS ${QT_ANDROID_ABIS}) foreach(abi IN ITEMS ${QT_ANDROID_ABIS})
set_property(TARGET ${PROJECT} PROPERTY QT_ANDROID_EXTRA_LIBS set_property(TARGET ${PROJECT} PROPERTY QT_ANDROID_EXTRA_LIBS
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/android/${abi}/libwg.so ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/android/${abi}/libwg-go.so ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg-go.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/android/${abi}/libwg-quick.so ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg-quick.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/shadowsocks/android/${abi}/libredsocks.so ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/shadowsocks/android/${abi}/libredsocks.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/shadowsocks/android/${abi}/libsslocal.so ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/shadowsocks/android/${abi}/libsslocal.so
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/shadowsocks/android/${abi}/libtun2socks.so ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/shadowsocks/android/${abi}/libtun2socks.so
+1 -7
View File
@@ -211,13 +211,7 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
localFile.write(data); localFile.write(data);
localFile.close(); localFile.close();
#ifdef Q_OS_WINDOWS error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toLocal8Bit().toStdString(), remotePath.toStdString(),
"non_desc");
#else
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(),
"non_desc");
#endif
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
return error; return error;
+13 -15
View File
@@ -222,7 +222,7 @@ namespace libssh {
return fromLibsshErrorCode(); return fromLibsshErrorCode();
} }
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const std::string& localPath, const std::string& remotePath, const std::string& fileDesc) ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const QString& localPath, const QString& remotePath, const QString &fileDesc)
{ {
m_sftpSession = sftp_new(m_session); m_sftpSession = sftp_new(m_session);
@@ -245,40 +245,38 @@ namespace libssh {
const size_t bufferSize = 16384; const size_t bufferSize = 16384;
char buffer[bufferSize]; char buffer[bufferSize];
file = sftp_open(m_sftpSession, remotePath.c_str(), accessType, S_IRWXU); file = sftp_open(m_sftpSession, remotePath.toStdString().c_str(), accessType, S_IRWXU);
if (file == nullptr) { if (file == nullptr) {
return closeSftpSession(); return closeSftpSession();
} }
int localFileSize = std::filesystem::file_size(localPath); int localFileSize = QFileInfo(localPath).size();
int chunksCount = localFileSize / (bufferSize); int chunksCount = localFileSize / (bufferSize);
std::ifstream fin(localPath, std::ios::binary | std::ios::in); QFile fin(localPath);
if (fin.is_open()) { if (fin.open(QIODevice::ReadOnly)) {
for (int currentChunkId = 0; currentChunkId < chunksCount; currentChunkId++) { for (int currentChunkId = 0; currentChunkId < chunksCount; currentChunkId++) {
fin.read(buffer, bufferSize); QByteArray chunk = fin.read(bufferSize);
if (chunk.size() != bufferSize) return ErrorCode::SshSftpEofError;
int bytesWritten = sftp_write(file, buffer, bufferSize); int bytesWritten = sftp_write(file, chunk.data(), chunk.size());
std::string chunk(buffer, bufferSize); if (bytesWritten != chunk.size()) {
if (bytesWritten != bufferSize) {
fin.close(); fin.close();
sftp_close(file); sftp_close(file);
return closeSftpSession(); return closeSftpSession();
} }
} }
int lastChunkSize = localFileSize % (bufferSize); int lastChunkSize = localFileSize % bufferSize;
if (lastChunkSize != 0) { if (lastChunkSize != 0) {
fin.read(buffer, lastChunkSize); QByteArray lastChunk = fin.read(lastChunkSize);
if (lastChunk.size() != lastChunkSize) return ErrorCode::SshSftpEofError;
std::string chunk(buffer, lastChunkSize); int bytesWritten = sftp_write(file, lastChunk.data(), lastChunkSize);
int bytesWritten = sftp_write(file, buffer, lastChunkSize);
if (bytesWritten != lastChunkSize) { if (bytesWritten != lastChunkSize) {
fin.close(); fin.close();
+3 -3
View File
@@ -33,9 +33,9 @@ namespace libssh {
const std::function<ErrorCode (const QString &, Client &)> &cbReadStdErr); const std::function<ErrorCode (const QString &, Client &)> &cbReadStdErr);
ErrorCode writeResponse(const QString &data); ErrorCode writeResponse(const QString &data);
ErrorCode sftpFileCopy(const SftpOverwriteMode overwriteMode, ErrorCode sftpFileCopy(const SftpOverwriteMode overwriteMode,
const std::string& localPath, const QString &localPath,
const std::string& remotePath, const QString &remotePath,
const std::string& fileDesc); const QString& fileDesc);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback); ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
private: private:
ErrorCode closeChannel(); ErrorCode closeChannel();
@@ -0,0 +1,6 @@
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" width="18" height="18" rx="5" fill="white"/>
<path d="M8.49219 13.5L8.49219 9.44141L14.0191 4.99484" stroke="#0E0E11" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.47363 5.49805L6.98828 8.0127" stroke="#0E0E11" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.4727 9.5L14.4727 4.5033L9.50195 4.5033" stroke="#0E0E11" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 511 B

@@ -85,6 +85,7 @@ target_sources(networkextension PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift ${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift ${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm ${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
) )
+3
View File
@@ -124,7 +124,10 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
// json.insert("hopindex", QJsonValue((double)hop.m_hopindex)); // json.insert("hopindex", QJsonValue((double)hop.m_hopindex));
json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key)); json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key));
json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip)); json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip));
// todo review wg ipv6
#ifndef Q_OS_WINDOWS
json.insert("deviceIpv6Address", "dead::1"); json.insert("deviceIpv6Address", "dead::1");
#endif
json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key)); json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key));
json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key)); json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key));
json.insert("serverIpv4AddrIn", wgConfig.value(amnezia::config_key::hostName)); json.insert("serverIpv4AddrIn", wgConfig.value(amnezia::config_key::hostName));
@@ -59,10 +59,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
var stopHandler: (() -> Void)? var stopHandler: (() -> Void)?
var protoType: TunnelProtoType = .none var protoType: TunnelProtoType = .none
override init() {
super.init()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) { override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
let tmpStr = String(data: messageData, encoding: .utf8)! let tmpStr = String(data: messageData, encoding: .utf8)!
wg_log(.error, message: tmpStr) wg_log(.error, message: tmpStr)
@@ -71,7 +67,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return return
} }
guard let completionHandler = completionHandler else { guard let completionHandler else {
log(.error, message: "Missing message completion handler") log(.error, message: "Missing message completion handler")
return return
} }
@@ -179,14 +175,16 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return return
} }
let wgConfigStr = String(data: wgConfig, encoding: .utf8)! guard let wgConfigStr = try? JSONDecoder().decode(WGConfig.self, from: wgConfig).str,
let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr)
guard let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr) else { else {
wg_log(.error, message: "Can't parse WireGuard config") wg_log(.error, message: "Can't parse WireGuard config")
completionHandler(nil) completionHandler(nil)
return return
} }
log(.info, message: "wgConfig: \(wgConfigStr.replacingOccurrences(of: "\n", with: " "))")
if tunnelConfiguration.peers.first!.allowedIPs if tunnelConfiguration.peers.first!.allowedIPs
.map({ $0.stringRepresentation }) .map({ $0.stringRepresentation })
.joined(separator: ", ") == "0.0.0.0/0, ::/0" { .joined(separator: ", ") == "0.0.0.0/0, ::/0" {
+135
View File
@@ -0,0 +1,135 @@
import Foundation
struct WGConfigData: Decodable {
let initPacketMagicHeader, responsePacketMagicHeader: String?
let underloadPacketMagicHeader, transportPacketMagicHeader: String?
let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String?
let initPacketJunkSize, responsePacketJunkSize: String?
var settings: String {
junkPacketCount == nil ? "" :
"""
Jc = \(junkPacketCount!)
Jmin = \(junkPacketMinSize!)
Jmax = \(junkPacketMaxSize!)
S1 = \(initPacketJunkSize!)
S2 = \(responsePacketJunkSize!)
H1 = \(initPacketMagicHeader!)
H2 = \(responsePacketMagicHeader!)
H3 = \(underloadPacketMagicHeader!)
H4 = \(transportPacketMagicHeader!)
"""
}
let clientIP: String
let clientPrivateKey: String
let clientPublicKey: String
let serverPublicKey: String
let presharedKey: String
let hostName: String
let port: Int
var allowedIPs: [String]
var persistentKeepAlive: String
enum CodingKeys: String, CodingKey {
case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2"
case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4"
case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax"
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2"
case clientIP = "client_ip" // "10.8.1.16"
case clientPrivateKey = "client_priv_key"
case clientPublicKey = "client_pub_key"
case serverPublicKey = "server_pub_key"
case presharedKey = "psk_key"
case allowedIPs = "allowed_ips"
case persistentKeepAlive = "persistent_keep_alive"
case hostName
case port
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.initPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .initPacketMagicHeader)
self.responsePacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .responsePacketMagicHeader)
self.underloadPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .underloadPacketMagicHeader)
self.transportPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .transportPacketMagicHeader)
self.junkPacketCount = try container.decodeIfPresent(String.self, forKey: .junkPacketCount)
self.junkPacketMinSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMinSize)
self.junkPacketMaxSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMaxSize)
self.initPacketJunkSize = try container.decodeIfPresent(String.self, forKey: .initPacketJunkSize)
self.responsePacketJunkSize = try container.decodeIfPresent(String.self, forKey: .responsePacketJunkSize)
self.clientIP = try container.decode(String.self, forKey: .clientIP)
self.clientPrivateKey = try container.decode(String.self, forKey: .clientPrivateKey)
self.clientPublicKey = try container.decode(String.self, forKey: .clientPublicKey)
self.serverPublicKey = try container.decode(String.self, forKey: .serverPublicKey)
self.presharedKey = try container.decode(String.self, forKey: .presharedKey)
self.allowedIPs = try container.decodeIfPresent([String].self, forKey: .allowedIPs) ?? ["0.0.0.0/0", "::/0"]
self.persistentKeepAlive = try container.decodeIfPresent(String.self, forKey: .persistentKeepAlive) ?? "25"
self.hostName = try container.decode(String.self, forKey: .hostName)
self.port = try container.decode(Int.self, forKey: .port)
}
}
struct WGConfig: Decodable {
let data: WGConfigData
let configVersion: Int
let description: String
let dns1: String
let dns2: String
let hostName: String
let `protocol`: String
let splitTunnelSites: [String]
let splitTunnelType: Int
enum CodingKeys: String, CodingKey {
case awgConfigData = "awg_config_data", wgConfigData = "wireguard_config_data"
case configData
case configVersion = "config_version"
case description
case dns1
case dns2
case hostName
case `protocol`
case splitTunnelSites
case splitTunnelType
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if container.contains(.awgConfigData) {
self.data = try container.decode(WGConfigData.self, forKey: .awgConfigData)
} else {
self.data = try container.decode(WGConfigData.self, forKey: .wgConfigData)
}
self.configVersion = try container.decode(Int.self, forKey: .configVersion)
self.description = try container.decode(String.self, forKey: .description)
self.dns1 = try container.decode(String.self, forKey: .dns1)
self.dns2 = try container.decode(String.self, forKey: .dns2)
self.hostName = try container.decode(String.self, forKey: .hostName)
self.protocol = try container.decode(String.self, forKey: .protocol)
self.splitTunnelSites = try container.decode([String].self, forKey: .splitTunnelSites)
self.splitTunnelType = try container.decode(Int.self, forKey: .splitTunnelType)
}
var str: String {
"""
[Interface]
Address = \(data.clientIP)/32
DNS = \(dns1), \(dns2)
PrivateKey = \(data.clientPrivateKey)
\(data.settings)
[Peer]
PublicKey = \(data.serverPublicKey)
PresharedKey = \(data.presharedKey)
AllowedIPs = \(data.allowedIPs.joined(separator: ", "))
Endpoint = \(data.hostName):\(data.port)
PersistentKeepalive = \(data.persistentKeepAlive)
"""
}
}
+4 -2
View File
@@ -401,7 +401,8 @@ bool IosController::setupWireGuard()
{ {
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::WireGuard)].toObject(); QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::WireGuard)].toObject();
QString wgConfig = config[config_key::config].toString(); QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
return startWireGuard(wgConfig); return startWireGuard(wgConfig);
} }
@@ -410,7 +411,8 @@ bool IosController::setupAwg()
{ {
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject(); QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject();
QString wgConfig = config[config_key::config].toString(); QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
return startWireGuard(wgConfig); return startWireGuard(wgConfig);
} }
+3 -1
View File
@@ -160,7 +160,6 @@
<file>ui/qml/Components/SettingsContainersListView.qml</file> <file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file> <file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
<file>ui/qml/Controls2/DividerType.qml</file> <file>ui/qml/Controls2/DividerType.qml</file>
<file>ui/qml/Controls2/DrawerType.qml</file>
<file>ui/qml/Controls2/StackViewType.qml</file> <file>ui/qml/Controls2/StackViewType.qml</file>
<file>ui/qml/Pages2/PageSettings.qml</file> <file>ui/qml/Pages2/PageSettings.qml</file>
<file>images/controls/amnezia.svg</file> <file>images/controls/amnezia.svg</file>
@@ -225,5 +224,8 @@
<file>ui/qml/Pages2/PageShareFullAccess.qml</file> <file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>images/controls/close.svg</file> <file>images/controls/close.svg</file>
<file>images/controls/search.svg</file> <file>images/controls/search.svg</file>
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
<file>images/controls/split-tunneling.svg</file>
<file>ui/qml/Controls2/DrawerType2.qml</file>
</qresource> </qresource>
</RCC> </RCC>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+17 -7
View File
@@ -70,14 +70,17 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
void ApiController::updateServerConfigFromApi() void ApiController::updateServerConfigFromApi()
{ {
QtConcurrent::run([this]() { QtConcurrent::run([this]() {
if (m_isConfigUpdateStarted) {
emit updateFinished(false);
return;
}
auto serverConfig = m_serversModel->getDefaultServerConfig(); auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray(); auto containerConfig = serverConfig.value(config_key::containers).toArray();
bool isConfigUpdateStarted = false;
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) { if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
emit updateStarted(); emit updateStarted();
isConfigUpdateStarted = true; m_isConfigUpdateStarted = true;
QNetworkAccessManager manager; QNetworkAccessManager manager;
@@ -110,6 +113,12 @@ void ApiController::updateServerConfigFromApi()
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
QByteArray ba_uncompressed = qUncompress(ba); QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) { if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed; ba = ba_uncompressed;
@@ -127,17 +136,18 @@ void ApiController::updateServerConfigFromApi()
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString(); auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer); serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig); m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
emit m_serversModel->defaultContainerChanged(ContainerProps::containerFromString(defaultContainer));
} else { } else {
qDebug() << reply->error(); qDebug() << reply->error();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError)); emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return; return;
} }
} }
emit updateFinished(isConfigUpdateStarted); emit updateFinished(m_isConfigUpdateStarted);
m_isConfigUpdateStarted = false;
return; return;
}); });
} }
@@ -153,5 +163,5 @@ void ApiController::clearApiConfig()
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None)); serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
m_serversModel->editServer(serverConfig); m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
} }
+2
View File
@@ -39,6 +39,8 @@ private:
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;
bool m_isConfigUpdateStarted = false;
}; };
#endif // APICONTROLLER_H #endif // APICONTROLLER_H
@@ -33,7 +33,7 @@ void ConnectionController::openConnection()
int serverIndex = m_serversModel->getDefaultServerIndex(); int serverIndex = m_serversModel->getDefaultServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = m_containersModel->getDefaultContainer(); DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
const QJsonObject &containerConfig = m_containersModel->getContainerConfig(container); const QJsonObject &containerConfig = m_containersModel->getContainerConfig(container);
if (container == DockerContainer::None) { if (container == DockerContainer::None) {
+47 -7
View File
@@ -8,6 +8,7 @@
#include <QImage> #include <QImage>
#include <QStandardPaths> #include <QStandardPaths>
#include "configurators/awg_configurator.h"
#include "configurators/cloak_configurator.h" #include "configurators/cloak_configurator.h"
#include "configurators/openvpn_configurator.h" #include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h" #include "configurators/shadowsocks_configurator.h"
@@ -45,7 +46,7 @@ void ExportController::generateFullAccessConfig()
{ {
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
QJsonObject config = m_settings->server(serverIndex); QJsonObject config = m_settings->server(serverIndex);
QJsonArray containers = config.value(config_key::containers).toArray(); QJsonArray containers = config.value(config_key::containers).toArray();
@@ -99,7 +100,7 @@ void ExportController::generateConnectionConfig(const QString &clientName)
{ {
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex()); DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -155,7 +156,7 @@ void ExportController::generateOpenVpnConfig(const QString &clientName)
{ {
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex()); DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -193,7 +194,7 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
{ {
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex()); DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -228,11 +229,50 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
emit exportConfigChanged(); emit exportConfigChanged();
} }
void ExportController::generateAwgConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
QString clientId;
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->awgConfigurator->genAwgConfig(credentials, container, containerConfig,
clientId, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Awg, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged();
}
void ExportController::generateShadowSocksConfig() void ExportController::generateShadowSocksConfig()
{ {
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex()); DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -268,7 +308,7 @@ void ExportController::generateCloakConfig()
{ {
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex()); DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -328,7 +368,7 @@ void ExportController::updateClientManagementModel(const DockerContainer contain
void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials) void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials)
{ {
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials, ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials,
m_serversModel->getCurrentlyProcessedServerIndex()); m_serversModel->getProcessedServerIndex());
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorString(errorCode));
} }
+1
View File
@@ -34,6 +34,7 @@ public slots:
void generateConnectionConfig(const QString &clientName); void generateConnectionConfig(const QString &clientName);
void generateOpenVpnConfig(const QString &clientName); void generateOpenVpnConfig(const QString &clientName);
void generateWireGuardConfig(const QString &clientName); void generateWireGuardConfig(const QString &clientName);
void generateAwgConfig(const QString &clientName);
void generateShadowSocksConfig(); void generateShadowSocksConfig();
void generateCloakConfig(); void generateCloakConfig();
+14 -14
View File
@@ -176,7 +176,7 @@ void InstallController::installServer(DockerContainer container, QJsonObject &co
void InstallController::installContainer(DockerContainer container, QJsonObject &config) void InstallController::installContainer(DockerContainer container, QJsonObject &config)
{ {
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials serverCredentials = ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
@@ -238,7 +238,7 @@ bool InstallController::isServerAlreadyExists()
void InstallController::scanServerForInstalledContainers() void InstallController::scanServerForInstalledContainers()
{ {
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials serverCredentials = ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
@@ -267,7 +267,7 @@ void InstallController::scanServerForInstalledContainers()
void InstallController::updateContainer(QJsonObject config) void InstallController::updateContainer(QJsonObject config)
{ {
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials serverCredentials = ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
@@ -283,8 +283,8 @@ void InstallController::updateContainer(QJsonObject config)
m_serversModel->updateContainerConfig(container, config); m_serversModel->updateContainerConfig(container, config);
m_protocolModel->updateModel(config); m_protocolModel->updateModel(config);
if ((serverIndex == m_serversModel->getDefaultServerIndex()) auto defaultContainer = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
&& (container == m_containersModel->getDefaultContainer())) { if ((serverIndex == m_serversModel->getDefaultServerIndex()) && (container == defaultContainer)) {
emit currentContainerUpdated(); emit currentContainerUpdated();
} else { } else {
emit updateContainerFinished(tr("Settings updated successfully")); emit updateContainerFinished(tr("Settings updated successfully"));
@@ -296,27 +296,27 @@ void InstallController::updateContainer(QJsonObject config)
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorString(errorCode));
} }
void InstallController::rebootCurrentlyProcessedServer() void InstallController::rebootProcessedServer()
{ {
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString(); QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
m_serversModel->rebootServer(); m_serversModel->rebootServer();
emit rebootCurrentlyProcessedServerFinished(tr("Server '%1' was rebooted").arg(serverName)); emit rebootProcessedServerFinished(tr("Server '%1' was rebooted").arg(serverName));
} }
void InstallController::removeCurrentlyProcessedServer() void InstallController::removeProcessedServer()
{ {
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString(); QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
m_serversModel->removeServer(); m_serversModel->removeServer();
emit removeCurrentlyProcessedServerFinished(tr("Server '%1' was removed").arg(serverName)); emit removeProcessedServerFinished(tr("Server '%1' was removed").arg(serverName));
} }
void InstallController::removeAllContainers() void InstallController::removeAllContainers()
{ {
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString(); QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
ErrorCode errorCode = m_serversModel->removeAllContainers(); ErrorCode errorCode = m_serversModel->removeAllContainers();
@@ -329,7 +329,7 @@ void InstallController::removeAllContainers()
void InstallController::removeCurrentlyProcessedContainer() void InstallController::removeCurrentlyProcessedContainer()
{ {
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString(); QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
int container = m_containersModel->getCurrentlyProcessedContainerIndex(); int container = m_containersModel->getCurrentlyProcessedContainerIndex();
@@ -377,7 +377,7 @@ void InstallController::mountSftpDrive(const QString &port, const QString &passw
QString mountPath; QString mountPath;
QString cmd; QString cmd;
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials serverCredentials = ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
QString hostname = serverCredentials.hostName; QString hostname = serverCredentials.hostName;
+4 -4
View File
@@ -30,8 +30,8 @@ public slots:
void updateContainer(QJsonObject config); void updateContainer(QJsonObject config);
void removeCurrentlyProcessedServer(); void removeProcessedServer();
void rebootCurrentlyProcessedServer(); void rebootProcessedServer();
void removeAllContainers(); void removeAllContainers();
void removeCurrentlyProcessedContainer(); void removeCurrentlyProcessedContainer();
@@ -54,8 +54,8 @@ signals:
void scanServerFinished(bool isInstalledContainerFound); void scanServerFinished(bool isInstalledContainerFound);
void rebootCurrentlyProcessedServerFinished(const QString &finishedMessage); void rebootProcessedServerFinished(const QString &finishedMessage);
void removeCurrentlyProcessedServerFinished(const QString &finishedMessage); void removeProcessedServerFinished(const QString &finishedMessage);
void removeAllContainersFinished(const QString &finishedMessage); void removeAllContainersFinished(const QString &finishedMessage);
void removeCurrentlyProcessedContainerFinished(const QString &finishedMessage); void removeCurrentlyProcessedContainerFinished(const QString &finishedMessage);
-30
View File
@@ -118,36 +118,6 @@ void PageController::showOnStartup()
} }
} }
void PageController::updateDrawerRootPage(PageLoader::PageEnum page)
{
m_drawerLayer = 0;
m_currentRootPage = page;
}
void PageController::goToDrawerRootPage()
{
m_drawerLayer = 0;
emit showTopCloseButton(false);
emit forceCloseDrawer();
}
void PageController::drawerOpen()
{
m_drawerLayer = m_drawerLayer + 1;
emit showTopCloseButton(true);
}
void PageController::drawerClose()
{
m_drawerLayer = m_drawerLayer -1;
if (m_drawerLayer <= 0) {
emit showTopCloseButton(false);
m_drawerLayer = 0;
}
}
bool PageController::isTriggeredByConnectButton() bool PageController::isTriggeredByConnectButton()
{ {
return m_isTriggeredByConnectButton; return m_isTriggeredByConnectButton;
-11
View File
@@ -82,11 +82,6 @@ public slots:
void showOnStartup(); void showOnStartup();
void updateDrawerRootPage(PageLoader::PageEnum page);
void goToDrawerRootPage();
void drawerOpen();
void drawerClose();
bool isTriggeredByConnectButton(); bool isTriggeredByConnectButton();
void setTriggeredBtConnectButton(bool trigger); void setTriggeredBtConnectButton(bool trigger);
@@ -118,17 +113,11 @@ signals:
void showPassphraseRequestDrawer(); void showPassphraseRequestDrawer();
void passphraseRequestDrawerClosed(QString passphrase); void passphraseRequestDrawerClosed(QString passphrase);
void showTopCloseButton(bool visible);
void forceCloseDrawer();
private: private:
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
PageLoader::PageEnum m_currentRootPage;
int m_drawerLayer;
bool m_isTriggeredByConnectButton; bool m_isTriggeredByConnectButton;
}; };
+1 -1
View File
@@ -28,7 +28,7 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
m_sitesModel(sitesModel), m_sitesModel(sitesModel),
m_settings(settings) m_settings(settings)
{ {
m_appVersion = QString("%1: %2 (%3)").arg(tr("Software version"), QString(APP_VERSION), __DATE__); m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH);
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
if (!m_settings->isScreenshotsEnabled()) { if (!m_settings->isScreenshotsEnabled()) {
-14
View File
@@ -39,7 +39,6 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const
case EasySetupOrderRole: return ContainerProps::easySetupOrder(container); case EasySetupOrderRole: return ContainerProps::easySetupOrder(container);
case IsInstalledRole: return m_containers.contains(container); case IsInstalledRole: return m_containers.contains(container);
case IsCurrentlyProcessedRole: return container == static_cast<DockerContainer>(m_currentlyProcessedContainerIndex); case IsCurrentlyProcessedRole: return container == static_cast<DockerContainer>(m_currentlyProcessedContainerIndex);
case IsDefaultRole: return container == m_defaultContainerIndex;
case IsSupportedRole: return ContainerProps::isSupportedByCurrentPlatform(container); case IsSupportedRole: return ContainerProps::isSupportedByCurrentPlatform(container);
case IsShareableRole: return ContainerProps::isShareable(container); case IsShareableRole: return ContainerProps::isShareable(container);
} }
@@ -64,18 +63,6 @@ void ContainersModel::updateModel(const QJsonArray &containers)
endResetModel(); endResetModel();
} }
void ContainersModel::setDefaultContainer(const int containerIndex)
{
m_defaultContainerIndex = static_cast<DockerContainer>(containerIndex);
emit dataChanged(index(containerIndex, 0), index(containerIndex, 0));
}
DockerContainer ContainersModel::getDefaultContainer()
{
return m_defaultContainerIndex;
}
void ContainersModel::setCurrentlyProcessedContainerIndex(int index) void ContainersModel::setCurrentlyProcessedContainerIndex(int index)
{ {
m_currentlyProcessedContainerIndex = index; m_currentlyProcessedContainerIndex = index;
@@ -127,7 +114,6 @@ QHash<int, QByteArray> ContainersModel::roleNames() const
roles[IsInstalledRole] = "isInstalled"; roles[IsInstalledRole] = "isInstalled";
roles[IsCurrentlyProcessedRole] = "isCurrentlyProcessed"; roles[IsCurrentlyProcessedRole] = "isCurrentlyProcessed";
roles[IsDefaultRole] = "isDefault";
roles[IsSupportedRole] = "isSupported"; roles[IsSupportedRole] = "isSupported";
roles[IsShareableRole] = "isShareable"; roles[IsShareableRole] = "isShareable";
return roles; return roles;
-5
View File
@@ -42,9 +42,6 @@ public:
public slots: public slots:
void updateModel(const QJsonArray &containers); void updateModel(const QJsonArray &containers);
DockerContainer getDefaultContainer();
void setDefaultContainer(const int containerIndex);
void setCurrentlyProcessedContainerIndex(int containerIndex); void setCurrentlyProcessedContainerIndex(int containerIndex);
int getCurrentlyProcessedContainerIndex(); int getCurrentlyProcessedContainerIndex();
@@ -58,14 +55,12 @@ protected:
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
signals: signals:
void defaultContainerChanged();
void containersModelUpdated(); void containersModelUpdated();
private: private:
QMap<DockerContainer, QJsonObject> m_containers; QMap<DockerContainer, QJsonObject> m_containers;
int m_currentlyProcessedContainerIndex; int m_currentlyProcessedContainerIndex;
DockerContainer m_defaultContainerIndex;
}; };
#endif // CONTAINERS_MODEL_H #endif // CONTAINERS_MODEL_H
+3
View File
@@ -45,6 +45,7 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
case LanguageSettings::AvailableLanguageEnum::Russian: strLanguage = "Русский"; break; case LanguageSettings::AvailableLanguageEnum::Russian: strLanguage = "Русский"; break;
case LanguageSettings::AvailableLanguageEnum::China_cn: strLanguage = "\347\256\200\344\275\223\344\270\255\346\226\207"; break; case LanguageSettings::AvailableLanguageEnum::China_cn: strLanguage = "\347\256\200\344\275\223\344\270\255\346\226\207"; break;
case LanguageSettings::AvailableLanguageEnum::Persian: strLanguage = "فارسی"; break; case LanguageSettings::AvailableLanguageEnum::Persian: strLanguage = "فارسی"; break;
case LanguageSettings::AvailableLanguageEnum::Arabic: strLanguage = "العربية"; break;
default: default:
break; break;
} }
@@ -59,6 +60,7 @@ void LanguageModel::changeLanguage(const LanguageSettings::AvailableLanguageEnum
case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break; case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break;
case LanguageSettings::AvailableLanguageEnum::China_cn: emit updateTranslations(QLocale::Chinese); break; case LanguageSettings::AvailableLanguageEnum::China_cn: emit updateTranslations(QLocale::Chinese); break;
case LanguageSettings::AvailableLanguageEnum::Persian: emit updateTranslations(QLocale::Persian); break; case LanguageSettings::AvailableLanguageEnum::Persian: emit updateTranslations(QLocale::Persian); break;
case LanguageSettings::AvailableLanguageEnum::Arabic: emit updateTranslations(QLocale::Arabic); break;
default: emit updateTranslations(QLocale::English); break; default: emit updateTranslations(QLocale::English); break;
} }
} }
@@ -71,6 +73,7 @@ int LanguageModel::getCurrentLanguageIndex()
case QLocale::Russian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Russian); break; case QLocale::Russian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Russian); break;
case QLocale::Chinese: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::China_cn); break; case QLocale::Chinese: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::China_cn); break;
case QLocale::Persian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Persian); break; case QLocale::Persian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Persian); break;
case QLocale::Arabic: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Arabic); break;
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break; default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
} }
} }
+2 -1
View File
@@ -13,7 +13,8 @@ namespace LanguageSettings
English, English,
Russian, Russian,
China_cn, China_cn,
Persian Persian,
Arabic
}; };
Q_ENUM_NS(AvailableLanguageEnum) Q_ENUM_NS(AvailableLanguageEnum)
+146 -113
View File
@@ -5,19 +5,13 @@
ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent) ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent) : m_settings(settings), QAbstractListModel(parent)
{ {
m_servers = m_settings->serversArray();
m_defaultServerIndex = m_settings->defaultServerIndex();
m_currentlyProcessedServerIndex = m_defaultServerIndex;
connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged); connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged);
connect(this, &ServersModel::defaultContainerChanged, this, &ServersModel::defaultServerDescriptionChanged);
connect(this, &ServersModel::defaultServerIndexChanged, this, [this](const int serverIndex) { connect(this, &ServersModel::defaultServerIndexChanged, this, [this](const int serverIndex) {
auto defaultContainer = ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString()); auto defaultContainer = ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString());
emit ServersModel::defaultContainerChanged(defaultContainer); emit ServersModel::defaultServerDefaultContainerChanged(defaultContainer);
}); emit ServersModel::defaultServerNameChanged();
connect(this, &ServersModel::currentlyProcessedServerIndexChanged, this, [this](const int serverIndex) { updateDefaultServerContainersModel();
auto defaultContainer = ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString());
emit ServersModel::defaultContainerChanged(defaultContainer);
}); });
} }
@@ -74,16 +68,14 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
return name; return name;
} }
case ServerDescriptionRole: { case ServerDescriptionRole: {
if (configVersion) { auto description = getServerDescription(server, index.row());
return server.value(config_key::description).toString(); return configVersion ? description : description + server.value(config_key::hostName).toString();
}
return server.value(config_key::hostName).toString();
} }
case HostNameRole: return server.value(config_key::hostName).toString(); case HostNameRole: return server.value(config_key::hostName).toString();
case CredentialsRole: return QVariant::fromValue(serverCredentials(index.row())); case CredentialsRole: return QVariant::fromValue(serverCredentials(index.row()));
case CredentialsLoginRole: return serverCredentials(index.row()).userName; case CredentialsLoginRole: return serverCredentials(index.row()).userName;
case IsDefaultRole: return index.row() == m_defaultServerIndex; case IsDefaultRole: return index.row() == m_defaultServerIndex;
case IsCurrentlyProcessedRole: return index.row() == m_currentlyProcessedServerIndex; case IsCurrentlyProcessedRole: return index.row() == m_processedServerIndex;
case HasWriteAccessRole: { case HasWriteAccessRole: {
auto credentials = serverCredentials(index.row()); auto credentials = serverCredentials(index.row());
return (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty()); return (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty());
@@ -95,6 +87,13 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
case DefaultContainerRole: { case DefaultContainerRole: {
return ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString()); return ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
} }
case IsServerFromApiRole: {
return server.value(config_key::configVersion).toInt();
}
case HasAmneziaDns: {
QString primaryDns = server.value(config_key::dns1).toString();
return primaryDns == protocols::dns::amneziaDnsIp;
}
} }
return QVariant(); return QVariant();
@@ -111,8 +110,9 @@ void ServersModel::resetModel()
beginResetModel(); beginResetModel();
m_servers = m_settings->serversArray(); m_servers = m_settings->serversArray();
m_defaultServerIndex = m_settings->defaultServerIndex(); m_defaultServerIndex = m_settings->defaultServerIndex();
m_currentlyProcessedServerIndex = m_defaultServerIndex; m_processedServerIndex = m_defaultServerIndex;
endResetModel(); endResetModel();
emit defaultServerIndexChanged(m_defaultServerIndex);
} }
void ServersModel::setDefaultServerIndex(const int index) void ServersModel::setDefaultServerIndex(const int index)
@@ -132,12 +132,7 @@ const QString ServersModel::getDefaultServerName()
return qvariant_cast<QString>(data(m_defaultServerIndex, NameRole)); return qvariant_cast<QString>(data(m_defaultServerIndex, NameRole));
} }
const QString ServersModel::getDefaultServerHostName() QString ServersModel::getServerDescription(const QJsonObject &server, const int index) const
{
return qvariant_cast<QString>(data(m_defaultServerIndex, HostNameRole));
}
QString ServersModel::getDefaultServerDescription(const QJsonObject &server)
{ {
const auto configVersion = server.value(config_key::configVersion).toInt(); const auto configVersion = server.value(config_key::configVersion).toInt();
@@ -145,13 +140,12 @@ QString ServersModel::getDefaultServerDescription(const QJsonObject &server)
if (configVersion) { if (configVersion) {
return server.value(config_key::description).toString(); return server.value(config_key::description).toString();
} else if (isDefaultServerHasWriteAccess()) { } else if (data(index, HasWriteAccessRole).toBool()) {
if (m_isAmneziaDnsEnabled if (m_isAmneziaDnsEnabled && isAmneziaDnsContainerInstalled(index)) {
&& isAmneziaDnsContainerInstalled(m_defaultServerIndex)) {
description += "Amnezia DNS | "; description += "Amnezia DNS | ";
} }
} else { } else {
if (isDefaultServerConfigContainsAmneziaDns()) { if (data(index, HasAmneziaDns).toBool()) {
description += "Amnezia DNS | "; description += "Amnezia DNS | ";
} }
} }
@@ -162,7 +156,7 @@ const QString ServersModel::getDefaultServerDescriptionCollapsed()
{ {
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject(); const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt(); const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getDefaultServerDescription(server); auto description = getServerDescription(server, m_defaultServerIndex);
if (configVersion) { if (configVersion) {
return description; return description;
} }
@@ -176,7 +170,7 @@ const QString ServersModel::getDefaultServerDescriptionExpanded()
{ {
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject(); const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt(); const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getDefaultServerDescription(server); auto description = getServerDescription(server, m_defaultServerIndex);
if (configVersion) { if (configVersion) {
return description; return description;
} }
@@ -199,26 +193,21 @@ bool ServersModel::hasServerWithWriteAccess()
return false; return false;
} }
void ServersModel::setCurrentlyProcessedServerIndex(const int index) void ServersModel::setProcessedServerIndex(const int index)
{ {
m_currentlyProcessedServerIndex = index; m_processedServerIndex = index;
updateContainersModel(); updateContainersModel();
emit currentlyProcessedServerIndexChanged(m_currentlyProcessedServerIndex); emit processedServerIndexChanged(m_processedServerIndex);
} }
int ServersModel::getCurrentlyProcessedServerIndex() int ServersModel::getProcessedServerIndex()
{ {
return m_currentlyProcessedServerIndex; return m_processedServerIndex;
} }
QString ServersModel::getCurrentlyProcessedServerHostName() const ServerCredentials ServersModel::getProcessedServerCredentials()
{ {
return qvariant_cast<QString>(data(m_currentlyProcessedServerIndex, HostNameRole)); return serverCredentials(m_processedServerIndex);
}
const ServerCredentials ServersModel::getCurrentlyProcessedServerCredentials()
{
return serverCredentials(m_currentlyProcessedServerIndex);
} }
const ServerCredentials ServersModel::getServerCredentials(const int index) const ServerCredentials ServersModel::getServerCredentials(const int index)
@@ -228,12 +217,17 @@ const ServerCredentials ServersModel::getServerCredentials(const int index)
bool ServersModel::isDefaultServerCurrentlyProcessed() bool ServersModel::isDefaultServerCurrentlyProcessed()
{ {
return m_defaultServerIndex == m_currentlyProcessedServerIndex; return m_defaultServerIndex == m_processedServerIndex;
} }
bool ServersModel::isCurrentlyProcessedServerHasWriteAccess() bool ServersModel::isDefaultServerFromApi()
{ {
return qvariant_cast<bool>(data(m_currentlyProcessedServerIndex, HasWriteAccessRole)); return qvariant_cast<bool>(data(m_defaultServerIndex, IsServerFromApiRole));
}
bool ServersModel::isProcessedServerHasWriteAccess()
{
return qvariant_cast<bool>(data(m_processedServerIndex, HasWriteAccessRole));
} }
bool ServersModel::isDefaultServerHasWriteAccess() bool ServersModel::isDefaultServerHasWriteAccess()
@@ -249,40 +243,42 @@ void ServersModel::addServer(const QJsonObject &server)
endResetModel(); endResetModel();
} }
void ServersModel::editServer(const QJsonObject &server) void ServersModel::editServer(const QJsonObject &server, const int serverIndex)
{ {
m_settings->editServer(m_currentlyProcessedServerIndex, server); m_settings->editServer(serverIndex, server);
m_servers.replace(m_currentlyProcessedServerIndex, m_settings->serversArray().at(m_currentlyProcessedServerIndex)); m_servers.replace(serverIndex, m_settings->serversArray().at(serverIndex));
emit dataChanged(index(m_currentlyProcessedServerIndex, 0), index(m_currentlyProcessedServerIndex, 0)); emit dataChanged(index(serverIndex, 0), index(serverIndex, 0));
if (serverIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
}
updateContainersModel(); updateContainersModel();
if (serverIndex == m_defaultServerIndex) {
auto defaultContainer = qvariant_cast<DockerContainer>(getDefaultServerData("defaultContainer"));
emit defaultServerDefaultContainerChanged(defaultContainer);
}
} }
void ServersModel::removeServer() void ServersModel::removeServer()
{ {
beginResetModel(); beginResetModel();
m_settings->removeServer(m_currentlyProcessedServerIndex); m_settings->removeServer(m_processedServerIndex);
m_servers = m_settings->serversArray(); m_servers = m_settings->serversArray();
if (m_settings->defaultServerIndex() == m_currentlyProcessedServerIndex) { if (m_settings->defaultServerIndex() == m_processedServerIndex) {
setDefaultServerIndex(0); setDefaultServerIndex(0);
} else if (m_settings->defaultServerIndex() > m_currentlyProcessedServerIndex) { } else if (m_settings->defaultServerIndex() > m_processedServerIndex) {
setDefaultServerIndex(m_settings->defaultServerIndex() - 1); setDefaultServerIndex(m_settings->defaultServerIndex() - 1);
} }
if (m_settings->serversCount() == 0) { if (m_settings->serversCount() == 0) {
setDefaultServerIndex(-1); setDefaultServerIndex(-1);
} }
setCurrentlyProcessedServerIndex(m_defaultServerIndex); setProcessedServerIndex(m_defaultServerIndex);
endResetModel(); endResetModel();
} }
bool ServersModel::isDefaultServerConfigContainsAmneziaDns()
{
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
QString primaryDns = server.value(config_key::dns1).toString();
return primaryDns == protocols::dns::amneziaDnsIp;
}
QHash<int, QByteArray> ServersModel::roleNames() const QHash<int, QByteArray> ServersModel::roleNames() const
{ {
QHash<int, QByteArray> roles; QHash<int, QByteArray> roles;
@@ -290,6 +286,8 @@ QHash<int, QByteArray> ServersModel::roleNames() const
roles[NameRole] = "serverName"; roles[NameRole] = "serverName";
roles[NameRole] = "name"; roles[NameRole] = "name";
roles[ServerDescriptionRole] = "serverDescription"; roles[ServerDescriptionRole] = "serverDescription";
roles[CollapsedServerDescriptionRole] = "collapsedServerDescription";
roles[ExpandedServerDescriptionRole] = "expandedServerDescription";
roles[HostNameRole] = "hostName"; roles[HostNameRole] = "hostName";
@@ -304,6 +302,8 @@ QHash<int, QByteArray> ServersModel::roleNames() const
roles[ContainsAmneziaDnsRole] = "containsAmneziaDns"; roles[ContainsAmneziaDnsRole] = "containsAmneziaDns";
roles[DefaultContainerRole] = "defaultContainer"; roles[DefaultContainerRole] = "defaultContainer";
roles[IsServerFromApiRole] = "isServerFromApi";
return roles; return roles;
} }
@@ -322,28 +322,29 @@ ServerCredentials ServersModel::serverCredentials(int index) const
void ServersModel::updateContainersModel() void ServersModel::updateContainersModel()
{ {
auto containers = m_servers.at(m_currentlyProcessedServerIndex).toObject().value(config_key::containers).toArray(); auto containers = m_servers.at(m_processedServerIndex).toObject().value(config_key::containers).toArray();
emit containersUpdated(containers); emit containersUpdated(containers);
} }
void ServersModel::updateDefaultServerContainersModel()
{
auto containers = m_servers.at(m_defaultServerIndex).toObject().value(config_key::containers).toArray();
emit defaultServerContainersUpdated(containers);
}
QJsonObject ServersModel::getDefaultServerConfig() QJsonObject ServersModel::getDefaultServerConfig()
{ {
return m_servers.at(m_defaultServerIndex).toObject(); return m_servers.at(m_defaultServerIndex).toObject();
} }
QJsonObject ServersModel::getCurrentlyProcessedServerConfig() void ServersModel::reloadDefaultServerContainerConfig()
{ {
return m_servers.at(m_currentlyProcessedServerIndex).toObject(); QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
}
void ServersModel::reloadContainerConfig()
{
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto container = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString()); auto container = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
auto containers = server.value(config_key::containers).toArray(); auto containers = server.value(config_key::containers).toArray();
auto config = m_settings->containerConfig(m_currentlyProcessedServerIndex, container); auto config = m_settings->containerConfig(m_defaultServerIndex, container);
for (auto i = 0; i < containers.size(); i++) { for (auto i = 0; i < containers.size(); i++) {
auto c = ContainerProps::containerFromString(containers.at(i).toObject().value(config_key::container).toString()); auto c = ContainerProps::containerFromString(containers.at(i).toObject().value(config_key::container).toString());
if (c == container) { if (c == container) {
@@ -353,13 +354,13 @@ void ServersModel::reloadContainerConfig()
} }
server.insert(config_key::containers, containers); server.insert(config_key::containers, containers);
editServer(server); editServer(server, m_defaultServerIndex);
} }
void ServersModel::updateContainerConfig(const int containerIndex, const QJsonObject config) void ServersModel::updateContainerConfig(const int containerIndex, const QJsonObject config)
{ {
auto container = static_cast<DockerContainer>(containerIndex); auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject(); QJsonObject server = m_servers.at(m_processedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray(); auto containers = server.value(config_key::containers).toArray();
for (auto i = 0; i < containers.size(); i++) { for (auto i = 0; i < containers.size(); i++) {
@@ -377,49 +378,38 @@ void ServersModel::updateContainerConfig(const int containerIndex, const QJsonOb
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
} }
editServer(server); editServer(server, m_processedServerIndex);
} }
void ServersModel::addContainerConfig(const int containerIndex, const QJsonObject config) void ServersModel::addContainerConfig(const int containerIndex, const QJsonObject config)
{ {
auto container = static_cast<DockerContainer>(containerIndex); auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject(); QJsonObject server = m_servers.at(m_processedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray(); auto containers = server.value(config_key::containers).toArray();
containers.push_back(config); containers.push_back(config);
server.insert(config_key::containers, containers); server.insert(config_key::containers, containers);
bool isDefaultContainerChanged = false;
auto defaultContainer = server.value(config_key::defaultContainer).toString(); auto defaultContainer = server.value(config_key::defaultContainer).toString();
if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None || ContainerProps::containerService(container) != ServiceType::Other)) { if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None || ContainerProps::containerService(container) != ServiceType::Other)) {
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
isDefaultContainerChanged = true;
} }
editServer(server); editServer(server, m_processedServerIndex);
if (isDefaultContainerChanged) {
emit defaultContainerChanged(container);
}
} }
void ServersModel::setDefaultContainer(const int containerIndex) void ServersModel::setDefaultContainer(const int serverIndex, const int containerIndex)
{ {
auto container = static_cast<DockerContainer>(containerIndex); auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject s = m_servers.at(m_currentlyProcessedServerIndex).toObject(); QJsonObject s = m_servers.at(serverIndex).toObject();
s.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); s.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
editServer(s); //check editServer(s, serverIndex); //check
emit defaultContainerChanged(container);
} }
DockerContainer ServersModel::getDefaultContainer() const QString ServersModel::getDefaultServerDefaultContainerName()
{ {
return qvariant_cast<DockerContainer>(data(m_currentlyProcessedServerIndex, DefaultContainerRole)); auto defaultContainer = qvariant_cast<DockerContainer>(getDefaultServerData("defaultContainer"));
}
const QString ServersModel::getDefaultContainerName()
{
auto defaultContainer = getDefaultContainer();
return ContainerProps::containerHumanNames().value(defaultContainer); return ContainerProps::containerHumanNames().value(defaultContainer);
} }
@@ -427,15 +417,14 @@ ErrorCode ServersModel::removeAllContainers()
{ {
ServerController serverController(m_settings); ServerController serverController(m_settings);
ErrorCode errorCode = ErrorCode errorCode =
serverController.removeAllContainers(m_settings->serverCredentials(m_currentlyProcessedServerIndex)); serverController.removeAllContainers(m_settings->serverCredentials(m_processedServerIndex));
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
QJsonObject s = m_servers.at(m_currentlyProcessedServerIndex).toObject(); QJsonObject s = m_servers.at(m_processedServerIndex).toObject();
s.insert(config_key::containers, {}); s.insert(config_key::containers, {});
s.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None)); s.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
editServer(s); editServer(s, m_processedServerIndex);
emit defaultContainerChanged(DockerContainer::None);
} }
return errorCode; return errorCode;
} }
@@ -443,7 +432,7 @@ ErrorCode ServersModel::removeAllContainers()
ErrorCode ServersModel::rebootServer() ErrorCode ServersModel::rebootServer()
{ {
ServerController serverController(m_settings); ServerController serverController(m_settings);
auto credentials = m_settings->serverCredentials(m_currentlyProcessedServerIndex); auto credentials = m_settings->serverCredentials(m_processedServerIndex);
ErrorCode errorCode = serverController.rebootServer(credentials); ErrorCode errorCode = serverController.rebootServer(credentials);
return errorCode; return errorCode;
@@ -452,13 +441,13 @@ ErrorCode ServersModel::rebootServer()
ErrorCode ServersModel::removeContainer(const int containerIndex) ErrorCode ServersModel::removeContainer(const int containerIndex)
{ {
ServerController serverController(m_settings); ServerController serverController(m_settings);
auto credentials = m_settings->serverCredentials(m_currentlyProcessedServerIndex); auto credentials = m_settings->serverCredentials(m_processedServerIndex);
auto dockerContainer = static_cast<DockerContainer>(containerIndex); auto dockerContainer = static_cast<DockerContainer>(containerIndex);
ErrorCode errorCode = serverController.removeContainer(credentials, dockerContainer); ErrorCode errorCode = serverController.removeContainer(credentials, dockerContainer);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject(); QJsonObject server = m_servers.at(m_processedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray(); auto containers = server.value(config_key::containers).toArray();
for (auto it = containers.begin(); it != containers.end(); it++) { for (auto it = containers.begin(); it != containers.end(); it++) {
@@ -480,32 +469,37 @@ ErrorCode ServersModel::removeContainer(const int containerIndex)
server.insert(config_key::defaultContainer, ContainerProps::containerToString(defaultContainer)); server.insert(config_key::defaultContainer, ContainerProps::containerToString(defaultContainer));
} }
editServer(server); editServer(server, m_processedServerIndex);
emit defaultContainerChanged(defaultContainer);
} }
return errorCode; return errorCode;
} }
void ServersModel::clearCachedProfiles() void ServersModel::clearCachedProfiles()
{ {
const auto &containers = m_settings->containers(m_currentlyProcessedServerIndex); const auto &containers = m_settings->containers(m_processedServerIndex);
for (DockerContainer container : containers.keys()) { for (DockerContainer container : containers.keys()) {
m_settings->clearLastConnectionConfig(m_currentlyProcessedServerIndex, container); m_settings->clearLastConnectionConfig(m_processedServerIndex, container);
} }
m_servers.replace(m_currentlyProcessedServerIndex, m_settings->server(m_currentlyProcessedServerIndex)); m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex));
if (m_processedServerIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
}
updateContainersModel(); updateContainersModel();
} }
void ServersModel::clearCachedProfile(const DockerContainer container) void ServersModel::clearCachedProfile(const DockerContainer container)
{ {
m_settings->clearLastConnectionConfig(m_currentlyProcessedServerIndex, container); m_settings->clearLastConnectionConfig(m_processedServerIndex, container);
m_servers.replace(m_currentlyProcessedServerIndex, m_settings->server(m_currentlyProcessedServerIndex)); m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex));
if (m_processedServerIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
}
updateContainersModel(); updateContainersModel();
} }
bool ServersModel::isAmneziaDnsContainerInstalled(const int serverIndex) bool ServersModel::isAmneziaDnsContainerInstalled(const int serverIndex) const
{ {
QJsonObject server = m_servers.at(serverIndex).toObject(); QJsonObject server = m_servers.at(serverIndex).toObject();
auto containers = server.value(config_key::containers).toArray(); auto containers = server.value(config_key::containers).toArray();
@@ -544,16 +538,6 @@ void ServersModel::toggleAmneziaDns(bool enabled)
emit defaultServerDescriptionChanged(); emit defaultServerDescriptionChanged();
} }
bool ServersModel::isDefaultServerFromApi()
{
return m_settings->server(m_defaultServerIndex).value(config_key::configVersion).toInt();
}
bool ServersModel::isCurrentlyProcessedServerFromApi()
{
return m_settings->server(m_currentlyProcessedServerIndex).value(config_key::configVersion).toInt();
}
bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc) bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc)
{ {
for (const auto &server : qAsConst(m_servers)) { for (const auto &server : qAsConst(m_servers)) {
@@ -564,3 +548,52 @@ bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc)
return false; return false;
} }
QVariant ServersModel::getDefaultServerData(const QString roleString)
{
auto roles = roleNames();
for (auto it = roles.begin(); it != roles.end(); it++) {
if (QString(it.value()) == roleString) {
return data(m_defaultServerIndex, it.key());
}
}
return {};
}
void ServersModel::setDefaultServerData(const QString roleString, const QVariant &value)
{
}
QVariant ServersModel::getProcessedServerData(const QString roleString)
{
auto roles = roleNames();
for (auto it = roles.begin(); it != roles.end(); it++) {
if (QString(it.value()) == roleString) {
return data(m_processedServerIndex, it.key());
}
}
return {};
}
void ServersModel::setProcessedServerData(const QString roleString, const QVariant &value)
{
}
bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
{
auto server = m_servers.at(m_defaultServerIndex).toObject();
auto defaultContainer = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
auto containerConfig = server.value(config_key::containers).toArray().at(defaultContainer).toObject();
auto protocolConfig = containerConfig.value(ContainerProps::containerTypeToString(defaultContainer)).toObject();
if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
return !(protocolConfig.value(config_key::last_config).toString().contains("AllowedIPs = 0.0.0.0/0, ::/0"));
} else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn || defaultContainer == DockerContainer::ShadowSocks) {
return !(protocolConfig.value(config_key::last_config).toString().contains("redirect-gateway"));
}
return false;
}
+38 -30
View File
@@ -12,7 +12,8 @@ public:
enum Roles { enum Roles {
NameRole = Qt::UserRole + 1, NameRole = Qt::UserRole + 1,
ServerDescriptionRole, ServerDescriptionRole,
CollapsedServerDescriptionRole,
ExpandedServerDescriptionRole,
HostNameRole, HostNameRole,
CredentialsRole, CredentialsRole,
@@ -25,7 +26,11 @@ public:
ContainsAmneziaDnsRole, ContainsAmneziaDnsRole,
DefaultContainerRole DefaultContainerRole,
IsServerFromApiRole,
HasAmneziaDns
}; };
ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr); ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
@@ -40,47 +45,43 @@ public:
Q_PROPERTY(int defaultIndex READ getDefaultServerIndex WRITE setDefaultServerIndex NOTIFY defaultServerIndexChanged) Q_PROPERTY(int defaultIndex READ getDefaultServerIndex WRITE setDefaultServerIndex NOTIFY defaultServerIndexChanged)
Q_PROPERTY(QString defaultServerName READ getDefaultServerName NOTIFY defaultServerNameChanged) Q_PROPERTY(QString defaultServerName READ getDefaultServerName NOTIFY defaultServerNameChanged)
Q_PROPERTY(QString defaultServerHostName READ getDefaultServerHostName NOTIFY defaultServerIndexChanged) Q_PROPERTY(QString defaultServerDefaultContainerName READ getDefaultServerDefaultContainerName NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(QString defaultContainerName READ getDefaultContainerName NOTIFY defaultContainerChanged) Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerDescriptionChanged) Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerDescriptionChanged) Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
Q_PROPERTY(int currentlyProcessedIndex READ getCurrentlyProcessedServerIndex WRITE setCurrentlyProcessedServerIndex Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
NOTIFY currentlyProcessedServerIndexChanged)
public slots: public slots:
void setDefaultServerIndex(const int index); void setDefaultServerIndex(const int index);
const int getDefaultServerIndex(); const int getDefaultServerIndex();
const QString getDefaultServerName(); const QString getDefaultServerName();
const QString getDefaultServerHostName();
const QString getDefaultServerDescriptionCollapsed(); const QString getDefaultServerDescriptionCollapsed();
const QString getDefaultServerDescriptionExpanded(); const QString getDefaultServerDescriptionExpanded();
const QString getDefaultServerDefaultContainerName();
bool isDefaultServerCurrentlyProcessed(); bool isDefaultServerCurrentlyProcessed();
bool isDefaultServerFromApi();
bool isCurrentlyProcessedServerHasWriteAccess(); bool isProcessedServerHasWriteAccess();
bool isDefaultServerHasWriteAccess(); bool isDefaultServerHasWriteAccess();
bool hasServerWithWriteAccess(); bool hasServerWithWriteAccess();
const int getServersCount(); const int getServersCount();
void setCurrentlyProcessedServerIndex(const int index); void setProcessedServerIndex(const int index);
int getCurrentlyProcessedServerIndex(); int getProcessedServerIndex();
QString getCurrentlyProcessedServerHostName(); const ServerCredentials getProcessedServerCredentials();
const ServerCredentials getCurrentlyProcessedServerCredentials();
const ServerCredentials getServerCredentials(const int index); const ServerCredentials getServerCredentials(const int index);
void addServer(const QJsonObject &server); void addServer(const QJsonObject &server);
void editServer(const QJsonObject &server); void editServer(const QJsonObject &server, const int serverIndex);
void removeServer(); void removeServer();
bool isDefaultServerConfigContainsAmneziaDns();
bool isAmneziaDnsContainerInstalled(const int serverIndex);
QJsonObject getDefaultServerConfig(); QJsonObject getDefaultServerConfig();
QJsonObject getCurrentlyProcessedServerConfig();
void reloadContainerConfig(); void reloadDefaultServerContainerConfig();
void updateContainerConfig(const int containerIndex, const QJsonObject config); void updateContainerConfig(const int containerIndex, const QJsonObject config);
void addContainerConfig(const int containerIndex, const QJsonObject config); void addContainerConfig(const int containerIndex, const QJsonObject config);
@@ -91,43 +92,50 @@ public slots:
ErrorCode removeAllContainers(); ErrorCode removeAllContainers();
ErrorCode rebootServer(); ErrorCode rebootServer();
void setDefaultContainer(const int containerIndex); void setDefaultContainer(const int serverIndex, const int containerIndex);
DockerContainer getDefaultContainer();
const QString getDefaultContainerName();
QStringList getAllInstalledServicesName(const int serverIndex); QStringList getAllInstalledServicesName(const int serverIndex);
void toggleAmneziaDns(bool enabled); void toggleAmneziaDns(bool enabled);
bool isDefaultServerFromApi();
bool isCurrentlyProcessedServerFromApi();
bool isServerFromApiAlreadyExists(const quint16 crc); bool isServerFromApiAlreadyExists(const quint16 crc);
QVariant getDefaultServerData(const QString roleString);
void setDefaultServerData(const QString roleString, const QVariant &value);
QVariant getProcessedServerData(const QString roleString);
void setProcessedServerData(const QString roleString, const QVariant &value);
bool isDefaultServerDefaultContainerHasSplitTunneling();
protected: protected:
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
signals: signals:
void currentlyProcessedServerIndexChanged(const int index); void processedServerIndexChanged(const int index);
void defaultServerIndexChanged(const int index); void defaultServerIndexChanged(const int index);
void defaultServerNameChanged(); void defaultServerNameChanged();
void defaultServerDescriptionChanged(); void defaultServerDescriptionChanged();
void containersUpdated(const QJsonArray &containers); void containersUpdated(const QJsonArray &containers);
void defaultContainerChanged(const int containerIndex); void defaultServerContainersUpdated(const QJsonArray &containers);
void defaultServerDefaultContainerChanged(const int containerIndex);
private: private:
ServerCredentials serverCredentials(int index) const; ServerCredentials serverCredentials(int index) const;
void updateContainersModel(); void updateContainersModel();
void updateDefaultServerContainersModel();
QString getDefaultServerDescription(const QJsonObject &server); QString getServerDescription(const QJsonObject &server, const int index) const;
bool isAmneziaDnsContainerInstalled(const int serverIndex) const;
QJsonArray m_servers; QJsonArray m_servers;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
int m_defaultServerIndex; int m_defaultServerIndex;
int m_currentlyProcessedServerIndex; int m_processedServerIndex;
bool m_isAmneziaDnsEnabled = m_settings->useAmneziaDns(); bool m_isAmneziaDnsEnabled = m_settings->useAmneziaDns();
}; };
+1
View File
@@ -113,6 +113,7 @@ void SitesModel::toggleSplitTunneling(bool enabled)
m_settings->setRouteMode(Settings::RouteMode::VpnAllSites); m_settings->setRouteMode(Settings::RouteMode::VpnAllSites);
} }
m_isSplitTunnelingEnabled = enabled; m_isSplitTunnelingEnabled = enabled;
emit splitTunnelingToggled();
} }
QVector<QPair<QString, QString> > SitesModel::getCurrentSites() QVector<QPair<QString, QString> > SitesModel::getCurrentSites()
+2
View File
@@ -22,6 +22,7 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_PROPERTY(int routeMode READ getRouteMode WRITE setRouteMode NOTIFY routeModeChanged) Q_PROPERTY(int routeMode READ getRouteMode WRITE setRouteMode NOTIFY routeModeChanged)
Q_PROPERTY(bool isTunnelingEnabled READ isSplitTunnelingEnabled NOTIFY splitTunnelingToggled)
public slots: public slots:
bool addSite(const QString &hostname, const QString &ip); bool addSite(const QString &hostname, const QString &ip);
@@ -38,6 +39,7 @@ public slots:
signals: signals:
void routeModeChanged(); void routeModeChanged();
void splitTunnelingToggled();
protected: protected:
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
+1 -2
View File
@@ -138,8 +138,7 @@ Button {
} }
onClicked: { onClicked: {
if (!ConnectionController.isConnectionInProgress) { ServersModel.setProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi() ApiController.updateServerConfigFromApi()
} }
}
} }
@@ -8,18 +8,24 @@ import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Config" import "../Config"
DrawerType { DrawerType2 {
id: root id: root
width: parent.width width: parent.width
height: parent.height * 0.4375 height: parent.height
expandedContent: ColumnLayout {
id: content
ColumnLayout {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
spacing: 0 spacing: 0
Component.onCompleted: {
root.expandedHeight = content.implicitHeight + 32
}
Header2Type { Header2Type {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
@@ -40,7 +46,7 @@ DrawerType {
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials) PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.visible = false root.close()
} }
} }
@@ -54,7 +60,7 @@ DrawerType {
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource) PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.visible = false root.close()
} }
} }
@@ -15,6 +15,7 @@ ListView {
id: menuContent id: menuContent
property var rootWidth property var rootWidth
property var selectedText
width: rootWidth width: rootWidth
height: menuContent.contentItem.height height: menuContent.contentItem.height
@@ -26,24 +27,6 @@ ListView {
id: containersRadioButtonGroup id: containersRadioButtonGroup
} }
Connections {
target: ServersModel
function onCurrentlyProcessedServerIndexChanged() {
if (ContainersModel.getDefaultContainer()) {
menuContent.checkCurrentItem()
}
}
}
function checkCurrentItem() {
var item = menuContent.itemAtIndex(currentIndex)
if (item !== null) {
var radioButton = item.children[0].children[0]
radioButton.checked = true
}
}
delegate: Item { delegate: Item {
implicitWidth: rootWidth implicitWidth: rootWidth
implicitHeight: content.implicitHeight implicitHeight: content.implicitHeight
@@ -69,7 +52,7 @@ ListView {
showImage: !isInstalled showImage: !isInstalled
checkable: isInstalled && !ConnectionController.isConnected && isSupported checkable: isInstalled && !ConnectionController.isConnected && isSupported
checked: isDefault checked: proxyDefaultServerContainersModel.mapToSource(index) === ServersModel.getDefaultServerData("defaultContainer")
onClicked: { onClicked: {
if (ConnectionController.isConnected && isInstalled) { if (ConnectionController.isConnected && isInstalled) {
@@ -78,18 +61,18 @@ ListView {
} }
if (checked) { if (checked) {
containersDropDown.menuVisible = false containersDropDown.close()
ServersModel.setDefaultContainer(proxyContainersModel.mapToSource(index)) ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyDefaultServerContainersModel.mapToSource(index))
} else { } else {
if (!isSupported && isInstalled) { if (!isSupported && isInstalled) {
PageController.showErrorMessage(qsTr("The selected protocol is not supported on the current platform")) PageController.showErrorMessage(qsTr("The selected protocol is not supported on the current platform"))
return return
} }
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(index)) ContainersModel.setCurrentlyProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false) InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.menuVisible = false containersDropDown.close()
} }
} }
@@ -0,0 +1,92 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
id: root
anchors.fill: parent
expandedHeight: parent.height * 0.7
expandedContent: ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Split tunneling")
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
}
LabelWithButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
text: qsTr("Split tunneling on the server")
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
// PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
// root.close()
}
}
DividerType {
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
}
LabelWithButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
enabled: ! ServersModel.isDefaultServerDefaultContainerHasSplitTunneling || !ServersModel.getDefaultServerData("isServerFromApi")
text: qsTr("Site-based split tunneling")
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
root.close()
}
}
DividerType {
}
LabelWithButtonType {
Layout.fillWidth: true
visible: false
text: qsTr("App-based split tunneling")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
// PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.close()
}
}
DividerType {
visible: false
}
}
}
+17 -10
View File
@@ -5,7 +5,7 @@ import QtQuick.Layouts
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
DrawerType { DrawerType2 {
id: root id: root
property string headerText property string headerText
@@ -16,23 +16,24 @@ DrawerType {
property var yesButtonFunction property var yesButtonFunction
property var noButtonFunction property var noButtonFunction
width: parent.width expandedContent: ColumnLayout {
height: content.implicitHeight + 32
ColumnLayout {
id: content id: content
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: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 8 spacing: 8
onImplicitHeightChanged: {
root.expandedHeight = content.implicitHeight + 32
}
Header2TextType { Header2TextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: headerText text: headerText
} }
@@ -40,6 +41,8 @@ DrawerType {
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
Layout.rightMargin: 16
Layout.leftMargin: 16
text: descriptionText text: descriptionText
} }
@@ -47,10 +50,12 @@ DrawerType {
BasicButtonType { BasicButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: yesButtonText text: yesButtonText
onClicked: { clickedFunc: function() {
if (yesButtonFunction && typeof yesButtonFunction === "function") { if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction() yesButtonFunction()
} }
@@ -59,6 +64,8 @@ DrawerType {
BasicButtonType { BasicButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
defaultColor: "transparent" defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08) hoveredColor: Qt.rgba(1, 1, 1, 0.08)
@@ -69,7 +76,7 @@ DrawerType {
text: noButtonText text: noButtonText
onClicked: { clickedFunc: function() {
if (noButtonFunction && typeof noButtonFunction === "function") { if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction() noButtonFunction()
} }
@@ -5,11 +5,17 @@ import QtQuick.Layouts
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
DrawerType { DrawerType2 {
id: root id: root
width: parent.width expandedContent: Item {
height: parent.height * 0.9 id: container
implicitHeight: root.height * 0.9
Component.onCompleted: {
root.expandedHeight = container.implicitHeight
}
ColumnLayout { ColumnLayout {
id: backButton id: backButton
@@ -135,4 +141,5 @@ DrawerType {
} }
} }
} }
}
} }
@@ -16,19 +16,18 @@ import "../Controls2/TextTypes"
import "../Config" import "../Config"
import "../Components" import "../Components"
DrawerType { DrawerType2 {
id: root id: root
property alias headerText: header.headerText property string headerText
property alias configContentHeaderText: configContentHeader.headerText property string configContentHeaderText
property alias contentVisible: content.visible property string contentVisible
property string configExtension: ".vpn" property string configExtension: ".vpn"
property string configCaption: qsTr("Save AmneziaVPN config") property string configCaption: qsTr("Save AmneziaVPN config")
property string configFileName: "amnezia_config" property string configFileName: "amnezia_config"
width: parent.width expandedHeight: parent.height * 0.9
height: parent.height * 0.9
onClosed: { onClosed: {
configExtension = ".vpn" configExtension = ".vpn"
@@ -36,8 +35,8 @@ DrawerType {
configFileName = "amnezia_config" configFileName = "amnezia_config"
} }
Item { expandedContent: Item {
anchors.fill: parent implicitHeight: root.expandedHeight
Header2Type { Header2Type {
id: header id: header
@@ -47,6 +46,8 @@ DrawerType {
anchors.topMargin: 20 anchors.topMargin: 20
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
headerText: root.headerText
} }
FlickableType { FlickableType {
@@ -64,6 +65,8 @@ DrawerType {
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
visible: root.contentVisible
BasicButtonType { BasicButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
@@ -71,7 +74,7 @@ DrawerType {
text: qsTr("Share") text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg" imageSource: "qrc:/images/controls/share-2.svg"
onClicked: { clickedFunc: function() {
var fileName = "" var fileName = ""
if (GC.isMobile()) { if (GC.isMobile()) {
fileName = configFileName + configExtension fileName = configFileName + configExtension
@@ -91,6 +94,7 @@ DrawerType {
} }
BasicButtonType { BasicButtonType {
id: copyConfigTextButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
@@ -103,20 +107,14 @@ DrawerType {
text: qsTr("Copy") text: qsTr("Copy")
imageSource: "qrc:/images/controls/copy.svg" imageSource: "qrc:/images/controls/copy.svg"
onClicked: {
configText.selectAll()
configText.copy()
configText.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
} }
BasicButtonType { BasicButtonType {
id: copyNativeConfigStringButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
visible: nativeConfigString.text !== "" visible: false
defaultColor: "transparent" defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08) hoveredColor: Qt.rgba(1, 1, 1, 0.08)
@@ -127,13 +125,6 @@ DrawerType {
text: qsTr("Copy config string") text: qsTr("Copy config string")
imageSource: "qrc:/images/controls/copy.svg" imageSource: "qrc:/images/controls/copy.svg"
onClicked: {
nativeConfigString.selectAll()
nativeConfigString.copy()
nativeConfigString.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
} }
BasicButtonType { BasicButtonType {
@@ -149,16 +140,43 @@ DrawerType {
text: qsTr("Show connection settings") text: qsTr("Show connection settings")
onClicked: { clickedFunc: function() {
configContentDrawer.visible = true configContentDrawer.open()
} }
} }
DrawerType { DrawerType2 {
id: configContentDrawer id: configContentDrawer
width: parent.width parent: root.parent
height: parent.height * 0.9
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedContent: 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"))
}
}
BackButtonType { BackButtonType {
id: backButton id: backButton
@@ -169,7 +187,7 @@ DrawerType {
anchors.topMargin: 16 anchors.topMargin: 16
backButtonFunction: function() { backButtonFunction: function() {
configContentDrawer.visible = false configContentDrawer.close()
} }
} }
@@ -191,12 +209,18 @@ DrawerType {
id: configContentHeader id: configContentHeader
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
headerText: root.configContentHeaderText
} }
TextField { TextField {
id: nativeConfigString id: nativeConfigString
visible: false visible: false
text: ExportController.nativeConfigString text: ExportController.nativeConfigString
onTextChanged: {
copyNativeConfigStringButton.visible = nativeConfigString.text !== ""
}
} }
TextArea { TextArea {
@@ -231,6 +255,7 @@ DrawerType {
} }
} }
} }
}
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
+60 -6
View File
@@ -16,19 +16,38 @@ Button {
property string textColor: "#0E0E11" property string textColor: "#0E0E11"
property string borderColor: "#D7D8DB" property string borderColor: "#D7D8DB"
property string borderFocusedColor: "#D7D8DB"
property int borderWidth: 0 property int borderWidth: 0
property int borderFocusedWidth: 1
property string imageSource property string imageSource
property string rightImageSource
property string leftImageColor: textColor
property bool squareLeftSide: false property bool squareLeftSide: false
property var clickedFunc
implicitHeight: 56 implicitHeight: 56
hoverEnabled: true hoverEnabled: true
background: Rectangle { background: Rectangle {
id: background id: background_border
color: "transparent"
border.color: root.activeFocus ? root.borderFocusedColor : "transparent"
border.width: root.activeFocus ? root.borderFocusedWidth : "transparent"
anchors.fill: parent anchors.fill: parent
radius: 16
Rectangle {
id: background
anchors.fill: background_border
anchors.margins: root.activeFocus ? 2: 0
radius: 16 radius: 16
color: { color: {
if (root.enabled) { if (root.enabled) {
@@ -40,8 +59,8 @@ Button {
return disabledColor return disabledColor
} }
} }
border.color: borderColor border.color: root.activeFocus ? "transparent" : borderColor
border.width: borderWidth border.width: root.activeFocus ? 0 : borderWidth
Behavior on color { Behavior on color {
PropertyAnimation { duration: 200 } PropertyAnimation { duration: 200 }
@@ -73,18 +92,20 @@ Button {
} }
} }
} }
}
MouseArea { MouseArea {
anchors.fill: background anchors.fill: background_border
enabled: false enabled: false
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }
contentItem: Item { contentItem: Item {
anchors.fill: background anchors.fill: background_border
implicitWidth: content.implicitWidth implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight implicitHeight: content.implicitHeight
RowLayout { RowLayout {
id: content id: content
anchors.centerIn: parent anchors.centerIn: parent
@@ -99,7 +120,7 @@ Button {
layer { layer {
enabled: true enabled: true
effect: ColorOverlay { effect: ColorOverlay {
color: textColor color: leftImageColor
} }
} }
} }
@@ -112,6 +133,39 @@ Button {
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
Image {
Layout.preferredHeight: 20
Layout.preferredWidth: 20
source: root.rightImageSource
visible: root.rightImageSource === "" ? false : true
layer {
enabled: true
effect: ColorOverlay {
color: textColor
}
}
}
}
}
Keys.onEnterPressed: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
Keys.onReturnPressed: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
onClicked: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
} }
} }
} }
-84
View File
@@ -1,84 +0,0 @@
import QtQuick
import QtQuick.Controls
import "../Config"
Drawer {
id: drawer
property bool needCloseButton: true
Connections {
target: PageController
function onForceCloseDrawer() {
visible = false
}
}
edge: Qt.BottomEdge
clip: true
modal: true
dragMargin: -10
enter: Transition {
SmoothedAnimation {
velocity: 4
}
}
exit: Transition {
SmoothedAnimation {
velocity: 4
}
}
background: Rectangle {
anchors.fill: parent
anchors.bottomMargin: -radius
radius: 16
color: "#1C1D21"
border.color: "#2C2D30"
border.width: 1
Rectangle {
visible: GC.isMobile()
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 10
width: 20
height: 2
color: "#2C2D30"
}
}
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
onAboutToShow: {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
}
onOpened: {
if (needCloseButton) {
PageController.drawerOpen()
}
}
onClosed: {
if (needCloseButton) {
PageController.drawerClose()
}
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
}
}
+242
View File
@@ -0,0 +1,242 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "TextTypes"
Item {
id: root
readonly property string drawerExpanded: "expanded"
readonly property string drawerCollapsed: "collapsed"
readonly property bool isOpened: drawerContent.state === root.drawerExpanded || (drawerContent.state === root.drawerCollapsed && dragArea.drag.active === true)
readonly property bool isClosed: drawerContent.state === root.drawerCollapsed && dragArea.drag.active === false
readonly property bool isExpanded: drawerContent.state === root.drawerExpanded
readonly property bool isCollapsed: drawerContent.state === root.drawerCollapsed
property Component collapsedContent
property Component expandedContent
property string defaultColor: "#1C1D21"
property string borderColor: "#2C2D30"
property real expandedHeight
property real collapsedHeight: 0
signal entered
signal exited
signal pressed(bool pressed, bool entered)
signal aboutToHide
signal aboutToShow
signal close
signal open
signal closed
signal opened
Connections {
target: root
function onClose() {
if (isCollapsed) {
return
}
aboutToHide()
drawerContent.state = root.drawerCollapsed
closed()
}
function onOpen() {
if (isExpanded) {
return
}
aboutToShow()
drawerContent.state = root.drawerExpanded
opened()
}
}
/** Set once based on first implicit height change once all children are layed out */
Component.onCompleted: {
if (root.isCollapsed && root.collapsedHeight == 0) {
root.collapsedHeight = drawerContent.implicitHeight
}
}
Rectangle {
id: background
anchors.fill: parent
color: root.isCollapsed ? "transparent" : Qt.rgba(14/255, 14/255, 17/255, 0.8)
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
MouseArea {
id: emptyArea
anchors.fill: parent
enabled: root.isExpanded
visible: enabled
onClicked: {
root.close()
}
}
MouseArea {
id: dragArea
anchors.fill: drawerContentBackground
cursorShape: root.isCollapsed ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
enabled: drawerContent.implicitHeight > 0
drag.target: drawerContent
drag.axis: Drag.YAxis
drag.maximumY: root.height - root.collapsedHeight
drag.minimumY: root.height - root.expandedHeight
/** If drag area is released at any point other than min or max y, transition to the other state */
onReleased: {
if (root.isCollapsed && drawerContent.y < dragArea.drag.maximumY) {
root.open()
return
}
if (root.isExpanded && drawerContent.y > dragArea.drag.minimumY) {
root.close()
return
}
}
onEntered: {
root.entered()
}
onExited: {
root.exited()
}
onPressedChanged: {
root.pressed(pressed, entered)
}
onClicked: {
if (root.isCollapsed) {
root.open()
}
}
}
Rectangle {
id: drawerContentBackground
anchors { left: drawerContent.left; right: drawerContent.right; top: drawerContent.top }
height: root.height
radius: 16
color: root.defaultColor
border.color: root.borderColor
border.width: 1
Rectangle {
width: parent.radius
height: parent.radius
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
color: parent.color
}
}
Item {
id: drawerContent
Drag.active: dragArea.drag.active
anchors.right: root.right
anchors.left: root.left
y: root.height - drawerContent.height
state: root.drawerCollapsed
implicitHeight: root.isCollapsed ? collapsedLoader.implicitHeight : expandedLoader.implicitHeight
onStateChanged: {
if (root.isCollapsed) {
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
return
}
if (root.isExpanded) {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
return
}
}
states: [
State {
name: root.drawerCollapsed
PropertyChanges {
target: drawerContent
y: root.height - root.collapsedHeight
}
},
State {
name: root.drawerExpanded
PropertyChanges {
target: drawerContent
y: dragArea.drag.minimumY
}
}
]
transitions: [
Transition {
from: root.drawerCollapsed
to: root.drawerExpanded
PropertyAnimation {
target: drawerContent
properties: "y"
duration: 200
}
},
Transition {
from: root.drawerExpanded
to: root.drawerCollapsed
PropertyAnimation {
target: drawerContent
properties: "y"
duration: 200
}
}
]
Loader {
id: collapsedLoader
visible: root.isCollapsed
sourceComponent: root.collapsedContent
anchors.right: parent.right
anchors.left: parent.left
}
Loader {
id: expandedLoader
visible: root.isExpanded
sourceComponent: root.expandedContent
anchors.right: parent.right
anchors.left: parent.left
}
}
}
+25 -13
View File
@@ -36,19 +36,23 @@ Item {
property int rootButtonTextBottomMargin: 16 property int rootButtonTextBottomMargin: 16
property real drawerHeight: 0.9 property real drawerHeight: 0.9
property Item drawerParent
property Component listView property Component listView
property alias menuVisible: menu.visible signal open
signal close
implicitWidth: rootButtonContent.implicitWidth implicitWidth: rootButtonContent.implicitWidth
implicitHeight: rootButtonContent.implicitHeight implicitHeight: rootButtonContent.implicitHeight
onMenuVisibleChanged: { onOpen: {
if (menuVisible) { menu.open()
rootButtonBackground.border.color = rootButtonPressedBorderColor rootButtonBackground.border.color = rootButtonPressedBorderColor
} else {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
} }
onClose: {
menu.close()
rootButtonBackground.border.color = rootButtonDefaultBorderColor
} }
onEnabledChanged: { onEnabledChanged: {
@@ -133,21 +137,21 @@ Item {
hoverEnabled: root.enabled ? true : false hoverEnabled: root.enabled ? true : false
onEntered: { onEntered: {
if (menu.visible === false) { if (menu.isClosed) {
rootButtonBackground.border.color = rootButtonHoveredBorderColor rootButtonBackground.border.color = rootButtonHoveredBorderColor
rootButtonBackground.color = rootButtonBackgroundHoveredColor rootButtonBackground.color = rootButtonBackgroundHoveredColor
} }
} }
onExited: { onExited: {
if (menu.visible === false) { if (menu.isClosed) {
rootButtonBackground.border.color = rootButtonDefaultBorderColor rootButtonBackground.border.color = rootButtonDefaultBorderColor
rootButtonBackground.color = rootButtonBackgroundColor rootButtonBackground.color = rootButtonBackgroundColor
} }
} }
onPressed: { onPressed: {
if (menu.visible === false) { if (menu.isClosed) {
rootButtonBackground.color = pressed ? rootButtonBackgroundPressedColor : entered ? rootButtonHoveredBorderColor : rootButtonDefaultBorderColor rootButtonBackground.color = pressed ? rootButtonBackgroundPressedColor : entered ? rootButtonHoveredBorderColor : rootButtonDefaultBorderColor
} }
} }
@@ -156,16 +160,23 @@ Item {
if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") { if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") {
rootButtonClickedFunction() rootButtonClickedFunction()
} else { } else {
menu.visible = true menu.open()
} }
} }
} }
DrawerType { DrawerType2 {
id: menu id: menu
width: parent.width parent: drawerParent
height: parent.height * drawerHeight
anchors.fill: parent
expandedHeight: drawerParent.height * drawerHeight
expandedContent: Item {
id: container
implicitHeight: menu.expandedHeight
ColumnLayout { ColumnLayout {
id: header id: header
@@ -178,7 +189,7 @@ Item {
BackButtonType { BackButtonType {
backButtonImage: root.headerBackButtonImage backButtonImage: root.headerBackButtonImage
backButtonFunction: function() { backButtonFunction: function() {
root.menuVisible = false menu.close()
} }
} }
} }
@@ -214,4 +225,5 @@ Item {
} }
} }
} }
}
} }
+15
View File
@@ -7,6 +7,8 @@ Item {
property StackView stackView: StackView.view property StackView stackView: StackView.view
property var defaultActiveFocusItem: null
// MouseArea { // MouseArea {
// id: globalMouseArea // id: globalMouseArea
// z: 99 // z: 99
@@ -19,4 +21,17 @@ Item {
// mouse.accepted = false // mouse.accepted = false
// } // }
// } // }
// Set a timer to set focus after a short delay
Timer {
id: timer
interval: 100 // Milliseconds
onTriggered: {
if (defaultActiveFocusItem) {
defaultActiveFocusItem.forceActiveFocus()
}
}
repeat: false // Stop the timer after one trigger
running: true // Start the timer
}
} }
+1 -1
View File
@@ -66,7 +66,7 @@ Popup {
borderWidth: 0 borderWidth: 0
text: qsTr("Close") text: qsTr("Close")
onClicked: { clickedFunc: function() {
root.close() root.close()
} }
} }
@@ -69,10 +69,13 @@ Item {
TextField { TextField {
id: textField id: textField
activeFocusOnTab: false
enabled: root.textFieldEditable enabled: root.textFieldEditable
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
placeholderText: root.textFieldPlaceholderText placeholderText: root.textFieldPlaceholderText
placeholderTextColor: "#494B50" placeholderTextColor: "#494B50"
@@ -142,7 +145,7 @@ Item {
Layout.preferredWidth: content.implicitHeight Layout.preferredWidth: content.implicitHeight
squareLeftSide: true squareLeftSide: true
onClicked: { clickedFunc: function() {
if (root.clickedFunc && typeof root.clickedFunc === "function") { if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc() root.clickedFunc()
} }
@@ -186,4 +189,12 @@ Item {
function getBackgroundBorderColor(noneFocusedColor) { function getBackgroundBorderColor(noneFocusedColor) {
return textField.focus ? root.borderFocusedColor : noneFocusedColor return textField.focus ? root.borderFocusedColor : noneFocusedColor
} }
Keys.onEnterPressed: {
KeyNavigation.tab.forceActiveFocus();
}
Keys.onReturnPressed: {
KeyNavigation.tab.forceActiveFocus();
}
} }
+99 -200
View File
@@ -18,199 +18,75 @@ import "../Components"
PageType { PageType {
id: root id: root
property string defaultColor: "#1C1D21"
property string borderColor: "#2C2D30"
Connections { Connections {
target: PageController target: PageController
function onRestorePageHomeState(isContainerInstalled) { function onRestorePageHomeState(isContainerInstalled) {
buttonContent.state = "expanded" drawer.open()
if (isContainerInstalled) { if (isContainerInstalled) {
containersDropDown.rootButtonClickedFunction() containersDropDown.rootButtonClickedFunction()
} }
} }
function onForceCloseDrawer() {
buttonContent.state = "collapsed"
}
}
MouseArea {
anchors.fill: parent
enabled: buttonContent.state === "expanded"
onClicked: {
buttonContent.state = "collapsed"
}
} }
Item { Item {
anchors.fill: parent anchors.fill: parent
anchors.bottomMargin: buttonContent.collapsedHeight anchors.bottomMargin: drawer.collapsedHeight
ConnectButton { ConnectButton {
id: connectButton
anchors.centerIn: parent anchors.centerIn: parent
} }
}
MouseArea { BasicButtonType {
id: dragArea anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 34
leftPadding: 16
rightPadding: 16
anchors.fill: buttonBackground implicitHeight: 36
cursorShape: buttonContent.state === "collapsed" ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
drag.target: buttonContent defaultColor: "transparent"
drag.axis: Drag.YAxis hoveredColor: Qt.rgba(1, 1, 1, 0.08)
drag.maximumY: root.height - buttonContent.collapsedHeight pressedColor: Qt.rgba(1, 1, 1, 0.12)
drag.minimumY: root.height - root.height * 0.9 disabledColor: "#878B91"
textColor: "#878B91"
leftImageColor: "transparent"
borderWidth: 0
/** If drag area is released at any point other than min or max y, transition to the other state */ property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled ||
onReleased: { (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi"))
if (buttonContent.state === "collapsed" && buttonContent.y < dragArea.drag.maximumY) {
buttonContent.state = "expanded"
return
}
if (buttonContent.state === "expanded" && buttonContent.y > dragArea.drag.minimumY) {
buttonContent.state = "collapsed"
return
}
}
onEntered: { text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
}
onExited: {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
}
onPressedChanged: {
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
}
imageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
rightImageSource: "qrc:/images/controls/chevron-down.svg"
onClicked: { onClicked: {
if (buttonContent.state === "collapsed") { homeSplitTunnelingDrawer.open()
buttonContent.state = "expanded" }
HomeSplitTunnelingDrawer {
id: homeSplitTunnelingDrawer
parent: root
} }
} }
} }
Rectangle {
id: buttonBackground
anchors { left: buttonContent.left; right: buttonContent.right; top: buttonContent.top } DrawerType2 {
height: root.height id: drawer
radius: 16 anchors.fill: parent
color: root.defaultColor
border.color: root.borderColor
border.width: 1
Rectangle {
width: parent.radius
height: parent.radius
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
color: parent.color
}
}
ColumnLayout {
id: buttonContent
/** Initial height of button content */
property int collapsedHeight: 0
/** True when expanded objects should be visible */
property bool expandedVisibility: buttonContent.state === "expanded" || (buttonContent.state === "collapsed" && dragArea.drag.active === true)
/** True when collapsed objects should be visible */
property bool collapsedVisibility: buttonContent.state === "collapsed" && dragArea.drag.active === false
Drag.active: dragArea.drag.active
anchors.right: root.right
anchors.left: root.left
y: root.height - buttonContent.height
Component.onCompleted: {
buttonContent.state = "collapsed"
}
/** Set once based on first implicit height change once all children are layed out */
onImplicitHeightChanged: {
if (buttonContent.state === "collapsed" && collapsedHeight == 0) {
collapsedHeight = implicitHeight
}
}
onStateChanged: {
if (buttonContent.state === "collapsed") {
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
PageController.drawerClose()
return
}
if (buttonContent.state === "expanded") {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
PageController.drawerOpen()
return
}
}
/** Two states of buttonContent, great place to add any future animations for the drawer */
states: [
State {
name: "collapsed"
PropertyChanges {
target: buttonContent
y: root.height - collapsedHeight
}
},
State {
name: "expanded"
PropertyChanges {
target: buttonContent
y: dragArea.drag.minimumY
}
}
]
transitions: [
Transition {
from: "collapsed"
to: "expanded"
PropertyAnimation {
target: buttonContent
properties: "y"
duration: 200
}
},
Transition {
from: "expanded"
to: "collapsed"
PropertyAnimation {
target: buttonContent
properties: "y"
duration: 200
}
}
]
collapsedContent: ColumnLayout {
DividerType { DividerType {
Layout.topMargin: 10 Layout.topMargin: 10
Layout.fillWidth: false Layout.fillWidth: false
Layout.preferredWidth: 20 Layout.preferredWidth: 20
Layout.preferredHeight: 2 Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: (buttonContent.collapsedVisibility || buttonContent.expandedVisibility)
} }
RowLayout { RowLayout {
@@ -218,13 +94,30 @@ PageType {
Layout.leftMargin: 24 Layout.leftMargin: 24
Layout.rightMargin: 24 Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: buttonContent.collapsedVisibility
spacing: 0 spacing: 0
Connections {
target: drawer
function onEntered() {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
}
function onExited() {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
}
function onPressed(pressed, entered) {
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
}
}
Header1TextType { Header1TextType {
id: collapsedButtonHeader id: collapsedButtonHeader
Layout.maximumWidth: buttonContent.width - 48 - 18 - 12 // todo Layout.maximumWidth: drawer.width - 48 - 18 - 12 // todo
maximumLineCount: 2 maximumLineCount: 2
elide: Qt.ElideRight elide: Qt.ElideRight
@@ -254,8 +147,8 @@ PageType {
bottomPadding: 3 bottomPadding: 3
onClicked: { onClicked: {
if (buttonContent.state === "collapsed") { if (drawer.isCollapsed) {
buttonContent.state = "expanded" drawer.open()
} }
} }
} }
@@ -265,16 +158,26 @@ PageType {
id: collapsedServerMenuDescription id: collapsedServerMenuDescription
Layout.bottomMargin: 44 Layout.bottomMargin: 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: buttonContent.collapsedVisibility
text: ServersModel.defaultServerDescriptionCollapsed text: ServersModel.defaultServerDescriptionCollapsed
} }
}
expandedContent: Item {
id: serverMenuContainer
implicitHeight: root.height * 0.9
Component.onCompleted: {
drawer.expandedHeight = serverMenuContainer.implicitHeight
}
ColumnLayout { ColumnLayout {
id: serversMenuHeader id: serversMenuHeader
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter anchors.top: parent.top
Layout.fillWidth: true anchors.right: parent.right
visible: buttonContent.expandedVisibility anchors.left: parent.left
Header1TextType { Header1TextType {
Layout.fillWidth: true Layout.fillWidth: true
@@ -290,7 +193,7 @@ PageType {
LabelTextType { LabelTextType {
id: expandedServersMenuDescription id: expandedServersMenuDescription
Layout.bottomMargin: 24 Layout.bottomMargin: ServersModel.isDefaultServerFromApi ? 69 : 24
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter verticalAlignment: Qt.AlignVCenter
@@ -301,6 +204,9 @@ PageType {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8 spacing: 8
visible: !ServersModel.isDefaultServerFromApi
onVisibleChanged: expandedServersMenuDescription.Layout
DropDownType { DropDownType {
id: containersDropDown id: containersDropDown
@@ -313,38 +219,43 @@ PageType {
rootButtonTextTopMargin: 8 rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8 rootButtonTextBottomMargin: 8
text: ServersModel.defaultContainerName text: ServersModel.defaultServerDefaultContainerName
textColor: "#0E0E11" textColor: "#0E0E11"
headerText: qsTr("VPN protocol") headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg" headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() { rootButtonClickedFunction: function() {
ServersModel.currentlyProcessedIndex = serversMenuContent.currentIndex containersDropDown.open()
containersDropDown.menuVisible = true
} }
drawerParent: root
listView: HomeContainersListView { listView: HomeContainersListView {
rootWidth: root.width rootWidth: root.width
Connections { Connections {
target: ServersModel target: ServersModel
function onCurrentlyProcessedServerIndexChanged() { function onDefaultServerIndexChanged() {
updateContainersModelFilters() updateContainersModelFilters()
} }
} }
function updateContainersModelFilters() { function updateContainersModelFilters() {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { if (ServersModel.isDefaultServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters() proxyDefaultServerContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else { } else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters() proxyDefaultServerContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
} }
} }
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxyContainersModel id: proxyDefaultServerContainersModel
sourceModel: ContainersModel sourceModel: DefaultServerContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
} }
Component.onCompleted: updateContainersModelFilters() Component.onCompleted: updateContainersModelFilters()
@@ -357,7 +268,6 @@ PageType {
Layout.topMargin: 48 Layout.topMargin: 48
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
visible: buttonContent.expandedVisibility
headerText: qsTr("Servers") headerText: qsTr("Servers")
} }
@@ -365,12 +275,14 @@ PageType {
Flickable { Flickable {
id: serversContainer id: serversContainer
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Layout.fillWidth: true anchors.top: serversMenuHeader.bottom
Layout.topMargin: 16 anchors.right: parent.right
contentHeight: col.implicitHeight anchors.left: parent.left
implicitHeight: root.height - (root.height * 0.1) - serversMenuHeader.implicitHeight - 52 //todo 52 is tabbar height anchors.topMargin: 16
visible: buttonContent.expandedVisibility
contentHeight: col.height + col.anchors.bottomMargin
implicitHeight: parent.height - serversMenuHeader.implicitHeight
clip: true clip: true
ScrollBar.vertical: ScrollBar { ScrollBar.vertical: ScrollBar {
@@ -386,6 +298,7 @@ PageType {
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.bottomMargin: 32
spacing: 16 spacing: 16
@@ -435,21 +348,7 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
text: name text: name
descriptionText: { descriptionText: serverDescription
var fullDescription = ""
if (hasWriteAccess) {
if (SettingsController.isAmneziaDnsEnabled()
&& ServersModel.isAmneziaDnsContainerInstalled(index)) {
fullDescription += "Amnezia DNS | "
}
} else {
if (containsAmneziaDns) {
fullDescription += "Amnezia DNS | "
}
}
return fullDescription += serverDescription
}
checked: index === serversMenuContent.currentIndex checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected checkable: !ConnectionController.isConnected
@@ -464,7 +363,6 @@ PageType {
serversMenuContent.currentIndex = index serversMenuContent.currentIndex = index
ServersModel.currentlyProcessedIndex = index
ServersModel.defaultIndex = index ServersModel.defaultIndex = index
} }
@@ -485,9 +383,9 @@ PageType {
z: 1 z: 1
onClicked: function() { onClicked: function() {
ServersModel.currentlyProcessedIndex = index ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo) PageController.goToPage(PageEnum.PageSettingsServerInfo)
buttonContent.state = "collapsed" drawer.close()
} }
} }
} }
@@ -503,4 +401,5 @@ PageType {
} }
} }
} }
}
} }
@@ -12,9 +12,12 @@ import "../Controls2/TextTypes"
import "../Config" import "../Config"
import "../Components" import "../Components"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
ColumnLayout { ColumnLayout {
id: backButton id: backButton
@@ -41,9 +44,11 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView { ListView {
id: listview id: listview
width: parent.width width: parent.width
@@ -55,9 +60,13 @@ PageType {
model: AwgConfigModel model: AwgConfigModel
delegate: Item { delegate: Item {
id: _delegate
implicitWidth: listview.width implicitWidth: listview.width
implicitHeight: col.implicitHeight implicitHeight: col.implicitHeight
property alias portTextField:portTextField
ColumnLayout { ColumnLayout {
id: col id: col
@@ -93,6 +102,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -116,6 +127,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -134,6 +147,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -152,6 +167,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: initPacketJunkSizeTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -170,6 +187,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: responsePacketJunkSizeTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -188,6 +207,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: initPacketMagicHeaderTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -206,6 +227,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: responsePacketMagicHeaderTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -224,6 +247,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: transportPacketMagicHeaderTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -242,6 +267,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: underloadPacketMagicHeaderTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -260,6 +287,8 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: saveRestartButton
} }
BasicButtonType { BasicButtonType {
@@ -275,24 +304,24 @@ PageType {
text: qsTr("Remove AmneziaWG") text: qsTr("Remove AmneziaWG")
onClicked: { onClicked: {
questionDrawer.headerText = qsTr("Remove AmneziaWG from server?") var headerText = qsTr("Remove AmneziaWG from server?")
questionDrawer.descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.") var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeCurrentlyProcessedContainer()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
BasicButtonType { BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
@@ -310,7 +339,7 @@ PageType {
text: qsTr("Save and Restart Amnezia") text: qsTr("Save and Restart Amnezia")
onClicked: { clickedFunc: function() {
forceActiveFocus() forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig()) InstallController.updateContainer(AwgConfigModel.getConfig())
@@ -318,11 +347,8 @@ PageType {
} }
} }
} }
}
}
QuestionDrawer { }
id: questionDrawer
} }
} }
} }
@@ -15,6 +15,8 @@ import "../Components"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
ColumnLayout { ColumnLayout {
id: backButton id: backButton
@@ -41,7 +43,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView { ListView {
id: listview id: listview
@@ -58,6 +60,8 @@ PageType {
implicitWidth: listview.width implicitWidth: listview.width
implicitHeight: col.implicitHeight implicitHeight: col.implicitHeight
property alias trafficFromField: trafficFromField
ColumnLayout { ColumnLayout {
id: col id: col
@@ -77,6 +81,8 @@ PageType {
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: trafficFromField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
@@ -96,9 +102,13 @@ PageType {
} }
} }
} }
KeyNavigation.tab: portTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
@@ -112,6 +122,8 @@ PageType {
port = textFieldText port = textFieldText
} }
} }
KeyNavigation.tab: saveRestartButton
} }
DropDownType { DropDownType {
@@ -122,6 +134,8 @@ PageType {
descriptionText: qsTr("Cipher") descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher") headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType { listView: ListViewWithRadioButtonType {
id: cipherListView id: cipherListView
@@ -138,7 +152,7 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
cipherDropDown.text = selectedText cipherDropDown.text = selectedText
cipher = cipherDropDown.text cipher = cipherDropDown.text
cipherDropDown.menuVisible = false cipherDropDown.close()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -154,13 +168,15 @@ PageType {
} }
BasicButtonType { BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia") text: qsTr("Save and Restart Amnezia")
onClicked: { clickedFunc: function() {
forceActiveFocus() forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(CloakConfigModel.getConfig()) InstallController.updateContainer(CloakConfigModel.getConfig())
@@ -16,6 +16,8 @@ import "../Components"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
ColumnLayout { ColumnLayout {
id: backButton id: backButton
@@ -42,7 +44,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView { ListView {
id: listview id: listview
@@ -59,6 +61,8 @@ PageType {
implicitWidth: listview.width implicitWidth: listview.width
implicitHeight: col.implicitHeight implicitHeight: col.implicitHeight
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
ColumnLayout { ColumnLayout {
id: col id: col
@@ -78,6 +82,8 @@ PageType {
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
@@ -89,6 +95,8 @@ PageType {
subnetAddress = textFieldText subnetAddress = textFieldText
} }
} }
KeyNavigation.tab: portTextField.enabled ? portTextField.textField : saveRestartButton
} }
ParagraphTextType { ParagraphTextType {
@@ -119,6 +127,9 @@ PageType {
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
@@ -134,6 +145,8 @@ PageType {
port = textFieldText port = textFieldText
} }
} }
KeyNavigation.tab: saveRestartButton
} }
SwitcherType { SwitcherType {
@@ -162,6 +175,8 @@ PageType {
descriptionText: qsTr("Hash") descriptionText: qsTr("Hash")
headerText: qsTr("Hash") headerText: qsTr("Hash")
drawerParent: root
listView: ListViewWithRadioButtonType { listView: ListViewWithRadioButtonType {
id: hashListView id: hashListView
@@ -183,7 +198,7 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
hashDropDown.text = selectedText hashDropDown.text = selectedText
hash = hashDropDown.text hash = hashDropDown.text
hashDropDown.menuVisible = false hashDropDown.close()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -208,6 +223,8 @@ PageType {
descriptionText: qsTr("Cipher") descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher") headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType { listView: ListViewWithRadioButtonType {
id: cipherListView id: cipherListView
@@ -229,7 +246,7 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
cipherDropDown.text = selectedText cipherDropDown.text = selectedText
cipher = cipherDropDown.text cipher = cipherDropDown.text
cipherDropDown.menuVisible = false cipherDropDown.close()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -363,32 +380,33 @@ PageType {
text: qsTr("Remove OpenVPN") text: qsTr("Remove OpenVPN")
onClicked: { clickedFunc: function() {
questionDrawer.headerText = qsTr("Remove OpenVpn from server?") var headerText = qsTr("Remove OpenVpn from server?")
questionDrawer.descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.") var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeCurrentlyProcessedContainer()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
BasicButtonType { BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia") text: qsTr("Save and Restart Amnezia")
onClicked: { clickedFunc: function() {
forceActiveFocus() forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(OpenVpnConfigModel.getConfig()) InstallController.updateContainer(OpenVpnConfigModel.getConfig())
@@ -398,9 +416,5 @@ PageType {
} }
} }
} }
QuestionDrawer {
id: questionDrawer
}
} }
} }
+19 -18
View File
@@ -90,11 +90,16 @@ PageType {
DividerType {} DividerType {}
DrawerType { DrawerType2 {
id: configContentDrawer id: configContentDrawer
width: parent.width expandedHeight: root.height * 0.9
height: parent.height * 0.9
parent: root
anchors.fill: parent
expandedContent: Item {
implicitHeight: configContentDrawer.expandedHeight
BackButtonType { BackButtonType {
id: backButton id: backButton
@@ -105,7 +110,7 @@ PageType {
anchors.topMargin: 16 anchors.topMargin: 16
backButtonFunction: function() { backButtonFunction: function() {
configContentDrawer.visible = false configContentDrawer.close()
} }
} }
@@ -163,32 +168,32 @@ PageType {
} }
} }
} }
}
LabelWithButtonType { LabelWithButtonType {
id: removeButton id: removeButton
width: parent.width width: parent.width
visible: ServersModel.isCurrentlyProcessedServerHasWriteAccess() visible: ServersModel.isProcessedServerHasWriteAccess()
text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName() text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName()
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName()) var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
questionDrawer.descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.") var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeCurrentlyProcessedContainer()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
MouseArea { MouseArea {
@@ -200,9 +205,5 @@ PageType {
DividerType {} DividerType {}
} }
QuestionDrawer {
id: questionDrawer
}
} }
} }
@@ -15,6 +15,8 @@ import "../Components"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
ColumnLayout { ColumnLayout {
id: backButton id: backButton
@@ -41,7 +43,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView { ListView {
id: listview id: listview
@@ -58,6 +60,8 @@ PageType {
implicitWidth: listview.width implicitWidth: listview.width
implicitHeight: col.implicitHeight implicitHeight: col.implicitHeight
property alias portTextField: portTextField
ColumnLayout { ColumnLayout {
id: col id: col
@@ -77,6 +81,8 @@ PageType {
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
@@ -90,6 +96,8 @@ PageType {
port = textFieldText port = textFieldText
} }
} }
KeyNavigation.tab: saveRestartButton
} }
DropDownType { DropDownType {
@@ -100,6 +108,8 @@ PageType {
descriptionText: qsTr("Cipher") descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher") headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType { listView: ListViewWithRadioButtonType {
id: cipherListView id: cipherListView
@@ -116,7 +126,7 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
cipherDropDown.text = selectedText cipherDropDown.text = selectedText
cipher = cipherDropDown.text cipher = cipherDropDown.text
cipherDropDown.menuVisible = false cipherDropDown.close()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -132,13 +142,15 @@ PageType {
} }
BasicButtonType { BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia") text: qsTr("Save and Restart Amnezia")
onClicked: { clickedFunc: function() {
forceActiveFocus() forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(ShadowSocksConfigModel.getConfig()) InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
@@ -63,19 +63,18 @@ PageType {
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName()) var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeCurrentlyProcessedContainer()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
MouseArea { MouseArea {
@@ -86,10 +85,6 @@ PageType {
} }
DividerType {} DividerType {}
QuestionDrawer {
id: questionDrawer
}
} }
} }
} }
@@ -49,7 +49,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView { ListView {
id: listview id: listview
@@ -88,7 +88,7 @@ PageType {
Layout.topMargin: 32 Layout.topMargin: 32
text: qsTr("Host") text: qsTr("Host")
descriptionText: ServersModel.getCurrentlyProcessedServerHostName() descriptionText: ServersModel.getProcessedServerData("HostName")
descriptionOnTop: true descriptionOnTop: true
@@ -170,7 +170,7 @@ PageType {
text: qsTr("Mount folder on device") text: qsTr("Mount folder on device")
onClicked: { clickedFunc: function() {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
InstallController.mountSftpDrive(port, password, username) InstallController.mountSftpDrive(port, password, username)
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
@@ -229,7 +229,7 @@ PageType {
text: qsTr("Detailed instructions") text: qsTr("Detailed instructions")
onClicked: { clickedFunc: function() {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") // Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
} }
} }
@@ -247,29 +247,24 @@ PageType {
text: qsTr("Remove SFTP and all data stored there") text: qsTr("Remove SFTP and all data stored there")
onClicked: { clickedFunc: function() {
questionDrawer.headerText = qsTr("Remove SFTP and all data stored there?") var headerText = qsTr("Remove SFTP and all data stored there?")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeCurrentlyProcessedContainer()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
}
}
}
} }
QuestionDrawer { showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
id: questionDrawer }
}
}
}
}
} }
} }
} }
@@ -125,26 +125,21 @@ PageType {
text: qsTr("Remove website") text: qsTr("Remove website")
onClicked: { clickedFunc: function() {
questionDrawer.headerText = qsTr("The site with all data will be removed from the tor network.") var headerText = qsTr("The site with all data will be removed from the tor network.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeCurrentlyProcessedContainer()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
} }
QuestionDrawer { showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
id: questionDrawer }
}
} }
} }
} }
+6 -4
View File
@@ -81,7 +81,7 @@ PageType {
text: qsTr("Card on Patreon") text: qsTr("Card on Patreon")
onClicked: function() { clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://www.patreon.com/amneziavpn")) Qt.openUrlExternally(qsTr("https://www.patreon.com/amneziavpn"))
} }
} }
@@ -101,7 +101,9 @@ PageType {
text: qsTr("Show other methods on Github") text: qsTr("Show other methods on Github")
onClicked: Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate")) clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate"))
}
} }
ParagraphTextType { ParagraphTextType {
@@ -173,7 +175,7 @@ PageType {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: SettingsController.getAppVersion() text: qsTr("Software version: %1").arg(SettingsController.getAppVersion())
color: "#878B91" color: "#878B91"
} }
@@ -191,7 +193,7 @@ PageType {
text: qsTr("Check for updates") text: qsTr("Check for updates")
onClicked: { clickedFunc: function() {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
} }
} }
@@ -84,6 +84,27 @@ PageType {
visible: !GC.isMobile() visible: !GC.isMobile()
} }
SwitcherType {
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.margins: 16
text: qsTr("Auto connect")
descriptionText: qsTr("Connect to VPN on app start")
checked: SettingsController.isAutoConnectEnabled()
onCheckedChanged: {
if (checked !== SettingsController.isAutoConnectEnabled()) {
SettingsController.toggleAutoConnect(checked)
}
}
}
DividerType {
visible: !GC.isMobile()
}
SwitcherType { SwitcherType {
visible: !GC.isMobile() visible: !GC.isMobile()
@@ -117,10 +138,6 @@ PageType {
} }
} }
SelectLanguageDrawer {
id: selectLanguageDrawer
}
DividerType {} DividerType {}
@@ -143,30 +160,33 @@ PageType {
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: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Reset settings and remove all data from the application?") var headerText = qsTr("Reset settings and remove all data from the application?")
questionDrawer.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.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
SettingsController.clearSettings() SettingsController.clearSettings()
PageController.replaceStartPage() PageController.replaceStartPage()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType {} DividerType {}
}
}
QuestionDrawer { SelectLanguageDrawer {
id: questionDrawer id: selectLanguageDrawer
}
} width: root.width
height: root.height
} }
} }
+9 -14
View File
@@ -88,7 +88,7 @@ PageType {
text: qsTr("Make a backup") text: qsTr("Make a backup")
onClicked: { clickedFunc: function() {
var fileName = "" var fileName = ""
if (GC.isMobile()) { if (GC.isMobile()) {
fileName = "AmneziaVPN.backup" fileName = "AmneziaVPN.backup"
@@ -121,7 +121,7 @@ PageType {
text: qsTr("Restore from backup") text: qsTr("Restore from backup")
onClicked: { 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)"))
if (filePath !== "") { if (filePath !== "") {
@@ -133,24 +133,19 @@ PageType {
} }
function restoreBackup(filePath) { function restoreBackup(filePath) {
questionDrawer.headerText = qsTr("Import settings from a backup file?") var headerText = qsTr("Import settings from a backup file?")
questionDrawer.descriptionText = qsTr("All current settings will be reset"); var descriptionText = qsTr("All current settings will be reset");
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
SettingsController.restoreAppConfig(filePath) SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
} }
QuestionDrawer { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
id: questionDrawer
} }
} }
@@ -41,27 +41,6 @@ PageType {
headerText: qsTr("Connection") headerText: qsTr("Connection")
} }
SwitcherType {
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.margins: 16
text: qsTr("Auto connect")
descriptionText: qsTr("Connect to VPN on app start")
checked: SettingsController.isAutoConnectEnabled()
onCheckedChanged: {
if (checked !== SettingsController.isAutoConnectEnabled()) {
SettingsController.toggleAutoConnect(checked)
}
}
}
DividerType {
visible: !GC.isMobile()
}
SwitcherType { SwitcherType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
+22 -15
View File
@@ -13,6 +13,8 @@ import "../Components"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: primaryDns.textField
BackButtonType { BackButtonType {
id: backButton id: backButton
@@ -28,10 +30,12 @@ PageType {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height contentHeight: content.height
enabled: !ServersModel.isDefaultServerFromApi() property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
enabled: !isServerFromApi
Component.onCompleted: { Component.onCompleted: {
if (ServersModel.isDefaultServerFromApi()) { if (isServerFromApi) {
PageController.showNotificationMessage(qsTr("Default server does not support custom dns")) PageController.showNotificationMessage(qsTr("Default server does not support custom dns"))
} }
} }
@@ -68,6 +72,8 @@ PageType {
textField.validator: RegularExpressionValidator { textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp() regularExpression: InstallController.ipAddressRegExp()
} }
KeyNavigation.tab: secondaryDns.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -80,6 +86,8 @@ PageType {
textField.validator: RegularExpressionValidator { textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp() regularExpression: InstallController.ipAddressRegExp()
} }
KeyNavigation.tab: saveButton
} }
BasicButtonType { BasicButtonType {
@@ -94,32 +102,33 @@ PageType {
text: qsTr("Restore default") text: qsTr("Restore default")
onClicked: function() { clickedFunc: function() {
questionDrawer.headerText = qsTr("Restore default DNS settings?") var headerText = qsTr("Restore default DNS settings?")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
SettingsController.primaryDns = "1.1.1.1" SettingsController.primaryDns = "1.1.1.1"
primaryDns.textFieldText = SettingsController.primaryDns primaryDns.textFieldText = SettingsController.primaryDns
SettingsController.secondaryDns = "1.0.0.1" SettingsController.secondaryDns = "1.0.0.1"
secondaryDns.textFieldText = SettingsController.secondaryDns secondaryDns.textFieldText = SettingsController.secondaryDns
PageController.showNotificationMessage(qsTr("Settings have been reset")) PageController.showNotificationMessage(qsTr("Settings have been reset"))
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
BasicButtonType { BasicButtonType {
id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Save") text: qsTr("Save")
onClicked: function() { clickedFunc: function() {
if (primaryDns.textFieldText !== SettingsController.primaryDns) { if (primaryDns.textFieldText !== SettingsController.primaryDns) {
SettingsController.primaryDns = primaryDns.textFieldText SettingsController.primaryDns = primaryDns.textFieldText
} }
@@ -130,8 +139,6 @@ PageType {
} }
} }
} }
QuestionDrawer {
id: questionDrawer
}
} }
} }
+7 -12
View File
@@ -143,21 +143,20 @@ PageType {
image: "qrc:/images/controls/delete.svg" image: "qrc:/images/controls/delete.svg"
onClicked: function() { onClicked: function() {
questionDrawer.headerText = qsTr("Clear logs?") var headerText = qsTr("Clear logs?")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
SettingsController.clearLogs() SettingsController.clearLogs()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs have been cleaned up")) PageController.showNotificationMessage(qsTr("Logs have been cleaned up"))
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
@@ -170,10 +169,6 @@ PageType {
} }
} }
} }
QuestionDrawer {
id: questionDrawer
}
} }
} }
} }
+49 -90
View File
@@ -28,7 +28,7 @@ PageType {
PageController.showErrorMessage(message) PageController.showErrorMessage(message)
} }
function onRemoveCurrentlyProcessedServerFinished(finishedMessage) { function onRemoveProcessedServerFinished(finishedMessage) {
if (!ServersModel.getServersCount()) { if (!ServersModel.getServersCount()) {
PageController.replaceStartPage() PageController.replaceStartPage()
} else { } else {
@@ -38,7 +38,7 @@ PageType {
PageController.showNotificationMessage(finishedMessage) PageController.showNotificationMessage(finishedMessage)
} }
function onRebootCurrentlyProcessedServerFinished(finishedMessage) { function onRebootProcessedServerFinished(finishedMessage) {
PageController.showNotificationMessage(finishedMessage) PageController.showNotificationMessage(finishedMessage)
} }
@@ -64,8 +64,8 @@ PageType {
Connections { Connections {
target: ServersModel target: ServersModel
function onCurrentlyProcessedServerIndexChanged() { function onProcessedServerIndexChanged() {
content.isServerWithWriteAccess = ServersModel.isCurrentlyProcessedServerHasWriteAccess() content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
} }
} }
@@ -82,7 +82,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
property bool isServerWithWriteAccess: ServersModel.isCurrentlyProcessedServerHasWriteAccess() property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
LabelWithButtonType { LabelWithButtonType {
visible: content.isServerWithWriteAccess visible: content.isServerWithWriteAccess
@@ -92,21 +92,20 @@ PageType {
descriptionText: qsTr("May be needed when changing other settings") descriptionText: qsTr("May be needed when changing other settings")
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Clear cached profiles?") var headerText = qsTr("Clear cached profiles?")
questionDrawer.descriptionText = qsTr("") var descriptionText = qsTr("")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
SettingsController.clearCachedProfiles() SettingsController.clearCachedProfiles()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
@@ -140,24 +139,23 @@ PageType {
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to reboot the server?") var headerText = qsTr("Do you want to reboot the server?")
questionDrawer.descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?") var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection() ConnectionController.closeConnection()
} }
InstallController.rebootCurrentlyProcessedServer() InstallController.rebootProcessedServer()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
@@ -172,24 +170,23 @@ PageType {
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to remove the server from application?") var headerText = qsTr("Do you want to remove the server from application?")
questionDrawer.descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.") var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection() ConnectionController.closeConnection()
} }
InstallController.removeCurrentlyProcessedServer() InstallController.removeProcessedServer()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
@@ -203,23 +200,22 @@ PageType {
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to clear server from Amnezia software?") var headerText = qsTr("Do you want to clear server from Amnezia software?")
questionDrawer.descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.") var descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection() ConnectionController.closeConnection()
} }
InstallController.removeAllContainers() InstallController.removeAllContainers()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
@@ -228,69 +224,32 @@ PageType {
} }
LabelWithButtonType { LabelWithButtonType {
visible: content.isServerWithWriteAccess visible: ServersModel.getProcessedServerData("isServerFromApi")
Layout.fillWidth: true
text: qsTr("Clear server from Amnezia software")
textColor: "#EB5757"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to clear server from Amnezia software?")
questionDrawer.descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.removeAllContainers()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
DividerType {
visible: content.isServerWithWriteAccess
}
LabelWithButtonType {
visible: ServersModel.isCurrentlyProcessedServerFromApi()
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Reset API config") text: qsTr("Reset API config")
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to reset API config?") var headerText = qsTr("Do you want to reset API config?")
questionDrawer.descriptionText = "" var descriptionText = ""
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
ApiController.clearApiConfig() ApiController.clearApiConfig()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType { DividerType {
visible: ServersModel.isCurrentlyProcessedServerFromApi() visible: ServersModel.getProcessedServerData("isServerFromApi")
}
QuestionDrawer {
id: questionDrawer
} }
} }
} }
+27 -14
View File
@@ -63,7 +63,7 @@ PageType {
headerText: name headerText: name
descriptionText: { descriptionText: {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { if (ServersModel.isProcessedServerHasWriteAccess()) {
return credentialsLogin + " · " + hostName return credentialsLogin + " · " + hostName
} else { } else {
return hostName return hostName
@@ -71,30 +71,33 @@ PageType {
} }
actionButtonFunction: function() { actionButtonFunction: function() {
serverNameEditDrawer.visible = true serverNameEditDrawer.open()
} }
} }
DrawerType { DrawerType2 {
id: serverNameEditDrawer id: serverNameEditDrawer
width: root.width parent: root
height: root.height * 0.35
onVisibleChanged: { anchors.fill: parent
if (serverNameEditDrawer.visible) { expandedHeight: root.height * 0.35
serverName.textField.forceActiveFocus()
}
}
ColumnLayout { expandedContent: ColumnLayout {
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: 16 anchors.topMargin: 32
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
Connections {
target: serverNameEditDrawer
function onOpened() {
serverName.textField.forceActiveFocus()
}
}
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: serverName id: serverName
@@ -103,14 +106,18 @@ PageType {
textFieldText: name textFieldText: name
textField.maximumLength: 30 textField.maximumLength: 30
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: saveButton
} }
BasicButtonType { BasicButtonType {
id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Save") text: qsTr("Save")
onClicked: { clickedFunc: function() {
if (serverName.textFieldText === "") { if (serverName.textFieldText === "") {
return return
} }
@@ -118,7 +125,13 @@ PageType {
if (serverName.textFieldText !== name) { if (serverName.textFieldText !== name) {
name = serverName.textFieldText name = serverName.textFieldText
} }
serverNameEditDrawer.visible = false serverNameEditDrawer.close()
}
}
Component.onCompleted: {
if (header.itemAt(0)) {
defaultActiveFocusItem = serverName.textField
} }
} }
} }
@@ -107,26 +107,25 @@ PageType {
width: parent.width width: parent.width
visible: ServersModel.isCurrentlyProcessedServerHasWriteAccess() visible: ServersModel.isProcessedServerHasWriteAccess()
text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName() text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName()
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName()) var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
questionDrawer.descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.") var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeCurrentlyProcessedContainer()
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
MouseArea { MouseArea {
@@ -138,9 +137,9 @@ PageType {
DividerType {} DividerType {}
} }
}
QuestionDrawer { QuestionDrawer {
id: questionDrawer id: questionDrawer
} }
}
} }
@@ -38,13 +38,13 @@ PageType {
Connections { Connections {
target: ServersModel target: ServersModel
function onCurrentlyProcessedServerIndexChanged() { function onProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters() settingsContainersListView.updateContainersModelFilters()
} }
} }
function updateContainersModelFilters() { function updateContainersModelFilters() {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { if (ServersModel.isProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters() proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else { } else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters() proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
@@ -38,13 +38,13 @@ PageType {
Connections { Connections {
target: ServersModel target: ServersModel
function onCurrentlyProcessedServerIndexChanged() { function onProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters() settingsContainersListView.updateContainersModelFilters()
} }
} }
function updateContainersModelFilters() { function updateContainersModelFilters() {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) { if (ServersModel.isProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters() proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters()
} else { } else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters() proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters()
@@ -55,6 +55,9 @@ PageType {
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxyContainersModel id: proxyContainersModel
sourceModel: ContainersModel sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
} }
Component.onCompleted: updateContainersModelFilters() Component.onCompleted: updateContainersModelFilters()
@@ -87,7 +87,7 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() { clickedFunction: function() {
ServersModel.currentlyProcessedIndex = index ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo) PageController.goToPage(PageEnum.PageSettingsServerInfo)
} }
} }
@@ -20,13 +20,23 @@ import "../Components"
PageType { PageType {
id: root id: root
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
defaultActiveFocusItem: website_ip_field.textField
property bool pageEnabled: { property bool pageEnabled: {
return !ConnectionController.isConnected && !ServersModel.isDefaultServerFromApi() return !ConnectionController.isConnected && !isServerFromApi
} }
Component.onCompleted: { Component.onCompleted: {
if (ServersModel.isDefaultServerFromApi()) { if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot change split tunneling settings during active connection"))
root.pageEnabled = false
} else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && isServerFromApi) {
PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function")) PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function"))
root.pageEnabled = false
} else {
root.pageEnabled = true
} }
} }
@@ -104,7 +114,7 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
checked: SitesModel.isSplitTunnelingEnabled() checked: SitesModel.isTunnelingEnabled
onToggled: { onToggled: {
SitesModel.toggleSplitTunneling(checked) SitesModel.toggleSplitTunneling(checked)
selector.text = root.routeModesModel[getRouteModesModelIndex()].name selector.text = root.routeModesModel[getRouteModesModelIndex()].name
@@ -121,6 +131,7 @@ PageType {
Layout.rightMargin: 16 Layout.rightMargin: 16
drawerHeight: 0.4375 drawerHeight: 0.4375
drawerParent: root
enabled: root.pageEnabled enabled: root.pageEnabled
@@ -135,7 +146,7 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
selector.text = selectedText selector.text = selectedText
selector.menuVisible = false selector.close()
if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) { if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) {
SitesModel.routeMode = root.routeModesModel[currentIndex].type SitesModel.routeMode = root.routeModesModel[currentIndex].type
} }
@@ -202,26 +213,21 @@ PageType {
rightImageColor: "#D7D8DB" rightImageColor: "#D7D8DB"
clickedFunction: function() { clickedFunction: function() {
questionDrawer.headerText = qsTr("Remove ") + url + "?" var headerText = qsTr("Remove ") + url + "?"
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.visible = false
SitesController.removeSite(index) SitesController.removeSite(index)
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.visible = false
} }
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType {} DividerType {}
QuestionDrawer {
id: questionDrawer
}
} }
} }
} }
@@ -249,6 +255,8 @@ PageType {
anchors.bottomMargin: 24 anchors.bottomMargin: 24
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: website_ip_field
Layout.fillWidth: true Layout.fillWidth: true
textFieldPlaceholderText: qsTr("website or IP") textFieldPlaceholderText: qsTr("website or IP")
@@ -275,16 +283,13 @@ PageType {
} }
} }
DrawerType { DrawerType2 {
id: moreActionsDrawer id: moreActionsDrawer
width: parent.width
height: parent.height * 0.4375
FlickableType {
anchors.fill: parent anchors.fill: parent
contentHeight: moreActionsDrawerContent.height expandedHeight: parent.height * 0.4375
ColumnLayout {
expandedContent: ColumnLayout {
id: moreActionsDrawerContent id: moreActionsDrawerContent
anchors.top: parent.top anchors.top: parent.top
@@ -338,13 +343,15 @@ PageType {
DividerType {} DividerType {}
} }
} }
}
DrawerType { DrawerType2 {
id: importSitesDrawer id: importSitesDrawer
width: parent.width anchors.fill: parent
height: parent.height * 0.4375 expandedHeight: parent.height * 0.4375
expandedContent: Item {
implicitHeight: importSitesDrawer.expandedHeight
BackButtonType { BackButtonType {
id: importSitesDrawerBackButton id: importSitesDrawerBackButton
@@ -422,4 +429,9 @@ PageType {
} }
} }
} }
}
QuestionDrawer {
id: questionDrawer
}
} }
@@ -12,6 +12,8 @@ import "../Controls2/TextTypes"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: hostname.textField
BackButtonType { BackButtonType {
id: backButton id: backButton
@@ -57,6 +59,8 @@ PageType {
onFocusChanged: { onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, ''); textField.text = textField.text.replace(/^\s+|\s+$/g, '');
} }
KeyNavigation.tab: username.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -65,6 +69,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
headerText: qsTr("Login to connect via SSH") headerText: qsTr("Login to connect via SSH")
textFieldPlaceholderText: "root" textFieldPlaceholderText: "root"
KeyNavigation.tab: secretData.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
@@ -85,15 +91,19 @@ PageType {
onFocusChanged: { onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, ''); textField.text = textField.text.replace(/^\s+|\s+$/g, '');
} }
KeyNavigation.tab: continueButton
} }
BasicButtonType { BasicButtonType {
id: continueButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
text: qsTr("Continue") text: qsTr("Continue")
onClicked: function() { clickedFunc: function() {
forceActiveFocus() forceActiveFocus()
if (!isCredentialsFilled()) { if (!isCredentialsFilled()) {
return return
+2 -3
View File
@@ -158,7 +158,7 @@ PageType {
text: qsTr("Continue") text: qsTr("Continue")
onClicked: function() { clickedFunc: function() {
if (root.isEasySetup) { if (root.isEasySetup) {
ContainersModel.setCurrentlyProcessedContainerIndex(containers.dockerContainer) ContainersModel.setCurrentlyProcessedContainerIndex(containers.dockerContainer)
PageController.goToPage(PageEnum.PageSetupWizardInstalling) PageController.goToPage(PageEnum.PageSetupWizardInstalling)
@@ -192,13 +192,12 @@ PageType {
return ContainersModel.isAnyContainerInstalled() return ContainersModel.isAnyContainerInstalled()
} }
return true return true
} }
text: qsTr("Set up later") text: qsTr("Set up later")
onClicked: function() { clickedFunc: function() {
PageController.goToPage(PageEnum.PageSetupWizardInstalling) PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.addEmptyServer() InstallController.addEmptyServer()
} }
@@ -26,7 +26,7 @@ PageType {
function onInstallContainerFinished(finishedMessage, isServiceInstall) { function onInstallContainerFinished(finishedMessage, isServiceInstall) {
if (!ConnectionController.isConnected && !isServiceInstall) { if (!ConnectionController.isConnected && !isServiceInstall) {
ServersModel.setDefaultContainer(ContainersModel.getCurrentlyProcessedContainerIndex()) ServersModel.setDefaultContainer(ServersModel.processedIndex, ContainersModel.getCurrentlyProcessedContainerIndex())
} }
PageController.closePage() // close installing page PageController.closePage() // close installing page
@@ -42,7 +42,7 @@ PageType {
function onInstallServerFinished(finishedMessage) { function onInstallServerFinished(finishedMessage) {
if (!ConnectionController.isConnected) { if (!ConnectionController.isConnected) {
ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1); ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1);
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex ServersModel.processedIndex = ServersModel.defaultIndex
} }
PageController.goToStartPage() PageController.goToStartPage()
@@ -55,7 +55,7 @@ PageType {
function onServerAlreadyExists(serverIndex) { function onServerAlreadyExists(serverIndex) {
PageController.goToStartPage() PageController.goToStartPage()
ServersModel.currentlyProcessedIndex = serverIndex ServersModel.processedIndex = serverIndex
PageController.goToPage(PageEnum.PageSettingsServerInfo, false) PageController.goToPage(PageEnum.PageSettingsServerInfo, false)
PageController.showErrorMessage(qsTr("The server has already been added to the application")) PageController.showErrorMessage(qsTr("The server has already been added to the application"))
@@ -165,7 +165,7 @@ PageType {
text: qsTr("Cancel installation") text: qsTr("Cancel installation")
onClicked: { clickedFunc: function() {
InstallController.cancelInstallation() InstallController.cancelInstallation()
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
} }
@@ -52,6 +52,8 @@ PageType {
implicitWidth: processedContainerListView.width implicitWidth: processedContainerListView.width
implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height
property alias port:port
ColumnLayout { ColumnLayout {
id: delegateContent id: delegateContent
@@ -92,16 +94,19 @@ PageType {
text: qsTr("More detailed") text: qsTr("More detailed")
onClicked: { clickedFunc: function() {
showDetailsDrawer.open() showDetailsDrawer.open()
} }
} }
DrawerType { DrawerType2 {
id: showDetailsDrawer id: showDetailsDrawer
parent: root
width: parent.width anchors.fill: parent
height: parent.height * 0.9 expandedHeight: parent.height * 0.9
expandedContent: Item {
implicitHeight: showDetailsDrawer.expandedHeight
BackButtonType { BackButtonType {
id: showDetailsBackButton id: showDetailsBackButton
@@ -165,13 +170,14 @@ PageType {
text: qsTr("Close") text: qsTr("Close")
onClicked: function() { clickedFunc: function() {
showDetailsDrawer.close() showDetailsDrawer.close()
} }
} }
} }
} }
} }
}
ParagraphTextType { ParagraphTextType {
id: transportProtoHeader id: transportProtoHeader
@@ -197,6 +203,8 @@ PageType {
headerText: qsTr("Port") headerText: qsTr("Port")
textField.maximumLength: 5 textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 } textField.validator: IntValidator { bottom: 1; top: 65535 }
KeyNavigation.tab: installButton
} }
Rectangle { Rectangle {
@@ -212,7 +220,7 @@ PageType {
text: qsTr("Install") text: qsTr("Install")
onClicked: function() { clickedFunc: function() {
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.install(dockerContainer, port.textFieldText, transportProtoSelector.currentIndex) InstallController.install(dockerContainer, port.textFieldText, transportProtoSelector.currentIndex)
} }
@@ -232,6 +240,8 @@ PageType {
var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto) var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto)
transportProtoSelector.visible = protocolSelectorVisible transportProtoSelector.visible = protocolSelectorVisible
transportProtoHeader.visible = protocolSelectorVisible transportProtoHeader.visible = protocolSelectorVisible
defaultActiveFocusItem = port.textField
} }
} }
} }
@@ -115,8 +115,8 @@ PageType {
text: qsTr("I have the data to connect") text: qsTr("I have the data to connect")
onClicked: { clickedFunc: function() {
connectionTypeSelection.visible = true connectionTypeSelection.open()
} }
} }
@@ -135,14 +135,16 @@ PageType {
text: qsTr("I have nothing") text: qsTr("I have nothing")
onClicked: Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide")) clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide"))
}
}
} }
} }
ConnectionTypeSelectionDrawer { ConnectionTypeSelectionDrawer {
id: connectionTypeSelection id: connectionTypeSelection
} }
}
BusyIndicatorType { BusyIndicatorType {
id: busyIndicator id: busyIndicator
@@ -12,6 +12,8 @@ import "../Config"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: textKey.textField
FlickableType { FlickableType {
id: fl id: fl
anchors.top: parent.top anchors.top: parent.top
@@ -56,11 +58,15 @@ PageType {
textField.text = "" textField.text = ""
textField.paste() textField.paste()
} }
KeyNavigation.tab: continueButton
} }
} }
} }
BasicButtonType { BasicButtonType {
id: continueButton
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -70,7 +76,7 @@ PageType {
text: qsTr("Continue") text: qsTr("Continue")
onClicked: function() { clickedFunc: function() {
ImportController.extractConfigFromCode(textKey.textFieldText) ImportController.extractConfigFromCode(textKey.textFieldText)
PageController.goToPage(PageEnum.PageSetupWizardViewConfig) PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
} }
@@ -30,7 +30,7 @@ PageType {
function onImportFinished() { function onImportFinished() {
if (!ConnectionController.isConnected) { if (!ConnectionController.isConnected) {
ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1); ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1);
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex ServersModel.processedIndex = ServersModel.defaultIndex
} }
PageController.goToStartPage() PageController.goToStartPage()
@@ -109,7 +109,7 @@ PageType {
text: showContent ? qsTr("Collapse content") : qsTr("Show content") text: showContent ? qsTr("Collapse content") : qsTr("Show content")
onClicked: { clickedFunc: function() {
showContent = !showContent showContent = !showContent
} }
} }
@@ -151,7 +151,7 @@ PageType {
Layout.bottomMargin: 32 Layout.bottomMargin: 32
text: qsTr("Connect") text: qsTr("Connect")
onClicked: { clickedFunc: function() {
ImportController.importConfig() ImportController.importConfig()
} }
} }
+86 -57
View File
@@ -16,10 +16,13 @@ import "../Components"
PageType { PageType {
id: root id: root
defaultActiveFocusItem: clientNameTextField.textField
enum ConfigType { enum ConfigType {
AmneziaConnection, AmneziaConnection,
OpenVpn, OpenVpn,
WireGuard, WireGuard,
Awg,
ShadowSocks, ShadowSocks,
Cloak Cloak
} }
@@ -29,7 +32,7 @@ PageType {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
ExportController.revokeConfig(index, ExportController.revokeConfig(index,
ContainersModel.getCurrentlyProcessedContainerIndex(), ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials()) ServersModel.getProcessedServerCredentials())
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Config revoked")) PageController.showNotificationMessage(qsTr("Config revoked"))
} }
@@ -41,14 +44,15 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.needCloseButton = false
shareConnectionDrawer.open() shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
switch (type) { switch (type) {
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(clientNameTextField.textFieldText); break; case PageShare.ConfigType.AmneziaConnection: {
ExportController.generateConnectionConfig(clientNameTextField.textFieldText);
break;
}
case PageShare.ConfigType.OpenVpn: { case PageShare.ConfigType.OpenVpn: {
ExportController.generateOpenVpnConfig(clientNameTextField.textFieldText) ExportController.generateOpenVpnConfig(clientNameTextField.textFieldText)
shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config") shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config")
@@ -63,6 +67,13 @@ PageType {
shareConnectionDrawer.configFileName = "amnezia_for_wireguard" shareConnectionDrawer.configFileName = "amnezia_for_wireguard"
break break
} }
case PageShare.ConfigType.Awg: {
ExportController.generateAwgConfig(clientNameTextField.textFieldText)
shareConnectionDrawer.configCaption = qsTr("Save AmneziaWG config")
shareConnectionDrawer.configExtension = ".conf"
shareConnectionDrawer.configFileName = "amnezia_for_awg"
break
}
case PageShare.ConfigType.ShadowSocks: { case PageShare.ConfigType.ShadowSocks: {
ExportController.generateShadowSocksConfig() ExportController.generateShadowSocksConfig()
shareConnectionDrawer.configCaption = qsTr("Save ShadowSocks config") shareConnectionDrawer.configCaption = qsTr("Save ShadowSocks config")
@@ -80,11 +91,6 @@ PageType {
} }
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true
} }
function onExportErrorOccurred(errorMessage) { function onExportErrorOccurred(errorMessage) {
@@ -115,6 +121,11 @@ PageType {
property string name: qsTr("WireGuard native format") property string name: qsTr("WireGuard native format")
property var type: PageShare.ConfigType.WireGuard property var type: PageShare.ConfigType.WireGuard
} }
QtObject {
id: awgConnectionFormat
property string name: qsTr("AmneziaWG native format")
property var type: PageShare.ConfigType.Awg
}
QtObject { QtObject {
id: shadowSocksConnectionFormat id: shadowSocksConnectionFormat
property string name: qsTr("ShadowSocks native format") property string name: qsTr("ShadowSocks native format")
@@ -129,7 +140,7 @@ PageType {
FlickableType { FlickableType {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height contentHeight: content.height + 10
ColumnLayout { ColumnLayout {
id: content id: content
@@ -154,14 +165,15 @@ PageType {
shareFullAccessDrawer.open() shareFullAccessDrawer.open()
} }
DrawerType { DrawerType2 {
id: shareFullAccessDrawer id: shareFullAccessDrawer
width: root.width parent: root
height: root.height * 0.45
anchors.fill: parent
expandedHeight: root.height * 0.45
ColumnLayout { expandedContent: ColumnLayout {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -234,7 +246,7 @@ PageType {
accessTypeSelector.currentIndex = 1 accessTypeSelector.currentIndex = 1
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(), ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials()) ServersModel.getProcessedServerCredentials())
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
} }
@@ -264,6 +276,8 @@ PageType {
textField.maximumLength: 20 textField.maximumLength: 20
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: shareButton
} }
DropDownType { DropDownType {
@@ -276,6 +290,7 @@ PageType {
Layout.topMargin: 16 Layout.topMargin: 16
drawerHeight: 0.4375 drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server") descriptionText: qsTr("Server")
headerText: qsTr("Server") headerText: qsTr("Server")
@@ -305,7 +320,7 @@ PageType {
serverSelector.severSelectorIndexChanged() serverSelector.severSelectorIndexChanged()
} }
serverSelector.menuVisible = false serverSelector.close()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -316,7 +331,7 @@ PageType {
function handler() { function handler() {
serverSelector.text = selectedText serverSelector.text = selectedText
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex) ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
} }
} }
} }
@@ -328,6 +343,7 @@ PageType {
Layout.topMargin: 16 Layout.topMargin: 16
drawerHeight: 0.5 drawerHeight: 0.5
drawerParent: root
descriptionText: qsTr("Protocol") descriptionText: qsTr("Protocol")
headerText: qsTr("Protocol") headerText: qsTr("Protocol")
@@ -358,14 +374,15 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
handler() handler()
protocolSelector.menuVisible = false protocolSelector.close()
} }
Connections { Connections {
target: serverSelector target: serverSelector
function onSeverSelectorIndexChanged() { function onSeverSelectorIndexChanged() {
protocolSelectorListView.currentIndex = proxyContainersModel.mapFromSource(ServersModel.getDefaultContainer()) var defaultContainer = proxyContainersModel.mapFromSource(ServersModel.getProcessedServerData("defaultContainer"))
protocolSelectorListView.currentIndex = defaultContainer
protocolSelectorListView.triggerCurrentItem() protocolSelectorListView.triggerCurrentItem()
} }
} }
@@ -387,7 +404,7 @@ PageType {
if (accessTypeSelector.currentIndex === 1) { if (accessTypeSelector.currentIndex === 1) {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(), ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials()) ServersModel.getProcessedServerCredentials())
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
} }
@@ -401,6 +418,8 @@ PageType {
root.connectionTypesModel.push(openVpnConnectionFormat) root.connectionTypesModel.push(openVpnConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-wireguard")) { } else if (index === ContainerProps.containerFromString("amnezia-wireguard")) {
root.connectionTypesModel.push(wireGuardConnectionFormat) root.connectionTypesModel.push(wireGuardConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-awg")) {
root.connectionTypesModel.push(awgConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-shadowsocks")) { } else if (index === ContainerProps.containerFromString("amnezia-shadowsocks")) {
root.connectionTypesModel.push(openVpnConnectionFormat) root.connectionTypesModel.push(openVpnConnectionFormat)
root.connectionTypesModel.push(shadowSocksConnectionFormat) root.connectionTypesModel.push(shadowSocksConnectionFormat)
@@ -422,6 +441,7 @@ PageType {
Layout.topMargin: 16 Layout.topMargin: 16
drawerHeight: 0.4375 drawerHeight: 0.4375
drawerParent: root
visible: accessTypeSelector.currentIndex === 0 visible: accessTypeSelector.currentIndex === 0
enabled: root.connectionTypesModel.length > 1 enabled: root.connectionTypesModel.length > 1
@@ -445,7 +465,7 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
exportTypeSelector.text = selectedText exportTypeSelector.text = selectedText
exportTypeSelector.currentIndex = currentIndex exportTypeSelector.currentIndex = currentIndex
exportTypeSelector.menuVisible = false exportTypeSelector.close()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -455,11 +475,9 @@ PageType {
} }
} }
ShareConnectionDrawer {
id: shareConnectionDrawer
}
BasicButtonType { BasicButtonType {
id: shareButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
@@ -469,7 +487,7 @@ PageType {
text: qsTr("Share") text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg" imageSource: "qrc:/images/controls/share-2.svg"
onClicked: { clickedFunc: function(){
if (clientNameTextField.textFieldText !== "") { if (clientNameTextField.textFieldText !== "") {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type) ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
} }
@@ -560,13 +578,15 @@ PageType {
DividerType {} DividerType {}
DrawerType { DrawerType2 {
id: clientInfoDrawer id: clientInfoDrawer
width: root.width parent: root
height: root.height * 0.5
ColumnLayout { anchors.fill: parent
expandedHeight: root.height * 0.5
expandedContent: ColumnLayout {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -597,30 +617,33 @@ PageType {
text: qsTr("Rename") text: qsTr("Rename")
onClicked: function() { clickedFunc: function() {
clientNameEditDrawer.open() clientNameEditDrawer.open()
} }
DrawerType { DrawerType2 {
id: clientNameEditDrawer id: clientNameEditDrawer
width: root.width parent: root
height: root.height * 0.35
onVisibleChanged: { anchors.fill: parent
if (clientNameEditDrawer.visible) { expandedHeight: root.height * 0.35
clientNameEditor.textField.forceActiveFocus()
}
}
ColumnLayout { expandedContent: ColumnLayout {
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: 16 anchors.topMargin: 32
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
Connections {
target: clientNameEditDrawer
function onOpened() {
clientNameEditor.textField.forceActiveFocus()
}
}
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: clientNameEditor id: clientNameEditor
Layout.fillWidth: true Layout.fillWidth: true
@@ -628,14 +651,18 @@ PageType {
textFieldText: clientName textFieldText: clientName
textField.maximumLength: 20 textField.maximumLength: 20
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: saveButton
} }
BasicButtonType { BasicButtonType {
id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Save") text: qsTr("Save")
onClicked: { clickedFunc: function() {
if (clientNameEditor.textFieldText === "") { if (clientNameEditor.textFieldText === "") {
return return
} }
@@ -645,7 +672,7 @@ PageType {
ExportController.renameClient(index, ExportController.renameClient(index,
clientNameEditor.textFieldText, clientNameEditor.textFieldText,
ContainersModel.getCurrentlyProcessedContainerIndex(), ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials()) ServersModel.getProcessedServerCredentials())
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
clientNameEditDrawer.close() clientNameEditDrawer.close()
} }
@@ -667,21 +694,22 @@ PageType {
text: qsTr("Revoke") text: qsTr("Revoke")
onClicked: function() { clickedFunc: function() {
questionDrawer.headerText = qsTr("Revoke the config for a user - %1?").arg(clientName) var headerText = qsTr("Revoke the config for a user - %1?").arg(clientName)
questionDrawer.descriptionText = qsTr("The user will no longer be able to connect to your server.") var descriptionText = qsTr("The user will no longer be able to connect to your server.")
questionDrawer.yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() { var yesButtonFunction = function() {
questionDrawer.close()
clientInfoDrawer.close() clientInfoDrawer.close()
root.revokeConfig(index) root.revokeConfig(index)
} }
questionDrawer.noButtonFunction = function() { var noButtonFunction = function() {
questionDrawer.close() }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
} }
questionDrawer.open()
} }
} }
} }
@@ -690,11 +718,12 @@ PageType {
} }
} }
QuestionDrawer { ShareConnectionDrawer {
id: questionDrawer id: shareConnectionDrawer
}
} anchors.fill: parent
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onPressed: function(mouse) { onPressed: function(mouse) {
+8 -10
View File
@@ -69,6 +69,7 @@ PageType {
Layout.topMargin: 16 Layout.topMargin: 16
drawerHeight: 0.4375 drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server") descriptionText: qsTr("Server")
headerText: qsTr("Server") headerText: qsTr("Server")
@@ -99,7 +100,7 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
serverSelector.menuVisible = false serverSelector.close()
} }
Component.onCompleted: { Component.onCompleted: {
@@ -110,7 +111,7 @@ PageType {
function handler() { function handler() {
serverSelector.text = selectedText serverSelector.text = selectedText
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex) ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
} }
} }
} }
@@ -122,12 +123,10 @@ PageType {
text: qsTr("Share") text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg" imageSource: "qrc:/images/controls/share-2.svg"
onClicked: function() { clickedFunc: function() {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.needCloseButton = false
shareConnectionDrawer.open() shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
@@ -140,16 +139,15 @@ PageType {
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true shareConnectionDrawer.contentVisible = true
} }
} }
}
}
ShareConnectionDrawer { ShareConnectionDrawer {
id: shareConnectionDrawer id: shareConnectionDrawer
}
} anchors.fill: parent
} }
} }
+12 -38
View File
@@ -20,22 +20,16 @@ PageType {
function onGoToPageHome() { function onGoToPageHome() {
tabBar.setCurrentIndex(0) tabBar.setCurrentIndex(0)
tabBarStackView.goToTabBarPage(PageEnum.PageHome) tabBarStackView.goToTabBarPage(PageEnum.PageHome)
PageController.updateDrawerRootPage(PageEnum.PageHome)
} }
function onGoToPageSettings() { function onGoToPageSettings() {
tabBar.setCurrentIndex(2) tabBar.setCurrentIndex(2)
tabBarStackView.goToTabBarPage(PageEnum.PageSettings) tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
PageController.updateDrawerRootPage(PageEnum.PageSettings)
} }
function onGoToPageViewConfig() { function onGoToPageViewConfig() {
var pagePath = PageController.getPagePath(PageEnum.PageSetupWizardViewConfig) var pagePath = PageController.getPagePath(PageEnum.PageSetupWizardViewConfig)
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition) tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
PageController.updateDrawerRootPage(PageEnum.PageSetupWizardViewConfig)
} }
function onShowBusyIndicator(visible) { function onShowBusyIndicator(visible) {
@@ -44,15 +38,14 @@ PageType {
tabBar.enabled = !visible tabBar.enabled = !visible
} }
// function onShowTopCloseButton(visible) {
// topCloseButton.visible = visible
// }
function onEnableTabBar(enabled) { function onEnableTabBar(enabled) {
tabBar.enabled = enabled tabBar.enabled = enabled
} }
function onClosePage() { function onClosePage() {
tabBar.isServerInfoShow = tabBarStackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageSettingsServerInfo)
&& tabBarStackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageSettingsSplitTunneling)
if (tabBarStackView.depth <= 1) { if (tabBarStackView.depth <= 1) {
return return
} }
@@ -61,13 +54,14 @@ PageType {
function onGoToPage(page, slide) { function onGoToPage(page, slide) {
var pagePath = PageController.getPagePath(page) var pagePath = PageController.getPagePath(page)
if (slide) { if (slide) {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition) tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
} else { } else {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.Immediate) tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.Immediate)
} }
PageController.updateDrawerRootPage(page) tabBar.isServerInfoShow = page === PageEnum.PageSettingsServerInfo || PageEnum.PageSettingsSplitTunneling || tabBar.isServerInfoShow
} }
function onGoToStartPage() { function onGoToStartPage() {
@@ -115,20 +109,12 @@ PageType {
function onNoInstalledContainers() { function onNoInstalledContainers() {
PageController.setTriggeredBtConnectButton(true) PageController.setTriggeredBtConnectButton(true)
ServersModel.currentlyProcessedIndex = ServersModel.getDefaultServerIndex() ServersModel.processedIndex = ServersModel.getDefaultServerIndex()
InstallController.setShouldCreateServer(false) InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardEasy) PageController.goToPage(PageEnum.PageSetupWizardEasy)
} }
} }
Connections {
target: ApiController
function onErrorOccurred(errorMessage) {
PageController.showErrorMessage(errorMessage)
}
}
StackViewType { StackViewType {
id: tabBarStackView id: tabBarStackView
@@ -146,26 +132,21 @@ PageType {
var pagePath = PageController.getPagePath(page) var pagePath = PageController.getPagePath(page)
tabBarStackView.clear(StackView.Immediate) tabBarStackView.clear(StackView.Immediate)
tabBarStackView.replace(pagePath, { "objectName" : pagePath }, StackView.Immediate) tabBarStackView.replace(pagePath, { "objectName" : pagePath }, StackView.Immediate)
tabBar.isServerInfoShow = false
PageController.updateDrawerRootPage(page)
} }
Component.onCompleted: { Component.onCompleted: {
var pagePath = PageController.getPagePath(PageEnum.PageHome) var pagePath = PageController.getPagePath(PageEnum.PageHome)
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex ServersModel.processedIndex = ServersModel.defaultIndex
tabBarStackView.push(pagePath, { "objectName" : pagePath }) tabBarStackView.push(pagePath, { "objectName" : pagePath })
} }
// onWidthChanged: {
// topCloseButton.x = tabBarStackView.x + tabBarStackView.width -
// topCloseButton.buttonWidth - topCloseButton.rightPadding
// }
} }
TabBar { TabBar {
id: tabBar id: tabBar
property int previousIndex: 0 property int previousIndex: 0
property bool isServerInfoShow: false
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
@@ -196,11 +177,11 @@ PageType {
} }
TabImageButtonType { TabImageButtonType {
isSelected: tabBar.currentIndex === 0 isSelected: tabBar.isServerInfoShow ? false : tabBar.currentIndex === 0
image: "qrc:/images/controls/home.svg" image: "qrc:/images/controls/home.svg"
onClicked: { onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageHome) tabBarStackView.goToTabBarPage(PageEnum.PageHome)
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex ServersModel.processedIndex = ServersModel.defaultIndex
tabBar.previousIndex = 0 tabBar.previousIndex = 0
} }
} }
@@ -230,7 +211,7 @@ PageType {
} }
TabImageButtonType { TabImageButtonType {
isSelected: tabBar.currentIndex === 2 isSelected: tabBar.isServerInfoShow ? true : tabBar.currentIndex === 2
image: "qrc:/images/controls/settings-2.svg" image: "qrc:/images/controls/settings-2.svg"
onClicked: { onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageSettings) tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
@@ -253,13 +234,6 @@ PageType {
z: 1 z: 1
} }
// TopCloseButtonType {
// id: topCloseButton
// x: tabBarStackView.width - topCloseButton.buttonWidth - topCloseButton.rightPadding
// z: 1
// }
ConnectionTypeSelectionDrawer { ConnectionTypeSelectionDrawer {
id: connectionTypeSelection id: connectionTypeSelection
+60 -23
View File
@@ -8,6 +8,7 @@ import PageEnum 1.0
import "Config" import "Config"
import "Controls2" import "Controls2"
import "Components"
Window { Window {
id: root id: root
@@ -130,32 +131,15 @@ Window {
} }
Item { Item {
anchors.right: parent.right anchors.fill: parent
anchors.left: parent.left
anchors.bottom: parent.bottom
implicitHeight: popupErrorMessage.height DrawerType2 {
DrawerType {
id: privateKeyPassphraseDrawer id: privateKeyPassphraseDrawer
width: root.width anchors.fill: parent
height: root.height * 0.35 expandedHeight: root.height * 0.35
onVisibleChanged: { expandedContent: ColumnLayout {
if (privateKeyPassphraseDrawer.visible) {
passphrase.textFieldText = ""
passphrase.textField.forceActiveFocus()
}
}
onAboutToHide: {
PageController.showBusyIndicator(true)
}
onAboutToShow: {
PageController.showBusyIndicator(false)
}
ColumnLayout {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -163,6 +147,24 @@ Window {
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
Connections {
target: privateKeyPassphraseDrawer
function onOpened() {
passphrase.textFieldText = ""
passphrase.textField.forceActiveFocus()
}
function onAboutToHide() {
if (passphrase.textFieldText !== "") {
PageController.showBusyIndicator(true)
}
}
function onAboutToShow() {
PageController.showBusyIndicator(false)
}
}
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: passphrase id: passphrase
@@ -176,9 +178,13 @@ Window {
clickedFunc: function() { clickedFunc: function() {
hidePassword = !hidePassword hidePassword = !hidePassword
} }
KeyNavigation.tab: saveButton
} }
BasicButtonType { BasicButtonType {
id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
defaultColor: "transparent" defaultColor: "transparent"
@@ -190,7 +196,7 @@ Window {
text: qsTr("Save") text: qsTr("Save")
onClicked: { clickedFunc: function() {
privateKeyPassphraseDrawer.close() privateKeyPassphraseDrawer.close()
PageController.passphraseRequestDrawerClosed(passphrase.textFieldText) PageController.passphraseRequestDrawerClosed(passphrase.textFieldText)
} }
@@ -199,6 +205,37 @@ Window {
} }
} }
Item {
anchors.fill: parent
QuestionDrawer {
id: questionDrawer
anchors.fill: parent
}
}
function showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) {
questionDrawer.headerText = headerText
questionDrawer.descriptionText = descriptionText
questionDrawer.yesButtonText = yesButtonText
questionDrawer.noButtonText = noButtonText
questionDrawer.yesButtonFunction = function() {
questionDrawer.close()
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
}
questionDrawer.noButtonFunction = function() {
questionDrawer.close()
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
}
questionDrawer.open()
}
FileDialog { FileDialog {
id: mainFileDialog id: mainFileDialog
+2 -1
View File
@@ -146,7 +146,8 @@ if [ "${MAC_CERT_PW+x}" ]; then
fi fi
echo "Building DMG installer..." echo "Building DMG installer..."
hdiutil create -size 120mb -volname AmneziaVPN -srcfolder $BUILD_DIR/installer/$APP_NAME.app -ov -format UDZO $DMG_FILENAME # Allow Terminal to make changes in Privacy & Security > App Management
hdiutil create -size 256mb -volname AmneziaVPN -srcfolder $BUILD_DIR/installer/$APP_NAME.app -ov -format UDZO $DMG_FILENAME
if [ "${MAC_CERT_PW+x}" ]; then if [ "${MAC_CERT_PW+x}" ]; then
echo "Signing DMG installer..." echo "Signing DMG installer..."