Compare commits

..

4 Commits

Author SHA1 Message Date
vladimir.kuznetsov 8336961fb4 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD 2024-02-15 21:00:21 +05:00
vladimir.kuznetsov de62d21362 serversModel cleanup 2024-02-15 15:55:10 +05:00
vladimir.kuznetsov 0659ba4a43 fixed get/set DefaultContainer 2024-02-12 17:03:42 +03:00
vladimir.kuznetsov 1be6618ceb removed get/set default container from containerModel 2024-02-12 17:02:22 +03:00
72 changed files with 1519 additions and 5381 deletions
-3
View File
@@ -131,6 +131,3 @@ client/3rd/ShadowSocks/ss_ios.xcconfig
# UML generated pics
out/
# CMake files
CMakeFiles/
-10
View File
@@ -15,15 +15,6 @@ set(PACKAGES
Core5Compat Concurrent LinguistTools
)
execute_process(
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMAND git rev-parse --short HEAD
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
if(IOS)
set(PACKAGES ${PACKAGES} Multimedia)
endif()
@@ -66,7 +57,6 @@ set(AMNEZIAVPN_TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_fa_IR.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ar.ts
)
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)
+3 -9
View File
@@ -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);
}
+7 -1
View File
@@ -211,7 +211,13 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
localFile.write(data);
localFile.close();
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
#ifdef Q_OS_WINDOWS
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toLocal8Bit().toStdString(), remotePath.toStdString(),
"non_desc");
#else
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(),
"non_desc");
#endif
if (error != ErrorCode::NoError) {
return error;
+15 -13
View File
@@ -222,7 +222,7 @@ namespace libssh {
return fromLibsshErrorCode();
}
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const QString& localPath, const QString& remotePath, const QString &fileDesc)
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const std::string& localPath, const std::string& remotePath, const std::string& fileDesc)
{
m_sftpSession = sftp_new(m_session);
@@ -245,38 +245,40 @@ namespace libssh {
const size_t bufferSize = 16384;
char buffer[bufferSize];
file = sftp_open(m_sftpSession, remotePath.toStdString().c_str(), accessType, S_IRWXU);
file = sftp_open(m_sftpSession, remotePath.c_str(), accessType, S_IRWXU);
if (file == nullptr) {
return closeSftpSession();
}
int localFileSize = QFileInfo(localPath).size();
int localFileSize = std::filesystem::file_size(localPath);
int chunksCount = localFileSize / (bufferSize);
QFile fin(localPath);
std::ifstream fin(localPath, std::ios::binary | std::ios::in);
if (fin.open(QIODevice::ReadOnly)) {
if (fin.is_open()) {
for (int currentChunkId = 0; currentChunkId < chunksCount; currentChunkId++) {
QByteArray chunk = fin.read(bufferSize);
if (chunk.size() != bufferSize) return ErrorCode::SshSftpEofError;
fin.read(buffer, bufferSize);
int bytesWritten = sftp_write(file, chunk.data(), chunk.size());
int bytesWritten = sftp_write(file, buffer, bufferSize);
if (bytesWritten != chunk.size()) {
std::string chunk(buffer, bufferSize);
if (bytesWritten != bufferSize) {
fin.close();
sftp_close(file);
return closeSftpSession();
}
}
int lastChunkSize = localFileSize % bufferSize;
int lastChunkSize = localFileSize % (bufferSize);
if (lastChunkSize != 0) {
QByteArray lastChunk = fin.read(lastChunkSize);
if (lastChunk.size() != lastChunkSize) return ErrorCode::SshSftpEofError;
fin.read(buffer, lastChunkSize);
int bytesWritten = sftp_write(file, lastChunk.data(), lastChunkSize);
std::string chunk(buffer, lastChunkSize);
int bytesWritten = sftp_write(file, buffer, lastChunkSize);
if (bytesWritten != lastChunkSize) {
fin.close();
+3 -3
View File
@@ -33,9 +33,9 @@ namespace libssh {
const std::function<ErrorCode (const QString &, Client &)> &cbReadStdErr);
ErrorCode writeResponse(const QString &data);
ErrorCode sftpFileCopy(const SftpOverwriteMode overwriteMode,
const QString &localPath,
const QString &remotePath,
const QString& fileDesc);
const std::string& localPath,
const std::string& remotePath,
const std::string& fileDesc);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
private:
ErrorCode closeChannel();
@@ -1,6 +0,0 @@
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" width="18" height="18" rx="5" fill="white"/>
<path d="M8.49219 13.5L8.49219 9.44141L14.0191 4.99484" stroke="#0E0E11" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.47363 5.49805L6.98828 8.0127" stroke="#0E0E11" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.4727 9.5L14.4727 4.5033L9.50195 4.5033" stroke="#0E0E11" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 511 B

@@ -85,7 +85,6 @@ target_sources(networkextension PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
)
-3
View File
@@ -124,10 +124,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
// json.insert("hopindex", QJsonValue((double)hop.m_hopindex));
json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key));
json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip));
// todo review wg ipv6
#ifndef Q_OS_WINDOWS
json.insert("deviceIpv6Address", "dead::1");
#endif
json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key));
json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key));
json.insert("serverIpv4AddrIn", wgConfig.value(amnezia::config_key::hostName));
@@ -59,6 +59,10 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
var stopHandler: (() -> Void)?
var protoType: TunnelProtoType = .none
override init() {
super.init()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
let tmpStr = String(data: messageData, encoding: .utf8)!
wg_log(.error, message: tmpStr)
@@ -67,7 +71,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let completionHandler else {
guard let completionHandler = completionHandler else {
log(.error, message: "Missing message completion handler")
return
}
@@ -175,16 +179,14 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let wgConfigStr = try? JSONDecoder().decode(WGConfig.self, from: wgConfig).str,
let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr)
else {
let wgConfigStr = String(data: wgConfig, encoding: .utf8)!
guard let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr) else {
wg_log(.error, message: "Can't parse WireGuard config")
completionHandler(nil)
return
}
log(.info, message: "wgConfig: \(wgConfigStr.replacingOccurrences(of: "\n", with: " "))")
if tunnelConfiguration.peers.first!.allowedIPs
.map({ $0.stringRepresentation })
.joined(separator: ", ") == "0.0.0.0/0, ::/0" {
-135
View File
@@ -1,135 +0,0 @@
import Foundation
struct WGConfigData: Decodable {
let initPacketMagicHeader, responsePacketMagicHeader: String?
let underloadPacketMagicHeader, transportPacketMagicHeader: String?
let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String?
let initPacketJunkSize, responsePacketJunkSize: String?
var settings: String {
junkPacketCount == nil ? "" :
"""
Jc = \(junkPacketCount!)
Jmin = \(junkPacketMinSize!)
Jmax = \(junkPacketMaxSize!)
S1 = \(initPacketJunkSize!)
S2 = \(responsePacketJunkSize!)
H1 = \(initPacketMagicHeader!)
H2 = \(responsePacketMagicHeader!)
H3 = \(underloadPacketMagicHeader!)
H4 = \(transportPacketMagicHeader!)
"""
}
let clientIP: String
let clientPrivateKey: String
let clientPublicKey: String
let serverPublicKey: String
let presharedKey: String
let hostName: String
let port: Int
var allowedIPs: [String]
var persistentKeepAlive: String
enum CodingKeys: String, CodingKey {
case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2"
case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4"
case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax"
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2"
case clientIP = "client_ip" // "10.8.1.16"
case clientPrivateKey = "client_priv_key"
case clientPublicKey = "client_pub_key"
case serverPublicKey = "server_pub_key"
case presharedKey = "psk_key"
case allowedIPs = "allowed_ips"
case persistentKeepAlive = "persistent_keep_alive"
case hostName
case port
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.initPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .initPacketMagicHeader)
self.responsePacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .responsePacketMagicHeader)
self.underloadPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .underloadPacketMagicHeader)
self.transportPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .transportPacketMagicHeader)
self.junkPacketCount = try container.decodeIfPresent(String.self, forKey: .junkPacketCount)
self.junkPacketMinSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMinSize)
self.junkPacketMaxSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMaxSize)
self.initPacketJunkSize = try container.decodeIfPresent(String.self, forKey: .initPacketJunkSize)
self.responsePacketJunkSize = try container.decodeIfPresent(String.self, forKey: .responsePacketJunkSize)
self.clientIP = try container.decode(String.self, forKey: .clientIP)
self.clientPrivateKey = try container.decode(String.self, forKey: .clientPrivateKey)
self.clientPublicKey = try container.decode(String.self, forKey: .clientPublicKey)
self.serverPublicKey = try container.decode(String.self, forKey: .serverPublicKey)
self.presharedKey = try container.decode(String.self, forKey: .presharedKey)
self.allowedIPs = try container.decodeIfPresent([String].self, forKey: .allowedIPs) ?? ["0.0.0.0/0", "::/0"]
self.persistentKeepAlive = try container.decodeIfPresent(String.self, forKey: .persistentKeepAlive) ?? "25"
self.hostName = try container.decode(String.self, forKey: .hostName)
self.port = try container.decode(Int.self, forKey: .port)
}
}
struct WGConfig: Decodable {
let data: WGConfigData
let configVersion: Int
let description: String
let dns1: String
let dns2: String
let hostName: String
let `protocol`: String
let splitTunnelSites: [String]
let splitTunnelType: Int
enum CodingKeys: String, CodingKey {
case awgConfigData = "awg_config_data", wgConfigData = "wireguard_config_data"
case configData
case configVersion = "config_version"
case description
case dns1
case dns2
case hostName
case `protocol`
case splitTunnelSites
case splitTunnelType
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if container.contains(.awgConfigData) {
self.data = try container.decode(WGConfigData.self, forKey: .awgConfigData)
} else {
self.data = try container.decode(WGConfigData.self, forKey: .wgConfigData)
}
self.configVersion = try container.decode(Int.self, forKey: .configVersion)
self.description = try container.decode(String.self, forKey: .description)
self.dns1 = try container.decode(String.self, forKey: .dns1)
self.dns2 = try container.decode(String.self, forKey: .dns2)
self.hostName = try container.decode(String.self, forKey: .hostName)
self.protocol = try container.decode(String.self, forKey: .protocol)
self.splitTunnelSites = try container.decode([String].self, forKey: .splitTunnelSites)
self.splitTunnelType = try container.decode(Int.self, forKey: .splitTunnelType)
}
var str: String {
"""
[Interface]
Address = \(data.clientIP)/32
DNS = \(dns1), \(dns2)
PrivateKey = \(data.clientPrivateKey)
\(data.settings)
[Peer]
PublicKey = \(data.serverPublicKey)
PresharedKey = \(data.presharedKey)
AllowedIPs = \(data.allowedIPs.joined(separator: ", "))
Endpoint = \(data.hostName):\(data.port)
PersistentKeepalive = \(data.persistentKeepAlive)
"""
}
}
+4 -6
View File
@@ -400,10 +400,9 @@ bool IosController::setupCloak()
bool IosController::setupWireGuard()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::WireGuard)].toObject();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
QString wgConfig = config[config_key::config].toString();
return startWireGuard(wgConfig);
}
@@ -411,9 +410,8 @@ bool IosController::setupAwg()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
QString wgConfig = config[config_key::config].toString();
return startWireGuard(wgConfig);
}
+1 -3
View File
@@ -160,6 +160,7 @@
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
<file>ui/qml/Controls2/DividerType.qml</file>
<file>ui/qml/Controls2/DrawerType.qml</file>
<file>ui/qml/Controls2/StackViewType.qml</file>
<file>ui/qml/Pages2/PageSettings.qml</file>
<file>images/controls/amnezia.svg</file>
@@ -224,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
+47 -63
View File
@@ -144,7 +144,7 @@
</message>
<message>
<source>Reconnect via VPN Procotol: </source>
<translation type="vanished">پروتکل VPN را متصل مجدد کنید" </translation>
<translation type="vanished">Переподключение через VPN протокол: </translation>
</message>
</context>
<context>
@@ -371,7 +371,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="vanished">همه کاربرانی که با آن‌ها این پروتکل VPN را به اشتراک گذاشته‌اید دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="vanished">Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="280"/>
@@ -604,7 +604,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="vanished">همه کاربرانی که با آن این پروتکل VPN را به اشتراک گذاشته‌اید دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="vanished">Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolOpenVpnSettings.qml" line="369"/>
@@ -656,7 +656,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="obsolete">همه کاربرانی که با آن این پروتکل VPN را به اشتراک گذاشته‌اید دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="obsolete">Все пользователи, с которыми вы поделились этим VPN-протоколом, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolRaw.qml" line="180"/>
@@ -697,7 +697,7 @@ Already installed containers were found on the server. All installed containers
<name>PageServerContainers</name>
<message>
<source>Continue</source>
<translation type="obsolete">ادامه دهید</translation>
<translation type="obsolete">Продолжить</translation>
</message>
</context>
<context>
@@ -847,13 +847,13 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="94"/>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL. </source>
<translation>استفاده &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; برای باز کردن این نشانی.</translation>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="103"/>
<source>After creating your onion site, it takes a few minutes for the Tor network to make it available for use.</source>
<translation>پس از ایجاد سایت پیاز خود، چند دقیقه طول می‌کشد تا شبکه تور آن را برای استفاده فراهم کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this url.</source>
@@ -870,7 +870,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>When configuring WordPress set the this address as domain.</source>
<translation type="vanished">هنگام تنظیم وردپرس، این آدرس پیاز را به عنوان دامنه مشخص کنید.</translation>
<translation type="vanished">При настройке WordPress укажите этот onion адрес в качестве домена.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="126"/>
@@ -940,7 +940,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="56"/>
<source>Support Amnezia</source>
<translation>پشتیبانی از Amnezia</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="71"/>
@@ -1022,11 +1022,6 @@ Already installed containers were found on the server. All installed containers
<source>https://amnezia.org</source>
<translation>https://amnezia.org</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="176"/>
<source>Software version: %1</source>
<translation>%1 :نسخه نرم‎افزار</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="192"/>
<source>Check for updates</source>
@@ -1220,7 +1215,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="86"/>
<source>When AmneziaDNS is not used or installed</source>
<translation>وقتی AmneziaDNS استفاده نشده یا نصب نشده است.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="120"/>
@@ -1256,7 +1251,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsDns.qml" line="35"/>
<source>Default server does not support custom dns</source>
<translation>سرور پیش‌فرض از دی‌ان‌اس سفارشی پشتیبانی نمی‌کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsDns.qml" line="53"/>
@@ -1438,27 +1433,27 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="139"/>
<source>Reboot server</source>
<translation>سرور را دوباره راه‌اندازی کنید.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="143"/>
<source>Do you want to reboot the server?</source>
<translation>آیا می‌خواهید سرور را دوباره راه‌اندازی کنید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="144"/>
<source>The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?</source>
<translation>فرآیند راه‌اندازی ممکن است حدود ۳۰ ثانیه طول بکشد. آیا مطمئن هستید که می‌خواهید ادامه دهید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="175"/>
<source>Do you want to remove the server from application?</source>
<translation>آیا می‌خواهید سرور را از برنامه حذف کنید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="206"/>
<source>Do you want to clear server from Amnezia software?</source>
<translation>آیا می‌خواهید سرور را از نرم‌افزار Amnezia پاک کنید؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="171"/>
@@ -1541,7 +1536,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<source>All users who you shared a connection with will no longer be able to connect to it.</source>
<translation type="vanished">تمام کاربرانی که با آن VPN را به اشتراک گذاشته‌اید، دیگر نمی‌توانند به آن متصل شوند.</translation>
<translation type="vanished">Все пользователи, которым вы поделились VPN, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="118"/>
@@ -1567,7 +1562,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="29"/>
<source>Default server does not support split tunneling function</source>
<translation>سرور پیش‌فرض از عملکرد تونل‌سازی تقسیم شده پشتیبانی نمی‌کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Addresses from the list should be accessed via VPN</source>
@@ -1614,17 +1609,17 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="59"/>
<source>Only the sites listed here will be accessed through the VPN</source>
<translation>تنها سایت‌های موجود در اینجا از طریق VPN دسترسی داده خواهند شد.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="254"/>
<source>website or IP</source>
<translation>وب‌سایت یا آدرس IP</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="298"/>
<source>Import / Export Sites</source>
<translation>وارد کردن / صادر کردن وب‌سایت‌ها</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="304"/>
@@ -1721,7 +1716,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<name>PageSetupWizardCredentials</name>
<message>
<source>Server connection</source>
<translation type="vanished">اتصال به سرور</translation>
<translation type="vanished">Подключение к серверу</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="51"/>
@@ -1828,12 +1823,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>سرور در حال حاضر به نرمافزار اضافه شده است</translation>
</message>
<message>
<source>Amnezia has detected that your server is currently </source>
<translation type="vanished">Amnezia has detected that your server is currently </translation>
<source>Amnesia has detected that your server is currently </source>
<translation type="vanished">Amnesia обнаружила, что ваш сервер в настоящее время </translation>
</message>
<message>
<source>busy installing other software. Amnezia installation </source>
<translation type="vanished">busy installing other software. Amnezia installation</translation>
<source>busy installing other software. Amnesia installation </source>
<translation type="vanished">занят установкой других протоколов или сервисов. Установка Amnesia </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardInstalling.qml" line="67"/>
@@ -2024,7 +2019,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
</message>
<message>
<source>VPN Access</source>
<translation type="vanished">دسترسی VPN</translation>
<translation type="vanished">VPN-Доступ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="220"/>
@@ -2033,11 +2028,11 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
</message>
<message>
<source>VPN access without the ability to manage the server</source>
<translation type="vanished">دسترسی به VPN بدون امکان مدیریت سرور</translation>
<translation type="vanished">Доступ к VPN, без возможности управления сервером</translation>
</message>
<message>
<source>Access to server management. The user with whom you share full access to the connection will be able to add and remove your protocols and services to the server, as well as change settings.</source>
<translation type="vanished">دسترسی به مدیریت سرور. کاربری که با او دسترسی کامل به اتصال را به اشتراک می‌گذارید، می‌تواند پروتکل‌ها و سرویس‌های شما را در سرور اضافه و حذف کند، همچنین تنظیمات را تغییر دهد.</translation>
<translation type="vanished">Доступ к управлению сервером. Пользователь, с которым вы делитесь полным доступом к соединению, сможет добавлять и удалять ваши протоколы и службы на сервере, а также изменять настройки.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="280"/>
@@ -2137,7 +2132,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="584"/>
<source>Creation date: </source>
<translation>تاریخ ایجاد:</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="598"/>
@@ -2162,7 +2157,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="671"/>
<source>Revoke the config for a user - %1?</source>
<translation> لغو پیکربندی برای یک کاربر %1؟</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Revoke the config for a user - </source>
@@ -2737,17 +2732,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../containers/containers_defs.cpp" line="101"/>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but it may be recognized by analysis systems in some highly censored regions.</source>
<translation>شدوساکس - ترافیک VPN را پنهان می کند، به طوری که مشابه ترافیک وب عادی می شود، اما ممکن است توسط سیستم های تجزیه و تحلیل در برخی از مناطق با سانسور شدید شناسایی شود.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="104"/>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation>OpenVPN روی Cloak - OpenVPN با VPN که به عنوان ترافیک وب پنهان می‌شود و مقاومت در برابر تشخیص فعال از طریق پیشرفته. ایده‌آل برای دور زدن مسدود کردن در مناطق با بالاترین سطوح سانسور</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="122"/>
<source>Create a file vault on your server to securely store and transfer files.</source>
<translation>ساختن یک گنجانده فایل بر روی سرور شما برای ذخیره و انتقال ایمن فایل‌ها</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="155"/>
@@ -2769,23 +2764,7 @@ If there is a extreme level of Internet censorship in your region, we advise you
* Not recognised by DPI analysis systems
* Works over TCP network protocol, 443 port.
</source>
<translation>این ترکیبی از پروتکل OpenVPN و پلاگین Cloak به طور خاص برای محافظت در برابر مسدود کردن طراحی شده است.
OpenVPN ارتباط امن VPN را با رمزگذاری تمام ترافیک اینترنتی بین مشتری و سرور فراهم می‌کند.
Cloak OpenVPN را از شناسایی و مسدود کردن محافظت می‌کند.
Cloak می‌تواند اطلاعات فراداده بسته را تغییر دهد تا ترافیک VPN را به طور کامل به عنوان ترافیک وب عادی پنهان کند و همچنین VPN را از شناسایی توسط Active Probing محافظت کند. این باعث می‌شود این سیستم بسیار مقاوم در برابر شناسایی شود.
فوراً پس از دریافت اولین بسته داده، Cloak اتصال ورودی را تأیید می‌کند. اگر تأیید اعتبار ناموفق باشد، پلاگین سرور را به عنوان یک وب‌سایت جعلی پنهان می‌کند و VPN شما برای سیستم‌های تجزیه و تحلیل غیر قابل دسترسی می‌شود.
اگر در منطقه شما سطح بسیار بالایی از سانسور اینترنت وجود دارد، به شما توصیه می‌شود که از اولین اتصال فقط از OpenVPN over Cloak استفاده کنید.
در دسترس در AmneziaVPN بر روی تمام پلتفرم‌ها
مصرف بالای برق در دستگاه‌های تلفن همراه
تنظیمات انعطاف پذیر
توسط سیستم‌های تجزیه و تحلیل DPI شناخته نمی‌شود
بر روی پروتکل شبکه TCP، پورت 443 کار می‌کند.</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="174"/>
@@ -3112,6 +3091,11 @@ This means that AmneziaWG keeps the fast performance of the original while addin
</context>
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="27"/>
<source>Software version</source>
<translation>نسخه نرمافزار</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="148"/>
<source>All settings have been reset to default values</source>
@@ -3249,7 +3233,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<message>
<location filename="../ui/qml/Controls2/TextFieldWithHeaderType.qml" line="105"/>
<source>The field can&apos;t be empty</source>
<translation>این فیلد نمی‌تواند خالی باشد.</translation>
<translation>Поле не может быть пустым</translation>
</message>
</context>
<context>
@@ -3337,23 +3321,23 @@ This means that AmneziaWG keeps the fast performance of the original while addin
</message>
<message>
<source>High</source>
<translation type="vanished">بالایی</translation>
<translation type="vanished">Высокий</translation>
</message>
<message>
<source>Medium</source>
<translation type="vanished">متوسط</translation>
<translation type="vanished">Средний</translation>
</message>
<message>
<source>Many foreign websites and VPN providers are blocked</source>
<translation type="vanished">بسیاری از وب‌سایت‌ها و ارائه‌دهندگان VPN خارجی مسدود شده‌اند.</translation>
<translation type="vanished">Многие иностранные сайты и VPN-провайдеры заблокированы</translation>
</message>
<message>
<source>Some foreign sites are blocked, but VPN providers are not blocked</source>
<translation type="vanished">بعضی از وب‌سایت‌های خارجی مسدود شده‌اند، اما ارائه‌دهندگان VPN مسدود نمی‌شوند.</translation>
<translation type="vanished">Некоторые иностранные сайты заблокированы, но VPN-провайдеры не блокируются</translation>
</message>
<message>
<source>I just want to increase the level of privacy</source>
<translation type="vanished">من فقط می‌خواهم سطح حریم خصوصی خود را افزایش دهم.</translation>
<translation type="vanished">Хочу просто повысить уровень приватности</translation>
</message>
</context>
<context>
+22 -22
View File
@@ -854,11 +854,11 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL.</source>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this url.</source>
<translation type="vanished">Используйте &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; для открытия этой ссылки.</translation>
</message>
<message>
<source>After creating your onion site, it takes a few minutes for the Tor network to make it available for use.</source>
<source>After installation it takes several minutes while your onion site will become available in the Tor Network.</source>
<translation type="vanished">Через несколько минут после установки ваш Onion сайт станет доступен в сети Tor.</translation>
</message>
<message>
@@ -938,7 +938,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="56"/>
<source>Support Amnezia</source>
<translation type="unfinished">Поддержите Amnezia</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="71"/>
@@ -1020,11 +1020,6 @@ Already installed containers were found on the server. All installed containers
<source>https://amnezia.org</source>
<translation>https://amnezia.org</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="176"/>
<source>Software version: %1</source>
<translation>Версия ПО: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="192"/>
<source>Check for updates</source>
@@ -1226,7 +1221,7 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>When AmneziaDNS is not used or installed</source>
<source>If AmneziaDNS is not used or installed</source>
<translation type="vanished">Эти адреса будут использоваться, если не включен AmneziaDNS</translation>
</message>
<message>
@@ -1263,7 +1258,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsDns.qml" line="58"/>
<source>When AmneziaDNS is not used or installed</source>
<source>If AmneziaDNS is not used or installed</source>
<translation>Эти адреса будут использоваться, если не включен или не установлен AmneziaDNS</translation>
</message>
<message>
@@ -1436,27 +1431,27 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="139"/>
<source>Reboot server</source>
<translation type="unfinished">Перезагрузить сервер</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="143"/>
<source>Do you want to reboot the server?</source>
<translation type="unfinished">Вы уверены, что хотите перезагрузить сервер?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="144"/>
<source>The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?</source>
<translation type="unfinished">Процесс перезагрузки может занять около 30 секунд. Вы уверены, что хотите продолжить?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="175"/>
<source>Do you want to remove the server from application?</source>
<translation type="unfinished">Вы уверена что хотите удалить сервер из приложения?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="206"/>
<source>Do you want to clear server from Amnezia software?</source>
<translation type="unfinished">Вы хотите очистить сервер от всех сервисов Amnezia?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="171"/>
@@ -1568,7 +1563,7 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>Only the sites listed here will be accesed via VPN</source>
<source>Addresses from the list should be accessed via VPN</source>
<translation type="vanished">Только адреса из списка должны открываться через VPN</translation>
</message>
<message>
@@ -1602,11 +1597,11 @@ Already installed containers were found on the server. All installed containers
<translation>Отменить</translation>
</message>
<message>
<source>Website or IP</source>
<source>Site or IP</source>
<translation type="vanished">Сайт или IP</translation>
</message>
<message>
<source>Import / Export Sites</source>
<source>Import/Export Sites</source>
<translation type="vanished">Импорт/экспорт Сайтов</translation>
</message>
<message>
@@ -2131,7 +2126,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="584"/>
<source>Creation date: </source>
<translation type="unfinished">Дата создания</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="598"/>
@@ -2813,11 +2808,11 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<translation>OpenVPN - популярный VPN-протокол, с гибкой настройкой. Имеет собственный протокол безопасности с SSL/TLS для обмена ключами.</translation>
</message>
<message>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but it may be recognized by analysis systems in some highly censored regions.</source>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but is recognised by analysis systems in some highly censored regions.</source>
<translation type="vanished">ShadowSocks - маскирует VPN-трафик под обычный веб-трафик, но распознается системами анализа в некоторых регионах с высоким уровнем цензуры.</translation>
</message>
<message>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probbing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="vanished">OpenVPN over Cloak - OpenVPN с маскировкой VPN под web-трафик и защитой от обнаружения active-probbing. Подходит для регионов с самым высоким уровнем цензуры.</translation>
</message>
<message>
@@ -2846,7 +2841,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<translation>Замените DNS-сервер на Amnezia DNS. Это повысит уровень конфиденциальности.</translation>
</message>
<message>
<source>Create a file vault on your server to securely store and transfer files.</source>
<source>Creates a file vault on your server to securely store and transfer files.</source>
<translation type="vanished">Создайте на сервере файловое хранилище для безопасного хранения и передачи файлов.</translation>
</message>
<message>
@@ -3063,6 +3058,11 @@ This means that AmneziaWG keeps the fast performance of the original while addin
</context>
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="27"/>
<source>Software version</source>
<translation>Версия ПО</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="148"/>
<source>All settings have been reset to default values</source>
+40 -48
View File
@@ -200,7 +200,7 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/controllers/installController.cpp" line="305"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation type="unfinished"> &apos;%1&apos; </translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="314"/>
@@ -891,10 +891,10 @@ Already installed containers were found on the server. All installed containers
<message>
<location filename="../ui/qml/Pages2/PageServiceTorWebsiteSettings.qml" line="103"/>
<source>After creating your onion site, it takes a few minutes for the Tor network to make it available for use.</source>
<translation>使Tor网络上可用</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this URL.</source>
<source>Use &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor Browser&lt;/a&gt; to open this url.</source>
<translation type="vanished"> &lt;a href=&quot;https://www.torproject.org/download/&quot; style=&quot;color: #FBB26A;&quot;&gt;Tor 浏览器&lt;/a&gt; 打开上面网址</translation>
</message>
<message>
@@ -984,7 +984,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="56"/>
<source>Support Amnezia</source>
<translation>Amnezia</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="71"/>
@@ -1067,11 +1067,6 @@ And if you don&apos;t like the app, all the more support it - the donation will
<source>https://amnezia.org</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="176"/>
<source>Software version: %1</source>
<translation>: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="192"/>
<source>Check for updates</source>
@@ -1266,7 +1261,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="86"/>
<source>When AmneziaDNS is not used or installed</source>
<translation>使AmneziaDNS时</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="120"/>
@@ -1484,12 +1479,12 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="143"/>
<source>Do you want to reboot the server?</source>
<translation type="unfinished"></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="206"/>
<source>Do you want to clear server from Amnezia software?</source>
<translation>Amnezia软件吗</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="92"/>
@@ -1525,12 +1520,12 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="139"/>
<source>Reboot server</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="144"/>
<source>The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?</source>
<translation> 30</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="171"/>
@@ -1540,7 +1535,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="175"/>
<source>Do you want to remove the server from application?</source>
<translation type="unfinished"></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remove server?</source>
@@ -1711,17 +1706,17 @@ And if you don&apos;t like the app, all the more support it - the donation will
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="59"/>
<source>Only the sites listed here will be accessed through the VPN</source>
<translation>VPN访问</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="254"/>
<source>website or IP</source>
<translation>IP</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="298"/>
<source>Import / Export Sites</source>
<translation>/</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsSplitTunneling.qml" line="304"/>
@@ -2143,12 +2138,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="120"/>
<source>ShadowSocks native format</source>
<translation>ShadowSocks原生格式</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="125"/>
<source>Cloak native format</source>
<translation>Cloak原生格式</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="150"/>
@@ -2158,18 +2153,18 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="178"/>
<source>Share full access to the server and VPN</source>
<translation>VPN的完全访问权限</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="179"/>
<source>Use for your own devices, or share with those you trust to manage the server.</source>
<translation type="unfinished"></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="486"/>
<source>Users</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="251"/>
@@ -2204,17 +2199,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="668"/>
<source>Revoke</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="671"/>
<source>Revoke the config for a user - %1?</source>
<translation>- %1?</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="672"/>
<source>The user will no longer be able to connect to your server.</source>
<translation type="unfinished"></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="673"/>
@@ -2300,12 +2295,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="34"/>
<source>Config revoked</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="262"/>
<source>User name</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="429"/>
@@ -2325,7 +2320,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="49"/>
<source>Full access to the server and VPN</source>
<translation>VPN的完全访问权限</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="57"/>
@@ -2336,7 +2331,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="58"/>
<source>If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. </source>
<translation>访VPN对所有用户的工作出现问题</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="73"/>
@@ -2827,7 +2822,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>The config does not contain any containers and credentials for connecting to the server</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>The config does not contain any containers and credentiaks for connecting to the server</source>
@@ -2836,7 +2831,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>Internal error</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="88"/>
@@ -2867,17 +2862,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../containers/containers_defs.cpp" line="101"/>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but it may be recognized by analysis systems in some highly censored regions.</source>
<translation>ShadowSocks - VPN流量使</translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="104"/>
<source>OpenVPN over Cloak - OpenVPN with masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="unfinished">OpenVPN over Cloak - OpenVPN与VPN结合Web流量</translation>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="122"/>
<source>Create a file vault on your server to securely store and transfer files.</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="155"/>
@@ -2912,23 +2907,15 @@ WireGuard is very susceptible to blocking due to its distinct packet signatures.
* Minimum number of settings
* Easily recognised by DPI analysis systems, susceptible to blocking
* Works over UDP network protocol.</source>
<translation>VPN协议
WireGuard提供稳定的VPN连接使OpenVPN相比WireGuard具有较低的延迟和更好的数据传输吞吐量
WireGuard非常容易被阻挡VPN协议不同使WireGuard数据包的一致签名模式更容易被高级深度数据包检测DPI
AmneziaVPN上适用于所有平台
DPI分析系统识别
UDP网络协议运行</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but is recognised by analysis systems in some highly censored regions.</source>
<translation type="vanished">ShadowSocks - VPN 使 Web </translation>
</message>
<message>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="vanished">OpenVPN over Cloak - OpenVPN与VPN结合Web流量</translation>
<source>OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probbing detection. Ideal for bypassing blocking in regions with the highest levels of censorship.</source>
<translation type="vanished">OpenVPN over Cloak - OpenVPN VPN </translation>
</message>
<message>
<location filename="../containers/containers_defs.cpp" line="108"/>
@@ -3211,6 +3198,11 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
</context>
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="27"/>
<source>Software version</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="132"/>
<source>Backup file is corrupted</source>
@@ -3254,7 +3246,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<message>
<location filename="../ui/qml/Components/ShareConnectionDrawer.qml" line="128"/>
<source>Copy config string</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Components/ShareConnectionDrawer.qml" line="150"/>
+4 -15
View File
@@ -70,17 +70,14 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
void ApiController::updateServerConfigFromApi()
{
QtConcurrent::run([this]() {
if (m_isConfigUpdateStarted) {
emit updateFinished(false);
return;
}
auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray();
bool isConfigUpdateStarted = false;
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
emit updateStarted();
m_isConfigUpdateStarted = true;
isConfigUpdateStarted = true;
QNetworkAccessManager manager;
@@ -113,12 +110,6 @@ void ApiController::updateServerConfigFromApi()
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
@@ -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;
});
}
-2
View File
@@ -39,8 +39,6 @@ private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
bool m_isConfigUpdateStarted = false;
};
#endif // APICONTROLLER_H
+30
View File
@@ -118,6 +118,36 @@ void PageController::showOnStartup()
}
}
void PageController::updateDrawerRootPage(PageLoader::PageEnum page)
{
m_drawerLayer = 0;
m_currentRootPage = page;
}
void PageController::goToDrawerRootPage()
{
m_drawerLayer = 0;
emit showTopCloseButton(false);
emit forceCloseDrawer();
}
void PageController::drawerOpen()
{
m_drawerLayer = m_drawerLayer + 1;
emit showTopCloseButton(true);
}
void PageController::drawerClose()
{
m_drawerLayer = m_drawerLayer -1;
if (m_drawerLayer <= 0) {
emit showTopCloseButton(false);
m_drawerLayer = 0;
}
}
bool PageController::isTriggeredByConnectButton()
{
return m_isTriggeredByConnectButton;
+11
View File
@@ -82,6 +82,11 @@ public slots:
void showOnStartup();
void updateDrawerRootPage(PageLoader::PageEnum page);
void goToDrawerRootPage();
void drawerOpen();
void drawerClose();
bool isTriggeredByConnectButton();
void setTriggeredBtConnectButton(bool trigger);
@@ -113,11 +118,17 @@ signals:
void showPassphraseRequestDrawer();
void passphraseRequestDrawerClosed(QString passphrase);
void showTopCloseButton(bool visible);
void forceCloseDrawer();
private:
QSharedPointer<ServersModel> m_serversModel;
std::shared_ptr<Settings> m_settings;
PageLoader::PageEnum m_currentRootPage;
int m_drawerLayer;
bool m_isTriggeredByConnectButton;
};
+1 -1
View File
@@ -28,7 +28,7 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
m_sitesModel(sitesModel),
m_settings(settings)
{
m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH);
m_appVersion = QString("%1: %2 (%3)").arg(tr("Software version"), QString(APP_VERSION), __DATE__);
#ifdef Q_OS_ANDROID
if (!m_settings->isScreenshotsEnabled()) {
-3
View File
@@ -45,7 +45,6 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
case LanguageSettings::AvailableLanguageEnum::Russian: strLanguage = "Русский"; break;
case LanguageSettings::AvailableLanguageEnum::China_cn: strLanguage = "\347\256\200\344\275\223\344\270\255\346\226\207"; break;
case LanguageSettings::AvailableLanguageEnum::Persian: strLanguage = "فارسی"; break;
case LanguageSettings::AvailableLanguageEnum::Arabic: strLanguage = "العربية"; break;
default:
break;
}
@@ -60,7 +59,6 @@ void LanguageModel::changeLanguage(const LanguageSettings::AvailableLanguageEnum
case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break;
case LanguageSettings::AvailableLanguageEnum::China_cn: emit updateTranslations(QLocale::Chinese); break;
case LanguageSettings::AvailableLanguageEnum::Persian: emit updateTranslations(QLocale::Persian); break;
case LanguageSettings::AvailableLanguageEnum::Arabic: emit updateTranslations(QLocale::Arabic); break;
default: emit updateTranslations(QLocale::English); break;
}
}
@@ -73,7 +71,6 @@ int LanguageModel::getCurrentLanguageIndex()
case QLocale::Russian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Russian); break;
case QLocale::Chinese: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::China_cn); break;
case QLocale::Persian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Persian); break;
case QLocale::Arabic: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Arabic); break;
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
}
}
+1 -2
View File
@@ -13,8 +13,7 @@ namespace LanguageSettings
English,
Russian,
China_cn,
Persian,
Arabic
Persian
};
Q_ENUM_NS(AvailableLanguageEnum)
+1 -21
View File
@@ -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;
}
-5
View File
@@ -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;
-1
View File
@@ -113,7 +113,6 @@ void SitesModel::toggleSplitTunneling(bool enabled)
m_settings->setRouteMode(Settings::RouteMode::VpnAllSites);
}
m_isSplitTunnelingEnabled = enabled;
emit splitTunnelingToggled();
}
QVector<QPair<QString, QString> > SitesModel::getCurrentSites()
-2
View File
@@ -22,7 +22,6 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_PROPERTY(int routeMode READ getRouteMode WRITE setRouteMode NOTIFY routeModeChanged)
Q_PROPERTY(bool isTunnelingEnabled READ isSplitTunnelingEnabled NOTIFY splitTunnelingToggled)
public slots:
bool addSite(const QString &hostname, const QString &ip);
@@ -39,7 +38,6 @@ public slots:
signals:
void routeModeChanged();
void splitTunnelingToggled();
protected:
QHash<int, QByteArray> roleNames() const override;
+4 -2
View File
@@ -138,7 +138,9 @@ Button {
}
onClicked: {
ServersModel.setProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi()
if (!ConnectionController.isConnectionInProgress) {
ServersModel.setCurrentlyProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi()
}
}
}
@@ -8,24 +8,18 @@ import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
DrawerType {
id: root
width: parent.width
height: parent.height
expandedContent: ColumnLayout {
id: content
height: parent.height * 0.4375
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Component.onCompleted: {
root.expandedHeight = content.implicitHeight + 32
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
@@ -46,7 +40,7 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.close()
root.visible = false
}
}
@@ -60,7 +54,7 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.close()
root.visible = false
}
}
@@ -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
}
}
}
+10 -17
View File
@@ -5,7 +5,7 @@ import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType2 {
DrawerType {
id: root
property string headerText
@@ -16,24 +16,23 @@ DrawerType2 {
property var yesButtonFunction
property var noButtonFunction
expandedContent: ColumnLayout {
width: parent.width
height: content.implicitHeight + 32
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 8
onImplicitHeightChanged: {
root.expandedHeight = content.implicitHeight + 32
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: headerText
}
@@ -41,8 +40,6 @@ DrawerType2 {
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.rightMargin: 16
Layout.leftMargin: 16
text: descriptionText
}
@@ -50,12 +47,10 @@ DrawerType2 {
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: yesButtonText
clickedFunc: function() {
onClicked: {
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
@@ -64,8 +59,6 @@ DrawerType2 {
BasicButtonType {
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
@@ -76,7 +69,7 @@ DrawerType2 {
text: noButtonText
clickedFunc: function() {
onClicked: {
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
@@ -5,136 +5,129 @@ import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType2 {
DrawerType {
id: root
expandedContent: Item {
id: container
width: parent.width
height: parent.height * 0.9
implicitHeight: root.height * 0.9
ColumnLayout {
id: backButton
Component.onCompleted: {
root.expandedHeight = container.implicitHeight
}
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
ColumnLayout {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
}
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
}
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
ColumnLayout {
id: content
ColumnLayout {
id: content
anchors.fill: parent
anchors.fill: parent
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Choose language")
headerText: qsTr("Choose language")
}
ListView {
id: listView
Layout.fillWidth: true
height: listView.contentItem.height
clip: true
interactive: false
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
ButtonGroup {
id: buttonGroup
}
ListView {
id: listView
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
Layout.fillWidth: true
height: listView.contentItem.height
ColumnLayout {
id: delegateContent
clip: true
interactive: false
anchors.fill: parent
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
RadioButton {
id: radioButton
ButtonGroup {
id: buttonGroup
}
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
hoverEnabled: true
ColumnLayout {
id: delegateContent
indicator: Rectangle {
anchors.fill: parent
color: radioButton.hovered ? "#2C2D30" : "#1C1D21"
anchors.fill: parent
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
RadioButton {
id: radioButton
RowLayout {
id: radioButtonContent
anchors.fill: parent
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
anchors.rightMargin: 16
anchors.leftMargin: 16
hoverEnabled: true
spacing: 0
indicator: Rectangle {
anchors.fill: parent
color: radioButton.hovered ? "#2C2D30" : "#1C1D21"
z: 1
Behavior on color {
PropertyAnimation { duration: 200 }
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
RowLayout {
id: radioButtonContent
anchors.fill: parent
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
anchors.rightMargin: 16
anchors.leftMargin: 16
width: 24
height: 24
spacing: 0
z: 1
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
width: 24
height: 24
Layout.rightMargin: 8
}
Layout.rightMargin: 8
}
}
ButtonGroup.group: buttonGroup
checked: listView.currentIndex === index
ButtonGroup.group: buttonGroup
checked: listView.currentIndex === index
onClicked: {
listView.currentIndex = index
LanguageModel.changeLanguage(languageIndex)
root.close()
}
onClicked: {
listView.currentIndex = index
LanguageModel.changeLanguage(languageIndex)
root.close()
}
}
}
@@ -16,18 +16,19 @@ import "../Controls2/TextTypes"
import "../Config"
import "../Components"
DrawerType2 {
DrawerType {
id: root
property string headerText
property string configContentHeaderText
property string contentVisible
property alias headerText: header.headerText
property alias configContentHeaderText: configContentHeader.headerText
property alias contentVisible: content.visible
property string configExtension: ".vpn"
property string configCaption: qsTr("Save AmneziaVPN config")
property string configFileName: "amnezia_config"
expandedHeight: parent.height * 0.9
width: parent.width
height: parent.height * 0.9
onClosed: {
configExtension = ".vpn"
@@ -35,8 +36,8 @@ DrawerType2 {
configFileName = "amnezia_config"
}
expandedContent: Item {
implicitHeight: root.expandedHeight
Item {
anchors.fill: parent
Header2Type {
id: header
@@ -46,8 +47,6 @@ DrawerType2 {
anchors.topMargin: 20
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: root.headerText
}
FlickableType {
@@ -65,8 +64,6 @@ DrawerType2 {
anchors.leftMargin: 16
anchors.rightMargin: 16
visible: root.contentVisible
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
@@ -74,7 +71,7 @@ DrawerType2 {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
clickedFunc: function() {
onClicked: {
var fileName = ""
if (GC.isMobile()) {
fileName = configFileName + configExtension
@@ -94,7 +91,6 @@ DrawerType2 {
}
BasicButtonType {
id: copyConfigTextButton
Layout.fillWidth: true
Layout.topMargin: 8
@@ -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"
}
}
}
+27 -81
View File
@@ -16,39 +16,47 @@ Button {
property string textColor: "#0E0E11"
property string borderColor: "#D7D8DB"
property string borderFocusedColor: "#D7D8DB"
property int borderWidth: 0
property int borderFocusedWidth: 1
property string imageSource
property string rightImageSource
property string leftImageColor: textColor
property bool squareLeftSide: false
property var clickedFunc
implicitHeight: 56
hoverEnabled: true
background: Rectangle {
id: background_border
color: "transparent"
border.color: root.activeFocus ? root.borderFocusedColor : "transparent"
border.width: root.activeFocus ? root.borderFocusedWidth : "transparent"
id: background
anchors.fill: parent
radius: 16
color: {
if (root.enabled) {
if (root.pressed) {
return pressedColor
}
return root.hovered ? hoveredColor : defaultColor
} else {
return disabledColor
}
}
border.color: borderColor
border.width: borderWidth
Behavior on color {
PropertyAnimation { duration: 200 }
}
Rectangle {
id: background
visible: root.squareLeftSide
anchors.fill: background_border
anchors.margins: root.activeFocus ? 2: 0
z: 1
radius: 16
width: parent.radius
height: parent.radius
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
color: {
if (root.enabled) {
if (root.pressed) {
@@ -59,53 +67,24 @@ Button {
return disabledColor
}
}
border.color: root.activeFocus ? "transparent" : borderColor
border.width: root.activeFocus ? 0 : borderWidth
Behavior on color {
PropertyAnimation { duration: 200 }
}
Rectangle {
visible: root.squareLeftSide
z: 1
width: parent.radius
height: parent.radius
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
color: {
if (root.enabled) {
if (root.pressed) {
return pressedColor
}
return root.hovered ? hoveredColor : defaultColor
} else {
return disabledColor
}
}
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
}
}
MouseArea {
anchors.fill: background_border
anchors.fill: background
enabled: false
cursorShape: Qt.PointingHandCursor
}
contentItem: Item {
anchors.fill: background_border
anchors.fill: background
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.centerIn: parent
@@ -120,7 +99,7 @@ Button {
layer {
enabled: true
effect: ColorOverlay {
color: leftImageColor
color: textColor
}
}
}
@@ -133,39 +112,6 @@ Button {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
Image {
Layout.preferredHeight: 20
Layout.preferredWidth: 20
source: root.rightImageSource
visible: root.rightImageSource === "" ? false : true
layer {
enabled: true
effect: ColorOverlay {
color: textColor
}
}
}
}
}
Keys.onEnterPressed: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
Keys.onReturnPressed: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
onClicked: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
}
+84
View File
@@ -0,0 +1,84 @@
import QtQuick
import QtQuick.Controls
import "../Config"
Drawer {
id: drawer
property bool needCloseButton: true
Connections {
target: PageController
function onForceCloseDrawer() {
visible = false
}
}
edge: Qt.BottomEdge
clip: true
modal: true
dragMargin: -10
enter: Transition {
SmoothedAnimation {
velocity: 4
}
}
exit: Transition {
SmoothedAnimation {
velocity: 4
}
}
background: Rectangle {
anchors.fill: parent
anchors.bottomMargin: -radius
radius: 16
color: "#1C1D21"
border.color: "#2C2D30"
border.width: 1
Rectangle {
visible: GC.isMobile()
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 10
width: 20
height: 2
color: "#2C2D30"
}
}
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
onAboutToShow: {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
}
onOpened: {
if (needCloseButton) {
PageController.drawerOpen()
}
}
onClosed: {
if (needCloseButton) {
PageController.drawerClose()
}
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
}
}
-242
View File
@@ -1,242 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "TextTypes"
Item {
id: root
readonly property string drawerExpanded: "expanded"
readonly property string drawerCollapsed: "collapsed"
readonly property bool isOpened: drawerContent.state === root.drawerExpanded || (drawerContent.state === root.drawerCollapsed && dragArea.drag.active === true)
readonly property bool isClosed: drawerContent.state === root.drawerCollapsed && dragArea.drag.active === false
readonly property bool isExpanded: drawerContent.state === root.drawerExpanded
readonly property bool isCollapsed: drawerContent.state === root.drawerCollapsed
property Component collapsedContent
property Component expandedContent
property string defaultColor: "#1C1D21"
property string borderColor: "#2C2D30"
property real expandedHeight
property real collapsedHeight: 0
signal entered
signal exited
signal pressed(bool pressed, bool entered)
signal aboutToHide
signal aboutToShow
signal close
signal open
signal closed
signal opened
Connections {
target: root
function onClose() {
if (isCollapsed) {
return
}
aboutToHide()
drawerContent.state = root.drawerCollapsed
closed()
}
function onOpen() {
if (isExpanded) {
return
}
aboutToShow()
drawerContent.state = root.drawerExpanded
opened()
}
}
/** Set once based on first implicit height change once all children are layed out */
Component.onCompleted: {
if (root.isCollapsed && root.collapsedHeight == 0) {
root.collapsedHeight = drawerContent.implicitHeight
}
}
Rectangle {
id: background
anchors.fill: parent
color: root.isCollapsed ? "transparent" : Qt.rgba(14/255, 14/255, 17/255, 0.8)
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
MouseArea {
id: emptyArea
anchors.fill: parent
enabled: root.isExpanded
visible: enabled
onClicked: {
root.close()
}
}
MouseArea {
id: dragArea
anchors.fill: drawerContentBackground
cursorShape: root.isCollapsed ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
enabled: drawerContent.implicitHeight > 0
drag.target: drawerContent
drag.axis: Drag.YAxis
drag.maximumY: root.height - root.collapsedHeight
drag.minimumY: root.height - root.expandedHeight
/** If drag area is released at any point other than min or max y, transition to the other state */
onReleased: {
if (root.isCollapsed && drawerContent.y < dragArea.drag.maximumY) {
root.open()
return
}
if (root.isExpanded && drawerContent.y > dragArea.drag.minimumY) {
root.close()
return
}
}
onEntered: {
root.entered()
}
onExited: {
root.exited()
}
onPressedChanged: {
root.pressed(pressed, entered)
}
onClicked: {
if (root.isCollapsed) {
root.open()
}
}
}
Rectangle {
id: drawerContentBackground
anchors { left: drawerContent.left; right: drawerContent.right; top: drawerContent.top }
height: root.height
radius: 16
color: root.defaultColor
border.color: root.borderColor
border.width: 1
Rectangle {
width: parent.radius
height: parent.radius
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
color: parent.color
}
}
Item {
id: drawerContent
Drag.active: dragArea.drag.active
anchors.right: root.right
anchors.left: root.left
y: root.height - drawerContent.height
state: root.drawerCollapsed
implicitHeight: root.isCollapsed ? collapsedLoader.implicitHeight : expandedLoader.implicitHeight
onStateChanged: {
if (root.isCollapsed) {
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
return
}
if (root.isExpanded) {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
return
}
}
states: [
State {
name: root.drawerCollapsed
PropertyChanges {
target: drawerContent
y: root.height - root.collapsedHeight
}
},
State {
name: root.drawerExpanded
PropertyChanges {
target: drawerContent
y: dragArea.drag.minimumY
}
}
]
transitions: [
Transition {
from: root.drawerCollapsed
to: root.drawerExpanded
PropertyAnimation {
target: drawerContent
properties: "y"
duration: 200
}
},
Transition {
from: root.drawerExpanded
to: root.drawerCollapsed
PropertyAnimation {
target: drawerContent
properties: "y"
duration: 200
}
}
]
Loader {
id: collapsedLoader
visible: root.isCollapsed
sourceComponent: root.collapsedContent
anchors.right: parent.right
anchors.left: parent.left
}
Loader {
id: expandedLoader
visible: root.isExpanded
sourceComponent: root.expandedContent
anchors.right: parent.right
anchors.left: parent.left
}
}
}
+43 -55
View File
@@ -36,23 +36,19 @@ Item {
property int rootButtonTextBottomMargin: 16
property real drawerHeight: 0.9
property Item drawerParent
property Component listView
signal open
signal close
property alias menuVisible: menu.visible
implicitWidth: rootButtonContent.implicitWidth
implicitHeight: rootButtonContent.implicitHeight
onOpen: {
menu.open()
rootButtonBackground.border.color = rootButtonPressedBorderColor
}
onClose: {
menu.close()
rootButtonBackground.border.color = rootButtonDefaultBorderColor
onMenuVisibleChanged: {
if (menuVisible) {
rootButtonBackground.border.color = rootButtonPressedBorderColor
} else {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
}
}
onEnabledChanged: {
@@ -137,21 +133,21 @@ Item {
hoverEnabled: root.enabled ? true : false
onEntered: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.border.color = rootButtonHoveredBorderColor
rootButtonBackground.color = rootButtonBackgroundHoveredColor
}
}
onExited: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
rootButtonBackground.color = rootButtonBackgroundColor
}
}
onPressed: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.color = pressed ? rootButtonBackgroundPressedColor : entered ? rootButtonHoveredBorderColor : rootButtonDefaultBorderColor
}
}
@@ -160,68 +156,60 @@ Item {
if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") {
rootButtonClickedFunction()
} else {
menu.open()
menu.visible = true
}
}
}
DrawerType2 {
DrawerType {
id: menu
parent: drawerParent
width: parent.width
height: parent.height * drawerHeight
anchors.fill: parent
expandedHeight: drawerParent.height * drawerHeight
ColumnLayout {
id: header
expandedContent: Item {
id: container
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
implicitHeight: menu.expandedHeight
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
root.menuVisible = false
}
}
}
ColumnLayout {
id: header
FlickableType {
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
menu.close()
}
}
}
spacing: 16
FlickableType {
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
Column {
id: col
anchors.top: parent.top
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16
headerText: root.headerText
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
width: parent.width
}
headerText: root.headerText
width: parent.width
}
Loader {
id: listViewLoader
sourceComponent: root.listView
}
Loader {
id: listViewLoader
sourceComponent: root.listView
}
}
}
-15
View File
@@ -7,8 +7,6 @@ Item {
property StackView stackView: StackView.view
property var defaultActiveFocusItem: null
// MouseArea {
// id: globalMouseArea
// z: 99
@@ -21,17 +19,4 @@ Item {
// mouse.accepted = false
// }
// }
// Set a timer to set focus after a short delay
Timer {
id: timer
interval: 100 // Milliseconds
onTriggered: {
if (defaultActiveFocusItem) {
defaultActiveFocusItem.forceActiveFocus()
}
}
repeat: false // Stop the timer after one trigger
running: true // Start the timer
}
}
+1 -1
View File
@@ -66,7 +66,7 @@ Popup {
borderWidth: 0
text: qsTr("Close")
clickedFunc: function() {
onClicked: {
root.close()
}
}
@@ -69,13 +69,10 @@ Item {
TextField {
id: textField
activeFocusOnTab: false
enabled: root.textFieldEditable
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
placeholderText: root.textFieldPlaceholderText
placeholderTextColor: "#494B50"
@@ -145,7 +142,7 @@ Item {
Layout.preferredWidth: content.implicitHeight
squareLeftSide: true
clickedFunc: function() {
onClicked: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
@@ -189,12 +186,4 @@ Item {
function getBackgroundBorderColor(noneFocusedColor) {
return textField.focus ? root.borderFocusedColor : noneFocusedColor
}
Keys.onEnterPressed: {
KeyNavigation.tab.forceActiveFocus();
}
Keys.onReturnPressed: {
KeyNavigation.tab.forceActiveFocus();
}
}
+390 -306
View File
@@ -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
}
}
}
+59 -60
View File
@@ -90,77 +90,71 @@ PageType {
DividerType {}
DrawerType2 {
DrawerType {
id: configContentDrawer
expandedHeight: root.height * 0.9
width: parent.width
height: parent.height * 0.9
parent: root
anchors.fill: parent
BackButtonType {
id: backButton
expandedContent: Item {
implicitHeight: configContentDrawer.expandedHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.close()
}
backButtonFunction: function() {
configContentDrawer.visible = false
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
ColumnLayout {
id: configContent
ColumnLayout {
id: configContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Connection options %1").arg(protocolName)
}
headerText: qsTr("Connection options %1").arg(protocolName)
}
TextArea {
id: configText
TextArea {
id: configText
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
padding: 0
leftPadding: 0
height: 24
padding: 0
leftPadding: 0
height: 24
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
text: rawConfig
text: rawConfig
wrapMode: Text.Wrap
wrapMode: Text.Wrap
background: Rectangle {
color: "transparent"
}
background: Rectangle {
color: "transparent"
}
}
}
@@ -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
}
}
}
+4 -6
View File
@@ -81,7 +81,7 @@ PageType {
text: qsTr("Card on Patreon")
clickedFunc: function() {
onClicked: function() {
Qt.openUrlExternally(qsTr("https://www.patreon.com/amneziavpn"))
}
}
@@ -101,9 +101,7 @@ PageType {
text: qsTr("Show other methods on Github")
clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate"))
}
onClicked: Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate"))
}
ParagraphTextType {
@@ -175,7 +173,7 @@ PageType {
horizontalAlignment: Text.AlignHCenter
text: qsTr("Software version: %1").arg(SettingsController.getAppVersion())
text: SettingsController.getAppVersion()
color: "#878B91"
}
@@ -193,7 +191,7 @@ PageType {
text: qsTr("Check for updates")
clickedFunc: function() {
onClicked: {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
@@ -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
}
}
+14 -9
View File
@@ -88,7 +88,7 @@ PageType {
text: qsTr("Make a backup")
clickedFunc: function() {
onClicked: {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN.backup"
@@ -121,7 +121,7 @@ PageType {
text: qsTr("Restore from backup")
clickedFunc: function() {
onClicked: {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
@@ -133,19 +133,24 @@ PageType {
}
function restoreBackup(filePath) {
var headerText = qsTr("Import settings from a backup file?")
var descriptionText = qsTr("All current settings will be reset");
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Import settings from a backup file?")
questionDrawer.descriptionText = qsTr("All current settings will be reset");
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
QuestionDrawer {
id: questionDrawer
}
}
+13 -18
View File
@@ -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
}
}
}
+12 -7
View File
@@ -143,20 +143,21 @@ PageType {
image: "qrc:/images/controls/delete.svg"
onClicked: function() {
var headerText = qsTr("Clear logs?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Clear logs?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
SettingsController.clearLogs()
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs have been cleaned up"))
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -169,6 +170,10 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
}
+50 -41
View File
@@ -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
}
}
}
}
+13 -26
View File
@@ -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
+3 -2
View File
@@ -158,7 +158,7 @@ PageType {
text: qsTr("Continue")
clickedFunc: function() {
onClicked: function() {
if (root.isEasySetup) {
ContainersModel.setCurrentlyProcessedContainerIndex(containers.dockerContainer)
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
@@ -192,12 +192,13 @@ PageType {
return ContainersModel.isAnyContainerInstalled()
}
return true
}
text: qsTr("Set up later")
clickedFunc: function() {
onClicked: function() {
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.addEmptyServer()
}
@@ -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()
}
}
+50 -60
View File
@@ -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) {
+11 -9
View File
@@ -69,7 +69,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server")
headerText: qsTr("Server")
@@ -100,7 +99,7 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
serverSelector.close()
serverSelector.menuVisible = false
}
Component.onCompleted: {
@@ -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
}
}
+36 -10
View File
@@ -20,16 +20,22 @@ PageType {
function onGoToPageHome() {
tabBar.setCurrentIndex(0)
tabBarStackView.goToTabBarPage(PageEnum.PageHome)
PageController.updateDrawerRootPage(PageEnum.PageHome)
}
function onGoToPageSettings() {
tabBar.setCurrentIndex(2)
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
PageController.updateDrawerRootPage(PageEnum.PageSettings)
}
function onGoToPageViewConfig() {
var pagePath = PageController.getPagePath(PageEnum.PageSetupWizardViewConfig)
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
PageController.updateDrawerRootPage(PageEnum.PageSetupWizardViewConfig)
}
function onShowBusyIndicator(visible) {
@@ -38,14 +44,15 @@ PageType {
tabBar.enabled = !visible
}
// function onShowTopCloseButton(visible) {
// topCloseButton.visible = visible
// }
function onEnableTabBar(enabled) {
tabBar.enabled = enabled
}
function onClosePage() {
tabBar.isServerInfoShow = tabBarStackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageSettingsServerInfo)
&& tabBarStackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageSettingsSplitTunneling)
if (tabBarStackView.depth <= 1) {
return
}
@@ -54,14 +61,13 @@ PageType {
function onGoToPage(page, slide) {
var pagePath = PageController.getPagePath(page)
if (slide) {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
} else {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.Immediate)
}
tabBar.isServerInfoShow = page === PageEnum.PageSettingsServerInfo || PageEnum.PageSettingsSplitTunneling || tabBar.isServerInfoShow
PageController.updateDrawerRootPage(page)
}
function onGoToStartPage() {
@@ -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
View File
@@ -8,7 +8,6 @@ import PageEnum 1.0
import "Config"
import "Controls2"
import "Components"
Window {
id: root
@@ -131,15 +130,32 @@ Window {
}
Item {
anchors.fill: parent
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
DrawerType2 {
implicitHeight: popupErrorMessage.height
DrawerType {
id: privateKeyPassphraseDrawer
anchors.fill: parent
expandedHeight: root.height * 0.35
width: root.width
height: root.height * 0.35
expandedContent: ColumnLayout {
onVisibleChanged: {
if (privateKeyPassphraseDrawer.visible) {
passphrase.textFieldText = ""
passphrase.textField.forceActiveFocus()
}
}
onAboutToHide: {
PageController.showBusyIndicator(true)
}
onAboutToShow: {
PageController.showBusyIndicator(false)
}
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -147,24 +163,6 @@ Window {
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: privateKeyPassphraseDrawer
function onOpened() {
passphrase.textFieldText = ""
passphrase.textField.forceActiveFocus()
}
function onAboutToHide() {
if (passphrase.textFieldText !== "") {
PageController.showBusyIndicator(true)
}
}
function onAboutToShow() {
PageController.showBusyIndicator(false)
}
}
TextFieldWithHeaderType {
id: passphrase
@@ -178,13 +176,9 @@ Window {
clickedFunc: function() {
hidePassword = !hidePassword
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
defaultColor: "transparent"
@@ -196,7 +190,7 @@ Window {
text: qsTr("Save")
clickedFunc: function() {
onClicked: {
privateKeyPassphraseDrawer.close()
PageController.passphraseRequestDrawerClosed(passphrase.textFieldText)
}
@@ -205,37 +199,6 @@ Window {
}
}
Item {
anchors.fill: parent
QuestionDrawer {
id: questionDrawer
anchors.fill: parent
}
}
function showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) {
questionDrawer.headerText = headerText
questionDrawer.descriptionText = descriptionText
questionDrawer.yesButtonText = yesButtonText
questionDrawer.noButtonText = noButtonText
questionDrawer.yesButtonFunction = function() {
questionDrawer.close()
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
}
questionDrawer.noButtonFunction = function() {
questionDrawer.close()
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
}
questionDrawer.open()
}
FileDialog {
id: mainFileDialog