Compare commits

...

26 Commits

Author SHA1 Message Date
vladimir.kuznetsov
bbcf928a66 added tab navigation to the share connection drawer 2024-02-19 19:17:24 +05:00
pokamest
a32952fde6 Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText for
all TextFields
2024-02-19 14:06:18 +00:00
isamnezia
9c4ee4014d Fix for Codacy: variable name should be between 3 and 40 characters long (#608)
Tiny fixes for iOS
2024-02-19 13:13:10 +00:00
pokamest
e402cacc05 Merge pull request #614 from amnezia-vpn/bugfix/translations
returned translation files to commit fab167bb34a9f7199359e3d8589a1cd1…
2024-02-19 02:23:39 -08:00
vladimir.kuznetsov
a98cd248d6 returned translation files to commit fab167bb34 2024-02-19 09:31:31 +05:00
pokamest
00fbfb6a01 Merge pull request #611 from amnezia-vpn/refactoring/show-installed-containers-first
show installed protocols first
2024-02-18 11:10:37 -08:00
vladimir.kuznetsov
86c31c3766 show installed protocols first in services tab and page home containers listview 2024-02-18 13:24:21 +05:00
agalehaga
698cfe910c add navigation using enter + buttons will be clicked if enter (if but… (#556)
Enter navigation
2024-02-17 21:09:05 +00:00
pokamest
16db23c159 Rewrite sftp file copy to Qt way (#562)
Rewrite sftp file copy to Qt way
2024-02-17 21:07:17 +00:00
Andrey Zaharow
b05a5ee1c6 fix connection button behavior (#595)
Fix connection button behavior
2024-02-17 19:57:31 +00:00
pokamest
8cb298937f Merge pull request #604 from amnezia-vpn/KsZnak-ru_translate
Update amneziavpn_ru.ts
2024-02-17 11:52:18 -08:00
Andrey Zaharow
68fe20ddf6 UI fixes (#596)
UI fixes
2024-02-17 19:48:41 +00:00
KsZnak
fab167bb34 Update amneziavpn_ru.ts 2024-02-17 20:29:25 +02:00
isamnezia
f640d4b5f5 Remove config string dependency (#577)
Remove WG/AWG config string dependency
2024-02-16 10:30:00 +00:00
Nethius
074562b141 feature/custom-drawer (#563)
Replaced all the DrawerType with DrawerType2
2024-02-16 10:24:06 +00:00
Shehab Ahmed
fd030a5fd4 Arabic translation (#594)
added Arabic translation
2024-02-16 10:19:47 +00:00
albexk
82fa6b13c6 Fix foreground service type (#592)
Fix foreground service type
2024-02-14 16:35:40 +00:00
pokamest
bf16298c40 Version bump - 4.4.0.0 2024-02-13 21:10:47 +00:00
pokamest
bcebb0a2b5 Merge pull request #580 from amnezia-vpn/feature/update-cloak-binary
Update AWG and Cloak libraries
2024-02-13 12:03:02 -08:00
pokamest
b27442cf74 Merge pull request #583 from amnezia-vpn/bugfix/double_clear_server_from_amnezia
fixed bug with double button clear server from amnezia software
2024-02-13 07:50:35 -08:00
Nethius
92fbbd4812 bugfix/default-container-index (#578)
fixed get/set DefaultContainer
2024-02-13 15:20:13 +00:00
agalehaga
321ed810e3 fixed bug with double button clear server from amnezia software 2024-02-13 15:16:04 +02:00
albexk
17ff530683 Merge branch 'fix/android' into feature/update-cloak-binary 2024-02-13 12:32:36 +03:00
pokamest
a416d03614 Merge pull request #581 from amnezia-vpn/fix/amn-go-version
Update amneziawg-apple to amneziawg-go v0.2.1
2024-02-12 13:08:19 -08:00
Igor Sorokin
4de9a274dd Update amneziawg-apple to amneziawg-go v0.2.1 2024-02-12 23:25:11 +03:00
Mykola Baibuz
0b8f3c9d9d Update Cloak binary to v2.8.0 2024-02-12 21:01:44 +02:00
72 changed files with 5119 additions and 1556 deletions

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.3.0.0
project(${PROJECT} VERSION 4.4.0.0
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 44)
set(APP_ANDROID_VERSION_CODE 46)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")

View File

@@ -57,6 +57,7 @@ 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)

View File

@@ -290,9 +290,6 @@ void AmneziaApplication::initModels()
m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
connect(m_serversModel.get(), &ServersModel::containersUpdated, m_containersModel.get(),
&ContainersModel::updateModel);
connect(m_serversModel.get(), &ServersModel::defaultContainerChanged, m_containersModel.get(),
&ContainersModel::setDefaultContainer);
m_containersModel->setDefaultContainer(m_serversModel->getDefaultContainer()); // make better?
m_languageModel.reset(new LanguageModel(m_settings, this));
m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
@@ -388,7 +385,13 @@ 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]() { 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](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);
}

View File

@@ -22,7 +22,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Enable when VPN-per-app mode will be implemented -->
@@ -137,14 +137,13 @@
android:name=".AmneziaVpnService"
android:process=":amneziaVpnService"
android:permission="android.permission.BIND_VPN_SERVICE"
android:foregroundServiceType="specialUse"
android:exported="false">
android:foregroundServiceType="systemExempted"
android:exported="false"
tools:ignore="ForegroundServicePermission">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="vpn" />
</service>
<provider

View File

@@ -4,7 +4,7 @@ import android.app.Notification
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
import android.net.VpnService
import android.os.Build
import android.os.Handler
@@ -156,7 +156,7 @@ class AmneziaVpnService : VpnService() {
*/
private val foregroundServiceTypeCompat
get() = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SPECIAL_USE
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> FOREGROUND_SERVICE_TYPE_MANIFEST
else -> 0
}

View File

@@ -211,13 +211,7 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
localFile.write(data);
localFile.close();
#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
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
if (error != ErrorCode::NoError) {
return error;

View File

@@ -222,7 +222,7 @@ namespace libssh {
return fromLibsshErrorCode();
}
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const std::string& localPath, const std::string& remotePath, const std::string& fileDesc)
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const QString& localPath, const QString& remotePath, const QString &fileDesc)
{
m_sftpSession = sftp_new(m_session);
@@ -245,40 +245,38 @@ namespace libssh {
const size_t bufferSize = 16384;
char buffer[bufferSize];
file = sftp_open(m_sftpSession, remotePath.c_str(), accessType, S_IRWXU);
file = sftp_open(m_sftpSession, remotePath.toStdString().c_str(), accessType, S_IRWXU);
if (file == nullptr) {
return closeSftpSession();
}
int localFileSize = std::filesystem::file_size(localPath);
int localFileSize = QFileInfo(localPath).size();
int chunksCount = localFileSize / (bufferSize);
std::ifstream fin(localPath, std::ios::binary | std::ios::in);
QFile fin(localPath);
if (fin.is_open()) {
if (fin.open(QIODevice::ReadOnly)) {
for (int currentChunkId = 0; currentChunkId < chunksCount; currentChunkId++) {
fin.read(buffer, bufferSize);
QByteArray chunk = fin.read(bufferSize);
if (chunk.size() != bufferSize) return ErrorCode::SshSftpEofError;
int bytesWritten = sftp_write(file, buffer, bufferSize);
int bytesWritten = sftp_write(file, chunk.data(), chunk.size());
std::string chunk(buffer, bufferSize);
if (bytesWritten != bufferSize) {
if (bytesWritten != chunk.size()) {
fin.close();
sftp_close(file);
return closeSftpSession();
}
}
int lastChunkSize = localFileSize % (bufferSize);
int lastChunkSize = localFileSize % bufferSize;
if (lastChunkSize != 0) {
fin.read(buffer, lastChunkSize);
QByteArray lastChunk = fin.read(lastChunkSize);
if (lastChunk.size() != lastChunkSize) return ErrorCode::SshSftpEofError;
std::string chunk(buffer, lastChunkSize);
int bytesWritten = sftp_write(file, buffer, lastChunkSize);
int bytesWritten = sftp_write(file, lastChunk.data(), lastChunkSize);
if (bytesWritten != lastChunkSize) {
fin.close();

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 std::string& localPath,
const std::string& remotePath,
const std::string& fileDesc);
const QString &localPath,
const QString &remotePath,
const QString& fileDesc);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
private:
ErrorCode closeChannel();

View File

@@ -85,6 +85,7 @@ 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
)

View File

@@ -59,10 +59,6 @@ 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)
@@ -71,7 +67,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let completionHandler = completionHandler else {
guard let completionHandler else {
log(.error, message: "Missing message completion handler")
return
}
@@ -179,14 +175,16 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
let wgConfigStr = String(data: wgConfig, encoding: .utf8)!
guard let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr) else {
guard let wgConfigStr = try? JSONDecoder().decode(WGConfig.self, from: wgConfig).str,
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" {

View File

@@ -0,0 +1,135 @@
import Foundation
struct WGConfigData: Decodable {
let initPacketMagicHeader, responsePacketMagicHeader: String?
let underloadPacketMagicHeader, transportPacketMagicHeader: String?
let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String?
let initPacketJunkSize, responsePacketJunkSize: String?
var settings: String {
junkPacketCount == nil ? "" :
"""
Jc = \(junkPacketCount!)
Jmin = \(junkPacketMinSize!)
Jmax = \(junkPacketMaxSize!)
S1 = \(initPacketJunkSize!)
S2 = \(responsePacketJunkSize!)
H1 = \(initPacketMagicHeader!)
H2 = \(responsePacketMagicHeader!)
H3 = \(underloadPacketMagicHeader!)
H4 = \(transportPacketMagicHeader!)
"""
}
let clientIP: String
let clientPrivateKey: String
let clientPublicKey: String
let serverPublicKey: String
let presharedKey: String
let hostName: String
let port: Int
var allowedIPs: [String]
var persistentKeepAlive: String
enum CodingKeys: String, CodingKey {
case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2"
case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4"
case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax"
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2"
case clientIP = "client_ip" // "10.8.1.16"
case clientPrivateKey = "client_priv_key"
case clientPublicKey = "client_pub_key"
case serverPublicKey = "server_pub_key"
case presharedKey = "psk_key"
case allowedIPs = "allowed_ips"
case persistentKeepAlive = "persistent_keep_alive"
case hostName
case port
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.initPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .initPacketMagicHeader)
self.responsePacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .responsePacketMagicHeader)
self.underloadPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .underloadPacketMagicHeader)
self.transportPacketMagicHeader = try container.decodeIfPresent(String.self, forKey: .transportPacketMagicHeader)
self.junkPacketCount = try container.decodeIfPresent(String.self, forKey: .junkPacketCount)
self.junkPacketMinSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMinSize)
self.junkPacketMaxSize = try container.decodeIfPresent(String.self, forKey: .junkPacketMaxSize)
self.initPacketJunkSize = try container.decodeIfPresent(String.self, forKey: .initPacketJunkSize)
self.responsePacketJunkSize = try container.decodeIfPresent(String.self, forKey: .responsePacketJunkSize)
self.clientIP = try container.decode(String.self, forKey: .clientIP)
self.clientPrivateKey = try container.decode(String.self, forKey: .clientPrivateKey)
self.clientPublicKey = try container.decode(String.self, forKey: .clientPublicKey)
self.serverPublicKey = try container.decode(String.self, forKey: .serverPublicKey)
self.presharedKey = try container.decode(String.self, forKey: .presharedKey)
self.allowedIPs = try container.decodeIfPresent([String].self, forKey: .allowedIPs) ?? ["0.0.0.0/0", "::/0"]
self.persistentKeepAlive = try container.decodeIfPresent(String.self, forKey: .persistentKeepAlive) ?? "25"
self.hostName = try container.decode(String.self, forKey: .hostName)
self.port = try container.decode(Int.self, forKey: .port)
}
}
struct WGConfig: Decodable {
let data: WGConfigData
let configVersion: Int
let description: String
let dns1: String
let dns2: String
let hostName: String
let `protocol`: String
let splitTunnelSites: [String]
let splitTunnelType: Int
enum CodingKeys: String, CodingKey {
case awgConfigData = "awg_config_data", wgConfigData = "wireguard_config_data"
case configData
case configVersion = "config_version"
case description
case dns1
case dns2
case hostName
case `protocol`
case splitTunnelSites
case splitTunnelType
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if container.contains(.awgConfigData) {
self.data = try container.decode(WGConfigData.self, forKey: .awgConfigData)
} else {
self.data = try container.decode(WGConfigData.self, forKey: .wgConfigData)
}
self.configVersion = try container.decode(Int.self, forKey: .configVersion)
self.description = try container.decode(String.self, forKey: .description)
self.dns1 = try container.decode(String.self, forKey: .dns1)
self.dns2 = try container.decode(String.self, forKey: .dns2)
self.hostName = try container.decode(String.self, forKey: .hostName)
self.protocol = try container.decode(String.self, forKey: .protocol)
self.splitTunnelSites = try container.decode([String].self, forKey: .splitTunnelSites)
self.splitTunnelType = try container.decode(Int.self, forKey: .splitTunnelType)
}
var str: String {
"""
[Interface]
Address = \(data.clientIP)/32
DNS = \(dns1), \(dns2)
PrivateKey = \(data.clientPrivateKey)
\(data.settings)
[Peer]
PublicKey = \(data.serverPublicKey)
PresharedKey = \(data.presharedKey)
AllowedIPs = \(data.allowedIPs.joined(separator: ", "))
Endpoint = \(data.hostName):\(data.port)
PersistentKeepalive = \(data.persistentKeepAlive)
"""
}
}

View File

@@ -400,9 +400,10 @@ bool IosController::setupCloak()
bool IosController::setupWireGuard()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::WireGuard)].toObject();
QString wgConfig = config[config_key::config].toString();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
return startWireGuard(wgConfig);
}
@@ -410,8 +411,9 @@ bool IosController::setupAwg()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject();
QString wgConfig = config[config_key::config].toString();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
return startWireGuard(wgConfig);
}

View File

@@ -160,7 +160,6 @@
<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>
@@ -225,5 +224,6 @@
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>images/controls/close.svg</file>
<file>images/controls/search.svg</file>
<file>ui/qml/Controls2/DrawerType2.qml</file>
</qresource>
</RCC>

File diff suppressed because it is too large Load Diff

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 installation it takes several minutes while your onion site will become available in the Tor Network.</source>
<source>After creating your onion site, it takes a few minutes for the Tor network to make it available for use.</source>
<translation type="vanished">Через несколько минут после установки ваш Onion сайт станет доступен в сети Tor.</translation>
</message>
<message>
@@ -1202,7 +1202,7 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="70"/>
<source>If AmneziaDNS is installed on the server</source>
<source>When AmneziaDNS is installed on the server</source>
<translation>Если он уставновлен на сервере</translation>
</message>
<message>
@@ -1221,7 +1221,7 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>If AmneziaDNS is not used or installed</source>
<source>When AmneziaDNS is not used or installed</source>
<translation type="vanished">Эти адреса будут использоваться, если не включен AmneziaDNS</translation>
</message>
<message>
@@ -1258,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>If AmneziaDNS is not used or installed</source>
<source>When AmneziaDNS is not used or installed</source>
<translation>Эти адреса будут использоваться, если не включен или не установлен AmneziaDNS</translation>
</message>
<message>
@@ -1431,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"></translation>
<translation type="unfinished">Процесс перезагрузки может занять около 30 секунд. Вы уверены, что хотите продолжить?</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"></translation>
<translation type="unfinished">Вы хотите очистить сервер от всех сервисов Amnezia?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerData.qml" line="171"/>
@@ -1563,7 +1563,7 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</message>
<message>
<source>Addresses from the list should be accessed via VPN</source>
<source>Only the sites listed here will be accesed via VPN</source>
<translation type="vanished">Только адреса из списка должны открываться через VPN</translation>
</message>
<message>
@@ -1597,11 +1597,11 @@ Already installed containers were found on the server. All installed containers
<translation>Отменить</translation>
</message>
<message>
<source>Site or IP</source>
<source>Website 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>
@@ -2126,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"/>
@@ -2808,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 is recognised by analysis systems in some highly censored regions.</source>
<source>ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but it may be 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-probbing 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-probing 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>
@@ -2841,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>Creates a file vault on your server to securely store and transfer files.</source>
<source>Create a file vault on your server to securely store and transfer files.</source>
<translation type="vanished">Создайте на сервере файловое хранилище для безопасного хранения и передачи файлов.</translation>
</message>
<message>

View File

@@ -70,14 +70,17 @@ 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();
isConfigUpdateStarted = true;
m_isConfigUpdateStarted = true;
QNetworkAccessManager manager;
@@ -110,6 +113,12 @@ 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;
@@ -133,11 +142,13 @@ void ApiController::updateServerConfigFromApi()
qDebug() << reply->error();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
}
emit updateFinished(isConfigUpdateStarted);
emit updateFinished(m_isConfigUpdateStarted);
m_isConfigUpdateStarted = false;
return;
});
}

View File

@@ -39,6 +39,8 @@ private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
bool m_isConfigUpdateStarted = false;
};
#endif // APICONTROLLER_H

View File

@@ -33,7 +33,7 @@ void ConnectionController::openConnection()
int serverIndex = m_serversModel->getDefaultServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = m_containersModel->getDefaultContainer();
DockerContainer container = m_serversModel->getDefaultContainer(serverIndex);
const QJsonObject &containerConfig = m_containersModel->getContainerConfig(container);
if (container == DockerContainer::None) {

View File

@@ -284,7 +284,7 @@ void InstallController::updateContainer(QJsonObject config)
m_protocolModel->updateModel(config);
if ((serverIndex == m_serversModel->getDefaultServerIndex())
&& (container == m_containersModel->getDefaultContainer())) {
&& (container == m_serversModel->getDefaultContainer(serverIndex))) {
emit currentContainerUpdated();
} else {
emit updateContainerFinished(tr("Settings updated successfully"));

View File

@@ -118,36 +118,6 @@ void PageController::showOnStartup()
}
}
void PageController::updateDrawerRootPage(PageLoader::PageEnum page)
{
m_drawerLayer = 0;
m_currentRootPage = page;
}
void PageController::goToDrawerRootPage()
{
m_drawerLayer = 0;
emit showTopCloseButton(false);
emit forceCloseDrawer();
}
void PageController::drawerOpen()
{
m_drawerLayer = m_drawerLayer + 1;
emit showTopCloseButton(true);
}
void PageController::drawerClose()
{
m_drawerLayer = m_drawerLayer -1;
if (m_drawerLayer <= 0) {
emit showTopCloseButton(false);
m_drawerLayer = 0;
}
}
bool PageController::isTriggeredByConnectButton()
{
return m_isTriggeredByConnectButton;

View File

@@ -82,11 +82,6 @@ public slots:
void showOnStartup();
void updateDrawerRootPage(PageLoader::PageEnum page);
void goToDrawerRootPage();
void drawerOpen();
void drawerClose();
bool isTriggeredByConnectButton();
void setTriggeredBtConnectButton(bool trigger);
@@ -118,17 +113,11 @@ 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;
};

View File

@@ -39,7 +39,6 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const
case EasySetupOrderRole: return ContainerProps::easySetupOrder(container);
case IsInstalledRole: return m_containers.contains(container);
case IsCurrentlyProcessedRole: return container == static_cast<DockerContainer>(m_currentlyProcessedContainerIndex);
case IsDefaultRole: return container == m_defaultContainerIndex;
case IsSupportedRole: return ContainerProps::isSupportedByCurrentPlatform(container);
case IsShareableRole: return ContainerProps::isShareable(container);
}
@@ -64,18 +63,6 @@ void ContainersModel::updateModel(const QJsonArray &containers)
endResetModel();
}
void ContainersModel::setDefaultContainer(const int containerIndex)
{
m_defaultContainerIndex = static_cast<DockerContainer>(containerIndex);
emit dataChanged(index(containerIndex, 0), index(containerIndex, 0));
}
DockerContainer ContainersModel::getDefaultContainer()
{
return m_defaultContainerIndex;
}
void ContainersModel::setCurrentlyProcessedContainerIndex(int index)
{
m_currentlyProcessedContainerIndex = index;
@@ -127,7 +114,6 @@ QHash<int, QByteArray> ContainersModel::roleNames() const
roles[IsInstalledRole] = "isInstalled";
roles[IsCurrentlyProcessedRole] = "isCurrentlyProcessed";
roles[IsDefaultRole] = "isDefault";
roles[IsSupportedRole] = "isSupported";
roles[IsShareableRole] = "isShareable";
return roles;

View File

@@ -42,9 +42,6 @@ public:
public slots:
void updateModel(const QJsonArray &containers);
DockerContainer getDefaultContainer();
void setDefaultContainer(const int containerIndex);
void setCurrentlyProcessedContainerIndex(int containerIndex);
int getCurrentlyProcessedContainerIndex();
@@ -58,14 +55,12 @@ protected:
QHash<int, QByteArray> roleNames() const override;
signals:
void defaultContainerChanged();
void containersModelUpdated();
private:
QMap<DockerContainer, QJsonObject> m_containers;
int m_currentlyProcessedContainerIndex;
DockerContainer m_defaultContainerIndex;
};
#endif // CONTAINERS_MODEL_H

View File

@@ -45,6 +45,7 @@ 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;
}
@@ -59,6 +60,7 @@ 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;
}
}
@@ -71,6 +73,7 @@ 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;
}
}

View File

@@ -13,7 +13,8 @@ namespace LanguageSettings
English,
Russian,
China_cn,
Persian
Persian,
Arabic
};
Q_ENUM_NS(AvailableLanguageEnum)

View File

@@ -403,23 +403,23 @@ void ServersModel::addContainerConfig(const int containerIndex, const QJsonObjec
}
}
void ServersModel::setDefaultContainer(const int containerIndex)
void ServersModel::setDefaultContainer(const int serverIndex, const int containerIndex)
{
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject s = m_servers.at(m_currentlyProcessedServerIndex).toObject();
QJsonObject s = m_servers.at(serverIndex).toObject();
s.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
editServer(s); //check
emit defaultContainerChanged(container);
}
DockerContainer ServersModel::getDefaultContainer()
DockerContainer ServersModel::getDefaultContainer(const int serverIndex)
{
return qvariant_cast<DockerContainer>(data(m_currentlyProcessedServerIndex, DefaultContainerRole));
return qvariant_cast<DockerContainer>(data(serverIndex, DefaultContainerRole));
}
const QString ServersModel::getDefaultContainerName()
{
auto defaultContainer = getDefaultContainer();
auto defaultContainer = getDefaultContainer(m_defaultServerIndex);
return ContainerProps::containerHumanNames().value(defaultContainer);
}

View File

@@ -91,8 +91,8 @@ public slots:
ErrorCode removeAllContainers();
ErrorCode rebootServer();
void setDefaultContainer(const int containerIndex);
DockerContainer getDefaultContainer();
void setDefaultContainer(const int serverIndex, const int containerIndex);
DockerContainer getDefaultContainer(const int serverIndex);
const QString getDefaultContainerName();
QStringList getAllInstalledServicesName(const int serverIndex);

View File

@@ -138,8 +138,7 @@ Button {
}
onClicked: {
if (!ConnectionController.isConnectionInProgress) {
ApiController.updateServerConfigFromApi()
}
ServersModel.setCurrentlyProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi()
}
}

View File

@@ -8,18 +8,24 @@ import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType {
DrawerType2 {
id: root
width: parent.width
height: parent.height * 0.4375
height: parent.height
expandedContent: ColumnLayout {
id: content
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
@@ -40,7 +46,7 @@ DrawerType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.visible = false
root.close()
}
}
@@ -54,7 +60,7 @@ DrawerType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.visible = false
root.close()
}
}

View File

@@ -26,24 +26,6 @@ ListView {
id: containersRadioButtonGroup
}
Connections {
target: ServersModel
function onCurrentlyProcessedServerIndexChanged() {
if (ContainersModel.getDefaultContainer()) {
menuContent.checkCurrentItem()
}
}
}
function checkCurrentItem() {
var item = menuContent.itemAtIndex(currentIndex)
if (item !== null) {
var radioButton = item.children[0].children[0]
radioButton.checked = true
}
}
delegate: Item {
implicitWidth: rootWidth
implicitHeight: content.implicitHeight
@@ -69,7 +51,7 @@ ListView {
showImage: !isInstalled
checkable: isInstalled && !ConnectionController.isConnected && isSupported
checked: isDefault
checked: proxyContainersModel.mapToSource(index) === ServersModel.getDefaultContainer(ServersModel.defaultIndex)
onClicked: {
if (ConnectionController.isConnected && isInstalled) {
@@ -78,8 +60,8 @@ ListView {
}
if (checked) {
containersDropDown.menuVisible = false
ServersModel.setDefaultContainer(proxyContainersModel.mapToSource(index))
containersDropDown.close()
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyContainersModel.mapToSource(index))
} else {
if (!isSupported && isInstalled) {
PageController.showErrorMessage(qsTr("The selected protocol is not supported on the current platform"))
@@ -89,7 +71,7 @@ ListView {
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.menuVisible = false
containersDropDown.close()
}
}

View File

@@ -5,7 +5,7 @@ import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType {
DrawerType2 {
id: root
property string headerText
@@ -16,23 +16,24 @@ DrawerType {
property var yesButtonFunction
property var noButtonFunction
width: parent.width
height: content.implicitHeight + 32
ColumnLayout {
expandedContent: 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
}
@@ -40,6 +41,8 @@ DrawerType {
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.rightMargin: 16
Layout.leftMargin: 16
text: descriptionText
}
@@ -47,10 +50,12 @@ DrawerType {
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: yesButtonText
onClicked: {
clickedFunc: function() {
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
@@ -59,6 +64,8 @@ DrawerType {
BasicButtonType {
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
@@ -69,7 +76,7 @@ DrawerType {
text: noButtonText
onClicked: {
clickedFunc: function() {
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}

View File

@@ -5,129 +5,136 @@ import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
DrawerType {
DrawerType2 {
id: root
width: parent.width
height: parent.height * 0.9
expandedContent: Item {
id: container
ColumnLayout {
id: backButton
implicitHeight: root.height * 0.9
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()
}
Component.onCompleted: {
root.expandedHeight = container.implicitHeight
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
ColumnLayout {
id: content
id: backButton
anchors.fill: parent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Choose language")
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
}
}
}
ListView {
id: listView
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Layout.fillWidth: true
height: listView.contentItem.height
ColumnLayout {
id: content
clip: true
interactive: false
anchors.fill: parent
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
ButtonGroup {
id: buttonGroup
headerText: qsTr("Choose language")
}
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
ListView {
id: listView
ColumnLayout {
id: delegateContent
Layout.fillWidth: true
height: listView.contentItem.height
anchors.fill: parent
clip: true
interactive: false
RadioButton {
id: radioButton
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
ButtonGroup {
id: buttonGroup
}
hoverEnabled: true
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
indicator: Rectangle {
anchors.fill: parent
color: radioButton.hovered ? "#2C2D30" : "#1C1D21"
ColumnLayout {
id: delegateContent
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
anchors.fill: parent
RowLayout {
id: radioButtonContent
anchors.fill: parent
RadioButton {
id: radioButton
anchors.rightMargin: 16
anchors.leftMargin: 16
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
spacing: 0
hoverEnabled: true
z: 1
indicator: Rectangle {
anchors.fill: parent
color: radioButton.hovered ? "#2C2D30" : "#1C1D21"
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
RowLayout {
id: radioButtonContent
anchors.fill: parent
width: 24
height: 24
anchors.rightMargin: 16
anchors.leftMargin: 16
Layout.rightMargin: 8
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
}
}
}
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()
}
}
}
}

View File

@@ -16,19 +16,18 @@ import "../Controls2/TextTypes"
import "../Config"
import "../Components"
DrawerType {
DrawerType2 {
id: root
property alias headerText: header.headerText
property alias configContentHeaderText: configContentHeader.headerText
property alias contentVisible: content.visible
property string headerText
property string configContentHeaderText
property string contentVisible
property string configExtension: ".vpn"
property string configCaption: qsTr("Save AmneziaVPN config")
property string configFileName: "amnezia_config"
width: parent.width
height: parent.height * 0.9
expandedHeight: parent.height * 0.9
onClosed: {
configExtension = ".vpn"
@@ -36,8 +35,16 @@ DrawerType {
configFileName = "amnezia_config"
}
Item {
anchors.fill: parent
expandedContent: Item {
implicitHeight: root.expandedHeight
Connections {
target: root
function onOpened() {
header.forceActiveFocus()
}
}
Header2Type {
id: header
@@ -47,6 +54,10 @@ DrawerType {
anchors.topMargin: 20
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: root.headerText
KeyNavigation.tab: shareButton
}
FlickableType {
@@ -64,14 +75,19 @@ DrawerType {
anchors.leftMargin: 16
anchors.rightMargin: 16
visible: root.contentVisible
BasicButtonType {
id: shareButton
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
onClicked: {
KeyNavigation.tab: copyConfigTextButton
clickedFunc: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = configFileName + configExtension
@@ -91,6 +107,7 @@ DrawerType {
}
BasicButtonType {
id: copyConfigTextButton
Layout.fillWidth: true
Layout.topMargin: 8
@@ -104,19 +121,15 @@ DrawerType {
text: qsTr("Copy")
imageSource: "qrc:/images/controls/copy.svg"
onClicked: {
configText.selectAll()
configText.copy()
configText.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
KeyNavigation.tab: copyNativeConfigStringButton.visible ? copyNativeConfigStringButton : showSettingsButton
}
BasicButtonType {
id: copyNativeConfigStringButton
Layout.fillWidth: true
Layout.topMargin: 8
visible: nativeConfigString.text !== ""
visible: false
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
@@ -128,15 +141,12 @@ DrawerType {
text: qsTr("Copy config string")
imageSource: "qrc:/images/controls/copy.svg"
onClicked: {
nativeConfigString.selectAll()
nativeConfigString.copy()
nativeConfigString.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
KeyNavigation.tab: showSettingsButton
}
BasicButtonType {
id: showSettingsButton
Layout.fillWidth: true
Layout.topMargin: 24
@@ -149,83 +159,119 @@ DrawerType {
text: qsTr("Show connection settings")
onClicked: {
configContentDrawer.visible = true
clickedFunc: function() {
configContentDrawer.open()
}
KeyNavigation.tab: header
}
DrawerType {
DrawerType2 {
id: configContentDrawer
width: parent.width
height: parent.height * 0.9
parent: root.parent
BackButtonType {
id: backButton
anchors.fill: parent
expandedHeight: parent.height * 0.9
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
expandedContent: Item {
id: configContentContainer
backButtonFunction: function() {
configContentDrawer.visible = false
implicitHeight: configContentDrawer.expandedHeight
Connections {
target: copyNativeConfigStringButton
function onClicked() {
nativeConfigString.selectAll()
nativeConfigString.copy()
nativeConfigString.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
Connections {
target: copyConfigTextButton
function onClicked() {
configText.selectAll()
configText.copy()
configText.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
TextField {
id: nativeConfigString
visible: false
text: ExportController.nativeConfigString
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.open()
}
}
TextArea {
id: configText
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
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
ColumnLayout {
id: configContent
padding: 0
leftPadding: 0
height: 24
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
readOnly: true
Header2Type {
id: configContentHeader
Layout.fillWidth: true
Layout.topMargin: 16
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
headerText: root.configContentHeaderText
}
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
TextField {
id: nativeConfigString
visible: false
text: ExportController.nativeConfigString
text: ExportController.config
onTextChanged: {
copyNativeConfigStringButton.visible = nativeConfigString.text !== ""
}
}
wrapMode: Text.Wrap
TextArea {
id: configText
background: Rectangle {
color: "transparent"
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"
}
}
}
}

View File

@@ -16,47 +16,38 @@ 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 bool squareLeftSide: false
property var clickedFunc
implicitHeight: 56
hoverEnabled: true
background: Rectangle {
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
id: focusBorder
Behavior on color {
PropertyAnimation { duration: 200 }
}
color: "transparent"
border.color: root.activeFocus ? root.borderFocusedColor : "transparent"
border.width: root.activeFocus ? root.borderFocusedWidth : "transparent"
anchors.fill: parent
radius: 16
Rectangle {
visible: root.squareLeftSide
id: background
z: 1
anchors.fill: focusBorder
anchors.margins: root.activeFocus ? 2 : 0
width: parent.radius
height: parent.radius
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
radius: root.activeFocus ? 14 : 16
color: {
if (root.enabled) {
if (root.pressed) {
@@ -67,24 +58,53 @@ Button {
return disabledColor
}
}
border.color: borderColor
border.width: 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
anchors.fill: focusBorder
enabled: false
cursorShape: Qt.PointingHandCursor
}
contentItem: Item {
anchors.fill: background
anchors.fill: focusBorder
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.centerIn: parent
@@ -114,4 +134,22 @@ Button {
}
}
}
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()
}
}
}

View File

@@ -1,84 +0,0 @@
import QtQuick
import QtQuick.Controls
import "../Config"
Drawer {
id: drawer
property bool needCloseButton: true
Connections {
target: PageController
function onForceCloseDrawer() {
visible = false
}
}
edge: Qt.BottomEdge
clip: true
modal: true
dragMargin: -10
enter: Transition {
SmoothedAnimation {
velocity: 4
}
}
exit: Transition {
SmoothedAnimation {
velocity: 4
}
}
background: Rectangle {
anchors.fill: parent
anchors.bottomMargin: -radius
radius: 16
color: "#1C1D21"
border.color: "#2C2D30"
border.width: 1
Rectangle {
visible: GC.isMobile()
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 10
width: 20
height: 2
color: "#2C2D30"
}
}
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
onAboutToShow: {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
}
onOpened: {
if (needCloseButton) {
PageController.drawerOpen()
}
}
onClosed: {
if (needCloseButton) {
PageController.drawerClose()
}
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
}
}

View File

@@ -0,0 +1,241 @@
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
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
}
}
}

View File

@@ -36,19 +36,23 @@ Item {
property int rootButtonTextBottomMargin: 16
property real drawerHeight: 0.9
property Item drawerParent
property Component listView
property alias menuVisible: menu.visible
signal open
signal close
implicitWidth: rootButtonContent.implicitWidth
implicitHeight: rootButtonContent.implicitHeight
onMenuVisibleChanged: {
if (menuVisible) {
rootButtonBackground.border.color = rootButtonPressedBorderColor
} else {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
}
onOpen: {
menu.open()
rootButtonBackground.border.color = rootButtonPressedBorderColor
}
onClose: {
menu.close()
rootButtonBackground.border.color = rootButtonDefaultBorderColor
}
onEnabledChanged: {
@@ -133,21 +137,21 @@ Item {
hoverEnabled: root.enabled ? true : false
onEntered: {
if (menu.visible === false) {
if (menu.isClosed) {
rootButtonBackground.border.color = rootButtonHoveredBorderColor
rootButtonBackground.color = rootButtonBackgroundHoveredColor
}
}
onExited: {
if (menu.visible === false) {
if (menu.isClosed) {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
rootButtonBackground.color = rootButtonBackgroundColor
}
}
onPressed: {
if (menu.visible === false) {
if (menu.isClosed) {
rootButtonBackground.color = pressed ? rootButtonBackgroundPressedColor : entered ? rootButtonHoveredBorderColor : rootButtonDefaultBorderColor
}
}
@@ -156,60 +160,68 @@ Item {
if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") {
rootButtonClickedFunction()
} else {
menu.visible = true
menu.open()
}
}
}
DrawerType {
DrawerType2 {
id: menu
width: parent.width
height: parent.height * drawerHeight
parent: drawerParent
ColumnLayout {
id: header
anchors.fill: parent
expandedHeight: drawerParent.height * drawerHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
expandedContent: Item {
id: container
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
root.menuVisible = false
}
}
}
implicitHeight: menu.expandedHeight
FlickableType {
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
ColumnLayout {
id: header
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
spacing: 16
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
menu.close()
}
}
}
Header2Type {
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.leftMargin: 16
anchors.rightMargin: 16
headerText: root.headerText
spacing: 16
width: parent.width
}
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
Loader {
id: listViewLoader
sourceComponent: root.listView
headerText: root.headerText
width: parent.width
}
Loader {
id: listViewLoader
sourceComponent: root.listView
}
}
}
}

View File

@@ -7,6 +7,8 @@ Item {
property StackView stackView: StackView.view
property var defaultActiveFocusItem: null
// MouseArea {
// id: globalMouseArea
// z: 99
@@ -19,4 +21,17 @@ 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
}
}

View File

@@ -66,7 +66,7 @@ Popup {
borderWidth: 0
text: qsTr("Close")
onClicked: {
clickedFunc: function() {
root.close()
}
}

View File

@@ -69,10 +69,13 @@ 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"
@@ -142,7 +145,7 @@ Item {
Layout.preferredWidth: content.implicitHeight
squareLeftSide: true
onClicked: {
clickedFunc: function() {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
@@ -186,4 +189,12 @@ Item {
function getBackgroundBorderColor(noneFocusedColor) {
return textField.focus ? root.borderFocusedColor : noneFocusedColor
}
Keys.onEnterPressed: {
KeyNavigation.tab.forceActiveFocus();
}
Keys.onReturnPressed: {
KeyNavigation.tab.forceActiveFocus();
}
}

View File

@@ -18,484 +18,358 @@ import "../Components"
PageType {
id: root
property string defaultColor: "#1C1D21"
property string borderColor: "#2C2D30"
Connections {
target: PageController
function onRestorePageHomeState(isContainerInstalled) {
buttonContent.state = "expanded"
drawer.open()
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: buttonContent.collapsedHeight
anchors.bottomMargin: drawer.collapsedHeight
ConnectButton {
anchors.centerIn: parent
}
}
MouseArea {
id: dragArea
anchors.fill: buttonBackground
cursorShape: buttonContent.state === "collapsed" ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
DrawerType2 {
id: drawer
anchors.fill: parent
drag.target: buttonContent
drag.axis: Drag.YAxis
drag.maximumY: root.height - buttonContent.collapsedHeight
drag.minimumY: root.height - root.height * 0.9
/** 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
}
}
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
}
onClicked: {
if (buttonContent.state === "collapsed") {
buttonContent.state = "expanded"
}
}
}
Rectangle {
id: buttonBackground
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
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 }
}
}
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: 16
Layout.rightMargin: 16
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
}
LabelTextType {
id: expandedServersMenuDescription
Layout.bottomMargin: 24
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionExpanded
collapsedContent: ColumnLayout {
DividerType {
Layout.topMargin: 10
Layout.fillWidth: false
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
RowLayout {
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8
DropDownType {
id: containersDropDown
spacing: 0
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.defaultContainerName
textColor: "#0E0E11"
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() {
ServersModel.currentlyProcessedIndex = serversMenuContent.currentIndex
containersDropDown.menuVisible = true
Connections {
target: drawer
function onEntered() {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
}
listView: HomeContainersListView {
rootWidth: root.width
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()
}
}
}
}
LabelTextType {
id: collapsedServerMenuDescription
Layout.bottomMargin: 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionCollapsed
}
}
expandedContent: Item {
id: serverMenuContainer
implicitHeight: root.height * 0.9
Component.onCompleted: {
drawer.expandedHeight = serverMenuContainer.implicitHeight
}
ColumnLayout {
id: serversMenuHeader
anchors.top: parent.top
anchors.right: parent.right
anchors.left: parent.left
Header1TextType {
Layout.fillWidth: true
Layout.topMargin: 14
Layout.leftMargin: 16
Layout.rightMargin: 16
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
}
LabelTextType {
id: expandedServersMenuDescription
Layout.bottomMargin: 24
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionExpanded
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8
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.defaultContainerName
textColor: "#0E0E11"
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() {
ServersModel.currentlyProcessedIndex = serversMenuContent.currentIndex
containersDropDown.open()
}
drawerParent: root
listView: HomeContainersListView {
rootWidth: root.width
Connections {
target: ServersModel
function onCurrentlyProcessedServerIndexChanged() {
updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
}
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
}
Component.onCompleted: updateContainersModelFilters()
}
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 48
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Servers")
}
}
Flickable {
id: serversContainer
anchors.top: serversMenuHeader.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.topMargin: 16
contentHeight: col.height + col.anchors.bottomMargin
implicitHeight: parent.height - serversMenuHeader.implicitHeight
clip: true
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversContainer.height >= serversContainer.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 32
spacing: 16
ButtonGroup {
id: serversRadioButtonGroup
}
ListView {
id: serversMenuContent
width: parent.width
height: serversMenuContent.contentItem.height
model: ServersModel
currentIndex: ServersModel.defaultIndex
Connections {
target: ServersModel
function onCurrentlyProcessedServerIndexChanged() {
updateContainersModelFilters()
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
}
}
function updateContainersModelFilters() {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
}
clip: true
interactive: false
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
}
delegate: Item {
id: menuContentDelegate
Component.onCompleted: updateContainersModelFilters()
}
}
}
property variant delegateData: model
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 48
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: buttonContent.expandedVisibility
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
headerText: qsTr("Servers")
}
}
ColumnLayout {
id: serverRadioButtonContent
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
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversContainer.height >= serversContainer.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
spacing: 0
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
RowLayout {
VerticalRadioButton {
id: serverRadioButton
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Layout.fillWidth: true
spacing: 16
text: name
descriptionText: {
var fullDescription = ""
if (hasWriteAccess) {
if (SettingsController.isAmneziaDnsEnabled()
&& ServersModel.isAmneziaDnsContainerInstalled(index)) {
fullDescription += "Amnezia DNS | "
}
} else {
if (containsAmneziaDns) {
fullDescription += "Amnezia DNS | "
}
}
ButtonGroup {
id: serversRadioButtonGroup
}
return fullDescription += serverDescription
}
ListView {
id: serversMenuContent
width: parent.width
height: serversMenuContent.contentItem.height
checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected
model: ServersModel
currentIndex: ServersModel.defaultIndex
ButtonGroup.group: serversRadioButtonGroup
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
}
}
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
clip: true
interactive: false
serversMenuContent.currentIndex = index
delegate: Item {
id: menuContentDelegate
ServersModel.currentlyProcessedIndex = index
ServersModel.defaultIndex = index
}
property variant delegateData: model
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
ImageButtonType {
image: "qrc:/images/controls/settings.svg"
imageColor: "#D7D8DB"
ColumnLayout {
id: serverRadioButtonContent
implicitWidth: 56
implicitHeight: 56
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
z: 1
spacing: 0
RowLayout {
VerticalRadioButton {
id: serverRadioButton
onClicked: function() {
ServersModel.currentlyProcessedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
drawer.close()
}
}
}
DividerType {
Layout.fillWidth: true
text: name
descriptionText: {
var fullDescription = ""
if (hasWriteAccess) {
if (SettingsController.isAmneziaDnsEnabled()
&& ServersModel.isAmneziaDnsContainerInstalled(index)) {
fullDescription += "Amnezia DNS | "
}
} else {
if (containsAmneziaDns) {
fullDescription += "Amnezia DNS | "
}
}
return fullDescription += serverDescription
}
checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected
ButtonGroup.group: serversRadioButtonGroup
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
serversMenuContent.currentIndex = index
ServersModel.currentlyProcessedIndex = index
ServersModel.defaultIndex = index
}
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
Layout.leftMargin: 0
Layout.rightMargin: 0
}
ImageButtonType {
image: "qrc:/images/controls/settings.svg"
imageColor: "#D7D8DB"
implicitWidth: 56
implicitHeight: 56
z: 1
onClicked: function() {
ServersModel.currentlyProcessedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
buttonContent.state = "collapsed"
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
}
}
}

View File

@@ -12,9 +12,12 @@ import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
ColumnLayout {
id: backButton
@@ -44,6 +47,8 @@ PageType {
enabled: ServersModel.isCurrentlyProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
@@ -55,9 +60,13 @@ PageType {
model: AwgConfigModel
delegate: Item {
id: _delegate
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias portTextField:portTextField
ColumnLayout {
id: col
@@ -93,6 +102,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
TextFieldWithHeaderType {
@@ -116,6 +127,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -134,6 +147,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -152,6 +167,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: initPacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -170,6 +187,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: responsePacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
@@ -188,6 +207,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: initPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -206,6 +227,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: responsePacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -224,6 +247,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: transportPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -242,6 +267,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: underloadPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
@@ -260,6 +287,8 @@ PageType {
}
checkEmptyText: true
KeyNavigation.tab: saveRestartButton
}
BasicButtonType {
@@ -275,24 +304,24 @@ PageType {
text: qsTr("Remove AmneziaWG")
onClicked: {
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 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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
@@ -310,7 +339,7 @@ PageType {
text: qsTr("Save and Restart Amnezia")
onClicked: {
clickedFunc: function() {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
@@ -318,11 +347,8 @@ PageType {
}
}
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
}

View File

@@ -15,6 +15,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
ColumnLayout {
id: backButton
@@ -58,6 +60,8 @@ PageType {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias trafficFromField: trafficFromField
ColumnLayout {
id: col
@@ -77,6 +81,8 @@ PageType {
}
TextFieldWithHeaderType {
id: trafficFromField
Layout.fillWidth: true
Layout.topMargin: 32
@@ -96,9 +102,13 @@ PageType {
}
}
}
KeyNavigation.tab: portTextField.textField
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
@@ -112,6 +122,8 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: saveRestartButton
}
DropDownType {
@@ -122,6 +134,8 @@ PageType {
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -138,7 +152,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.menuVisible = false
cipherDropDown.close()
}
Component.onCompleted: {
@@ -154,13 +168,15 @@ PageType {
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia")
onClicked: {
clickedFunc: function() {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(CloakConfigModel.getConfig())

View File

@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
ColumnLayout {
id: backButton
@@ -53,12 +55,14 @@ PageType {
clip: true
interactive: false
model: OpenVpnConfigModel
model: OpenVpnConfigModel
delegate: Item {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
ColumnLayout {
id: col
@@ -78,6 +82,8 @@ PageType {
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 32
@@ -89,6 +95,8 @@ PageType {
subnetAddress = textFieldText
}
}
KeyNavigation.tab: portTextField.enabled ? portTextField.textField : saveRestartButton
}
ParagraphTextType {
@@ -119,6 +127,9 @@ PageType {
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
@@ -134,6 +145,8 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: saveRestartButton
}
SwitcherType {
@@ -162,6 +175,8 @@ PageType {
descriptionText: qsTr("Hash")
headerText: qsTr("Hash")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: hashListView
@@ -183,7 +198,7 @@ PageType {
clickedFunction: function() {
hashDropDown.text = selectedText
hash = hashDropDown.text
hashDropDown.menuVisible = false
hashDropDown.close()
}
Component.onCompleted: {
@@ -208,6 +223,8 @@ PageType {
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -229,7 +246,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.menuVisible = false
cipherDropDown.close()
}
Component.onCompleted: {
@@ -363,32 +380,33 @@ PageType {
text: qsTr("Remove OpenVPN")
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")
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")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia")
onClicked: {
clickedFunc: function() {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
@@ -398,9 +416,5 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}

View File

@@ -90,71 +90,77 @@ PageType {
DividerType {}
DrawerType {
DrawerType2 {
id: configContentDrawer
width: parent.width
height: parent.height * 0.9
expandedHeight: root.height * 0.9
BackButtonType {
id: backButton
parent: root
anchors.fill: parent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
expandedContent: Item {
implicitHeight: configContentDrawer.expandedHeight
backButtonFunction: function() {
configContentDrawer.visible = false
}
}
BackButtonType {
id: backButton
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
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
ColumnLayout {
id: configContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Connection options %1").arg(protocolName)
backButtonFunction: function() {
configContentDrawer.close()
}
}
TextArea {
id: configText
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
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
ColumnLayout {
id: configContent
padding: 0
leftPadding: 0
height: 24
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
headerText: qsTr("Connection options %1").arg(protocolName)
}
text: rawConfig
TextArea {
id: configText
wrapMode: Text.Wrap
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
background: Rectangle {
color: "transparent"
padding: 0
leftPadding: 0
height: 24
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
text: rawConfig
wrapMode: Text.Wrap
background: Rectangle {
color: "transparent"
}
}
}
}
@@ -175,20 +181,19 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
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 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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
@@ -200,9 +205,5 @@ PageType {
DividerType {}
}
QuestionDrawer {
id: questionDrawer
}
}
}

View File

@@ -15,6 +15,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
ColumnLayout {
id: backButton
@@ -58,6 +60,8 @@ PageType {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias portTextField: portTextField
ColumnLayout {
id: col
@@ -77,6 +81,8 @@ PageType {
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
@@ -90,6 +96,8 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: saveRestartButton
}
DropDownType {
@@ -100,6 +108,8 @@ PageType {
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -116,7 +126,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.menuVisible = false
cipherDropDown.close()
}
Component.onCompleted: {
@@ -132,13 +142,15 @@ PageType {
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("Save and Restart Amnezia")
onClicked: {
clickedFunc: function() {
forceActiveFocus()
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())

View File

@@ -63,19 +63,18 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
@@ -86,10 +85,6 @@ PageType {
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
}

View File

@@ -170,7 +170,7 @@ PageType {
text: qsTr("Mount folder on device")
onClicked: {
clickedFunc: function() {
PageController.showBusyIndicator(true)
InstallController.mountSftpDrive(port, password, username)
PageController.showBusyIndicator(false)
@@ -229,7 +229,7 @@ PageType {
text: qsTr("Detailed instructions")
onClicked: {
clickedFunc: function() {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
@@ -247,29 +247,24 @@ PageType {
text: qsTr("Remove SFTP and all data stored there")
onClicked: {
questionDrawer.headerText = qsTr("Remove SFTP and all data stored there?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
clickedFunc: function() {
var headerText = qsTr("Remove SFTP and all data stored there?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}

View File

@@ -125,26 +125,21 @@ PageType {
text: qsTr("Remove website")
onClicked: {
questionDrawer.headerText = qsTr("The site with all data will be removed from the tor network.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
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")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}

View File

@@ -81,7 +81,7 @@ PageType {
text: qsTr("Card on Patreon")
onClicked: function() {
clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://www.patreon.com/amneziavpn"))
}
}
@@ -101,7 +101,9 @@ PageType {
text: qsTr("Show other methods on Github")
onClicked: Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate"))
clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client#donate"))
}
}
ParagraphTextType {
@@ -191,7 +193,7 @@ PageType {
text: qsTr("Check for updates")
onClicked: {
clickedFunc: function() {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}

View File

@@ -117,10 +117,6 @@ PageType {
}
}
SelectLanguageDrawer {
id: selectLanguageDrawer
}
DividerType {}
@@ -143,30 +139,33 @@ PageType {
text: qsTr("Reset settings and remove all data from the application")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: "#EB5757"
clickedFunction: function() {
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 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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
SettingsController.clearSettings()
PageController.replaceStartPage()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
SelectLanguageDrawer {
id: selectLanguageDrawer
width: root.width
height: root.height
}
}

View File

@@ -88,7 +88,7 @@ PageType {
text: qsTr("Make a backup")
onClicked: {
clickedFunc: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN.backup"
@@ -121,7 +121,7 @@ PageType {
text: qsTr("Restore from backup")
onClicked: {
clickedFunc: function() {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
@@ -133,24 +133,19 @@ PageType {
}
function restoreBackup(filePath) {
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 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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.showBusyIndicator(true)
SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
}
QuestionDrawer {
id: questionDrawer
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}

View File

@@ -13,6 +13,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: primaryDns.textField
BackButtonType {
id: backButton
@@ -68,6 +70,8 @@ PageType {
textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp()
}
KeyNavigation.tab: secondaryDns.textField
}
TextFieldWithHeaderType {
@@ -80,6 +84,8 @@ PageType {
textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp()
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
@@ -94,32 +100,33 @@ PageType {
text: qsTr("Restore default")
onClicked: function() {
questionDrawer.headerText = qsTr("Restore default DNS settings?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
clickedFunc: function() {
var headerText = qsTr("Restore default DNS settings?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
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"))
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
onClicked: function() {
clickedFunc: function() {
if (primaryDns.textFieldText !== SettingsController.primaryDns) {
SettingsController.primaryDns = primaryDns.textFieldText
}
@@ -130,8 +137,6 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}

View File

@@ -143,21 +143,20 @@ PageType {
image: "qrc:/images/controls/delete.svg"
onClicked: function() {
questionDrawer.headerText = qsTr("Clear logs?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var headerText = qsTr("Clear logs?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.showBusyIndicator(true)
SettingsController.clearLogs()
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs have been cleaned up"))
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
@@ -170,10 +169,6 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
}

View File

@@ -92,21 +92,20 @@ PageType {
descriptionText: qsTr("May be needed when changing other settings")
clickedFunction: function() {
questionDrawer.headerText = qsTr("Clear cached profiles?")
questionDrawer.descriptionText = qsTr("")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var headerText = qsTr("Clear cached profiles?")
var descriptionText = qsTr("")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.showBusyIndicator(true)
SettingsController.clearCachedProfiles()
PageController.showBusyIndicator(false)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
@@ -140,13 +139,12 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
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 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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
@@ -154,10 +152,10 @@ PageType {
InstallController.rebootCurrentlyProcessedServer()
PageController.showBusyIndicator(false)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
@@ -172,13 +170,12 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
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 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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
@@ -186,10 +183,10 @@ PageType {
InstallController.removeCurrentlyProcessedServer()
PageController.showBusyIndicator(false)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
@@ -203,55 +200,22 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to clear server from Amnezia software?")
questionDrawer.descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.removeAllContainers()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
}
}
DividerType {
visible: content.isServerWithWriteAccess
}
LabelWithButtonType {
visible: content.isServerWithWriteAccess
Layout.fillWidth: true
text: qsTr("Clear server from Amnezia software")
textColor: "#EB5757"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to clear server from Amnezia software?")
questionDrawer.descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.removeAllContainers()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
@@ -267,31 +231,26 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to reset API config?")
questionDrawer.descriptionText = ""
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var headerText = qsTr("Do you want to reset API config?")
var descriptionText = ""
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.showBusyIndicator(true)
ApiController.clearApiConfig()
PageController.showBusyIndicator(false)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {
visible: ServersModel.isCurrentlyProcessedServerFromApi()
}
QuestionDrawer {
id: questionDrawer
}
}
}
}

View File

@@ -71,30 +71,33 @@ PageType {
}
actionButtonFunction: function() {
serverNameEditDrawer.visible = true
serverNameEditDrawer.open()
}
}
DrawerType {
DrawerType2 {
id: serverNameEditDrawer
width: root.width
height: root.height * 0.35
parent: root
onVisibleChanged: {
if (serverNameEditDrawer.visible) {
serverName.textField.forceActiveFocus()
}
}
anchors.fill: parent
expandedHeight: root.height * 0.35
ColumnLayout {
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.topMargin: 32
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: serverNameEditDrawer
function onOpened() {
serverName.textField.forceActiveFocus()
}
}
TextFieldWithHeaderType {
id: serverName
@@ -103,14 +106,18 @@ PageType {
textFieldText: name
textField.maximumLength: 30
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
onClicked: {
clickedFunc: function() {
if (serverName.textFieldText === "") {
return
}
@@ -118,7 +125,13 @@ PageType {
if (serverName.textFieldText !== name) {
name = serverName.textFieldText
}
serverNameEditDrawer.visible = false
serverNameEditDrawer.close()
}
}
Component.onCompleted: {
if (header.itemAt(0)) {
defaultActiveFocusItem = serverName.textField
}
}
}

View File

@@ -113,20 +113,19 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
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 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.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
@@ -138,9 +137,9 @@ PageType {
DividerType {}
}
}
QuestionDrawer {
id: questionDrawer
}
QuestionDrawer {
id: questionDrawer
}
}

View File

@@ -55,6 +55,9 @@ PageType {
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
}
Component.onCompleted: updateContainersModelFilters()

View File

@@ -20,6 +20,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: website_ip_field.textField
property bool pageEnabled: {
return !ConnectionController.isConnected && !ServersModel.isDefaultServerFromApi()
}
@@ -121,6 +123,7 @@ PageType {
Layout.rightMargin: 16
drawerHeight: 0.4375
drawerParent: root
enabled: root.pageEnabled
@@ -135,7 +138,7 @@ PageType {
clickedFunction: function() {
selector.text = selectedText
selector.menuVisible = false
selector.close()
if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) {
SitesModel.routeMode = root.routeModesModel[currentIndex].type
}
@@ -202,26 +205,21 @@ PageType {
rightImageColor: "#D7D8DB"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Remove ") + url + "?"
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var headerText = qsTr("Remove ") + url + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
var yesButtonFunction = function() {
SitesController.removeSite(index)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
var noButtonFunction = function() {
}
questionDrawer.visible = true
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
}
@@ -249,6 +247,8 @@ PageType {
anchors.bottomMargin: 24
TextFieldWithHeaderType {
id: website_ip_field
Layout.fillWidth: true
textFieldPlaceholderText: qsTr("website or IP")
@@ -275,151 +275,155 @@ PageType {
}
}
DrawerType {
DrawerType2 {
id: moreActionsDrawer
width: parent.width
height: parent.height * 0.4375
anchors.fill: parent
expandedHeight: parent.height * 0.4375
FlickableType {
anchors.fill: parent
contentHeight: moreActionsDrawerContent.height
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 {}
}
}
}
DrawerType {
id: importSitesDrawer
width: parent.width
height: parent.height * 0.4375
BackButtonType {
id: importSitesDrawerBackButton
expandedContent: 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")
}
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 {}
}
}
FlickableType {
anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
DrawerType2 {
id: importSitesDrawer
contentHeight: importSitesDrawerContent.height
anchors.fill: parent
expandedHeight: parent.height * 0.4375
ColumnLayout {
id: importSitesDrawerContent
expandedContent: Item {
implicitHeight: importSitesDrawer.expandedHeight
BackButtonType {
id: importSitesDrawerBackButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
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)
backButtonFunction: function() {
importSitesDrawer.close()
moreActionsDrawer.close()
}
}
DividerType {}
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 {}
}
}
}
}
QuestionDrawer {
id: questionDrawer
}
}

View File

@@ -12,6 +12,8 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: hostname.textField
BackButtonType {
id: backButton
@@ -57,6 +59,8 @@ PageType {
onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '');
}
KeyNavigation.tab: username.textField
}
TextFieldWithHeaderType {
@@ -65,6 +69,8 @@ PageType {
Layout.fillWidth: true
headerText: qsTr("Login to connect via SSH")
textFieldPlaceholderText: "root"
KeyNavigation.tab: secretData.textField
}
TextFieldWithHeaderType {
@@ -85,15 +91,19 @@ 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")
onClicked: function() {
clickedFunc: function() {
forceActiveFocus()
if (!isCredentialsFilled()) {
return

View File

@@ -158,7 +158,7 @@ PageType {
text: qsTr("Continue")
onClicked: function() {
clickedFunc: function() {
if (root.isEasySetup) {
ContainersModel.setCurrentlyProcessedContainerIndex(containers.dockerContainer)
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
@@ -192,13 +192,12 @@ PageType {
return ContainersModel.isAnyContainerInstalled()
}
return true
}
text: qsTr("Set up later")
onClicked: function() {
clickedFunc: function() {
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.addEmptyServer()
}

View File

@@ -26,7 +26,7 @@ PageType {
function onInstallContainerFinished(finishedMessage, isServiceInstall) {
if (!ConnectionController.isConnected && !isServiceInstall) {
ServersModel.setDefaultContainer(ContainersModel.getCurrentlyProcessedContainerIndex())
ServersModel.setDefaultContainer(ServersModel.currentlyProcessedIndex, ContainersModel.getCurrentlyProcessedContainerIndex())
}
PageController.closePage() // close installing page
@@ -165,7 +165,7 @@ PageType {
text: qsTr("Cancel installation")
onClicked: {
clickedFunc: function() {
InstallController.cancelInstallation()
PageController.showBusyIndicator(true)
}

View File

@@ -52,6 +52,8 @@ PageType {
implicitWidth: processedContainerListView.width
implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height
property alias port:port
ColumnLayout {
id: delegateContent
@@ -92,81 +94,85 @@ PageType {
text: qsTr("More detailed")
onClicked: {
clickedFunc: function() {
showDetailsDrawer.open()
}
}
DrawerType {
DrawerType2 {
id: showDetailsDrawer
parent: root
width: parent.width
height: parent.height * 0.9
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedContent: Item {
implicitHeight: showDetailsDrawer.expandedHeight
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
BackButtonType {
id: showDetailsBackButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.topMargin: 16
Header2Type {
id: showDetailsDrawerHeader
Layout.fillWidth: true
Layout.topMargin: 16
backButtonFunction: function() {
showDetailsDrawer.close()
}
}
headerText: name
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
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
ColumnLayout {
id: showDetailsDrawerContent
text: detailedDescription
textFormat: Text.MarkdownText
}
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
}
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")
onClicked: function() {
showDetailsDrawer.close()
clickedFunc: function() {
showDetailsDrawer.close()
}
}
}
}
@@ -197,6 +203,8 @@ PageType {
headerText: qsTr("Port")
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
KeyNavigation.tab: installButton
}
Rectangle {
@@ -212,7 +220,7 @@ PageType {
text: qsTr("Install")
onClicked: function() {
clickedFunc: function() {
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.install(dockerContainer, port.textFieldText, transportProtoSelector.currentIndex)
}
@@ -232,6 +240,8 @@ PageType {
var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto)
transportProtoSelector.visible = protocolSelectorVisible
transportProtoHeader.visible = protocolSelectorVisible
defaultActiveFocusItem = port.textField
}
}
}

View File

@@ -115,8 +115,8 @@ PageType {
text: qsTr("I have the data to connect")
onClicked: {
connectionTypeSelection.visible = true
clickedFunc: function() {
connectionTypeSelection.open()
}
}
@@ -135,13 +135,15 @@ PageType {
text: qsTr("I have nothing")
onClicked: Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide"))
clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide"))
}
}
}
}
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection
}
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection
}
BusyIndicatorType {

View File

@@ -12,6 +12,8 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: textKey.textField
FlickableType {
id: fl
anchors.top: parent.top
@@ -56,11 +58,15 @@ PageType {
textField.text = ""
textField.paste()
}
KeyNavigation.tab: continueButton
}
}
}
BasicButtonType {
id: continueButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -70,7 +76,7 @@ PageType {
text: qsTr("Continue")
onClicked: function() {
clickedFunc: function() {
ImportController.extractConfigFromCode(textKey.textFieldText)
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
}

View File

@@ -109,7 +109,7 @@ PageType {
text: showContent ? qsTr("Collapse content") : qsTr("Show content")
onClicked: {
clickedFunc: function() {
showContent = !showContent
}
}
@@ -151,7 +151,7 @@ PageType {
Layout.bottomMargin: 32
text: qsTr("Connect")
onClicked: {
clickedFunc: function() {
ImportController.importConfig()
}
}

View File

@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: clientNameTextField.textField
enum ConfigType {
AmneziaConnection,
OpenVpn,
@@ -41,8 +43,6 @@ 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,11 +80,6 @@ PageType {
}
PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true
}
function onExportErrorOccurred(errorMessage) {
@@ -129,7 +124,7 @@ PageType {
FlickableType {
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
contentHeight: content.height + 10
ColumnLayout {
id: content
@@ -154,14 +149,15 @@ PageType {
shareFullAccessDrawer.open()
}
DrawerType {
DrawerType2 {
id: shareFullAccessDrawer
width: root.width
height: root.height * 0.45
parent: root
anchors.fill: parent
expandedHeight: root.height * 0.45
ColumnLayout {
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -264,6 +260,8 @@ PageType {
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: shareButton
}
DropDownType {
@@ -276,6 +274,7 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server")
headerText: qsTr("Server")
@@ -305,7 +304,7 @@ PageType {
serverSelector.severSelectorIndexChanged()
}
serverSelector.menuVisible = false
serverSelector.close()
}
Component.onCompleted: {
@@ -328,6 +327,7 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.5
drawerParent: root
descriptionText: qsTr("Protocol")
headerText: qsTr("Protocol")
@@ -358,14 +358,15 @@ PageType {
clickedFunction: function() {
handler()
protocolSelector.menuVisible = false
protocolSelector.close()
}
Connections {
target: serverSelector
function onSeverSelectorIndexChanged() {
protocolSelectorListView.currentIndex = proxyContainersModel.mapFromSource(ServersModel.getDefaultContainer())
var defaultContainer = proxyContainersModel.mapFromSource(ServersModel.getDefaultContainer(ServersModel.currentlyProcessedIndex))
protocolSelectorListView.currentIndex = defaultContainer
protocolSelectorListView.triggerCurrentItem()
}
}
@@ -422,6 +423,7 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
visible: accessTypeSelector.currentIndex === 0
enabled: root.connectionTypesModel.length > 1
@@ -445,7 +447,7 @@ PageType {
clickedFunction: function() {
exportTypeSelector.text = selectedText
exportTypeSelector.currentIndex = currentIndex
exportTypeSelector.menuVisible = false
exportTypeSelector.close()
}
Component.onCompleted: {
@@ -455,11 +457,9 @@ PageType {
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
}
BasicButtonType {
id: shareButton
Layout.fillWidth: true
Layout.topMargin: 40
@@ -469,7 +469,7 @@ PageType {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
onClicked: {
clickedFunc: function(){
if (clientNameTextField.textFieldText !== "") {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
}
@@ -560,13 +560,15 @@ PageType {
DividerType {}
DrawerType {
DrawerType2 {
id: clientInfoDrawer
width: root.width
height: root.height * 0.5
parent: root
ColumnLayout {
anchors.fill: parent
expandedHeight: root.height * 0.5
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -597,30 +599,33 @@ PageType {
text: qsTr("Rename")
onClicked: function() {
clickedFunc: function() {
clientNameEditDrawer.open()
}
DrawerType {
DrawerType2 {
id: clientNameEditDrawer
width: root.width
height: root.height * 0.35
parent: root
onVisibleChanged: {
if (clientNameEditDrawer.visible) {
clientNameEditor.textField.forceActiveFocus()
}
}
anchors.fill: parent
expandedHeight: root.height * 0.35
ColumnLayout {
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.topMargin: 32
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: clientNameEditDrawer
function onOpened() {
clientNameEditor.textField.forceActiveFocus()
}
}
TextFieldWithHeaderType {
id: clientNameEditor
Layout.fillWidth: true
@@ -628,14 +633,18 @@ PageType {
textFieldText: clientName
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
onClicked: {
clickedFunc: function() {
if (clientNameEditor.textFieldText === "") {
return
}
@@ -667,21 +676,20 @@ PageType {
text: qsTr("Revoke")
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")
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")
questionDrawer.yesButtonFunction = function() {
questionDrawer.close()
var yesButtonFunction = function() {
clientInfoDrawer.close()
root.revokeConfig(index)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.close()
var noButtonFunction = function() {
}
questionDrawer.open()
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
@@ -689,12 +697,15 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onPressed: function(mouse) {

View File

@@ -69,6 +69,7 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server")
headerText: qsTr("Server")
@@ -99,7 +100,7 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
serverSelector.menuVisible = false
serverSelector.close()
}
Component.onCompleted: {
@@ -122,12 +123,10 @@ PageType {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
onClicked: function() {
clickedFunc: 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)
@@ -140,16 +139,15 @@ PageType {
PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
}
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
}
}

View File

@@ -20,22 +20,16 @@ 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) {
@@ -44,15 +38,13 @@ 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)
if (tabBarStackView.depth <= 1) {
return
}
@@ -61,13 +53,14 @@ 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)
}
PageController.updateDrawerRootPage(page)
tabBar.isServerInfoShow = page === PageEnum.PageSettingsServerInfo || tabBar.isServerInfoShow
}
function onGoToStartPage() {
@@ -121,14 +114,6 @@ PageType {
}
}
Connections {
target: ApiController
function onErrorOccurred(errorMessage) {
PageController.showErrorMessage(errorMessage)
}
}
StackViewType {
id: tabBarStackView
@@ -146,8 +131,7 @@ PageType {
var pagePath = PageController.getPagePath(page)
tabBarStackView.clear(StackView.Immediate)
tabBarStackView.replace(pagePath, { "objectName" : pagePath }, StackView.Immediate)
PageController.updateDrawerRootPage(page)
tabBar.isServerInfoShow = false
}
Component.onCompleted: {
@@ -155,17 +139,13 @@ PageType {
ServersModel.currentlyProcessedIndex = ServersModel.defaultIndex
tabBarStackView.push(pagePath, { "objectName" : pagePath })
}
// onWidthChanged: {
// topCloseButton.x = tabBarStackView.x + tabBarStackView.width -
// topCloseButton.buttonWidth - topCloseButton.rightPadding
// }
}
TabBar {
id: tabBar
property int previousIndex: 0
property bool isServerInfoShow: false
anchors.right: parent.right
anchors.left: parent.left
@@ -196,7 +176,7 @@ PageType {
}
TabImageButtonType {
isSelected: tabBar.currentIndex === 0
isSelected: tabBar.isServerInfoShow ? false : tabBar.currentIndex === 0
image: "qrc:/images/controls/home.svg"
onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageHome)
@@ -230,7 +210,7 @@ PageType {
}
TabImageButtonType {
isSelected: tabBar.currentIndex === 2
isSelected: tabBar.isServerInfoShow ? true : tabBar.currentIndex === 2
image: "qrc:/images/controls/settings-2.svg"
onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
@@ -253,13 +233,6 @@ PageType {
z: 1
}
// TopCloseButtonType {
// id: topCloseButton
// x: tabBarStackView.width - topCloseButton.buttonWidth - topCloseButton.rightPadding
// z: 1
// }
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection

View File

@@ -8,6 +8,7 @@ import PageEnum 1.0
import "Config"
import "Controls2"
import "Components"
Window {
id: root
@@ -130,32 +131,15 @@ Window {
}
Item {
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.fill: parent
implicitHeight: popupErrorMessage.height
DrawerType {
DrawerType2 {
id: privateKeyPassphraseDrawer
width: root.width
height: root.height * 0.35
anchors.fill: parent
expandedHeight: root.height * 0.35
onVisibleChanged: {
if (privateKeyPassphraseDrawer.visible) {
passphrase.textFieldText = ""
passphrase.textField.forceActiveFocus()
}
}
onAboutToHide: {
PageController.showBusyIndicator(true)
}
onAboutToShow: {
PageController.showBusyIndicator(false)
}
ColumnLayout {
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -163,6 +147,24 @@ 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
@@ -176,9 +178,13 @@ Window {
clickedFunc: function() {
hidePassword = !hidePassword
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
defaultColor: "transparent"
@@ -190,7 +196,7 @@ Window {
text: qsTr("Save")
onClicked: {
clickedFunc: function() {
privateKeyPassphraseDrawer.close()
PageController.passphraseRequestDrawerClosed(passphrase.textFieldText)
}
@@ -199,6 +205,37 @@ Window {
}
}
Item {
anchors.fill: parent
QuestionDrawer {
id: questionDrawer
anchors.fill: parent
}
}
function showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) {
questionDrawer.headerText = headerText
questionDrawer.descriptionText = descriptionText
questionDrawer.yesButtonText = yesButtonText
questionDrawer.noButtonText = noButtonText
questionDrawer.yesButtonFunction = function() {
questionDrawer.close()
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
}
questionDrawer.noButtonFunction = function() {
questionDrawer.close()
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
}
questionDrawer.open()
}
FileDialog {
id: mainFileDialog