Compare commits

..

39 Commits

Author SHA1 Message Date
lunardunno 28907241df Merge branch '3rd_adaptation_to_diff_OS' into sudo_not_found 2024-02-14 06:50:34 +04:00
lunardunno 1aec417fc9 Merge pull request #588 from amnezia-vpn/test/docker-ce
Check which containerization application will be installed
2024-02-14 04:27:01 +04:00
lunardunno fc0a9fd74f check and change locale
Checking and changing the locale for correct error handling by the server controller.
2024-02-14 03:46:03 +04:00
lunardunno 11fef3c653 checking of docker installation results 2024-02-14 03:39:07 +04:00
lunardunno 1226d1b287 Check moby and podman 2024-02-13 17:25:36 +04:00
lunardunno 1028f6998f docker-ce support
Implementation of docker-ce support, for Fedora and CentOS
2024-02-12 06:18:59 +04:00
lunardunno c5afd4a85a checking_result_docker_installation 2023-12-15 05:30:13 +04:00
lunardunno 3289819673 rollback some changes 2023-11-30 15:31:32 +04:00
lunardunno e80562c60f rollback servercontroller.cpp 2023-11-30 15:27:50 +04:00
lunardunno a8b5601777 rollback check_server_is_busy.sh 2023-11-30 15:24:39 +04:00
lunardunno fe50027edf remove exit 1 for check sudo 2023-11-30 15:10:47 +04:00
lunardunno 72beb609c4 some rollback 2023-11-30 14:50:21 +04:00
lunardunno b934ff9437 Packet manager check for Install_docker.sh 2023-11-30 14:31:53 +04:00
lunardunno 9cbf62ae7a sudo not installed for check 2023-11-30 14:24:54 +04:00
lunardunno c8e65abca0 check for sudo
check_server_is_busy.sh

check for sudo presence during execution check_server_is_busy.sh
2023-11-30 14:18:35 +04:00
lunardunno ca3b1c9aba return exit 1 for sudo 2023-11-30 13:51:14 +04:00
lunardunno e22e6e252b check sudo fuser lsof 2023-11-30 12:25:26 +04:00
lunardunno 9dd99f8080 checking of installation results psmisc 2023-11-30 11:22:49 +04:00
lunardunno 01fab70c14 back to basics 2023-11-30 01:28:55 +04:00
lunardunno 1c42e5e1b4 deleting " exit 1;" 2023-11-29 14:07:03 +04:00
lunardunno 0a564692ac re_some changes
adding " exit 1;"
2023-11-29 12:42:13 +04:00
lunardunno 075b83a990 some changes
adding " exit 1;"
2023-11-29 12:35:49 +04:00
lunardunno f0adbfed67 test without sudo 2023-11-29 12:08:59 +04:00
lunardunno 06cbaa75c8 removed comment for sudo 2023-11-29 10:57:26 +04:00
lunardunno 5b29678348 some change
rearranging the message about the absence of sudo
2023-11-29 10:26:29 +04:00
lunardunno 63161df66b added comment for sudo
added a comment for the log when there is no sudo
2023-11-29 09:35:23 +04:00
lunardunno b6467cc279 removing redundant line
removing a redundant line due to the introduction of direct verification of the installation result lsof, psmisc (fuser), sudo, docker|docker.io
2023-11-29 08:33:14 +04:00
lunardunno e451862dd2 checking of installation results
Direct checking of installation results has been introduced for lsof psmisc sudo docker.
2023-11-28 19:23:19 +04:00
lunardunno 76f05da9c9 introduced direct check sudo
introduced a direct check for the presence of the sudo package, after attempting to install sudo
2023-11-27 15:40:33 +04:00
lunardunno 7f10a1349d fix then\ 2023-11-27 15:38:26 +04:00
lunardunno b7fa882422 introduced direct check sudo
introduced a direct check for the presence of the sudo package, after attempting to install sudo
2023-11-27 15:29:58 +04:00
lunardunno 94effbd0b3 introduced sudo package check
indirect method, a check for the presence of the sudo package has been introduced
2023-11-27 12:10:50 +04:00
lunardunno 1f7714791e Improve end 2023-11-27 09:34:18 +04:00
lunardunno b60d9639e9 introduction checking docker status 2023-11-26 07:57:22 +04:00
lunardunno fcc7894527 replacing sudo with docker 2023-11-25 06:38:47 +04:00
lunardunno cb2c4a7a3a fix premature script termination
Fix premature script termination for $dist=debian and $dist=centos.
Introduced for debugging $dist=fedora
2023-11-25 05:31:00 +04:00
lunardunno 4c1bada05d -sudo 2023-11-23 16:19:33 +04:00
lunardunno 8fd83f15e0 test sudo-test command not found 2023-11-23 15:49:06 +04:00
lunardunno 2d1b3e36f1 test sudo command not found 2023-11-23 12:48:18 +04:00
88 changed files with 1835 additions and 5792 deletions
+7 -7
View File
@@ -14,8 +14,8 @@ jobs:
runs-on: ubuntu-20.04
env:
QT_VERSION: 6.6.2
QIF_VERSION: 4.7
QT_VERSION: 6.5.1
QIF_VERSION: 4.6
steps:
- name: 'Install Qt'
@@ -72,8 +72,8 @@ jobs:
runs-on: windows-latest
env:
QT_VERSION: 6.6.2
QIF_VERSION: 4.7
QT_VERSION: 6.5.1
QIF_VERSION: 4.6
BUILD_ARCH: 64
steps:
@@ -134,7 +134,7 @@ jobs:
runs-on: macos-13
env:
QT_VERSION: 6.6.2
QT_VERSION: 6.5.2
CC: cc
CXX: c++
@@ -227,7 +227,7 @@ jobs:
env:
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
QT_VERSION: 6.4.3
QIF_VERSION: 4.7
QIF_VERSION: 4.6
steps:
- name: 'Setup xcode'
@@ -286,7 +286,7 @@ jobs:
env:
ANDROID_BUILD_PLATFORM: android-34
QT_VERSION: 6.6.2
QT_VERSION: 6.6.1
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
steps:
-3
View File
@@ -131,6 +131,3 @@ client/3rd/ShadowSocks/ss_ios.xcconfig
# UML generated pics
out/
# CMake files
CMakeFiles/
+1 -1
View File
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 46)
set(APP_ANDROID_VERSION_CODE 45)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
-10
View File
@@ -15,15 +15,6 @@ set(PACKAGES
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)
set(PACKAGES ${PACKAGES} Multimedia)
endif()
@@ -66,7 +57,6 @@ set(AMNEZIAVPN_TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.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_ar.ts
)
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)
+4 -16
View File
@@ -286,16 +286,10 @@ void AmneziaApplication::initModels()
m_containersModel.reset(new ContainersModel(this));
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_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
connect(m_serversModel.get(), &ServersModel::containersUpdated, m_containersModel.get(),
&ContainersModel::updateModel);
connect(m_serversModel.get(), &ServersModel::defaultServerContainersUpdated, m_defaultServerContainersModel.get(),
&ContainersModel::updateModel);
m_serversModel->resetModel();
m_languageModel.reset(new LanguageModel(m_settings, this));
m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
@@ -339,7 +333,7 @@ void AmneziaApplication::initModels()
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, this,
[this](const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials) {
m_serversModel->reloadDefaultServerContainerConfig();
m_serversModel->reloadContainerConfig();
m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
emit m_configurator->clientModelUpdated();
});
@@ -391,13 +385,7 @@ void AmneziaApplication::initControllers()
m_engine->rootContext()->setContextProperty("ApiController", m_apiController.get());
connect(m_apiController.get(), &ApiController::updateStarted, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Connecting); });
connect(m_apiController.get(), &ApiController::errorOccurred, this, [this](const QString &errorMessage) {
if (m_connectionController->isConnectionInProgress()) {
emit m_pageController->showErrorMessage(errorMessage);
}
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(),
&ConnectionController::toggleConnection);
connect(m_apiController.get(), &ApiController::errorOccurred, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); });
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(), &ConnectionController::toggleConnection);
}
-1
View File
@@ -92,7 +92,6 @@ private:
QCommandLineParser m_parser;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ContainersModel> m_defaultServerContainersModel;
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<ProtocolsModel> m_protocolsModel;
+5 -4
View File
@@ -22,7 +22,7 @@
<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.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Enable when VPN-per-app mode will be implemented -->
@@ -137,13 +137,14 @@
android:name=".AmneziaVpnService"
android:process=":amneziaVpnService"
android:permission="android.permission.BIND_VPN_SERVICE"
android:foregroundServiceType="systemExempted"
android:exported="false"
tools:ignore="ForegroundServicePermission">
android:foregroundServiceType="specialUse"
android:exported="false">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="vpn" />
</service>
<provider
@@ -4,7 +4,7 @@ import android.app.Notification
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
import android.net.VpnService
import android.os.Build
import android.os.Handler
@@ -156,7 +156,7 @@ class AmneziaVpnService : VpnService() {
*/
private val foregroundServiceTypeCompat
get() = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SPECIAL_USE
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> FOREGROUND_SERVICE_TYPE_MANIFEST
else -> 0
}
+7 -1
View File
@@ -211,7 +211,13 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
localFile.write(data);
localFile.close();
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
#ifdef Q_OS_WINDOWS
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) {
return error;
+15 -13
View File
@@ -222,7 +222,7 @@ namespace libssh {
return fromLibsshErrorCode();
}
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const QString& localPath, const QString& remotePath, const QString &fileDesc)
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const std::string& localPath, const std::string& remotePath, const std::string& fileDesc)
{
m_sftpSession = sftp_new(m_session);
@@ -245,38 +245,40 @@ namespace libssh {
const size_t bufferSize = 16384;
char buffer[bufferSize];
file = sftp_open(m_sftpSession, remotePath.toStdString().c_str(), accessType, S_IRWXU);
file = sftp_open(m_sftpSession, remotePath.c_str(), accessType, S_IRWXU);
if (file == nullptr) {
return closeSftpSession();
}
int localFileSize = QFileInfo(localPath).size();
int localFileSize = std::filesystem::file_size(localPath);
int chunksCount = localFileSize / (bufferSize);
QFile fin(localPath);
std::ifstream fin(localPath, std::ios::binary | std::ios::in);
if (fin.open(QIODevice::ReadOnly)) {
if (fin.is_open()) {
for (int currentChunkId = 0; currentChunkId < chunksCount; currentChunkId++) {
QByteArray chunk = fin.read(bufferSize);
if (chunk.size() != bufferSize) return ErrorCode::SshSftpEofError;
fin.read(buffer, bufferSize);
int bytesWritten = sftp_write(file, chunk.data(), chunk.size());
int bytesWritten = sftp_write(file, buffer, bufferSize);
if (bytesWritten != chunk.size()) {
std::string chunk(buffer, bufferSize);
if (bytesWritten != bufferSize) {
fin.close();
sftp_close(file);
return closeSftpSession();
}
}
int lastChunkSize = localFileSize % bufferSize;
int lastChunkSize = localFileSize % (bufferSize);
if (lastChunkSize != 0) {
QByteArray lastChunk = fin.read(lastChunkSize);
if (lastChunk.size() != lastChunkSize) return ErrorCode::SshSftpEofError;
fin.read(buffer, lastChunkSize);
int bytesWritten = sftp_write(file, lastChunk.data(), lastChunkSize);
std::string chunk(buffer, lastChunkSize);
int bytesWritten = sftp_write(file, buffer, lastChunkSize);
if (bytesWritten != lastChunkSize) {
fin.close();
+3 -3
View File
@@ -33,9 +33,9 @@ namespace libssh {
const std::function<ErrorCode (const QString &, Client &)> &cbReadStdErr);
ErrorCode writeResponse(const QString &data);
ErrorCode sftpFileCopy(const SftpOverwriteMode overwriteMode,
const QString &localPath,
const QString &remotePath,
const QString& fileDesc);
const std::string& localPath,
const std::string& remotePath,
const std::string& fileDesc);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
private:
ErrorCode closeChannel();
@@ -1,6 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 511 B

@@ -85,7 +85,6 @@ target_sources(networkextension PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
)
-3
View File
@@ -124,10 +124,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
// json.insert("hopindex", QJsonValue((double)hop.m_hopindex));
json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key));
json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip));
// todo review wg ipv6
#ifndef Q_OS_WINDOWS
json.insert("deviceIpv6Address", "dead::1");
#endif
json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key));
json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key));
json.insert("serverIpv4AddrIn", wgConfig.value(amnezia::config_key::hostName));
@@ -59,6 +59,10 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
var stopHandler: (() -> Void)?
var protoType: TunnelProtoType = .none
override init() {
super.init()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
let tmpStr = String(data: messageData, encoding: .utf8)!
wg_log(.error, message: tmpStr)
@@ -67,7 +71,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let completionHandler else {
guard let completionHandler = completionHandler else {
log(.error, message: "Missing message completion handler")
return
}
@@ -175,16 +179,14 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let wgConfigStr = try? JSONDecoder().decode(WGConfig.self, from: wgConfig).str,
let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr)
else {
let wgConfigStr = String(data: wgConfig, encoding: .utf8)!
guard let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr) else {
wg_log(.error, message: "Can't parse WireGuard config")
completionHandler(nil)
return
}
log(.info, message: "wgConfig: \(wgConfigStr.replacingOccurrences(of: "\n", with: " "))")
if tunnelConfiguration.peers.first!.allowedIPs
.map({ $0.stringRepresentation })
.joined(separator: ", ") == "0.0.0.0/0, ::/0" {
-135
View File
@@ -1,135 +0,0 @@
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 -6
View File
@@ -400,10 +400,9 @@ bool IosController::setupCloak()
bool IosController::setupWireGuard()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::WireGuard)].toObject();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
QString wgConfig = config[config_key::config].toString();
return startWireGuard(wgConfig);
}
@@ -411,9 +410,8 @@ bool IosController::setupAwg()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
QString wgConfig = config[config_key::config].toString();
return startWireGuard(wgConfig);
}
+1 -4
View File
@@ -160,6 +160,7 @@
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.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/Pages2/PageSettings.qml</file>
<file>images/controls/amnezia.svg</file>
@@ -224,9 +225,5 @@
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>images/controls/close.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>
<file>ui/qml/Components/FadeBehavior.qml</file>
</qresource>
</RCC>
+35 -12
View File
@@ -1,20 +1,43 @@
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="> /dev/null 2>&1"; docker_pkg="docker"; dist="archlinux";\
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; what_pkg="-s install"; docker_pkg="docker.io"; dist="debian";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; what_pkg="--assumeno install --setopt=tsflags=test"; docker_pkg="docker"; dist="fedora";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; what_pkg="--assumeno install --setopt=tsflags=test"; docker_pkg="docker"; dist="centos";\
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; what_pkg="-Sp"; docker_pkg="docker"; dist="archlinux";\
else echo "Packet manager not found"; exit 1; fi;\
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, What pkg command: $what_pkg, Docker pkg: $docker_pkg";\
if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi;\
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo; fi;\
if ! command -v fuser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst psmisc; fi;\
if ! command -v lsof > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst lsof; fi;\
if ! command -v docker > /dev/null 2>&1; then \
sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
sleep 5; sudo systemctl enable --now docker; sleep 5;\
CHECK_LOCALE=$(locale | grep -c 'LANG=en_US.UTF-8');\
if [ "$CHECK_LOCALE" = "0" ]; then \
CHECK_LOCALE=$(locale | grep -c 'LANG=C.UTF-8');\
if [ "$CHECK_LOCALE" = "0" ]; then \
CHECK_LOCALE=$(locale -a | grep -c 'en_US.utf8');\
if [ "$CHECK_LOCALE" != "0" ]; then export LC_ALL=en_US.UTF-8;\
else \
CHECK_LOCALE=$(locale -a | grep 'C.utf8');\
if [ "$CHECK_LOCALE" != "0" ]; then export LC_ALL=C.UTF-8; fi;\
fi;\
fi;\
fi;\
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo;\
if ! command -v sudo > /dev/null 2>&1; then sudo; exit 1; fi;\
fi;\
if ! command -v fuser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst psmisc;\
if ! command -v fuser > /dev/null 2>&1; then fuser; exit 1; fi;\
fi;\
if ! command -v lsof > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst lsof;\
if ! command -v lsof > /dev/null 2>&1; then lsof; exit 1; fi;\
fi;\
if ! command -v docker > /dev/null 2>&1; then sudo $pm $check_pkgs;\
check_podman=$(sudo $pm $what_pkg $docker_pkg 2>&1 | grep -c podman-docker);\
check_moby=$(sudo $pm $what_pkg $docker_pkg 2>&1 | grep -c moby-engine);\
if [ "$check_podman" != "0" ] || [ "$check_moby" != "0" ]; then echo "Container is not supported"; exit 1;\
else sudo $pm $silent_inst $docker_pkg;\
if ! command -v docker > /dev/null 2>&1; then docker; exit 1;\
else sleep 5; sudo systemctl enable --now docker; sleep 5; fi;\
fi;\
fi;\
if [ "$(systemctl is-active docker)" != "active" ]; then \
sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
sleep 5; sudo systemctl start docker; sleep 5;\
fi;\
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install sudo, command not found"; exit 1; fi;\
if ! command -v docker > /dev/null 2>&1; then echo "Failed to install docker, command not found"; exit 1; fi;\
docker --version
File diff suppressed because it is too large Load Diff
+47 -63
View File
@@ -144,7 +144,7 @@
</message>
<message>
<source>Reconnect via VPN Procotol: </source>
<translation type="vanished">پروتکل VPN را متصل مجدد کنید" </translation>
<translation type="vanished">Переподключение через VPN протокол: </translation>
</message>
</context>
<context>
@@ -371,7 +371,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="vanished">همه کاربرانی که با آن‌ها این پروتکل VPN را به اشتراک گذاشته‌اید دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="vanished">Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="280"/>
@@ -604,7 +604,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="vanished">همه کاربرانی که با آن این پروتکل VPN را به اشتراک گذاشته‌اید دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="vanished">Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolOpenVpnSettings.qml" line="369"/>
@@ -656,7 +656,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="obsolete">همه کاربرانی که با آن این پروتکل VPN را به اشتراک گذاشته‌اید دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="obsolete">Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolRaw.qml" line="180"/>
@@ -697,7 +697,7 @@ Already installed containers were found on the server. All installed containers
<name>PageServerContainers</name>
<message>
<source>Continue</source>
<translation type="obsolete">ادامه دهید</translation>
<translation type="obsolete">Продолжить</translation>
</message>
</context>
<context>
@@ -847,13 +847,13 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="94"/>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL. </source>
<translation>استفاده &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; برای باز کردن این نشانی.</translation>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="103"/>
<source>After creating your onion site, it takes a few minutes for the Tor network to make it available for use.</source>
<translation>پس از ایجاد سایت پیاز خود، چند دقیقه طول می‌کشد تا شبکه تور آن را برای استفاده فراهم کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this url.</source>
@@ -870,7 +870,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>When configuring WordPress set the this address as domain.</source>
<translation type="vanished">هنگام تنظیم وردپرس، این آدرس پیاز را به عنوان دامنه مشخص کنید.</translation>
<translation type="vanished">При настройке WordPress укажите этот onion адрес в качестве домена.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="126"/>
@@ -940,7 +940,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="56"/>
<source>Support Amnezia</source>
<translation>پشتیبانی از Amnezia</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="71"/>
@@ -1022,11 +1022,6 @@ Already installed containers were found on the server. All installed containers
<source>https://amnezia.org</source>
<translation>https://amnezia.org</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="176"/>
<source>Software version: %1</source>
<translation>%1 :نسخه نرم‎افزار</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="192"/>
<source>Check for updates</source>
@@ -1220,7 +1215,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="86"/>
<source>When AmneziaDNS is not used or installed</source>
<translation>وقتی AmneziaDNS استفاده نشده یا نصب نشده است.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="120"/>
@@ -1256,7 +1251,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsDns.qml" line="35"/>
<source>Default server does not support custom dns</source>
<translation>سرور پیش‌فرض از دی‌ان‌اس سفارشی پشتیبانی نمی‌کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsDns.qml" line="53"/>
@@ -1438,27 +1433,27 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="139"/>
<source>Reboot server</source>
<translation>سرور را دوباره راه‌اندازی کنید.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="143"/>
<source>Do you want to reboot the server?</source>
<translation>آیا می‌خواهید سرور را دوباره راه‌اندازی کنید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="144"/>
<source>The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?</source>
<translation>فرآیند راه‌اندازی ممکن است حدود ۳۰ ثانیه طول بکشد. آیا مطمئن هستید که می‌خواهید ادامه دهید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="175"/>
<source>Do you want to remove the server from application?</source>
<translation>آیا می‌خواهید سرور را از برنامه حذف کنید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="206"/>
<source>Do you want to clear server from Amnezia software?</source>
<translation>آیا می‌خواهید سرور را از نرم‌افزار Amnezia پاک کنید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="171"/>
@@ -1541,7 +1536,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="vanished">تمام کاربرانی که با آن VPN را به اشتراک گذاشته‌اید، دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="vanished">Все пользователи, которым вы поделились VPN, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="118"/>
@@ -1567,7 +1562,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="29"/>
<source>Default server does not support split tunneling function</source>
<translation>سرور پیش‌فرض از عملکرد تونل‌سازی تقسیم شده پشتیبانی نمی‌کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Addresses from the list should be accessed via VPN</source>
@@ -1614,17 +1609,17 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="59"/>
<source>Only the sites listed here will be accessed through the VPN</source>
<translation>تنها سایت‌های موجود در اینجا از طریق VPN دسترسی داده خواهند شد.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="254"/>
<source>website or IP</source>
<translation>وب‌سایت یا آدرس IP</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="298"/>
<source>Import / Export Sites</source>
<translation>وارد کردن / صادر کردن وب‌سایت‌ها</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="304"/>
@@ -1721,7 +1716,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<name>PageSetupWizardCredentials</name>
<message>
<source>Server connection</source>
<translation type="vanished">اتصال به سرور</translation>
<translation type="vanished">Подключение к серверу</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="51"/>
@@ -1828,12 +1823,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>سرور در حال حاضر به نرم‎افزار اضافه شده است</translation>
</message>
<message>
<source>Amnezia has detected that your server is currently </source>
<translation type="vanished">Amnezia has detected that your server is currently </translation>
<source>Amnesia has detected that your server is currently </source>
<translation type="vanished">Amnesia обнаружила, что ваш сервер в настоящее время </translation>
</message>
<message>
<source>busy installing other software. Amnezia installation </source>
<translation type="vanished">busy installing other software. Amnezia installation</translation>
<source>busy installing other software. Amnesia installation </source>
<translation type="vanished">занят установкой других протоколов или сервисов. Установка Amnesia </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="67"/>
@@ -2024,7 +2019,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
</message>
<message>
<source>VPN Access</source>
<translation type="vanished">دسترسی VPN</translation>
<translation type="vanished">VPN-Доступ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="220"/>
@@ -2033,11 +2028,11 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
</message>
<message>
<source>VPN access without the ability to manage the server</source>
<translation type="vanished">دسترسی به VPN بدون امکان مدیریت سرور</translation>
<translation type="vanished">Доступ к VPN, без возможности управления сервером</translation>
</message>
<message>
<source>Access to server management. The user with whom you share full access to the connection will be able to add and remove your protocols and services to the server, as well as change settings.</source>
<translation type="vanished">دسترسی به مدیریت سرور. کاربری که با او دسترسی کامل به اتصال را به اشتراک می‌گذارید، می‌تواند پروتکل‌ها و سرویس‌های شما را در سرور اضافه و حذف کند، همچنین تنظیمات را تغییر دهد.</translation>
<translation type="vanished">Доступ к управлению сервером. Пользователь, с которым вы делитесь полным доступом к соединению, сможет добавлять и удалять ваши протоколы и службы на сервере, а также изменять настройки.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="280"/>
@@ -2137,7 +2132,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="584"/>
<source>Creation date: </source>
<translation>تاریخ ایجاد:</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="598"/>
@@ -2162,7 +2157,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="671"/>
<source>Revoke the config for a user - %1?</source>
<translation> لغو پیکربندی برای یک کاربر %1؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Revoke the config for a user - </source>
@@ -2737,17 +2732,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../containers/containers_defs.cpp" line="101"/>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but it may be recognized by analysis systems in some highly censored regions.</source>
<translation>شدوساکس - ترافیک VPN را پنهان می کند، به طوری که مشابه ترافیک وب عادی می شود، اما ممکن است توسط سیستم های تجزیه و تحلیل در برخی از مناطق با سانسور شدید شناسایی شود.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="104"/>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation>OpenVPN روی Cloak - OpenVPN با VPN که به عنوان ترافیک وب پنهان می‌شود و مقاومت در برابر تشخیص فعال از طریق پیشرفته. ایده‌آل برای دور زدن مسدود کردن در مناطق با بالاترین سطوح سانسور</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="122"/>
<source>Create a file vault on your server to securely store and transfer files.</source>
<translation>ساختن یک گنجانده فایل بر روی سرور شما برای ذخیره و انتقال ایمن فایل‌ها</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="155"/>
@@ -2769,23 +2764,7 @@ If there is a extreme level of Internet censorship in your region, we advise you
* Not recognised by DPI analysis systems
* Works over TCP network protocol, 443 port.
</source>
<translation>این ترکیبی از پروتکل OpenVPN و پلاگین Cloak به طور خاص برای محافظت در برابر مسدود کردن طراحی شده است.
OpenVPN ارتباط امن VPN را با رمزگذاری تمام ترافیک اینترنتی بین مشتری و سرور فراهم می‌کند.
Cloak OpenVPN را از شناسایی و مسدود کردن محافظت می‌کند.
Cloak می‌تواند اطلاعات فراداده بسته را تغییر دهد تا ترافیک VPN را به طور کامل به عنوان ترافیک وب عادی پنهان کند و همچنین VPN را از شناسایی توسط Active Probing محافظت کند. این باعث می‌شود این سیستم بسیار مقاوم در برابر شناسایی شود.
فوراً پس از دریافت اولین بسته داده، Cloak اتصال ورودی را تأیید می‌کند. اگر تأیید اعتبار ناموفق باشد، پلاگین سرور را به عنوان یک وب‌سایت جعلی پنهان می‌کند و VPN شما برای سیستم‌های تجزیه و تحلیل غیر قابل دسترسی می‌شود.
اگر در منطقه شما سطح بسیار بالایی از سانسور اینترنت وجود دارد، به شما توصیه می‌شود که از اولین اتصال فقط از OpenVPN over Cloak استفاده کنید.
در دسترس در AmneziaVPN بر روی تمام پلتفرم‌ها
مصرف بالای برق در دستگاه‌های تلفن همراه
تنظیمات انعطاف پذیر
توسط سیستم‌های تجزیه و تحلیل DPI شناخته نمی‌شود
بر روی پروتکل شبکه TCP، پورت 443 کار می‌کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="174"/>
@@ -3112,6 +3091,11 @@ This means that AmneziaWG keeps the fast performance of the original while addin
</context>
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="27"/>
<source>Software version</source>
<translation>نسخه نرم‎افزار</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="148"/>
<source>All settings have been reset to default values</source>
@@ -3249,7 +3233,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<message>
<location filename="../ui/qml/Controls2/TextFieldWithHeaderType.qml" line="105"/>
<source>The field can&apos;t be empty</source>
<translation>این فیلد نمی‌تواند خالی باشد.</translation>
<translation>Поле не может быть пустым</translation>
</message>
</context>
<context>
@@ -3337,23 +3321,23 @@ This means that AmneziaWG keeps the fast performance of the original while addin
</message>
<message>
<source>High</source>
<translation type="vanished">بالایی</translation>
<translation type="vanished">Высокий</translation>
</message>
<message>
<source>Medium</source>
<translation type="vanished">متوسط</translation>
<translation type="vanished">Средний</translation>
</message>
<message>
<source>Many foreign websites and VPN providers are blocked</source>
<translation type="vanished">بسیاری از وب‌سایت‌ها و ارائه‌دهندگان VPN خارجی مسدود شده‌اند.</translation>
<translation type="vanished">Многие иностранные сайты и VPN-провайдеры заблокированы</translation>
</message>
<message>
<source>Some foreign sites are blocked, but VPN providers are not blocked</source>
<translation type="vanished">بعضی از وب‌سایت‌های خارجی مسدود شده‌اند، اما ارائه‌دهندگان VPN مسدود نمی‌شوند.</translation>
<translation type="vanished">Некоторые иностранные сайты заблокированы, но VPN-провайдеры не блокируются</translation>
</message>
<message>
<source>I just want to increase the level of privacy</source>
<translation type="vanished">من فقط می‌خواهم سطح حریم خصوصی خود را افزایش دهم.</translation>
<translation type="vanished">Хочу просто повысить уровень приватности</translation>
</message>
</context>
<context>
+22 -22
View File
@@ -854,11 +854,11 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL.</source>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this url.</source>
<translation type="vanished">Используйте &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; для открытия этой ссылки.</translation>
</message>
<message>
<source>After creating your onion site, it takes a few minutes for the Tor network to make it available for use.</source>
<source>After installation it takes several minutes while your onion site will become available in the Tor Network.</source>
<translation type="vanished">Через несколько минут после установки ваш Onion сайт станет доступен в сети Tor.</translation>
</message>
<message>
@@ -938,7 +938,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="56"/>
<source>Support Amnezia</source>
<translation type="unfinished">Поддержите Amnezia</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="71"/>
@@ -1020,11 +1020,6 @@ Already installed containers were found on the server. All installed containers
<source>https://amnezia.org</source>
<translation>https://amnezia.org</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="176"/>
<source>Software version: %1</source>
<translation>Версия ПО: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="192"/>
<source>Check for updates</source>
@@ -1226,7 +1221,7 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>When AmneziaDNS is not used or installed</source>
<source>If AmneziaDNS is not used or installed</source>
<translation type="vanished">Эти адреса будут использоваться, если не включен AmneziaDNS</translation>
</message>
<message>
@@ -1263,7 +1258,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsDns.qml" line="58"/>
<source>When AmneziaDNS is not used or installed</source>
<source>If AmneziaDNS is not used or installed</source>
<translation>Эти адреса будут использоваться, если не включен или не установлен AmneziaDNS</translation>
</message>
<message>
@@ -1436,27 +1431,27 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="139"/>
<source>Reboot server</source>
<translation type="unfinished">Перезагрузить сервер</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="143"/>
<source>Do you want to reboot the server?</source>
<translation type="unfinished">Вы уверены, что хотите перезагрузить сервер?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="144"/>
<source>The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?</source>
<translation type="unfinished">Процесс перезагрузки может занять около 30 секунд. Вы уверены, что хотите продолжить?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="175"/>
<source>Do you want to remove the server from application?</source>
<translation type="unfinished">Вы уверена что хотите удалить сервер из приложения?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="206"/>
<source>Do you want to clear server from Amnezia software?</source>
<translation type="unfinished">Вы хотите очистить сервер от всех сервисов Amnezia?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="171"/>
@@ -1568,7 +1563,7 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>Only the sites listed here will be accesed via VPN</source>
<source>Addresses from the list should be accessed via VPN</source>
<translation type="vanished">Только адреса из списка должны открываться через VPN</translation>
</message>
<message>
@@ -1602,11 +1597,11 @@ Already installed containers were found on the server. All installed containers
<translation>Отменить</translation>
</message>
<message>
<source>Website or IP</source>
<source>Site or IP</source>
<translation type="vanished">Сайт или IP</translation>
</message>
<message>
<source>Import / Export Sites</source>
<source>Import/Export Sites</source>
<translation type="vanished">Импорт/экспорт Сайтов</translation>
</message>
<message>
@@ -2131,7 +2126,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="584"/>
<source>Creation date: </source>
<translation type="unfinished">Дата создания</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="598"/>
@@ -2813,11 +2808,11 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<translation>OpenVPN - популярный VPN-протокол, с гибкой настройкой. Имеет собственный протокол безопасности с SSL/TLS для обмена ключами.</translation>
</message>
<message>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but it may be recognized by analysis systems in some highly censored regions.</source>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but is recognised by analysis systems in some highly censored regions.</source>
<translation type="vanished">ShadowSocks - маскирует VPN-трафик под обычный веб-трафик, но распознается системами анализа в некоторых регионах с высоким уровнем цензуры.</translation>
</message>
<message>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probbing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="vanished">OpenVPN over Cloak - OpenVPN с маскировкой VPN под web-трафик и защитой от обнаружения active-probbing. Подходит для регионов с самым высоким уровнем цензуры.</translation>
</message>
<message>
@@ -2846,7 +2841,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<translation>Замените DNS-сервер на Amnezia DNS. Это повысит уровень конфиденциальности.</translation>
</message>
<message>
<source>Create a file vault on your server to securely store and transfer files.</source>
<source>Creates a file vault on your server to securely store and transfer files.</source>
<translation type="vanished">Создайте на сервере файловое хранилище для безопасного хранения и передачи файлов.</translation>
</message>
<message>
@@ -3063,6 +3058,11 @@ This means that AmneziaWG keeps the fast performance of the original while addin
</context>
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="27"/>
<source>Software version</source>
<translation>Версия ПО</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="148"/>
<source>All settings have been reset to default values</source>
+40 -48
View File
@@ -200,7 +200,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/controllers/installController.cpp" line="305"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation type="unfinished">服务器 &apos;%1&apos; 已重新启动</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="314"/>
@@ -891,10 +891,10 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="103"/>
<source>After creating your onion site, it takes a few minutes for the Tor network to make it available for use.</source>
<translation>创建您的洋葱网站后,需要几分钟时间,才能使其在Tor网络上可用</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL.</source>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this url.</source>
<translation type="vanished">用 &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor 浏览器&lt;/a&gt; 打开上面网址</translation>
</message>
<message>
@@ -984,7 +984,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="56"/>
<source>Support Amnezia</source>
<translation>支持Amnezia</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="71"/>
@@ -1067,11 +1067,6 @@ And if you don&apos;t like the app, all the more support it - the donation will
<source>https://amnezia.org</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="176"/>
<source>Software version: %1</source>
<translation>软件版本: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="192"/>
<source>Check for updates</source>
@@ -1266,7 +1261,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="86"/>
<source>When AmneziaDNS is not used or installed</source>
<translation>当未使用或未安装AmneziaDNS时</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="120"/>
@@ -1484,12 +1479,12 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="143"/>
<source>Do you want to reboot the server?</source>
<translation type="unfinished">您想重新启动服务器吗?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="206"/>
<source>Do you want to clear server from Amnezia software?</source>
<translation>您要清除服务器上的Amnezia软件吗?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="92"/>
@@ -1525,12 +1520,12 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="139"/>
<source>Reboot server</source>
<translation>重新启动服务器</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="144"/>
<source>The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?</source>
<translation> 重新启动过程可能需要大约30秒。您确定要继续吗?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="171"/>
@@ -1540,7 +1535,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="175"/>
<source>Do you want to remove the server from application?</source>
<translation type="unfinished">您想要从应用程序中移除服务器吗?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remove server?</source>
@@ -1711,17 +1706,17 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="59"/>
<source>Only the sites listed here will be accessed through the VPN</source>
<translation>只有这里列出的网站将通过VPN访问</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="254"/>
<source>website or IP</source>
<translation>网站或IP</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="298"/>
<source>Import / Export Sites</source>
<translation>导入/导出网站</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="304"/>
@@ -2143,12 +2138,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="120"/>
<source>ShadowSocks native format</source>
<translation>ShadowSocks原生格式</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="125"/>
<source>Cloak native format</source>
<translation>Cloak原生格式</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="150"/>
@@ -2158,18 +2153,18 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="178"/>
<source>Share full access to the server and VPN</source>
<translation>共享服务器和VPN的完全访问权限</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="179"/>
<source>Use for your own devices, or share with those you trust to manage the server.</source>
<translation type="unfinished">用于您自己的设备,或与您信任的人共享以管理服务器</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="486"/>
<source>Users</source>
<translation>用户</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="251"/>
@@ -2204,17 +2199,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="668"/>
<source>Revoke</source>
<translation>撤销</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="671"/>
<source>Revoke the config for a user - %1?</source>
<translation>撤销用户的配置- %1?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="672"/>
<source>The user will no longer be able to connect to your server.</source>
<translation type="unfinished">该用户将无法再连接到您的服务器</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="673"/>
@@ -2300,12 +2295,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="34"/>
<source>Config revoked</source>
<translation>配置已撤销</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="262"/>
<source>User name</source>
<translation>用户名</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="429"/>
@@ -2325,7 +2320,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="49"/>
<source>Full access to the server and VPN</source>
<translation>对服务器和VPN的完全访问权限</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="57"/>
@@ -2336,7 +2331,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="58"/>
<source>If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. </source>
<translation>如果您与其他人共享完全访问权限,他们可以从服务器中删除和添加协议和服务,这将导致VPN对所有用户的工作出现问题。</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="73"/>
@@ -2827,7 +2822,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>The config does not contain any containers and credentials for connecting to the server</source>
<translation>配置不包含任何用于连接服务器的容器和凭据</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>The config does not contain any containers and credentiaks for connecting to the server</source>
@@ -2836,7 +2831,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>Internal error</source>
<translation></translation>
<translation>内部错误</translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="88"/>
@@ -2867,17 +2862,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../containers/containers_defs.cpp" line="101"/>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but it may be recognized by analysis systems in some highly censored regions.</source>
<translation>ShadowSocks - 掩盖VPN流量,使其类似于正常的网络流量,但在一些高度审查的地区可能会被分析系统识别</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="104"/>
<source>OpenVPN over Cloak - OpenVPN with masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="unfinished">OpenVPN over Cloak - OpenVPN与VPN结合,伪装成Web流量,并保护免受主动探测的侦测。非常适合在具有最高审查水平的地区绕过封锁</translation>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="122"/>
<source>Create a file vault on your server to securely store and transfer files.</source>
<translation>在您的服务器上创建一个文件保险库,用于安全存储和传输文件。</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="155"/>
@@ -2912,23 +2907,15 @@ WireGuard is very susceptible to blocking due to its distinct packet signatures.
* Minimum number of settings
* Easily recognised by DPI analysis systems, susceptible to blocking
* Works over UDP network protocol.</source>
<translation>一个相对较新的流行VPN协议,具有简化的架构。
WireGuard提供稳定的VPN连接,并在所有设备上具有高性能。它使用硬编码的加密设置。与OpenVPN相比,WireGuard具有较低的延迟和更好的数据传输吞吐量。
WireGuard非常容易被阻挡,因为其独特的数据包签名。与一些其他VPN协议不同,这些协议使用混淆技术,WireGuard数据包的一致签名模式更容易被高级深度数据包检测(DPI)系统和其他网络监控工具识别和阻挡。
在AmneziaVPN上适用于所有平台
低功耗
最少的设置
易于被DPI分析系统识别,容易被阻挡
通过UDP网络协议运行。</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but is recognised by analysis systems in some highly censored regions.</source>
<translation type="vanished">ShadowSocks - 混淆 VPN 流量,使其与正常的 Web 流量相似,但在一些审查力度高的地区可以被分析系统识别。</translation>
</message>
<message>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="vanished">OpenVPN over Cloak - OpenVPN与VPN结合,伪装成Web流量,并保护免受主动探测的侦测。非常适合在具有最高审查水平的地区绕过封锁</translation>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probbing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="vanished">OpenVPN over Cloak - OpenVPN 与 VPN 具有伪装成网络流量和防止主动探测检测的保护。非常适合绕过审查力度特别强的地区的封锁。</translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="108"/>
@@ -3211,6 +3198,11 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
</context>
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="27"/>
<source>Software version</source>
<translation>软件版本</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="132"/>
<source>Backup file is corrupted</source>
@@ -3254,7 +3246,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<message>
<location filename="../ui/qml/Components/ShareConnectionDrawer.qml" line="128"/>
<source>Copy config string</source>
<translation>复制配置字符串</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Components/ShareConnectionDrawer.qml" line="150"/>
+7 -17
View File
@@ -70,17 +70,14 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
void ApiController::updateServerConfigFromApi()
{
QtConcurrent::run([this]() {
if (m_isConfigUpdateStarted) {
emit updateFinished(false);
return;
}
auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray();
bool isConfigUpdateStarted = false;
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
emit updateStarted();
m_isConfigUpdateStarted = true;
isConfigUpdateStarted = true;
QNetworkAccessManager manager;
@@ -113,12 +110,6 @@ void ApiController::updateServerConfigFromApi()
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
@@ -136,18 +127,17 @@ void ApiController::updateServerConfigFromApi()
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
m_serversModel->editServer(serverConfig);
emit m_serversModel->defaultContainerChanged(ContainerProps::containerFromString(defaultContainer));
} else {
qDebug() << reply->error();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
}
emit updateFinished(m_isConfigUpdateStarted);
m_isConfigUpdateStarted = false;
emit updateFinished(isConfigUpdateStarted);
return;
});
}
@@ -163,5 +153,5 @@ void ApiController::clearApiConfig()
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
m_serversModel->editServer(serverConfig);
}
-2
View File
@@ -39,8 +39,6 @@ private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
bool m_isConfigUpdateStarted = false;
};
#endif // APICONTROLLER_H
@@ -33,7 +33,7 @@ void ConnectionController::openConnection()
int serverIndex = m_serversModel->getDefaultServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
DockerContainer container = m_serversModel->getDefaultContainer(serverIndex);
const QJsonObject &containerConfig = m_containersModel->getContainerConfig(container);
if (container == DockerContainer::None) {
@@ -61,7 +61,7 @@ void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
m_state = state;
m_isConnected = false;
m_connectionStateText = tr("Connecting...");
m_connectionStateText = tr("Connection...");
switch (state) {
case Vpn::ConnectionState::Connected: {
m_isConnectionInProgress = false;
+7 -47
View File
@@ -8,7 +8,6 @@
#include <QImage>
#include <QStandardPaths>
#include "configurators/awg_configurator.h"
#include "configurators/cloak_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
@@ -46,7 +45,7 @@ void ExportController::generateFullAccessConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
QJsonObject config = m_settings->server(serverIndex);
QJsonArray containers = config.value(config_key::containers).toArray();
@@ -100,7 +99,7 @@ void ExportController::generateConnectionConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -156,7 +155,7 @@ void ExportController::generateOpenVpnConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -194,7 +193,7 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -229,50 +228,11 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
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()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -308,7 +268,7 @@ void ExportController::generateCloakConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
@@ -368,7 +328,7 @@ void ExportController::updateClientManagementModel(const DockerContainer contain
void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials)
{
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials,
m_serversModel->getProcessedServerIndex());
m_serversModel->getCurrentlyProcessedServerIndex());
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
-1
View File
@@ -34,7 +34,6 @@ public slots:
void generateConnectionConfig(const QString &clientName);
void generateOpenVpnConfig(const QString &clientName);
void generateWireGuardConfig(const QString &clientName);
void generateAwgConfig(const QString &clientName);
void generateShadowSocksConfig();
void generateCloakConfig();
+14 -14
View File
@@ -176,7 +176,7 @@ void InstallController::installServer(DockerContainer container, QJsonObject &co
void InstallController::installContainer(DockerContainer container, QJsonObject &config)
{
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
@@ -238,7 +238,7 @@ bool InstallController::isServerAlreadyExists()
void InstallController::scanServerForInstalledContainers()
{
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
@@ -267,7 +267,7 @@ void InstallController::scanServerForInstalledContainers()
void InstallController::updateContainer(QJsonObject config)
{
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials serverCredentials =
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_protocolModel->updateModel(config);
auto defaultContainer = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
if ((serverIndex == m_serversModel->getDefaultServerIndex()) && (container == defaultContainer)) {
if ((serverIndex == m_serversModel->getDefaultServerIndex())
&& (container == m_serversModel->getDefaultContainer(serverIndex))) {
emit currentContainerUpdated();
} else {
emit updateContainerFinished(tr("Settings updated successfully"));
@@ -296,27 +296,27 @@ void InstallController::updateContainer(QJsonObject config)
emit installationErrorOccurred(errorString(errorCode));
}
void InstallController::rebootProcessedServer()
void InstallController::rebootCurrentlyProcessedServer()
{
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
m_serversModel->rebootServer();
emit rebootProcessedServerFinished(tr("Server '%1' was rebooted").arg(serverName));
emit rebootCurrentlyProcessedServerFinished(tr("Server '%1' was rebooted").arg(serverName));
}
void InstallController::removeProcessedServer()
void InstallController::removeCurrentlyProcessedServer()
{
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
m_serversModel->removeServer();
emit removeProcessedServerFinished(tr("Server '%1' was removed").arg(serverName));
emit removeCurrentlyProcessedServerFinished(tr("Server '%1' was removed").arg(serverName));
}
void InstallController::removeAllContainers()
{
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
ErrorCode errorCode = m_serversModel->removeAllContainers();
@@ -329,7 +329,7 @@ void InstallController::removeAllContainers()
void InstallController::removeCurrentlyProcessedContainer()
{
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
int container = m_containersModel->getCurrentlyProcessedContainerIndex();
@@ -377,7 +377,7 @@ void InstallController::mountSftpDrive(const QString &port, const QString &passw
QString mountPath;
QString cmd;
int serverIndex = m_serversModel->getProcessedServerIndex();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
QString hostname = serverCredentials.hostName;
+4 -4
View File
@@ -30,8 +30,8 @@ public slots:
void updateContainer(QJsonObject config);
void removeProcessedServer();
void rebootProcessedServer();
void removeCurrentlyProcessedServer();
void rebootCurrentlyProcessedServer();
void removeAllContainers();
void removeCurrentlyProcessedContainer();
@@ -54,8 +54,8 @@ signals:
void scanServerFinished(bool isInstalledContainerFound);
void rebootProcessedServerFinished(const QString &finishedMessage);
void removeProcessedServerFinished(const QString &finishedMessage);
void rebootCurrentlyProcessedServerFinished(const QString &finishedMessage);
void removeCurrentlyProcessedServerFinished(const QString &finishedMessage);
void removeAllContainersFinished(const QString &finishedMessage);
void removeCurrentlyProcessedContainerFinished(const QString &finishedMessage);
+30
View File
@@ -118,6 +118,36 @@ 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()
{
return m_isTriggeredByConnectButton;
+11
View File
@@ -82,6 +82,11 @@ public slots:
void showOnStartup();
void updateDrawerRootPage(PageLoader::PageEnum page);
void goToDrawerRootPage();
void drawerOpen();
void drawerClose();
bool isTriggeredByConnectButton();
void setTriggeredBtConnectButton(bool trigger);
@@ -113,11 +118,17 @@ signals:
void showPassphraseRequestDrawer();
void passphraseRequestDrawerClosed(QString passphrase);
void showTopCloseButton(bool visible);
void forceCloseDrawer();
private:
QSharedPointer<ServersModel> m_serversModel;
std::shared_ptr<Settings> m_settings;
PageLoader::PageEnum m_currentRootPage;
int m_drawerLayer;
bool m_isTriggeredByConnectButton;
};
+1 -1
View File
@@ -28,7 +28,7 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
m_sitesModel(sitesModel),
m_settings(settings)
{
m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH);
m_appVersion = QString("%1: %2 (%3)").arg(tr("Software version"), QString(APP_VERSION), __DATE__);
#ifdef Q_OS_ANDROID
if (!m_settings->isScreenshotsEnabled()) {
-3
View File
@@ -45,7 +45,6 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
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::Persian: strLanguage = "فارسی"; break;
case LanguageSettings::AvailableLanguageEnum::Arabic: strLanguage = "العربية"; break;
default:
break;
}
@@ -60,7 +59,6 @@ void LanguageModel::changeLanguage(const LanguageSettings::AvailableLanguageEnum
case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break;
case LanguageSettings::AvailableLanguageEnum::China_cn: emit updateTranslations(QLocale::Chinese); 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;
}
}
@@ -73,7 +71,6 @@ int LanguageModel::getCurrentLanguageIndex()
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::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;
}
}
+1 -2
View File
@@ -13,8 +13,7 @@ namespace LanguageSettings
English,
Russian,
China_cn,
Persian,
Arabic
Persian
};
Q_ENUM_NS(AvailableLanguageEnum)
+111 -144
View File
@@ -5,13 +5,19 @@
ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent)
{
connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged);
m_servers = m_settings->serversArray();
m_defaultServerIndex = m_settings->defaultServerIndex();
m_currentlyProcessedServerIndex = m_defaultServerIndex;
connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged);
connect(this, &ServersModel::defaultContainerChanged, this, &ServersModel::defaultServerDescriptionChanged);
connect(this, &ServersModel::defaultServerIndexChanged, this, [this](const int serverIndex) {
auto defaultContainer = ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString());
emit ServersModel::defaultServerDefaultContainerChanged(defaultContainer);
emit ServersModel::defaultServerNameChanged();
updateDefaultServerContainersModel();
emit ServersModel::defaultContainerChanged(defaultContainer);
});
connect(this, &ServersModel::currentlyProcessedServerIndexChanged, this, [this](const int serverIndex) {
auto defaultContainer = ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString());
emit ServersModel::defaultContainerChanged(defaultContainer);
});
}
@@ -68,14 +74,16 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
return name;
}
case ServerDescriptionRole: {
auto description = getServerDescription(server, index.row());
return configVersion ? description : description + server.value(config_key::hostName).toString();
if (configVersion) {
return server.value(config_key::description).toString();
}
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 CredentialsLoginRole: return serverCredentials(index.row()).userName;
case IsDefaultRole: return index.row() == m_defaultServerIndex;
case IsCurrentlyProcessedRole: return index.row() == m_processedServerIndex;
case IsCurrentlyProcessedRole: return index.row() == m_currentlyProcessedServerIndex;
case HasWriteAccessRole: {
auto credentials = serverCredentials(index.row());
return (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty());
@@ -87,13 +95,6 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
case DefaultContainerRole: {
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();
@@ -110,9 +111,8 @@ void ServersModel::resetModel()
beginResetModel();
m_servers = m_settings->serversArray();
m_defaultServerIndex = m_settings->defaultServerIndex();
m_processedServerIndex = m_defaultServerIndex;
m_currentlyProcessedServerIndex = m_defaultServerIndex;
endResetModel();
emit defaultServerIndexChanged(m_defaultServerIndex);
}
void ServersModel::setDefaultServerIndex(const int index)
@@ -132,7 +132,12 @@ const QString ServersModel::getDefaultServerName()
return qvariant_cast<QString>(data(m_defaultServerIndex, NameRole));
}
QString ServersModel::getServerDescription(const QJsonObject &server, const int index) const
const QString ServersModel::getDefaultServerHostName()
{
return qvariant_cast<QString>(data(m_defaultServerIndex, HostNameRole));
}
QString ServersModel::getDefaultServerDescription(const QJsonObject &server)
{
const auto configVersion = server.value(config_key::configVersion).toInt();
@@ -140,12 +145,13 @@ QString ServersModel::getServerDescription(const QJsonObject &server, const int
if (configVersion) {
return server.value(config_key::description).toString();
} else if (data(index, HasWriteAccessRole).toBool()) {
if (m_isAmneziaDnsEnabled && isAmneziaDnsContainerInstalled(index)) {
} else if (isDefaultServerHasWriteAccess()) {
if (m_isAmneziaDnsEnabled
&& isAmneziaDnsContainerInstalled(m_defaultServerIndex)) {
description += "Amnezia DNS | ";
}
} else {
if (data(index, HasAmneziaDns).toBool()) {
if (isDefaultServerConfigContainsAmneziaDns()) {
description += "Amnezia DNS | ";
}
}
@@ -156,7 +162,7 @@ const QString ServersModel::getDefaultServerDescriptionCollapsed()
{
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getServerDescription(server, m_defaultServerIndex);
auto description = getDefaultServerDescription(server);
if (configVersion) {
return description;
}
@@ -170,7 +176,7 @@ const QString ServersModel::getDefaultServerDescriptionExpanded()
{
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getServerDescription(server, m_defaultServerIndex);
auto description = getDefaultServerDescription(server);
if (configVersion) {
return description;
}
@@ -193,21 +199,26 @@ bool ServersModel::hasServerWithWriteAccess()
return false;
}
void ServersModel::setProcessedServerIndex(const int index)
void ServersModel::setCurrentlyProcessedServerIndex(const int index)
{
m_processedServerIndex = index;
m_currentlyProcessedServerIndex = index;
updateContainersModel();
emit processedServerIndexChanged(m_processedServerIndex);
emit currentlyProcessedServerIndexChanged(m_currentlyProcessedServerIndex);
}
int ServersModel::getProcessedServerIndex()
int ServersModel::getCurrentlyProcessedServerIndex()
{
return m_processedServerIndex;
return m_currentlyProcessedServerIndex;
}
const ServerCredentials ServersModel::getProcessedServerCredentials()
QString ServersModel::getCurrentlyProcessedServerHostName()
{
return serverCredentials(m_processedServerIndex);
return qvariant_cast<QString>(data(m_currentlyProcessedServerIndex, HostNameRole));
}
const ServerCredentials ServersModel::getCurrentlyProcessedServerCredentials()
{
return serverCredentials(m_currentlyProcessedServerIndex);
}
const ServerCredentials ServersModel::getServerCredentials(const int index)
@@ -217,17 +228,12 @@ const ServerCredentials ServersModel::getServerCredentials(const int index)
bool ServersModel::isDefaultServerCurrentlyProcessed()
{
return m_defaultServerIndex == m_processedServerIndex;
return m_defaultServerIndex == m_currentlyProcessedServerIndex;
}
bool ServersModel::isDefaultServerFromApi()
bool ServersModel::isCurrentlyProcessedServerHasWriteAccess()
{
return qvariant_cast<bool>(data(m_defaultServerIndex, IsServerFromApiRole));
}
bool ServersModel::isProcessedServerHasWriteAccess()
{
return qvariant_cast<bool>(data(m_processedServerIndex, HasWriteAccessRole));
return qvariant_cast<bool>(data(m_currentlyProcessedServerIndex, HasWriteAccessRole));
}
bool ServersModel::isDefaultServerHasWriteAccess()
@@ -243,42 +249,40 @@ void ServersModel::addServer(const QJsonObject &server)
endResetModel();
}
void ServersModel::editServer(const QJsonObject &server, const int serverIndex)
void ServersModel::editServer(const QJsonObject &server)
{
m_settings->editServer(serverIndex, server);
m_servers.replace(serverIndex, m_settings->serversArray().at(serverIndex));
emit dataChanged(index(serverIndex, 0), index(serverIndex, 0));
if (serverIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
}
m_settings->editServer(m_currentlyProcessedServerIndex, server);
m_servers.replace(m_currentlyProcessedServerIndex, m_settings->serversArray().at(m_currentlyProcessedServerIndex));
emit dataChanged(index(m_currentlyProcessedServerIndex, 0), index(m_currentlyProcessedServerIndex, 0));
updateContainersModel();
if (serverIndex == m_defaultServerIndex) {
auto defaultContainer = qvariant_cast<DockerContainer>(getDefaultServerData("defaultContainer"));
emit defaultServerDefaultContainerChanged(defaultContainer);
}
}
void ServersModel::removeServer()
{
beginResetModel();
m_settings->removeServer(m_processedServerIndex);
m_settings->removeServer(m_currentlyProcessedServerIndex);
m_servers = m_settings->serversArray();
if (m_settings->defaultServerIndex() == m_processedServerIndex) {
if (m_settings->defaultServerIndex() == m_currentlyProcessedServerIndex) {
setDefaultServerIndex(0);
} else if (m_settings->defaultServerIndex() > m_processedServerIndex) {
} else if (m_settings->defaultServerIndex() > m_currentlyProcessedServerIndex) {
setDefaultServerIndex(m_settings->defaultServerIndex() - 1);
}
if (m_settings->serversCount() == 0) {
setDefaultServerIndex(-1);
}
setProcessedServerIndex(m_defaultServerIndex);
setCurrentlyProcessedServerIndex(m_defaultServerIndex);
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> roles;
@@ -286,8 +290,6 @@ QHash<int, QByteArray> ServersModel::roleNames() const
roles[NameRole] = "serverName";
roles[NameRole] = "name";
roles[ServerDescriptionRole] = "serverDescription";
roles[CollapsedServerDescriptionRole] = "collapsedServerDescription";
roles[ExpandedServerDescriptionRole] = "expandedServerDescription";
roles[HostNameRole] = "hostName";
@@ -302,8 +304,6 @@ QHash<int, QByteArray> ServersModel::roleNames() const
roles[ContainsAmneziaDnsRole] = "containsAmneziaDns";
roles[DefaultContainerRole] = "defaultContainer";
roles[IsServerFromApiRole] = "isServerFromApi";
return roles;
}
@@ -322,29 +322,28 @@ ServerCredentials ServersModel::serverCredentials(int index) const
void ServersModel::updateContainersModel()
{
auto containers = m_servers.at(m_processedServerIndex).toObject().value(config_key::containers).toArray();
auto containers = m_servers.at(m_currentlyProcessedServerIndex).toObject().value(config_key::containers).toArray();
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()
{
return m_servers.at(m_defaultServerIndex).toObject();
}
void ServersModel::reloadDefaultServerContainerConfig()
QJsonObject ServersModel::getCurrentlyProcessedServerConfig()
{
QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
return m_servers.at(m_currentlyProcessedServerIndex).toObject();
}
void ServersModel::reloadContainerConfig()
{
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto container = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
auto containers = server.value(config_key::containers).toArray();
auto config = m_settings->containerConfig(m_defaultServerIndex, container);
auto config = m_settings->containerConfig(m_currentlyProcessedServerIndex, container);
for (auto i = 0; i < containers.size(); i++) {
auto c = ContainerProps::containerFromString(containers.at(i).toObject().value(config_key::container).toString());
if (c == container) {
@@ -354,13 +353,13 @@ void ServersModel::reloadDefaultServerContainerConfig()
}
server.insert(config_key::containers, containers);
editServer(server, m_defaultServerIndex);
editServer(server);
}
void ServersModel::updateContainerConfig(const int containerIndex, const QJsonObject config)
{
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject server = m_servers.at(m_processedServerIndex).toObject();
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
for (auto i = 0; i < containers.size(); i++) {
@@ -378,25 +377,30 @@ void ServersModel::updateContainerConfig(const int containerIndex, const QJsonOb
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
}
editServer(server, m_processedServerIndex);
editServer(server);
}
void ServersModel::addContainerConfig(const int containerIndex, const QJsonObject config)
{
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject server = m_servers.at(m_processedServerIndex).toObject();
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
containers.push_back(config);
server.insert(config_key::containers, containers);
bool isDefaultContainerChanged = false;
auto defaultContainer = server.value(config_key::defaultContainer).toString();
if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None || ContainerProps::containerService(container) != ServiceType::Other)) {
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
isDefaultContainerChanged = true;
}
editServer(server, m_processedServerIndex);
editServer(server);
if (isDefaultContainerChanged) {
emit defaultContainerChanged(container);
}
}
void ServersModel::setDefaultContainer(const int serverIndex, const int containerIndex)
@@ -404,12 +408,18 @@ void ServersModel::setDefaultContainer(const int serverIndex, const int containe
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject s = m_servers.at(serverIndex).toObject();
s.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
editServer(s, serverIndex); //check
editServer(s); //check
emit defaultContainerChanged(container);
}
const QString ServersModel::getDefaultServerDefaultContainerName()
DockerContainer ServersModel::getDefaultContainer(const int serverIndex)
{
auto defaultContainer = qvariant_cast<DockerContainer>(getDefaultServerData("defaultContainer"));
return qvariant_cast<DockerContainer>(data(serverIndex, DefaultContainerRole));
}
const QString ServersModel::getDefaultContainerName()
{
auto defaultContainer = getDefaultContainer(m_defaultServerIndex);
return ContainerProps::containerHumanNames().value(defaultContainer);
}
@@ -417,14 +427,15 @@ ErrorCode ServersModel::removeAllContainers()
{
ServerController serverController(m_settings);
ErrorCode errorCode =
serverController.removeAllContainers(m_settings->serverCredentials(m_processedServerIndex));
serverController.removeAllContainers(m_settings->serverCredentials(m_currentlyProcessedServerIndex));
if (errorCode == ErrorCode::NoError) {
QJsonObject s = m_servers.at(m_processedServerIndex).toObject();
QJsonObject s = m_servers.at(m_currentlyProcessedServerIndex).toObject();
s.insert(config_key::containers, {});
s.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
editServer(s, m_processedServerIndex);
editServer(s);
emit defaultContainerChanged(DockerContainer::None);
}
return errorCode;
}
@@ -432,7 +443,7 @@ ErrorCode ServersModel::removeAllContainers()
ErrorCode ServersModel::rebootServer()
{
ServerController serverController(m_settings);
auto credentials = m_settings->serverCredentials(m_processedServerIndex);
auto credentials = m_settings->serverCredentials(m_currentlyProcessedServerIndex);
ErrorCode errorCode = serverController.rebootServer(credentials);
return errorCode;
@@ -441,13 +452,13 @@ ErrorCode ServersModel::rebootServer()
ErrorCode ServersModel::removeContainer(const int containerIndex)
{
ServerController serverController(m_settings);
auto credentials = m_settings->serverCredentials(m_processedServerIndex);
auto credentials = m_settings->serverCredentials(m_currentlyProcessedServerIndex);
auto dockerContainer = static_cast<DockerContainer>(containerIndex);
ErrorCode errorCode = serverController.removeContainer(credentials, dockerContainer);
if (errorCode == ErrorCode::NoError) {
QJsonObject server = m_servers.at(m_processedServerIndex).toObject();
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
for (auto it = containers.begin(); it != containers.end(); it++) {
@@ -469,37 +480,32 @@ ErrorCode ServersModel::removeContainer(const int containerIndex)
server.insert(config_key::defaultContainer, ContainerProps::containerToString(defaultContainer));
}
editServer(server, m_processedServerIndex);
editServer(server);
emit defaultContainerChanged(defaultContainer);
}
return errorCode;
}
void ServersModel::clearCachedProfiles()
{
const auto &containers = m_settings->containers(m_processedServerIndex);
const auto &containers = m_settings->containers(m_currentlyProcessedServerIndex);
for (DockerContainer container : containers.keys()) {
m_settings->clearLastConnectionConfig(m_processedServerIndex, container);
m_settings->clearLastConnectionConfig(m_currentlyProcessedServerIndex, container);
}
m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex));
if (m_processedServerIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
}
m_servers.replace(m_currentlyProcessedServerIndex, m_settings->server(m_currentlyProcessedServerIndex));
updateContainersModel();
}
void ServersModel::clearCachedProfile(const DockerContainer container)
{
m_settings->clearLastConnectionConfig(m_processedServerIndex, container);
m_settings->clearLastConnectionConfig(m_currentlyProcessedServerIndex, container);
m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex));
if (m_processedServerIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
}
m_servers.replace(m_currentlyProcessedServerIndex, m_settings->server(m_currentlyProcessedServerIndex));
updateContainersModel();
}
bool ServersModel::isAmneziaDnsContainerInstalled(const int serverIndex) const
bool ServersModel::isAmneziaDnsContainerInstalled(const int serverIndex)
{
QJsonObject server = m_servers.at(serverIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
@@ -538,6 +544,16 @@ void ServersModel::toggleAmneziaDns(bool enabled)
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)
{
for (const auto &server : qAsConst(m_servers)) {
@@ -548,52 +564,3 @@ bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc)
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;
}
+30 -38
View File
@@ -12,8 +12,7 @@ public:
enum Roles {
NameRole = Qt::UserRole + 1,
ServerDescriptionRole,
CollapsedServerDescriptionRole,
ExpandedServerDescriptionRole,
HostNameRole,
CredentialsRole,
@@ -26,11 +25,7 @@ public:
ContainsAmneziaDnsRole,
DefaultContainerRole,
IsServerFromApiRole,
HasAmneziaDns
DefaultContainerRole
};
ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
@@ -45,43 +40,47 @@ public:
Q_PROPERTY(int defaultIndex READ getDefaultServerIndex WRITE setDefaultServerIndex NOTIFY defaultServerIndexChanged)
Q_PROPERTY(QString defaultServerName READ getDefaultServerName NOTIFY defaultServerNameChanged)
Q_PROPERTY(QString defaultServerDefaultContainerName READ getDefaultServerDefaultContainerName NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY defaultServerDefaultContainerChanged)
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
Q_PROPERTY(QString defaultServerHostName READ getDefaultServerHostName NOTIFY defaultServerIndexChanged)
Q_PROPERTY(QString defaultContainerName READ getDefaultContainerName NOTIFY defaultContainerChanged)
Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerDescriptionChanged)
Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerDescriptionChanged)
Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
Q_PROPERTY(int currentlyProcessedIndex READ getCurrentlyProcessedServerIndex WRITE setCurrentlyProcessedServerIndex
NOTIFY currentlyProcessedServerIndexChanged)
public slots:
void setDefaultServerIndex(const int index);
const int getDefaultServerIndex();
const QString getDefaultServerName();
const QString getDefaultServerHostName();
const QString getDefaultServerDescriptionCollapsed();
const QString getDefaultServerDescriptionExpanded();
const QString getDefaultServerDefaultContainerName();
bool isDefaultServerCurrentlyProcessed();
bool isDefaultServerFromApi();
bool isProcessedServerHasWriteAccess();
bool isCurrentlyProcessedServerHasWriteAccess();
bool isDefaultServerHasWriteAccess();
bool hasServerWithWriteAccess();
const int getServersCount();
void setProcessedServerIndex(const int index);
int getProcessedServerIndex();
void setCurrentlyProcessedServerIndex(const int index);
int getCurrentlyProcessedServerIndex();
const ServerCredentials getProcessedServerCredentials();
QString getCurrentlyProcessedServerHostName();
const ServerCredentials getCurrentlyProcessedServerCredentials();
const ServerCredentials getServerCredentials(const int index);
void addServer(const QJsonObject &server);
void editServer(const QJsonObject &server, const int serverIndex);
void editServer(const QJsonObject &server);
void removeServer();
QJsonObject getDefaultServerConfig();
bool isDefaultServerConfigContainsAmneziaDns();
bool isAmneziaDnsContainerInstalled(const int serverIndex);
void reloadDefaultServerContainerConfig();
QJsonObject getDefaultServerConfig();
QJsonObject getCurrentlyProcessedServerConfig();
void reloadContainerConfig();
void updateContainerConfig(const int containerIndex, const QJsonObject config);
void addContainerConfig(const int containerIndex, const QJsonObject config);
@@ -93,49 +92,42 @@ public slots:
ErrorCode rebootServer();
void setDefaultContainer(const int serverIndex, const int containerIndex);
DockerContainer getDefaultContainer(const int serverIndex);
const QString getDefaultContainerName();
QStringList getAllInstalledServicesName(const int serverIndex);
void toggleAmneziaDns(bool enabled);
bool isDefaultServerFromApi();
bool isCurrentlyProcessedServerFromApi();
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:
QHash<int, QByteArray> roleNames() const override;
signals:
void processedServerIndexChanged(const int index);
void currentlyProcessedServerIndexChanged(const int index);
void defaultServerIndexChanged(const int index);
void defaultServerNameChanged();
void defaultServerDescriptionChanged();
void containersUpdated(const QJsonArray &containers);
void defaultServerContainersUpdated(const QJsonArray &containers);
void defaultServerDefaultContainerChanged(const int containerIndex);
void defaultContainerChanged(const int containerIndex);
private:
ServerCredentials serverCredentials(int index) const;
void updateContainersModel();
void updateDefaultServerContainersModel();
QString getServerDescription(const QJsonObject &server, const int index) const;
bool isAmneziaDnsContainerInstalled(const int serverIndex) const;
QString getDefaultServerDescription(const QJsonObject &server);
QJsonArray m_servers;
std::shared_ptr<Settings> m_settings;
int m_defaultServerIndex;
int m_processedServerIndex;
int m_currentlyProcessedServerIndex;
bool m_isAmneziaDnsEnabled = m_settings->useAmneziaDns();
};
-1
View File
@@ -113,7 +113,6 @@ void SitesModel::toggleSplitTunneling(bool enabled)
m_settings->setRouteMode(Settings::RouteMode::VpnAllSites);
}
m_isSplitTunnelingEnabled = enabled;
emit splitTunnelingToggled();
}
QVector<QPair<QString, QString> > SitesModel::getCurrentSites()
-2
View File
@@ -22,7 +22,6 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_PROPERTY(int routeMode READ getRouteMode WRITE setRouteMode NOTIFY routeModeChanged)
Q_PROPERTY(bool isTunnelingEnabled READ isSplitTunnelingEnabled NOTIFY splitTunnelingToggled)
public slots:
bool addSite(const QString &hostname, const QString &ip);
@@ -39,7 +38,6 @@ public slots:
signals:
void routeModeChanged();
void splitTunnelingToggled();
protected:
QHash<int, QByteArray> roleNames() const override;
+4 -2
View File
@@ -138,7 +138,9 @@ Button {
}
onClicked: {
ServersModel.setProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi()
if (!ConnectionController.isConnectionInProgress) {
ServersModel.setCurrentlyProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi()
}
}
}
@@ -8,24 +8,18 @@ import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
DrawerType {
id: root
width: parent.width
height: parent.height
expandedContent: ColumnLayout {
id: content
height: parent.height * 0.4375
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Component.onCompleted: {
root.expandedHeight = content.implicitHeight + 32
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
@@ -46,7 +40,7 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.close()
root.visible = false
}
}
@@ -60,7 +54,7 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.close()
root.visible = false
}
}
-35
View File
@@ -1,35 +0,0 @@
import QtQuick 2.15
import QtQml 2.15
Behavior {
id: root
property QtObject fadeTarget: targetProperty.object
property string fadeProperty: "opacity"
property int fadeDuration: 200
property int fadeValue: 0
property string easingType: "Quad"
property alias exitAnimation: exitAnimation
property alias enterAnimation: enterAnimation
SequentialAnimation {
NumberAnimation {
id: exitAnimation
target: root.fadeTarget
property: root.fadeProperty
duration: root.fadeDuration
to: root.fadeValue
easing.type: root.easingType === "Linear" ? Easing.Linear : Easing["In"+root.easingType]
}
PropertyAction { }
NumberAnimation {
id: enterAnimation
target: root.fadeTarget
property: root.fadeProperty
duration: root.fadeDuration
to: target[property]
easing.type: root.easingType === "Linear" ? Easing.Linear : Easing["Out"+root.easingType]
}
}
}
@@ -15,7 +15,6 @@ ListView {
id: menuContent
property var rootWidth
property var selectedText
width: rootWidth
height: menuContent.contentItem.height
@@ -52,7 +51,7 @@ ListView {
showImage: !isInstalled
checkable: isInstalled && !ConnectionController.isConnected && isSupported
checked: proxyDefaultServerContainersModel.mapToSource(index) === ServersModel.getDefaultServerData("defaultContainer")
checked: proxyContainersModel.mapToSource(index) === ServersModel.getDefaultContainer(ServersModel.defaultIndex)
onClicked: {
if (ConnectionController.isConnected && isInstalled) {
@@ -61,18 +60,18 @@ ListView {
}
if (checked) {
containersDropDown.close()
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyDefaultServerContainersModel.mapToSource(index))
containersDropDown.menuVisible = false
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyContainersModel.mapToSource(index))
} else {
if (!isSupported && isInstalled) {
PageController.showErrorMessage(qsTr("The selected protocol is not supported on the current platform"))
return
}
ContainersModel.setCurrentlyProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.close()
containersDropDown.menuVisible = false
}
}
@@ -1,92 +0,0 @@
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
}
}
}
+10 -17
View File
@@ -5,7 +5,7 @@ import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType2 {
DrawerType {
id: root
property string headerText
@@ -16,24 +16,23 @@ DrawerType2 {
property var yesButtonFunction
property var noButtonFunction
expandedContent: ColumnLayout {
width: parent.width
height: content.implicitHeight + 32
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 8
onImplicitHeightChanged: {
root.expandedHeight = content.implicitHeight + 32
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: headerText
}
@@ -41,8 +40,6 @@ DrawerType2 {
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.rightMargin: 16
Layout.leftMargin: 16
text: descriptionText
}
@@ -50,12 +47,10 @@ DrawerType2 {
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: yesButtonText
clickedFunc: function() {
onClicked: {
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
@@ -64,8 +59,6 @@ DrawerType2 {
BasicButtonType {
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
@@ -76,7 +69,7 @@ DrawerType2 {
text: noButtonText
clickedFunc: function() {
onClicked: {
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
@@ -5,136 +5,129 @@ import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType2 {
DrawerType {
id: root
expandedContent: Item {
id: container
width: parent.width
height: parent.height * 0.9
implicitHeight: root.height * 0.9
ColumnLayout {
id: backButton
Component.onCompleted: {
root.expandedHeight = container.implicitHeight
}
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
ColumnLayout {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
}
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
}
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
ColumnLayout {
id: content
ColumnLayout {
id: content
anchors.fill: parent
anchors.fill: parent
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Choose language")
headerText: qsTr("Choose language")
}
ListView {
id: listView
Layout.fillWidth: true
height: listView.contentItem.height
clip: true
interactive: false
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
ButtonGroup {
id: buttonGroup
}
ListView {
id: listView
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
Layout.fillWidth: true
height: listView.contentItem.height
ColumnLayout {
id: delegateContent
clip: true
interactive: false
anchors.fill: parent
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
RadioButton {
id: radioButton
ButtonGroup {
id: buttonGroup
}
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
hoverEnabled: true
ColumnLayout {
id: delegateContent
indicator: Rectangle {
anchors.fill: parent
color: radioButton.hovered ? "#2C2D30" : "#1C1D21"
anchors.fill: parent
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
RadioButton {
id: radioButton
RowLayout {
id: radioButtonContent
anchors.fill: parent
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
anchors.rightMargin: 16
anchors.leftMargin: 16
hoverEnabled: true
spacing: 0
indicator: Rectangle {
anchors.fill: parent
color: radioButton.hovered ? "#2C2D30" : "#1C1D21"
z: 1
Behavior on color {
PropertyAnimation { duration: 200 }
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
RowLayout {
id: radioButtonContent
anchors.fill: parent
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
anchors.rightMargin: 16
anchors.leftMargin: 16
width: 24
height: 24
spacing: 0
z: 1
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
width: 24
height: 24
Layout.rightMargin: 8
}
Layout.rightMargin: 8
}
}
ButtonGroup.group: buttonGroup
checked: listView.currentIndex === index
ButtonGroup.group: buttonGroup
checked: listView.currentIndex === index
onClicked: {
listView.currentIndex = index
LanguageModel.changeLanguage(languageIndex)
root.close()
}
onClicked: {
listView.currentIndex = index
LanguageModel.changeLanguage(languageIndex)
root.close()
}
}
}
@@ -16,18 +16,19 @@ import "../Controls2/TextTypes"
import "../Config"
import "../Components"
DrawerType2 {
DrawerType {
id: root
property string headerText
property string configContentHeaderText
property string contentVisible
property alias headerText: header.headerText
property alias configContentHeaderText: configContentHeader.headerText
property alias contentVisible: content.visible
property string configExtension: ".vpn"
property string configCaption: qsTr("Save AmneziaVPN config")
property string configFileName: "amnezia_config"
expandedHeight: parent.height * 0.9
width: parent.width
height: parent.height * 0.9
onClosed: {
configExtension = ".vpn"
@@ -35,8 +36,8 @@ DrawerType2 {
configFileName = "amnezia_config"
}
expandedContent: Item {
implicitHeight: root.expandedHeight
Item {
anchors.fill: parent
Header2Type {
id: header
@@ -46,8 +47,6 @@ DrawerType2 {
anchors.topMargin: 20
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: root.headerText
}
FlickableType {
@@ -65,8 +64,6 @@ DrawerType2 {
anchors.leftMargin: 16
anchors.rightMargin: 16
visible: root.contentVisible
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
@@ -74,7 +71,7 @@ DrawerType2 {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
clickedFunc: function() {
onClicked: {
var fileName = ""
if (GC.isMobile()) {
fileName = configFileName + configExtension
@@ -94,7 +91,6 @@ DrawerType2 {
}
BasicButtonType {
id: copyConfigTextButton
Layout.fillWidth: true
Layout.topMargin: 8
@@ -107,14 +103,20 @@ DrawerType2 {
text: qsTr("Copy")
imageSource: "qrc:/images/controls/copy.svg"
onClicked: {
configText.selectAll()
configText.copy()
configText.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
BasicButtonType {
id: copyNativeConfigStringButton
Layout.fillWidth: true
Layout.topMargin: 8
visible: false
visible: nativeConfigString.text !== ""
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
@@ -125,6 +127,13 @@ DrawerType2 {
text: qsTr("Copy config string")
imageSource: "qrc:/images/controls/copy.svg"
onClicked: {
nativeConfigString.selectAll()
nativeConfigString.copy()
nativeConfigString.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
BasicButtonType {
@@ -140,117 +149,83 @@ DrawerType2 {
text: qsTr("Show connection settings")
clickedFunc: function() {
configContentDrawer.open()
onClicked: {
configContentDrawer.visible = true
}
}
DrawerType2 {
DrawerType {
id: configContentDrawer
parent: root.parent
width: parent.width
height: parent.height * 0.9
anchors.fill: parent
expandedHeight: parent.height * 0.9
BackButtonType {
id: backButton
expandedContent: Item {
id: configContentContainer
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
implicitHeight: configContentDrawer.expandedHeight
Connections {
target: copyNativeConfigStringButton
function onClicked() {
nativeConfigString.selectAll()
nativeConfigString.copy()
nativeConfigString.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
backButtonFunction: function() {
configContentDrawer.visible = false
}
}
Connections {
target: copyConfigTextButton
function onClicked() {
configText.selectAll()
configText.copy()
configText.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
ColumnLayout {
id: configContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type {
id: configContentHeader
Layout.fillWidth: true
Layout.topMargin: 16
}
}
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.close()
TextField {
id: nativeConfigString
visible: false
text: ExportController.nativeConfigString
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
TextArea {
id: configText
ColumnLayout {
id: configContent
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
padding: 0
leftPadding: 0
height: 24
Header2Type {
id: configContentHeader
Layout.fillWidth: true
Layout.topMargin: 16
readOnly: true
headerText: root.configContentHeaderText
}
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
TextField {
id: nativeConfigString
visible: false
text: ExportController.nativeConfigString
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
onTextChanged: {
copyNativeConfigStringButton.visible = nativeConfigString.text !== ""
}
}
text: ExportController.config
TextArea {
id: configText
wrapMode: Text.Wrap
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
padding: 0
leftPadding: 0
height: 24
readOnly: true
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
text: ExportController.config
wrapMode: Text.Wrap
background: Rectangle {
color: "transparent"
}
background: Rectangle {
color: "transparent"
}
}
}
+27 -81
View File
@@ -16,39 +16,47 @@ Button {
property string textColor: "#0E0E11"
property string borderColor: "#D7D8DB"
property string borderFocusedColor: "#D7D8DB"
property int borderWidth: 0
property int borderFocusedWidth: 1
property string imageSource
property string rightImageSource
property string leftImageColor: textColor
property bool squareLeftSide: false
property var clickedFunc
implicitHeight: 56
hoverEnabled: true
background: Rectangle {
id: background_border
color: "transparent"
border.color: root.activeFocus ? root.borderFocusedColor : "transparent"
border.width: root.activeFocus ? root.borderFocusedWidth : "transparent"
id: background
anchors.fill: parent
radius: 16
color: {
if (root.enabled) {
if (root.pressed) {
return pressedColor
}
return root.hovered ? hoveredColor : defaultColor
} else {
return disabledColor
}
}
border.color: borderColor
border.width: borderWidth
Behavior on color {
PropertyAnimation { duration: 200 }
}
Rectangle {
id: background
visible: root.squareLeftSide
anchors.fill: background_border
anchors.margins: root.activeFocus ? 2: 0
z: 1
radius: 16
width: parent.radius
height: parent.radius
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
color: {
if (root.enabled) {
if (root.pressed) {
@@ -59,53 +67,24 @@ Button {
return disabledColor
}
}
border.color: root.activeFocus ? "transparent" : borderColor
border.width: root.activeFocus ? 0 : borderWidth
Behavior on color {
PropertyAnimation { duration: 200 }
}
Rectangle {
visible: root.squareLeftSide
z: 1
width: parent.radius
height: parent.radius
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
color: {
if (root.enabled) {
if (root.pressed) {
return pressedColor
}
return root.hovered ? hoveredColor : defaultColor
} else {
return disabledColor
}
}
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
}
}
MouseArea {
anchors.fill: background_border
anchors.fill: background
enabled: false
cursorShape: Qt.PointingHandCursor
}
contentItem: Item {
anchors.fill: background_border
anchors.fill: background
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.centerIn: parent
@@ -120,7 +99,7 @@ Button {
layer {
enabled: true
effect: ColorOverlay {
color: leftImageColor
color: textColor
}
}
}
@@ -133,39 +112,6 @@ Button {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
Image {
Layout.preferredHeight: 20
Layout.preferredWidth: 20
source: root.rightImageSource
visible: root.rightImageSource === "" ? false : true
layer {
enabled: true
effect: ColorOverlay {
color: textColor
}
}
}
}
}
Keys.onEnterPressed: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
Keys.onReturnPressed: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
onClicked: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
}
+84
View File
@@ -0,0 +1,84 @@
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
@@ -1,242 +0,0 @@
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
}
}
}
+43 -55
View File
@@ -36,23 +36,19 @@ Item {
property int rootButtonTextBottomMargin: 16
property real drawerHeight: 0.9
property Item drawerParent
property Component listView
signal open
signal close
property alias menuVisible: menu.visible
implicitWidth: rootButtonContent.implicitWidth
implicitHeight: rootButtonContent.implicitHeight
onOpen: {
menu.open()
rootButtonBackground.border.color = rootButtonPressedBorderColor
}
onClose: {
menu.close()
rootButtonBackground.border.color = rootButtonDefaultBorderColor
onMenuVisibleChanged: {
if (menuVisible) {
rootButtonBackground.border.color = rootButtonPressedBorderColor
} else {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
}
}
onEnabledChanged: {
@@ -137,21 +133,21 @@ Item {
hoverEnabled: root.enabled ? true : false
onEntered: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.border.color = rootButtonHoveredBorderColor
rootButtonBackground.color = rootButtonBackgroundHoveredColor
}
}
onExited: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
rootButtonBackground.color = rootButtonBackgroundColor
}
}
onPressed: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.color = pressed ? rootButtonBackgroundPressedColor : entered ? rootButtonHoveredBorderColor : rootButtonDefaultBorderColor
}
}
@@ -160,68 +156,60 @@ Item {
if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") {
rootButtonClickedFunction()
} else {
menu.open()
menu.visible = true
}
}
}
DrawerType2 {
DrawerType {
id: menu
parent: drawerParent
width: parent.width
height: parent.height * drawerHeight
anchors.fill: parent
expandedHeight: drawerParent.height * drawerHeight
ColumnLayout {
id: header
expandedContent: Item {
id: container
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
implicitHeight: menu.expandedHeight
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
root.menuVisible = false
}
}
}
ColumnLayout {
id: header
FlickableType {
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
menu.close()
}
}
}
spacing: 16
FlickableType {
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
Column {
id: col
anchors.top: parent.top
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16
headerText: root.headerText
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
width: parent.width
}
headerText: root.headerText
width: parent.width
}
Loader {
id: listViewLoader
sourceComponent: root.listView
}
Loader {
id: listViewLoader
sourceComponent: root.listView
}
}
}
-15
View File
@@ -7,8 +7,6 @@ Item {
property StackView stackView: StackView.view
property var defaultActiveFocusItem: null
// MouseArea {
// id: globalMouseArea
// z: 99
@@ -21,17 +19,4 @@ Item {
// 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
text: qsTr("Close")
clickedFunc: function() {
onClicked: {
root.close()
}
}
@@ -69,13 +69,10 @@ Item {
TextField {
id: textField
activeFocusOnTab: false
enabled: root.textFieldEditable
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
placeholderText: root.textFieldPlaceholderText
placeholderTextColor: "#494B50"
@@ -145,7 +142,7 @@ Item {
Layout.preferredWidth: content.implicitHeight
squareLeftSide: true
clickedFunc: function() {
onClicked: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
@@ -189,12 +186,4 @@ Item {
function getBackgroundBorderColor(noneFocusedColor) {
return textField.focus ? root.borderFocusedColor : noneFocusedColor
}
Keys.onEnterPressed: {
KeyNavigation.tab.forceActiveFocus();
}
Keys.onReturnPressed: {
KeyNavigation.tab.forceActiveFocus();
}
}
+408 -335
View File
@@ -18,411 +18,484 @@ import "../Components"
PageType {
id: root
property string defaultColor: "#1C1D21"
property string borderColor: "#2C2D30"
Connections {
target: PageController
function onRestorePageHomeState(isContainerInstalled) {
drawer.open()
buttonContent.state = "expanded"
if (isContainerInstalled) {
containersDropDown.rootButtonClickedFunction()
}
}
function onForceCloseDrawer() {
buttonContent.state = "collapsed"
}
}
MouseArea {
anchors.fill: parent
enabled: buttonContent.state === "expanded"
onClicked: {
buttonContent.state = "collapsed"
}
}
Item {
anchors.fill: parent
anchors.bottomMargin: drawer.collapsedHeight
anchors.bottomMargin: buttonContent.collapsedHeight
ConnectButton {
id: connectButton
anchors.centerIn: parent
}
}
BasicButtonType {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 34
leftPadding: 16
rightPadding: 16
MouseArea {
id: dragArea
implicitHeight: 36
anchors.fill: buttonBackground
cursorShape: buttonContent.state === "collapsed" ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
disabledColor: "#878B91"
textColor: "#878B91"
leftImageColor: "transparent"
borderWidth: 0
drag.target: buttonContent
drag.axis: Drag.YAxis
drag.maximumY: root.height - buttonContent.collapsedHeight
drag.minimumY: root.height - root.height * 0.9
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled ||
(ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi"))
text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
imageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
rightImageSource: "qrc:/images/controls/chevron-down.svg"
onClicked: {
homeSplitTunnelingDrawer.open()
/** If drag area is released at any point other than min or max y, transition to the other state */
onReleased: {
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
}
}
HomeSplitTunnelingDrawer {
id: homeSplitTunnelingDrawer
onEntered: {
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
}
parent: root
onClicked: {
if (buttonContent.state === "collapsed") {
buttonContent.state = "expanded"
}
}
}
Rectangle {
id: buttonBackground
DrawerType2 {
id: drawer
anchors.fill: parent
anchors { left: buttonContent.left; right: buttonContent.right; top: buttonContent.top }
height: root.height
radius: 16
color: root.defaultColor
border.color: root.borderColor
border.width: 1
collapsedContent: ColumnLayout {
DividerType {
Layout.topMargin: 10
Layout.fillWidth: false
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
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
}
}
]
DividerType {
Layout.topMargin: 10
Layout.fillWidth: false
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: (buttonContent.collapsedVisibility || buttonContent.expandedVisibility)
}
RowLayout {
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: buttonContent.collapsedVisibility
spacing: 0
Header1TextType {
id: collapsedButtonHeader
Layout.maximumWidth: buttonContent.width - 48 - 18 - 12 // todo
maximumLineCount: 2
elide: Qt.ElideRight
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
}
RowLayout {
ImageButtonType {
id: collapsedButtonChevron
Layout.leftMargin: 8
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
imageColor: "#d7d8db"
icon.width: 18
icon.height: 18
backgroundRadius: 16
horizontalPadding: 4
topPadding: 4
bottomPadding: 3
onClicked: {
if (buttonContent.state === "collapsed") {
buttonContent.state = "expanded"
}
}
}
}
LabelTextType {
id: collapsedServerMenuDescription
Layout.bottomMargin: 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: buttonContent.collapsedVisibility
text: ServersModel.defaultServerDescriptionCollapsed
}
ColumnLayout {
id: serversMenuHeader
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Layout.fillWidth: true
visible: buttonContent.expandedVisibility
Header1TextType {
Layout.fillWidth: true
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.leftMargin: 16
Layout.rightMargin: 16
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 {
id: collapsedButtonHeader
Layout.maximumWidth: drawer.width - 48 - 18 - 12 // todo
maximumLineCount: 2
elide: Qt.ElideRight
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
}
ImageButtonType {
id: collapsedButtonChevron
Layout.leftMargin: 8
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
imageColor: "#d7d8db"
icon.width: 18
icon.height: 18
backgroundRadius: 16
horizontalPadding: 4
topPadding: 4
bottomPadding: 3
onClicked: {
if (drawer.isCollapsed) {
drawer.open()
}
}
}
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
}
LabelTextType {
id: collapsedServerMenuDescription
Layout.bottomMargin: 44
id: expandedServersMenuDescription
Layout.bottomMargin: 24
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionExpanded
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionCollapsed
spacing: 8
FadeBehavior on text { }
DropDownType {
id: containersDropDown
Connections {
target: drawer
rootButtonImageColor: "#0E0E11"
rootButtonBackgroundColor: "#D7D8DB"
rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
rootButtonHoveredBorderColor: "transparent"
rootButtonDefaultBorderColor: "transparent"
rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8
function onOpen() {
collapsedServerMenuDescription.text = ServersModel.defaultServerDescriptionExpanded
text: ServersModel.defaultContainerName
textColor: "#0E0E11"
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() {
ServersModel.currentlyProcessedIndex = serversMenuContent.currentIndex
containersDropDown.menuVisible = true
}
function onClose() {
collapsedServerMenuDescription.text = ServersModel.defaultServerDescriptionCollapsed
}
}
}
}
expandedContent: Item {
id: serverMenuContainer
implicitHeight: root.height * 0.9
Component.onCompleted: {
drawer.expandedHeight = serverMenuContainer.implicitHeight
}
ColumnLayout {
id: serversMenuHeader
anchors.top: parent.top
anchors.right: parent.right
anchors.left: parent.left
Header1TextType {
Layout.fillWidth: true
Layout.topMargin: 14
Layout.leftMargin: 16
Layout.rightMargin: 16
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
}
LabelTextType {
id: expandedServersMenuDescription
Layout.bottomMargin: ServersModel.isDefaultServerFromApi ? 69 : 24
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionCollapsed
FadeBehavior on text { }
Connections {
target: drawer
function onOpen() {
expandedServersMenuDescription.text = ServersModel.defaultServerDescriptionExpanded
}
function onClose() {
expandedServersMenuDescription.text = ServersModel.defaultServerDescriptionCollapsed
}
}
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8
visible: !ServersModel.isDefaultServerFromApi
onVisibleChanged: expandedServersMenuDescription.Layout
DropDownType {
id: containersDropDown
rootButtonImageColor: "#0E0E11"
rootButtonBackgroundColor: "#D7D8DB"
rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
rootButtonHoveredBorderColor: "transparent"
rootButtonDefaultBorderColor: "transparent"
rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8
text: ServersModel.defaultServerDefaultContainerName
textColor: "#0E0E11"
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() {
containersDropDown.open()
}
drawerParent: root
listView: HomeContainersListView {
rootWidth: root.width
Connections {
target: ServersModel
function onDefaultServerIndexChanged() {
updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isDefaultServerHasWriteAccess()) {
proxyDefaultServerContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyDefaultServerContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
}
model: SortFilterProxyModel {
id: proxyDefaultServerContainersModel
sourceModel: DefaultServerContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
}
Component.onCompleted: updateContainersModelFilters()
}
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 48
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Servers")
}
}
Flickable {
id: serversContainer
anchors.top: serversMenuHeader.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.topMargin: 16
contentHeight: col.height + col.anchors.bottomMargin
implicitHeight: parent.height - serversMenuHeader.implicitHeight
clip: true
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversContainer.height >= serversContainer.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 32
spacing: 16
ButtonGroup {
id: serversRadioButtonGroup
}
ListView {
id: serversMenuContent
width: parent.width
height: serversMenuContent.contentItem.height
model: ServersModel
currentIndex: ServersModel.defaultIndex
listView: HomeContainersListView {
rootWidth: root.width
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
function onCurrentlyProcessedServerIndexChanged() {
updateContainersModelFilters()
}
}
clip: true
interactive: false
function updateContainersModelFilters() {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
}
delegate: Item {
id: menuContentDelegate
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
}
property variant delegateData: model
Component.onCompleted: updateContainersModelFilters()
}
}
}
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 48
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: buttonContent.expandedVisibility
ColumnLayout {
id: serverRadioButtonContent
headerText: qsTr("Servers")
}
}
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Flickable {
id: serversContainer
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Layout.fillWidth: true
Layout.topMargin: 16
contentHeight: col.implicitHeight
implicitHeight: root.height - (root.height * 0.1) - serversMenuHeader.implicitHeight - 52 //todo 52 is tabbar height
visible: buttonContent.expandedVisibility
clip: true
spacing: 0
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversContainer.height >= serversContainer.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
RowLayout {
VerticalRadioButton {
id: serverRadioButton
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
Layout.fillWidth: true
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
text: name
descriptionText: serverDescription
spacing: 16
checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected
ButtonGroup {
id: serversRadioButtonGroup
}
ButtonGroup.group: serversRadioButtonGroup
ListView {
id: serversMenuContent
width: parent.width
height: serversMenuContent.contentItem.height
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
model: ServersModel
currentIndex: ServersModel.defaultIndex
serversMenuContent.currentIndex = index
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
}
}
ServersModel.defaultIndex = index
}
clip: true
interactive: false
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
delegate: Item {
id: menuContentDelegate
ImageButtonType {
image: "qrc:/images/controls/settings.svg"
imageColor: "#D7D8DB"
property variant delegateData: model
implicitWidth: 56
implicitHeight: 56
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
z: 1
ColumnLayout {
id: serverRadioButtonContent
onClicked: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
drawer.close()
}
}
}
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
RowLayout {
VerticalRadioButton {
id: serverRadioButton
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
text: name
descriptionText: {
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
checkable: !ConnectionController.isConnected
ButtonGroup.group: serversRadioButtonGroup
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
serversMenuContent.currentIndex = index
ServersModel.currentlyProcessedIndex = index
ServersModel.defaultIndex = index
}
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
ImageButtonType {
image: "qrc:/images/controls/settings.svg"
imageColor: "#D7D8DB"
implicitWidth: 56
implicitHeight: 56
z: 1
onClicked: function() {
ServersModel.currentlyProcessedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
buttonContent.state = "collapsed"
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
}
}
}
@@ -12,12 +12,9 @@ import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
ColumnLayout {
id: backButton
@@ -44,11 +41,9 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess()
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
@@ -60,13 +55,9 @@ PageType {
model: AwgConfigModel
delegate: Item {
id: _delegate
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias portTextField:portTextField
ColumnLayout {
id: col
@@ -102,8 +93,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
TextFieldWithHeaderType {
@@ -127,8 +116,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -147,8 +134,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -167,8 +152,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: initPacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -187,8 +170,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: responsePacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -207,8 +188,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: initPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -227,8 +206,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: responsePacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -247,8 +224,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: transportPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -267,8 +242,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: underloadPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -287,8 +260,6 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: saveRestartButton
}
BasicButtonType {
@@ -304,24 +275,24 @@ PageType {
text: qsTr("Remove AmneziaWG")
onClicked: {
var headerText = qsTr("Remove AmneziaWG from server?")
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.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.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
@@ -339,7 +310,7 @@ PageType {
text: qsTr("Save and Restart Amnezia")
clickedFunc: function() {
onClicked: {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
@@ -347,8 +318,11 @@ PageType {
}
}
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
@@ -15,8 +15,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
ColumnLayout {
id: backButton
@@ -43,7 +41,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess()
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
ListView {
id: listview
@@ -60,8 +58,6 @@ PageType {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias trafficFromField: trafficFromField
ColumnLayout {
id: col
@@ -81,8 +77,6 @@ PageType {
}
TextFieldWithHeaderType {
id: trafficFromField
Layout.fillWidth: true
Layout.topMargin: 32
@@ -102,13 +96,9 @@ PageType {
}
}
}
KeyNavigation.tab: portTextField.textField
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
@@ -122,8 +112,6 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: saveRestartButton
}
DropDownType {
@@ -134,8 +122,6 @@ PageType {
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -152,7 +138,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.close()
cipherDropDown.menuVisible = false
}
Component.onCompleted: {
@@ -168,15 +154,13 @@ PageType {
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia")
clickedFunc: function() {
onClicked: {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(CloakConfigModel.getConfig())
@@ -16,8 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
ColumnLayout {
id: backButton
@@ -44,7 +42,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess()
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
ListView {
id: listview
@@ -55,14 +53,12 @@ PageType {
clip: true
interactive: false
model: OpenVpnConfigModel
model: OpenVpnConfigModel
delegate: Item {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
ColumnLayout {
id: col
@@ -82,8 +78,6 @@ PageType {
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 32
@@ -95,8 +89,6 @@ PageType {
subnetAddress = textFieldText
}
}
KeyNavigation.tab: portTextField.enabled ? portTextField.textField : saveRestartButton
}
ParagraphTextType {
@@ -127,9 +119,6 @@ PageType {
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
@@ -145,8 +134,6 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: saveRestartButton
}
SwitcherType {
@@ -175,8 +162,6 @@ PageType {
descriptionText: qsTr("Hash")
headerText: qsTr("Hash")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: hashListView
@@ -198,7 +183,7 @@ PageType {
clickedFunction: function() {
hashDropDown.text = selectedText
hash = hashDropDown.text
hashDropDown.close()
hashDropDown.menuVisible = false
}
Component.onCompleted: {
@@ -223,8 +208,6 @@ PageType {
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -246,7 +229,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.close()
cipherDropDown.menuVisible = false
}
Component.onCompleted: {
@@ -380,33 +363,32 @@ PageType {
text: qsTr("Remove OpenVPN")
clickedFunc: function() {
var headerText = qsTr("Remove OpenVpn from server?")
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
onClicked: {
questionDrawer.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.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia")
clickedFunc: function() {
onClicked: {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
@@ -416,5 +398,9 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
+60 -61
View File
@@ -90,77 +90,71 @@ PageType {
DividerType {}
DrawerType2 {
DrawerType {
id: configContentDrawer
expandedHeight: root.height * 0.9
width: parent.width
height: parent.height * 0.9
parent: root
anchors.fill: parent
BackButtonType {
id: backButton
expandedContent: Item {
implicitHeight: configContentDrawer.expandedHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.close()
}
backButtonFunction: function() {
configContentDrawer.visible = false
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
ColumnLayout {
id: configContent
ColumnLayout {
id: configContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Connection options %1").arg(protocolName)
}
headerText: qsTr("Connection options %1").arg(protocolName)
}
TextArea {
id: configText
TextArea {
id: configText
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
padding: 0
leftPadding: 0
height: 24
padding: 0
leftPadding: 0
height: 24
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
text: rawConfig
text: rawConfig
wrapMode: Text.Wrap
wrapMode: Text.Wrap
background: Rectangle {
color: "transparent"
}
background: Rectangle {
color: "transparent"
}
}
}
@@ -175,25 +169,26 @@ PageType {
width: parent.width
visible: ServersModel.isProcessedServerHasWriteAccess()
visible: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName()
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.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.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
MouseArea {
@@ -205,5 +200,9 @@ PageType {
DividerType {}
}
QuestionDrawer {
id: questionDrawer
}
}
}
@@ -15,8 +15,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
ColumnLayout {
id: backButton
@@ -43,7 +41,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess()
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
ListView {
id: listview
@@ -60,8 +58,6 @@ PageType {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias portTextField: portTextField
ColumnLayout {
id: col
@@ -81,8 +77,6 @@ PageType {
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
@@ -96,8 +90,6 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: saveRestartButton
}
DropDownType {
@@ -108,8 +100,6 @@ PageType {
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -126,7 +116,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.close()
cipherDropDown.menuVisible = false
}
Component.onCompleted: {
@@ -142,15 +132,13 @@ PageType {
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia")
clickedFunc: function() {
onClicked: {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
@@ -63,18 +63,19 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
MouseArea {
@@ -85,6 +86,10 @@ PageType {
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
}
@@ -49,7 +49,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess()
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
ListView {
id: listview
@@ -88,7 +88,7 @@ PageType {
Layout.topMargin: 32
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("HostName")
descriptionText: ServersModel.getCurrentlyProcessedServerHostName()
descriptionOnTop: true
@@ -170,7 +170,7 @@ PageType {
text: qsTr("Mount folder on device")
clickedFunc: function() {
onClicked: {
PageController.showBusyIndicator(true)
InstallController.mountSftpDrive(port, password, username)
PageController.showBusyIndicator(false)
@@ -229,7 +229,7 @@ PageType {
text: qsTr("Detailed instructions")
clickedFunc: function() {
onClicked: {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
@@ -247,24 +247,29 @@ PageType {
text: qsTr("Remove SFTP and all data stored there")
clickedFunc: function() {
var headerText = qsTr("Remove SFTP and all data stored there?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
onClicked: {
questionDrawer.headerText = qsTr("Remove SFTP and all data stored there?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
}
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
@@ -125,21 +125,26 @@ PageType {
text: qsTr("Remove website")
clickedFunc: function() {
var headerText = qsTr("The site with all data will be removed from the tor network.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
onClicked: {
questionDrawer.headerText = qsTr("The site with all data will be removed from the tor network.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
+4 -6
View File
@@ -81,7 +81,7 @@ PageType {
text: qsTr("Card on Patreon")
clickedFunc: function() {
onClicked: function() {
Qt.openUrlExternally(qsTr("https://www.patreon.com/amneziavpn"))
}
}
@@ -101,9 +101,7 @@ PageType {
text: qsTr("Show other methods on Github")
clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate"))
}
onClicked: Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate"))
}
ParagraphTextType {
@@ -175,7 +173,7 @@ PageType {
horizontalAlignment: Text.AlignHCenter
text: qsTr("Software version: %1").arg(SettingsController.getAppVersion())
text: SettingsController.getAppVersion()
color: "#878B91"
}
@@ -193,7 +191,7 @@ PageType {
text: qsTr("Check for updates")
clickedFunc: function() {
onClicked: {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
@@ -84,27 +84,6 @@ PageType {
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 {
visible: !GC.isMobile()
@@ -138,6 +117,10 @@ PageType {
}
}
SelectLanguageDrawer {
id: selectLanguageDrawer
}
DividerType {}
@@ -160,33 +143,30 @@ PageType {
text: qsTr("Reset settings and remove all data from the application")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Reset settings and remove all data from the application?")
var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.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.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
SettingsController.clearSettings()
PageController.replaceStartPage()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
SelectLanguageDrawer {
id: selectLanguageDrawer
width: root.width
height: root.height
}
}
+14 -9
View File
@@ -88,7 +88,7 @@ PageType {
text: qsTr("Make a backup")
clickedFunc: function() {
onClicked: {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN.backup"
@@ -121,7 +121,7 @@ PageType {
text: qsTr("Restore from backup")
clickedFunc: function() {
onClicked: {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
@@ -133,19 +133,24 @@ PageType {
}
function restoreBackup(filePath) {
var headerText = qsTr("Import settings from a backup file?")
var descriptionText = qsTr("All current settings will be reset");
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Import settings from a backup file?")
questionDrawer.descriptionText = qsTr("All current settings will be reset");
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
QuestionDrawer {
id: questionDrawer
}
}
@@ -41,6 +41,27 @@ PageType {
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 {
Layout.fillWidth: true
Layout.margins: 16
+15 -22
View File
@@ -13,8 +13,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: primaryDns.textField
BackButtonType {
id: backButton
@@ -30,12 +28,10 @@ PageType {
anchors.bottom: parent.bottom
contentHeight: content.height
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
enabled: !isServerFromApi
enabled: !ServersModel.isDefaultServerFromApi()
Component.onCompleted: {
if (isServerFromApi) {
if (ServersModel.isDefaultServerFromApi()) {
PageController.showNotificationMessage(qsTr("Default server does not support custom dns"))
}
}
@@ -72,8 +68,6 @@ PageType {
textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp()
}
KeyNavigation.tab: secondaryDns.textField
}
TextFieldWithHeaderType {
@@ -86,8 +80,6 @@ PageType {
textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp()
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
@@ -102,33 +94,32 @@ PageType {
text: qsTr("Restore default")
clickedFunc: function() {
var headerText = qsTr("Restore default DNS settings?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
onClicked: function() {
questionDrawer.headerText = qsTr("Restore default DNS settings?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
SettingsController.primaryDns = "1.1.1.1"
primaryDns.textFieldText = SettingsController.primaryDns
SettingsController.secondaryDns = "1.0.0.1"
secondaryDns.textFieldText = SettingsController.secondaryDns
PageController.showNotificationMessage(qsTr("Settings have been reset"))
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
clickedFunc: function() {
onClicked: function() {
if (primaryDns.textFieldText !== SettingsController.primaryDns) {
SettingsController.primaryDns = primaryDns.textFieldText
}
@@ -139,6 +130,8 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
+12 -7
View File
@@ -143,20 +143,21 @@ PageType {
image: "qrc:/images/controls/delete.svg"
onClicked: function() {
var headerText = qsTr("Clear logs?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Clear logs?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
SettingsController.clearLogs()
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs have been cleaned up"))
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -169,6 +170,10 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
}
+58 -49
View File
@@ -28,7 +28,7 @@ PageType {
PageController.showErrorMessage(message)
}
function onRemoveProcessedServerFinished(finishedMessage) {
function onRemoveCurrentlyProcessedServerFinished(finishedMessage) {
if (!ServersModel.getServersCount()) {
PageController.replaceStartPage()
} else {
@@ -38,7 +38,7 @@ PageType {
PageController.showNotificationMessage(finishedMessage)
}
function onRebootProcessedServerFinished(finishedMessage) {
function onRebootCurrentlyProcessedServerFinished(finishedMessage) {
PageController.showNotificationMessage(finishedMessage)
}
@@ -64,8 +64,8 @@ PageType {
Connections {
target: ServersModel
function onProcessedServerIndexChanged() {
content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
function onCurrentlyProcessedServerIndexChanged() {
content.isServerWithWriteAccess = ServersModel.isCurrentlyProcessedServerHasWriteAccess()
}
}
@@ -82,7 +82,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
property bool isServerWithWriteAccess: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
LabelWithButtonType {
visible: content.isServerWithWriteAccess
@@ -92,20 +92,21 @@ PageType {
descriptionText: qsTr("May be needed when changing other settings")
clickedFunction: function() {
var headerText = qsTr("Clear cached profiles?")
var descriptionText = qsTr("")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Clear cached profiles?")
questionDrawer.descriptionText = qsTr("")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
SettingsController.clearCachedProfiles()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -139,23 +140,24 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to reboot the server?")
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.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?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.rebootProcessedServer()
InstallController.rebootCurrentlyProcessedServer()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -170,23 +172,24 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to remove the server from application?")
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Do you want to remove the server from application?")
questionDrawer.descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.removeProcessedServer()
InstallController.removeCurrentlyProcessedServer()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -200,22 +203,23 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to clear server from Amnezia software?")
var descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
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")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.removeAllContainers()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -224,32 +228,37 @@ PageType {
}
LabelWithButtonType {
visible: ServersModel.getProcessedServerData("isServerFromApi")
visible: ServersModel.isCurrentlyProcessedServerFromApi()
Layout.fillWidth: true
text: qsTr("Reset API config")
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to reset API config?")
var descriptionText = ""
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Do you want to reset API config?")
questionDrawer.descriptionText = ""
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
ApiController.clearApiConfig()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
DividerType {
visible: ServersModel.getProcessedServerData("isServerFromApi")
visible: ServersModel.isCurrentlyProcessedServerFromApi()
}
QuestionDrawer {
id: questionDrawer
}
}
}
+14 -27
View File
@@ -63,7 +63,7 @@ PageType {
headerText: name
descriptionText: {
if (ServersModel.isProcessedServerHasWriteAccess()) {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) {
return credentialsLogin + " · " + hostName
} else {
return hostName
@@ -71,33 +71,30 @@ PageType {
}
actionButtonFunction: function() {
serverNameEditDrawer.open()
serverNameEditDrawer.visible = true
}
}
DrawerType2 {
DrawerType {
id: serverNameEditDrawer
parent: root
width: root.width
height: root.height * 0.35
anchors.fill: parent
expandedHeight: root.height * 0.35
onVisibleChanged: {
if (serverNameEditDrawer.visible) {
serverName.textField.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: serverNameEditDrawer
function onOpened() {
serverName.textField.forceActiveFocus()
}
}
TextFieldWithHeaderType {
id: serverName
@@ -106,18 +103,14 @@ PageType {
textFieldText: name
textField.maximumLength: 30
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
clickedFunc: function() {
onClicked: {
if (serverName.textFieldText === "") {
return
}
@@ -125,13 +118,7 @@ PageType {
if (serverName.textFieldText !== name) {
name = serverName.textFieldText
}
serverNameEditDrawer.close()
}
}
Component.onCompleted: {
if (header.itemAt(0)) {
defaultActiveFocusItem = serverName.textField
serverNameEditDrawer.visible = false
}
}
}
@@ -107,25 +107,26 @@ PageType {
width: parent.width
visible: ServersModel.isProcessedServerHasWriteAccess()
visible: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName()
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.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.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
MouseArea {
@@ -137,9 +138,9 @@ PageType {
DividerType {}
}
}
QuestionDrawer {
id: questionDrawer
QuestionDrawer {
id: questionDrawer
}
}
}
@@ -38,13 +38,13 @@ PageType {
Connections {
target: ServersModel
function onProcessedServerIndexChanged() {
function onCurrentlyProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isProcessedServerHasWriteAccess()) {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
@@ -38,13 +38,13 @@ PageType {
Connections {
target: ServersModel
function onProcessedServerIndexChanged() {
function onCurrentlyProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isProcessedServerHasWriteAccess()) {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters()
@@ -55,9 +55,6 @@ PageType {
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
}
Component.onCompleted: updateContainersModelFilters()
@@ -87,7 +87,7 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
ServersModel.processedIndex = index
ServersModel.currentlyProcessedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
}
}
@@ -20,23 +20,13 @@ import "../Components"
PageType {
id: root
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
defaultActiveFocusItem: website_ip_field.textField
property bool pageEnabled: {
return !ConnectionController.isConnected && !isServerFromApi
return !ConnectionController.isConnected && !ServersModel.isDefaultServerFromApi()
}
Component.onCompleted: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot change split tunneling settings during active connection"))
root.pageEnabled = false
} else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && isServerFromApi) {
if (ServersModel.isDefaultServerFromApi()) {
PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function"))
root.pageEnabled = false
} else {
root.pageEnabled = true
}
}
@@ -114,7 +104,7 @@ PageType {
Layout.fillWidth: true
Layout.rightMargin: 16
checked: SitesModel.isTunnelingEnabled
checked: SitesModel.isSplitTunnelingEnabled()
onToggled: {
SitesModel.toggleSplitTunneling(checked)
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
@@ -131,7 +121,6 @@ PageType {
Layout.rightMargin: 16
drawerHeight: 0.4375
drawerParent: root
enabled: root.pageEnabled
@@ -146,7 +135,7 @@ PageType {
clickedFunction: function() {
selector.text = selectedText
selector.close()
selector.menuVisible = false
if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) {
SitesModel.routeMode = root.routeModesModel[currentIndex].type
}
@@ -213,21 +202,26 @@ PageType {
rightImageColor: "#D7D8DB"
clickedFunction: function() {
var headerText = qsTr("Remove ") + url + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Remove ") + url + "?"
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
SitesController.removeSite(index)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
}
@@ -255,8 +249,6 @@ PageType {
anchors.bottomMargin: 24
TextFieldWithHeaderType {
id: website_ip_field
Layout.fillWidth: true
textFieldPlaceholderText: qsTr("website or IP")
@@ -283,155 +275,151 @@ PageType {
}
}
DrawerType2 {
DrawerType {
id: moreActionsDrawer
anchors.fill: parent
expandedHeight: parent.height * 0.4375
width: parent.width
height: parent.height * 0.4375
expandedContent: ColumnLayout {
id: moreActionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import / Export Sites")
}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Import")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
importSitesDrawer.open()
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Save site list")
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "amnezia_sites.json"
} else {
fileName = SystemController.getFileName(qsTr("Save sites"),
qsTr("Sites files (*.json)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_sites",
true,
".json")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
SitesController.exportSites(fileName)
moreActionsDrawer.close()
PageController.showBusyIndicator(false)
}
}
}
DividerType {}
}
}
DrawerType2 {
id: importSitesDrawer
anchors.fill: parent
expandedHeight: parent.height * 0.4375
expandedContent: Item {
implicitHeight: importSitesDrawer.expandedHeight
BackButtonType {
id: importSitesDrawerBackButton
FlickableType {
anchors.fill: parent
contentHeight: moreActionsDrawerContent.height
ColumnLayout {
id: moreActionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
importSitesDrawer.close()
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import / Export Sites")
}
}
FlickableType {
anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
LabelWithButtonType {
Layout.fillWidth: true
contentHeight: importSitesDrawerContent.height
text: qsTr("Import")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
ColumnLayout {
id: importSitesDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import a list of sites")
clickedFunction: function() {
importSitesDrawer.open()
}
}
LabelWithButtonType {
Layout.fillWidth: true
DividerType {}
text: qsTr("Replace site list")
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Save site list")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "amnezia_sites.json"
} else {
fileName = SystemController.getFileName(qsTr("Save sites"),
qsTr("Sites files (*.json)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_sites",
true,
".json")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
SitesController.exportSites(fileName)
moreActionsDrawer.close()
PageController.showBusyIndicator(false)
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Add imported sites to existing ones")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false)
}
}
}
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.close()
moreActionsDrawer.close()
}
DividerType {}
}
DividerType {}
}
}
}
QuestionDrawer {
id: questionDrawer
DrawerType {
id: importSitesDrawer
width: parent.width
height: parent.height * 0.4375
BackButtonType {
id: importSitesDrawerBackButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
importSitesDrawer.close()
}
}
FlickableType {
anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: importSitesDrawerContent.height
ColumnLayout {
id: importSitesDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import a list of sites")
}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Replace site list")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Add imported sites to existing ones")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false)
}
}
}
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.close()
moreActionsDrawer.close()
}
DividerType {}
}
}
}
}
@@ -12,8 +12,6 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: hostname.textField
BackButtonType {
id: backButton
@@ -59,8 +57,6 @@ PageType {
onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '');
}
KeyNavigation.tab: username.textField
}
TextFieldWithHeaderType {
@@ -69,8 +65,6 @@ PageType {
Layout.fillWidth: true
headerText: qsTr("Login to connect via SSH")
textFieldPlaceholderText: "root"
KeyNavigation.tab: secretData.textField
}
TextFieldWithHeaderType {
@@ -91,19 +85,15 @@ PageType {
onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '');
}
KeyNavigation.tab: continueButton
}
BasicButtonType {
id: continueButton
Layout.fillWidth: true
Layout.topMargin: 24
text: qsTr("Continue")
clickedFunc: function() {
onClicked: function() {
forceActiveFocus()
if (!isCredentialsFilled()) {
return
+3 -2
View File
@@ -158,7 +158,7 @@ PageType {
text: qsTr("Continue")
clickedFunc: function() {
onClicked: function() {
if (root.isEasySetup) {
ContainersModel.setCurrentlyProcessedContainerIndex(containers.dockerContainer)
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
@@ -192,12 +192,13 @@ PageType {
return ContainersModel.isAnyContainerInstalled()
}
return true
}
text: qsTr("Set up later")
clickedFunc: function() {
onClicked: function() {
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.addEmptyServer()
}
@@ -26,7 +26,7 @@ PageType {
function onInstallContainerFinished(finishedMessage, isServiceInstall) {
if (!ConnectionController.isConnected && !isServiceInstall) {
ServersModel.setDefaultContainer(ServersModel.processedIndex, ContainersModel.getCurrentlyProcessedContainerIndex())
ServersModel.setDefaultContainer(ServersModel.currentlyProcessedIndex, ContainersModel.getCurrentlyProcessedContainerIndex())
}
PageController.closePage() // close installing page
@@ -42,7 +42,7 @@ PageType {
function onInstallServerFinished(finishedMessage) {
if (!ConnectionController.isConnected) {
ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1);
ServersModel.processedIndex = ServersModel.defaultIndex
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex
}
PageController.goToStartPage()
@@ -55,7 +55,7 @@ PageType {
function onServerAlreadyExists(serverIndex) {
PageController.goToStartPage()
ServersModel.processedIndex = serverIndex
ServersModel.currentlyProcessedIndex = serverIndex
PageController.goToPage(PageEnum.PageSettingsServerInfo, false)
PageController.showErrorMessage(qsTr("The server has already been added to the application"))
@@ -165,7 +165,7 @@ PageType {
text: qsTr("Cancel installation")
clickedFunc: function() {
onClicked: {
InstallController.cancelInstallation()
PageController.showBusyIndicator(true)
}
@@ -52,8 +52,6 @@ PageType {
implicitWidth: processedContainerListView.width
implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height
property alias port:port
ColumnLayout {
id: delegateContent
@@ -94,85 +92,81 @@ PageType {
text: qsTr("More detailed")
clickedFunc: function() {
onClicked: {
showDetailsDrawer.open()
}
}
DrawerType2 {
DrawerType {
id: showDetailsDrawer
parent: root
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedContent: Item {
implicitHeight: showDetailsDrawer.expandedHeight
width: parent.width
height: parent.height * 0.9
BackButtonType {
id: showDetailsBackButton
BackButtonType {
id: showDetailsBackButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
showDetailsDrawer.close()
}
}
FlickableType {
anchors.top: showDetailsBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: {
var emptySpaceHeight = parent.height - showDetailsBackButton.implicitHeight - showDetailsBackButton.anchors.topMargin
return (showDetailsDrawerContent.height > emptySpaceHeight) ?
showDetailsDrawerContent.height : emptySpaceHeight
}
ColumnLayout {
id: showDetailsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
backButtonFunction: function() {
showDetailsDrawer.close()
}
}
Header2Type {
id: showDetailsDrawerHeader
Layout.fillWidth: true
Layout.topMargin: 16
FlickableType {
anchors.top: showDetailsBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: {
var emptySpaceHeight = parent.height - showDetailsBackButton.implicitHeight - showDetailsBackButton.anchors.topMargin
return (showDetailsDrawerContent.height > emptySpaceHeight) ?
showDetailsDrawerContent.height : emptySpaceHeight
headerText: name
}
ColumnLayout {
id: showDetailsDrawerContent
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type {
id: showDetailsDrawerHeader
Layout.fillWidth: true
Layout.topMargin: 16
headerText: name
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
text: detailedDescription
textFormat: Text.MarkdownText
}
text: detailedDescription
textFormat: Text.MarkdownText
}
Rectangle {
Layout.fillHeight: true
color: "transparent"
}
Rectangle {
Layout.fillHeight: true
color: "transparent"
}
BasicButtonType {
Layout.fillWidth: true
Layout.bottomMargin: 32
BasicButtonType {
Layout.fillWidth: true
Layout.bottomMargin: 32
text: qsTr("Close")
text: qsTr("Close")
clickedFunc: function() {
showDetailsDrawer.close()
}
onClicked: function() {
showDetailsDrawer.close()
}
}
}
@@ -203,8 +197,6 @@ PageType {
headerText: qsTr("Port")
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
KeyNavigation.tab: installButton
}
Rectangle {
@@ -220,7 +212,7 @@ PageType {
text: qsTr("Install")
clickedFunc: function() {
onClicked: function() {
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.install(dockerContainer, port.textFieldText, transportProtoSelector.currentIndex)
}
@@ -240,8 +232,6 @@ PageType {
var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto)
transportProtoSelector.visible = protocolSelectorVisible
transportProtoHeader.visible = protocolSelectorVisible
defaultActiveFocusItem = port.textField
}
}
}
@@ -115,8 +115,8 @@ PageType {
text: qsTr("I have the data to connect")
clickedFunc: function() {
connectionTypeSelection.open()
onClicked: {
connectionTypeSelection.visible = true
}
}
@@ -135,15 +135,13 @@ PageType {
text: qsTr("I have nothing")
clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide"))
}
onClicked: Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide"))
}
}
}
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection
}
}
BusyIndicatorType {
@@ -12,8 +12,6 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: textKey.textField
FlickableType {
id: fl
anchors.top: parent.top
@@ -58,15 +56,11 @@ PageType {
textField.text = ""
textField.paste()
}
KeyNavigation.tab: continueButton
}
}
}
BasicButtonType {
id: continueButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -76,7 +70,7 @@ PageType {
text: qsTr("Continue")
clickedFunc: function() {
onClicked: function() {
ImportController.extractConfigFromCode(textKey.textFieldText)
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
}
@@ -30,7 +30,7 @@ PageType {
function onImportFinished() {
if (!ConnectionController.isConnected) {
ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1);
ServersModel.processedIndex = ServersModel.defaultIndex
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex
}
PageController.goToStartPage()
@@ -109,7 +109,7 @@ PageType {
text: showContent ? qsTr("Collapse content") : qsTr("Show content")
clickedFunc: function() {
onClicked: {
showContent = !showContent
}
}
@@ -151,7 +151,7 @@ PageType {
Layout.bottomMargin: 32
text: qsTr("Connect")
clickedFunc: function() {
onClicked: {
ImportController.importConfig()
}
}
+57 -85
View File
@@ -16,13 +16,10 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: clientNameTextField.textField
enum ConfigType {
AmneziaConnection,
OpenVpn,
WireGuard,
Awg,
ShadowSocks,
Cloak
}
@@ -32,7 +29,7 @@ PageType {
PageController.showBusyIndicator(true)
ExportController.revokeConfig(index,
ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getProcessedServerCredentials())
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Config revoked"))
}
@@ -44,15 +41,14 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.needCloseButton = false
shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true)
switch (type) {
case PageShare.ConfigType.AmneziaConnection: {
ExportController.generateConnectionConfig(clientNameTextField.textFieldText);
break;
}
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(clientNameTextField.textFieldText); break;
case PageShare.ConfigType.OpenVpn: {
ExportController.generateOpenVpnConfig(clientNameTextField.textFieldText)
shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config")
@@ -67,13 +63,6 @@ PageType {
shareConnectionDrawer.configFileName = "amnezia_for_wireguard"
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: {
ExportController.generateShadowSocksConfig()
shareConnectionDrawer.configCaption = qsTr("Save ShadowSocks config")
@@ -91,6 +80,11 @@ PageType {
}
PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true
}
function onExportErrorOccurred(errorMessage) {
@@ -121,11 +115,6 @@ PageType {
property string name: qsTr("WireGuard native format")
property var type: PageShare.ConfigType.WireGuard
}
QtObject {
id: awgConnectionFormat
property string name: qsTr("AmneziaWG native format")
property var type: PageShare.ConfigType.Awg
}
QtObject {
id: shadowSocksConnectionFormat
property string name: qsTr("ShadowSocks native format")
@@ -140,7 +129,7 @@ PageType {
FlickableType {
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height + 10
contentHeight: content.height
ColumnLayout {
id: content
@@ -165,15 +154,14 @@ PageType {
shareFullAccessDrawer.open()
}
DrawerType2 {
DrawerType {
id: shareFullAccessDrawer
parent: root
width: root.width
height: root.height * 0.45
anchors.fill: parent
expandedHeight: root.height * 0.45
expandedContent: ColumnLayout {
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -246,7 +234,7 @@ PageType {
accessTypeSelector.currentIndex = 1
PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getProcessedServerCredentials())
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
}
}
@@ -276,8 +264,6 @@ PageType {
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: shareButton
}
DropDownType {
@@ -290,7 +276,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server")
headerText: qsTr("Server")
@@ -320,7 +305,7 @@ PageType {
serverSelector.severSelectorIndexChanged()
}
serverSelector.close()
serverSelector.menuVisible = false
}
Component.onCompleted: {
@@ -331,7 +316,7 @@ PageType {
function handler() {
serverSelector.text = selectedText
ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex)
}
}
}
@@ -343,7 +328,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.5
drawerParent: root
descriptionText: qsTr("Protocol")
headerText: qsTr("Protocol")
@@ -374,14 +358,14 @@ PageType {
clickedFunction: function() {
handler()
protocolSelector.close()
protocolSelector.menuVisible = false
}
Connections {
target: serverSelector
function onSeverSelectorIndexChanged() {
var defaultContainer = proxyContainersModel.mapFromSource(ServersModel.getProcessedServerData("defaultContainer"))
var defaultContainer = proxyContainersModel.mapFromSource(ServersModel.getDefaultContainer(ServersModel.currentlyProcessedIndex))
protocolSelectorListView.currentIndex = defaultContainer
protocolSelectorListView.triggerCurrentItem()
}
@@ -404,7 +388,7 @@ PageType {
if (accessTypeSelector.currentIndex === 1) {
PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getProcessedServerCredentials())
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
}
}
@@ -418,8 +402,6 @@ PageType {
root.connectionTypesModel.push(openVpnConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-wireguard")) {
root.connectionTypesModel.push(wireGuardConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-awg")) {
root.connectionTypesModel.push(awgConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-shadowsocks")) {
root.connectionTypesModel.push(openVpnConnectionFormat)
root.connectionTypesModel.push(shadowSocksConnectionFormat)
@@ -441,7 +423,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
visible: accessTypeSelector.currentIndex === 0
enabled: root.connectionTypesModel.length > 1
@@ -465,7 +446,7 @@ PageType {
clickedFunction: function() {
exportTypeSelector.text = selectedText
exportTypeSelector.currentIndex = currentIndex
exportTypeSelector.close()
exportTypeSelector.menuVisible = false
}
Component.onCompleted: {
@@ -475,9 +456,11 @@ PageType {
}
}
BasicButtonType {
id: shareButton
ShareConnectionDrawer {
id: shareConnectionDrawer
}
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 40
@@ -487,7 +470,7 @@ PageType {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
clickedFunc: function(){
onClicked: {
if (clientNameTextField.textFieldText !== "") {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
}
@@ -578,15 +561,13 @@ PageType {
DividerType {}
DrawerType2 {
DrawerType {
id: clientInfoDrawer
parent: root
width: root.width
height: root.height * 0.5
anchors.fill: parent
expandedHeight: root.height * 0.5
expandedContent: ColumnLayout {
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -617,33 +598,30 @@ PageType {
text: qsTr("Rename")
clickedFunc: function() {
onClicked: function() {
clientNameEditDrawer.open()
}
DrawerType2 {
DrawerType {
id: clientNameEditDrawer
parent: root
width: root.width
height: root.height * 0.35
anchors.fill: parent
expandedHeight: root.height * 0.35
onVisibleChanged: {
if (clientNameEditDrawer.visible) {
clientNameEditor.textField.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: clientNameEditDrawer
function onOpened() {
clientNameEditor.textField.forceActiveFocus()
}
}
TextFieldWithHeaderType {
id: clientNameEditor
Layout.fillWidth: true
@@ -651,18 +629,14 @@ PageType {
textFieldText: clientName
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
clickedFunc: function() {
onClicked: {
if (clientNameEditor.textFieldText === "") {
return
}
@@ -672,7 +646,7 @@ PageType {
ExportController.renameClient(index,
clientNameEditor.textFieldText,
ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getProcessedServerCredentials())
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
clientNameEditDrawer.close()
}
@@ -694,20 +668,21 @@ PageType {
text: qsTr("Revoke")
clickedFunc: function() {
var headerText = qsTr("Revoke the config for a user - %1?").arg(clientName)
var descriptionText = qsTr("The user will no longer be able to connect to your server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
onClicked: function() {
questionDrawer.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.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.close()
clientInfoDrawer.close()
root.revokeConfig(index)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.close()
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.open()
}
}
}
@@ -715,15 +690,12 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onPressed: function(mouse) {
+12 -10
View File
@@ -69,7 +69,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server")
headerText: qsTr("Server")
@@ -100,7 +99,7 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
serverSelector.close()
serverSelector.menuVisible = false
}
Component.onCompleted: {
@@ -111,7 +110,7 @@ PageType {
function handler() {
serverSelector.text = selectedText
ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex)
}
}
}
@@ -123,10 +122,12 @@ PageType {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
clickedFunc: function() {
onClicked: function() {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.needCloseButton = false
shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true)
@@ -139,15 +140,16 @@ PageType {
PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
}
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
}
}
+39 -13
View File
@@ -20,16 +20,22 @@ PageType {
function onGoToPageHome() {
tabBar.setCurrentIndex(0)
tabBarStackView.goToTabBarPage(PageEnum.PageHome)
PageController.updateDrawerRootPage(PageEnum.PageHome)
}
function onGoToPageSettings() {
tabBar.setCurrentIndex(2)
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
PageController.updateDrawerRootPage(PageEnum.PageSettings)
}
function onGoToPageViewConfig() {
var pagePath = PageController.getPagePath(PageEnum.PageSetupWizardViewConfig)
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
PageController.updateDrawerRootPage(PageEnum.PageSetupWizardViewConfig)
}
function onShowBusyIndicator(visible) {
@@ -38,14 +44,15 @@ PageType {
tabBar.enabled = !visible
}
// function onShowTopCloseButton(visible) {
// topCloseButton.visible = visible
// }
function onEnableTabBar(enabled) {
tabBar.enabled = enabled
}
function onClosePage() {
tabBar.isServerInfoShow = tabBarStackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageSettingsServerInfo)
&& tabBarStackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageSettingsSplitTunneling)
if (tabBarStackView.depth <= 1) {
return
}
@@ -54,14 +61,13 @@ PageType {
function onGoToPage(page, slide) {
var pagePath = PageController.getPagePath(page)
if (slide) {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
} else {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.Immediate)
}
tabBar.isServerInfoShow = page === PageEnum.PageSettingsServerInfo || PageEnum.PageSettingsSplitTunneling || tabBar.isServerInfoShow
PageController.updateDrawerRootPage(page)
}
function onGoToStartPage() {
@@ -109,12 +115,20 @@ PageType {
function onNoInstalledContainers() {
PageController.setTriggeredBtConnectButton(true)
ServersModel.processedIndex = ServersModel.getDefaultServerIndex()
ServersModel.currentlyProcessedIndex = ServersModel.getDefaultServerIndex()
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardEasy)
}
}
Connections {
target: ApiController
function onErrorOccurred(errorMessage) {
PageController.showErrorMessage(errorMessage)
}
}
StackViewType {
id: tabBarStackView
@@ -132,21 +146,26 @@ PageType {
var pagePath = PageController.getPagePath(page)
tabBarStackView.clear(StackView.Immediate)
tabBarStackView.replace(pagePath, { "objectName" : pagePath }, StackView.Immediate)
tabBar.isServerInfoShow = false
PageController.updateDrawerRootPage(page)
}
Component.onCompleted: {
var pagePath = PageController.getPagePath(PageEnum.PageHome)
ServersModel.processedIndex = ServersModel.defaultIndex
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex
tabBarStackView.push(pagePath, { "objectName" : pagePath })
}
// onWidthChanged: {
// topCloseButton.x = tabBarStackView.x + tabBarStackView.width -
// topCloseButton.buttonWidth - topCloseButton.rightPadding
// }
}
TabBar {
id: tabBar
property int previousIndex: 0
property bool isServerInfoShow: false
anchors.right: parent.right
anchors.left: parent.left
@@ -177,11 +196,11 @@ PageType {
}
TabImageButtonType {
isSelected: tabBar.isServerInfoShow ? false : tabBar.currentIndex === 0
isSelected: tabBar.currentIndex === 0
image: "qrc:/images/controls/home.svg"
onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageHome)
ServersModel.processedIndex = ServersModel.defaultIndex
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex
tabBar.previousIndex = 0
}
}
@@ -211,7 +230,7 @@ PageType {
}
TabImageButtonType {
isSelected: tabBar.isServerInfoShow ? true : tabBar.currentIndex === 2
isSelected: tabBar.currentIndex === 2
image: "qrc:/images/controls/settings-2.svg"
onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
@@ -234,6 +253,13 @@ PageType {
z: 1
}
// TopCloseButtonType {
// id: topCloseButton
// x: tabBarStackView.width - topCloseButton.buttonWidth - topCloseButton.rightPadding
// z: 1
// }
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection
+23 -60
View File
@@ -8,7 +8,6 @@ import PageEnum 1.0
import "Config"
import "Controls2"
import "Components"
Window {
id: root
@@ -131,15 +130,32 @@ Window {
}
Item {
anchors.fill: parent
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
DrawerType2 {
implicitHeight: popupErrorMessage.height
DrawerType {
id: privateKeyPassphraseDrawer
anchors.fill: parent
expandedHeight: root.height * 0.35
width: root.width
height: root.height * 0.35
expandedContent: ColumnLayout {
onVisibleChanged: {
if (privateKeyPassphraseDrawer.visible) {
passphrase.textFieldText = ""
passphrase.textField.forceActiveFocus()
}
}
onAboutToHide: {
PageController.showBusyIndicator(true)
}
onAboutToShow: {
PageController.showBusyIndicator(false)
}
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -147,24 +163,6 @@ Window {
anchors.leftMargin: 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 {
id: passphrase
@@ -178,13 +176,9 @@ Window {
clickedFunc: function() {
hidePassword = !hidePassword
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
defaultColor: "transparent"
@@ -196,7 +190,7 @@ Window {
text: qsTr("Save")
clickedFunc: function() {
onClicked: {
privateKeyPassphraseDrawer.close()
PageController.passphraseRequestDrawerClosed(passphrase.textFieldText)
}
@@ -205,37 +199,6 @@ 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 {
id: mainFileDialog
+1 -2
View File
@@ -146,8 +146,7 @@ if [ "${MAC_CERT_PW+x}" ]; then
fi
echo "Building DMG installer..."
# 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
hdiutil create -size 120mb -volname AmneziaVPN -srcfolder $BUILD_DIR/installer/$APP_NAME.app -ov -format UDZO $DMG_FILENAME
if [ "${MAC_CERT_PW+x}" ]; then
echo "Signing DMG installer..."