mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-21 02:01:03 +07:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8336961fb4 | |||
| de62d21362 | |||
| 0659ba4a43 | |||
| 1be6618ceb |
@@ -131,6 +131,3 @@ client/3rd/ShadowSocks/ss_ios.xcconfig
|
||||
|
||||
# UML generated pics
|
||||
out/
|
||||
|
||||
# CMake files
|
||||
CMakeFiles/
|
||||
@@ -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)
|
||||
|
||||
@@ -391,13 +391,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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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)
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,8 +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>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL. </source>
|
||||
<translation>استفاده <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> برای باز کردن این نشانی.</translation>
|
||||
<source>Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> 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 <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> 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's okay as long as it'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'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>
|
||||
|
||||
@@ -854,11 +854,11 @@ Already installed containers were found on the server. All installed containers
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL.</source>
|
||||
<source>Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this url.</source>
|
||||
<translation type="vanished">Используйте <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> для открытия этой ссылки.</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'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'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>
|
||||
|
||||
@@ -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 '%1' was rebooted</source>
|
||||
<translation type="unfinished">服务器 '%1' 已重新启动</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 <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this URL.</source>
|
||||
<source>Use <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor Browser</a> to open this url.</source>
|
||||
<translation type="vanished">用 <a href="https://www.torproject.org/download/" style="color: #FBB26A;">Tor 浏览器</a> 打开上面网址</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -984,7 +984,7 @@ And if you don'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'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'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'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'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'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'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'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'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"/>
|
||||
|
||||
@@ -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;
|
||||
@@ -141,13 +132,11 @@ void ApiController::updateServerConfigFromApi()
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ private:
|
||||
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
|
||||
bool m_isConfigUpdateStarted = false;
|
||||
};
|
||||
|
||||
#endif // APICONTROLLER_H
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ namespace LanguageSettings
|
||||
English,
|
||||
Russian,
|
||||
China_cn,
|
||||
Persian,
|
||||
Arabic
|
||||
Persian
|
||||
};
|
||||
Q_ENUM_NS(AvailableLanguageEnum)
|
||||
|
||||
|
||||
@@ -220,11 +220,6 @@ bool ServersModel::isDefaultServerCurrentlyProcessed()
|
||||
return m_defaultServerIndex == m_processedServerIndex;
|
||||
}
|
||||
|
||||
bool ServersModel::isDefaultServerFromApi()
|
||||
{
|
||||
return qvariant_cast<bool>(data(m_defaultServerIndex, IsServerFromApiRole));
|
||||
}
|
||||
|
||||
bool ServersModel::isProcessedServerHasWriteAccess()
|
||||
{
|
||||
return qvariant_cast<bool>(data(m_processedServerIndex, HasWriteAccessRole));
|
||||
@@ -254,7 +249,7 @@ void ServersModel::editServer(const QJsonObject &server, const int serverIndex)
|
||||
}
|
||||
updateContainersModel();
|
||||
|
||||
if (serverIndex == m_defaultServerIndex) {
|
||||
if (isDefaultServerCurrentlyProcessed()) {
|
||||
auto defaultContainer = qvariant_cast<DockerContainer>(getDefaultServerData("defaultContainer"));
|
||||
emit defaultServerDefaultContainerChanged(defaultContainer);
|
||||
}
|
||||
@@ -582,18 +577,3 @@ void ServersModel::setProcessedServerData(const QString roleString, const QVaria
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -48,8 +48,6 @@ public:
|
||||
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(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
|
||||
|
||||
@@ -61,7 +59,6 @@ public slots:
|
||||
const QString getDefaultServerDescriptionExpanded();
|
||||
const QString getDefaultServerDefaultContainerName();
|
||||
bool isDefaultServerCurrentlyProcessed();
|
||||
bool isDefaultServerFromApi();
|
||||
|
||||
bool isProcessedServerHasWriteAccess();
|
||||
bool isDefaultServerHasWriteAccess();
|
||||
@@ -106,8 +103,6 @@ public slots:
|
||||
QVariant getProcessedServerData(const QString roleString);
|
||||
void setProcessedServerData(const QString roleString, const QVariant &value);
|
||||
|
||||
bool isDefaultServerDefaultContainerHasSplitTunneling();
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ ListView {
|
||||
}
|
||||
|
||||
if (checked) {
|
||||
containersDropDown.close()
|
||||
containersDropDown.menuVisible = false
|
||||
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyDefaultServerContainersModel.mapToSource(index))
|
||||
} else {
|
||||
if (!isSupported && isInstalled) {
|
||||
@@ -72,7 +72,7 @@ ListView {
|
||||
ContainersModel.setCurrentlyProcessedContainerIndex(proxyDefaultServerContainersModel.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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -108,7 +104,7 @@ DrawerType2 {
|
||||
text: qsTr("Copy")
|
||||
imageSource: "qrc:/images/controls/copy.svg"
|
||||
|
||||
clickedFunc: function() {
|
||||
onClicked: {
|
||||
configText.selectAll()
|
||||
configText.copy()
|
||||
configText.select(0, 0)
|
||||
@@ -117,11 +113,10 @@ DrawerType2 {
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: copyNativeConfigStringButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
|
||||
visible: false
|
||||
visible: nativeConfigString.text !== ""
|
||||
|
||||
defaultColor: "transparent"
|
||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
||||
@@ -133,7 +128,7 @@ DrawerType2 {
|
||||
text: qsTr("Copy config string")
|
||||
imageSource: "qrc:/images/controls/copy.svg"
|
||||
|
||||
clickedFunc: function() {
|
||||
onClicked: {
|
||||
nativeConfigString.selectAll()
|
||||
nativeConfigString.copy()
|
||||
nativeConfigString.select(0, 0)
|
||||
@@ -154,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.open()
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+390
-306
@@ -18,383 +18,467 @@ 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
|
||||
|
||||
}
|
||||
expandedContent: Item {
|
||||
id: serverMenuContainer
|
||||
DropDownType {
|
||||
id: containersDropDown
|
||||
|
||||
implicitHeight: root.height * 0.9
|
||||
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
|
||||
|
||||
Component.onCompleted: {
|
||||
drawer.expandedHeight = serverMenuContainer.implicitHeight
|
||||
}
|
||||
text: ServersModel.defaultServerDefaultContainerName
|
||||
textColor: "#0E0E11"
|
||||
headerText: qsTr("VPN protocol")
|
||||
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
|
||||
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.defaultServerDescriptionExpanded
|
||||
}
|
||||
|
||||
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
|
||||
rootButtonClickedFunction: function() {
|
||||
containersDropDown.menuVisible = true
|
||||
}
|
||||
|
||||
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 onDefaultServerIndexChanged() {
|
||||
updateContainersModelFilters()
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
function updateContainersModelFilters() {
|
||||
if (ServersModel.isDefaultServerHasWriteAccess()) {
|
||||
proxyDefaultServerContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
|
||||
} else {
|
||||
proxyDefaultServerContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: menuContentDelegate
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyDefaultServerContainersModel
|
||||
sourceModel: DefaultServerContainersModel
|
||||
}
|
||||
|
||||
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: 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.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.processedIndex = 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
|
||||
|
||||
@@ -47,8 +44,6 @@ PageType {
|
||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,19 +175,20 @@ PageType {
|
||||
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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,10 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
SelectLanguageDrawer {
|
||||
id: selectLanguageDrawer
|
||||
}
|
||||
|
||||
|
||||
DividerType {}
|
||||
|
||||
@@ -139,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: primaryDns.textField
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
@@ -72,8 +70,6 @@ PageType {
|
||||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: secondaryDns.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
@@ -86,8 +82,6 @@ PageType {
|
||||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: saveButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
@@ -102,33 +96,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 +132,8 @@ PageType {
|
||||
}
|
||||
}
|
||||
}
|
||||
QuestionDrawer {
|
||||
id: questionDrawer
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,12 +140,13 @@ 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()
|
||||
@@ -152,10 +154,10 @@ PageType {
|
||||
InstallController.rebootProcessedServer()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
questionDrawer.noButtonFunction = function() {
|
||||
questionDrawer.visible = false
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
questionDrawer.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,12 +172,13 @@ 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()
|
||||
@@ -183,10 +186,10 @@ PageType {
|
||||
InstallController.removeProcessedServer()
|
||||
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,33 +228,38 @@ 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")
|
||||
}
|
||||
|
||||
QuestionDrawer {
|
||||
id: questionDrawer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,19 +113,20 @@ PageType {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +55,6 @@ PageType {
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyContainersModel
|
||||
sourceModel: ContainersModel
|
||||
sorters: [
|
||||
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: updateContainersModelFilters()
|
||||
|
||||
@@ -21,22 +21,13 @@ PageType {
|
||||
id: root
|
||||
|
||||
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
|
||||
|
||||
defaultActiveFocusItem: website_ip_field.textField
|
||||
|
||||
property bool pageEnabled: {
|
||||
return !ConnectionController.isConnected && !isServerFromApi
|
||||
}
|
||||
|
||||
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 (isServerFromApi) {
|
||||
PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function"))
|
||||
root.pageEnabled = false
|
||||
} else {
|
||||
root.pageEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +105,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 +122,6 @@ PageType {
|
||||
Layout.rightMargin: 16
|
||||
|
||||
drawerHeight: 0.4375
|
||||
drawerParent: root
|
||||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
@@ -146,7 +136,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 +203,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 +250,6 @@ PageType {
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: website_ip_field
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
textFieldPlaceholderText: qsTr("website or IP")
|
||||
@@ -283,155 +276,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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
defaultActiveFocusItem: clientNameTextField.textField
|
||||
|
||||
enum ConfigType {
|
||||
AmneziaConnection,
|
||||
OpenVpn,
|
||||
@@ -43,6 +41,8 @@ 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)
|
||||
@@ -80,6 +80,11 @@ PageType {
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
shareConnectionDrawer.needCloseButton = true
|
||||
PageController.showTopCloseButton(true)
|
||||
|
||||
shareConnectionDrawer.contentVisible = true
|
||||
}
|
||||
|
||||
function onExportErrorOccurred(errorMessage) {
|
||||
@@ -124,7 +129,7 @@ PageType {
|
||||
FlickableType {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height + 10
|
||||
contentHeight: content.height
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
@@ -149,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
|
||||
@@ -260,8 +264,6 @@ PageType {
|
||||
textField.maximumLength: 20
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: shareButton
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
@@ -274,7 +276,6 @@ PageType {
|
||||
Layout.topMargin: 16
|
||||
|
||||
drawerHeight: 0.4375
|
||||
drawerParent: root
|
||||
|
||||
descriptionText: qsTr("Server")
|
||||
headerText: qsTr("Server")
|
||||
@@ -304,7 +305,7 @@ PageType {
|
||||
serverSelector.severSelectorIndexChanged()
|
||||
}
|
||||
|
||||
serverSelector.close()
|
||||
serverSelector.menuVisible = false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -327,7 +328,6 @@ PageType {
|
||||
Layout.topMargin: 16
|
||||
|
||||
drawerHeight: 0.5
|
||||
drawerParent: root
|
||||
|
||||
descriptionText: qsTr("Protocol")
|
||||
headerText: qsTr("Protocol")
|
||||
@@ -358,7 +358,7 @@ PageType {
|
||||
clickedFunction: function() {
|
||||
handler()
|
||||
|
||||
protocolSelector.close()
|
||||
protocolSelector.menuVisible = false
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -423,7 +423,6 @@ PageType {
|
||||
Layout.topMargin: 16
|
||||
|
||||
drawerHeight: 0.4375
|
||||
drawerParent: root
|
||||
|
||||
visible: accessTypeSelector.currentIndex === 0
|
||||
enabled: root.connectionTypesModel.length > 1
|
||||
@@ -447,7 +446,7 @@ PageType {
|
||||
clickedFunction: function() {
|
||||
exportTypeSelector.text = selectedText
|
||||
exportTypeSelector.currentIndex = currentIndex
|
||||
exportTypeSelector.close()
|
||||
exportTypeSelector.menuVisible = false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -457,9 +456,11 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: shareButton
|
||||
ShareConnectionDrawer {
|
||||
id: shareConnectionDrawer
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
|
||||
@@ -469,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)
|
||||
}
|
||||
@@ -560,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
|
||||
@@ -599,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
|
||||
@@ -633,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
|
||||
}
|
||||
@@ -676,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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -697,15 +690,12 @@ PageType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QuestionDrawer {
|
||||
id: questionDrawer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShareConnectionDrawer {
|
||||
id: shareConnectionDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: function(mouse) {
|
||||
|
||||
@@ -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: {
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
@@ -115,6 +121,14 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ApiController
|
||||
|
||||
function onErrorOccurred(errorMessage) {
|
||||
PageController.showErrorMessage(errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
StackViewType {
|
||||
id: tabBarStackView
|
||||
|
||||
@@ -132,7 +146,8 @@ 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: {
|
||||
@@ -140,13 +155,17 @@ PageType {
|
||||
ServersModel.processedIndex = 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,7 +196,7 @@ PageType {
|
||||
}
|
||||
|
||||
TabImageButtonType {
|
||||
isSelected: tabBar.isServerInfoShow ? false : tabBar.currentIndex === 0
|
||||
isSelected: tabBar.currentIndex === 0
|
||||
image: "qrc:/images/controls/home.svg"
|
||||
onClicked: {
|
||||
tabBarStackView.goToTabBarPage(PageEnum.PageHome)
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user