Compare commits

..

8 Commits

Author SHA1 Message Date
lunardunno
6dceb3df54 force C.UTF-8 assignment
Force C.UTF-8 if the system language is other than en_US.
Temporary simplification of script stopping for moby and podman.
Stop script execution if Docker is not active.
2024-02-15 01:22:15 +04:00
lunardunno
cc8ce440a8 locale check simplified 2024-02-14 09:45:46 +04:00
lunardunno
03b5f84574 Introduction of direct checking of package installation results. (#591)
Introduction of direct checking of package installation results.
2024-02-14 07:53:21 +04:00
lunardunno
1aec417fc9 Merge pull request #588 from amnezia-vpn/test/docker-ce
Check which containerization application will be installed
2024-02-14 04:27:01 +04:00
lunardunno
fc0a9fd74f check and change locale
Checking and changing the locale for correct error handling by the server controller.
2024-02-14 03:46:03 +04:00
lunardunno
11fef3c653 checking of docker installation results 2024-02-14 03:39:07 +04:00
lunardunno
1226d1b287 Check moby and podman 2024-02-13 17:25:36 +04:00
lunardunno
1028f6998f docker-ce support
Implementation of docker-ce support, for Fedora and CentOS
2024-02-12 06:18:59 +04:00
66 changed files with 5543 additions and 8215 deletions

View File

@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 46)
set(APP_ANDROID_VERSION_CODE 45)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")

View File

@@ -57,7 +57,6 @@ set(AMNEZIAVPN_TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_fa_IR.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ar.ts
)
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)

View File

@@ -385,13 +385,7 @@ void AmneziaApplication::initControllers()
m_engine->rootContext()->setContextProperty("ApiController", m_apiController.get());
connect(m_apiController.get(), &ApiController::updateStarted, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Connecting); });
connect(m_apiController.get(), &ApiController::errorOccurred, this, [this](const QString &errorMessage) {
if (m_connectionController->isConnectionInProgress()) {
emit m_pageController->showErrorMessage(errorMessage);
}
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(),
&ConnectionController::toggleConnection);
connect(m_apiController.get(), &ApiController::errorOccurred, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); });
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(), &ConnectionController::toggleConnection);
}

View File

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

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_SYSTEM_EXEMPTED
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
import android.net.VpnService
import android.os.Build
import android.os.Handler
@@ -156,7 +156,7 @@ class AmneziaVpnService : VpnService() {
*/
private val foregroundServiceTypeCompat
get() = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SPECIAL_USE
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> FOREGROUND_SERVICE_TYPE_MANIFEST
else -> 0
}

View File

@@ -211,7 +211,13 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
localFile.write(data);
localFile.close();
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName(), remotePath, "non_desc");
#ifdef Q_OS_WINDOWS
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toLocal8Bit().toStdString(), remotePath.toStdString(),
"non_desc");
#else
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(),
"non_desc");
#endif
if (error != ErrorCode::NoError) {
return error;

View File

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

View File

@@ -33,9 +33,9 @@ namespace libssh {
const std::function<ErrorCode (const QString &, Client &)> &cbReadStdErr);
ErrorCode writeResponse(const QString &data);
ErrorCode sftpFileCopy(const SftpOverwriteMode overwriteMode,
const QString &localPath,
const QString &remotePath,
const QString& fileDesc);
const std::string& localPath,
const std::string& remotePath,
const std::string& fileDesc);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &passphraseCallback);
private:
ErrorCode closeChannel();

View File

@@ -85,7 +85,6 @@ target_sources(networkextension PRIVATE
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPNAdapterDelegate.swift
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
)

View File

@@ -59,6 +59,10 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
var stopHandler: (() -> Void)?
var protoType: TunnelProtoType = .none
override init() {
super.init()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)? = nil) {
let tmpStr = String(data: messageData, encoding: .utf8)!
wg_log(.error, message: tmpStr)
@@ -67,7 +71,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let completionHandler else {
guard let completionHandler = completionHandler else {
log(.error, message: "Missing message completion handler")
return
}
@@ -175,16 +179,14 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
return
}
guard let wgConfigStr = try? JSONDecoder().decode(WGConfig.self, from: wgConfig).wg,
let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr)
else {
let wgConfigStr = String(data: wgConfig, encoding: .utf8)!
guard let tunnelConfiguration = try? TunnelConfiguration(fromWgQuickConfig: wgConfigStr) else {
wg_log(.error, message: "Can't parse WireGuard config")
completionHandler(nil)
return
}
log(.info, message: "wgConfig: \(wgConfigStr.replacingOccurrences(of: "\n", with: " "))")
if tunnelConfiguration.peers.first!.allowedIPs
.map({ $0.stringRepresentation })
.joined(separator: ", ") == "0.0.0.0/0, ::/0" {

View File

@@ -1,133 +0,0 @@
import Foundation
struct WGConfigData: Decodable {
let h1, h2, h3, h4: String?
let jc, jmax, jmin: String?
let s1, s2: String?
var settings: String {
jc == nil ? "" :
"""
Jc = \(jc!)
Jmin = \(jmin!)
Jmax = \(jmax!)
S1 = \(s1!)
S2 = \(s2!)
H1 = \(h1!)
H2 = \(h2!)
H3 = \(h3!)
H4 = \(h4!)
"""
}
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 h1 = "H1", h2 = "H2", h3 = "H3", h4 = "H4"
case jc = "Jc", jmax = "Jmax", jmin = "Jmin"
case s1 = "S1", s2 = "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.h1 = try container.decodeIfPresent(String.self, forKey: .h1)
self.h2 = try container.decodeIfPresent(String.self, forKey: .h2)
self.h3 = try container.decodeIfPresent(String.self, forKey: .h3)
self.h4 = try container.decodeIfPresent(String.self, forKey: .h4)
self.jc = try container.decodeIfPresent(String.self, forKey: .jc)
self.jmax = try container.decodeIfPresent(String.self, forKey: .jmax)
self.jmin = try container.decodeIfPresent(String.self, forKey: .jmin)
self.s1 = try container.decodeIfPresent(String.self, forKey: .s1)
self.s2 = try container.decodeIfPresent(String.self, forKey: .s2)
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 wg: 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,10 +400,9 @@ bool IosController::setupCloak()
bool IosController::setupWireGuard()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::WireGuard)].toObject();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
QString wgConfig = config[config_key::config].toString();
return startWireGuard(wgConfig);
}
@@ -411,9 +410,8 @@ bool IosController::setupAwg()
{
QJsonObject config = m_rawConfig[ProtocolProps::key_proto_config_data(amnezia::Proto::Awg)].toObject();
QJsonDocument doc(m_rawConfig);
QString wgConfig(doc.toJson(QJsonDocument::Compact));
QString wgConfig = config[config_key::config].toString();
return startWireGuard(wgConfig);
}

View File

@@ -160,6 +160,7 @@
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
<file>ui/qml/Controls2/DividerType.qml</file>
<file>ui/qml/Controls2/DrawerType.qml</file>
<file>ui/qml/Controls2/StackViewType.qml</file>
<file>ui/qml/Pages2/PageSettings.qml</file>
<file>images/controls/amnezia.svg</file>
@@ -224,6 +225,5 @@
<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>

View File

@@ -1,20 +1,35 @@
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="> /dev/null 2>&1"; docker_pkg="docker"; dist="archlinux";\
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; what_pkg="-s install"; docker_pkg="docker.io"; dist="debian";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; what_pkg="--assumeno install --setopt=tsflags=test"; docker_pkg="docker"; dist="fedora";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; what_pkg="--assumeno install --setopt=tsflags=test"; docker_pkg="docker"; dist="centos";\
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; what_pkg="-Sp"; docker_pkg="docker"; dist="archlinux";\
else echo "Packet manager not found"; exit 1; fi;\
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, What pkg command: $what_pkg, Docker pkg: $docker_pkg";\
if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi;\
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo; fi;\
if ! command -v fuser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst psmisc; fi;\
if ! command -v lsof > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst lsof; fi;\
if ! command -v docker > /dev/null 2>&1; then \
sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
sleep 5; sudo systemctl enable --now docker; sleep 5;\
if [ "$(echo $LANG)" != "en_US.UTF-8" ] && [ "$(echo $LANG)" != "C.UTF-8" ]; then \
if [ "$(locale -a | grep -c 'en_US.utf8')" != "0" ]; then export LC_ALL=en_US.UTF-8;\
else export LC_ALL=C.UTF-8; fi;\
fi;\
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo;\
if ! command -v sudo > /dev/null 2>&1; then sudo; exit 1; fi;\
fi;\
if ! command -v fuser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst psmisc;\
if ! command -v fuser > /dev/null 2>&1; then fuser; exit 1; fi;\
fi;\
if ! command -v lsof > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst lsof;\
if ! command -v lsof > /dev/null 2>&1; then lsof; exit 1; fi;\
fi;\
if ! command -v docker > /dev/null 2>&1; then sudo $pm $check_pkgs;\
check_podman=$(sudo $pm $what_pkg $docker_pkg 2>&1 | grep -c podman-docker);\
check_moby=$(sudo $pm $what_pkg $docker_pkg 2>&1 | grep -c moby-engine);\
if [ "$check_podman" != "0" ] || [ "$check_moby" != "0" ]; then echo "Docker is not supported"; docker; exit 1;\
else sudo $pm $silent_inst $docker_pkg;\
if ! command -v docker > /dev/null 2>&1; then docker; exit 1;\
else sleep 5; sudo systemctl enable --now docker; sleep 5; fi;\
fi;\
fi;\
if [ "$(systemctl is-active docker)" != "active" ]; then \
sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
sleep 5; sudo systemctl start docker; sleep 5;\
if [ "$(systemctl is-active docker)" != "active" ]; then echo "Failed to status docker, command not found"; fi;\
fi;\
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install sudo, command not found"; exit 1; fi;\
docker --version

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -70,17 +70,14 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
void ApiController::updateServerConfigFromApi()
{
QtConcurrent::run([this]() {
if (m_isConfigUpdateStarted) {
emit updateFinished(false);
return;
}
auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray();
bool isConfigUpdateStarted = false;
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
emit updateStarted();
m_isConfigUpdateStarted = true;
isConfigUpdateStarted = true;
QNetworkAccessManager manager;
@@ -113,12 +110,6 @@ void ApiController::updateServerConfigFromApi()
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
@@ -142,13 +133,11 @@ void ApiController::updateServerConfigFromApi()
qDebug() << reply->error();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
}
emit updateFinished(m_isConfigUpdateStarted);
m_isConfigUpdateStarted = false;
emit updateFinished(isConfigUpdateStarted);
return;
});
}

View File

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

View File

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

View File

@@ -82,6 +82,11 @@ public slots:
void showOnStartup();
void updateDrawerRootPage(PageLoader::PageEnum page);
void goToDrawerRootPage();
void drawerOpen();
void drawerClose();
bool isTriggeredByConnectButton();
void setTriggeredBtConnectButton(bool trigger);
@@ -113,11 +118,17 @@ signals:
void showPassphraseRequestDrawer();
void passphraseRequestDrawerClosed(QString passphrase);
void showTopCloseButton(bool visible);
void forceCloseDrawer();
private:
QSharedPointer<ServersModel> m_serversModel;
std::shared_ptr<Settings> m_settings;
PageLoader::PageEnum m_currentRootPage;
int m_drawerLayer;
bool m_isTriggeredByConnectButton;
};

View File

@@ -45,7 +45,6 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
case LanguageSettings::AvailableLanguageEnum::Russian: strLanguage = "Русский"; break;
case LanguageSettings::AvailableLanguageEnum::China_cn: strLanguage = "\347\256\200\344\275\223\344\270\255\346\226\207"; break;
case LanguageSettings::AvailableLanguageEnum::Persian: strLanguage = "فارسی"; break;
case LanguageSettings::AvailableLanguageEnum::Arabic: strLanguage = "العربية"; break;
default:
break;
}
@@ -60,7 +59,6 @@ void LanguageModel::changeLanguage(const LanguageSettings::AvailableLanguageEnum
case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break;
case LanguageSettings::AvailableLanguageEnum::China_cn: emit updateTranslations(QLocale::Chinese); break;
case LanguageSettings::AvailableLanguageEnum::Persian: emit updateTranslations(QLocale::Persian); break;
case LanguageSettings::AvailableLanguageEnum::Arabic: emit updateTranslations(QLocale::Arabic); break;
default: emit updateTranslations(QLocale::English); break;
}
}
@@ -73,7 +71,6 @@ int LanguageModel::getCurrentLanguageIndex()
case QLocale::Russian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Russian); break;
case QLocale::Chinese: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::China_cn); break;
case QLocale::Persian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Persian); break;
case QLocale::Arabic: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Arabic); break;
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
}
}

View File

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

View File

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

View File

@@ -8,24 +8,18 @@ import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
DrawerType {
id: root
width: parent.width
height: parent.height
expandedContent: ColumnLayout {
id: content
height: parent.height * 0.4375
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Component.onCompleted: {
root.expandedHeight = content.implicitHeight + 32
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
@@ -46,7 +40,7 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.close()
root.visible = false
}
}
@@ -60,7 +54,7 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.close()
root.visible = false
}
}

View File

@@ -60,7 +60,7 @@ ListView {
}
if (checked) {
containersDropDown.close()
containersDropDown.menuVisible = false
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyContainersModel.mapToSource(index))
} else {
if (!isSupported && isInstalled) {
@@ -71,7 +71,7 @@ ListView {
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.close()
containersDropDown.menuVisible = false
}
}

View File

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

View File

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

View File

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

View File

@@ -16,37 +16,47 @@ Button {
property string textColor: "#0E0E11"
property string borderColor: "#D7D8DB"
property string borderFocusedColor: "#D7D8DB"
property int borderWidth: 0
property int borderFocusedWidth: 1
property string imageSource
property bool squareLeftSide: false
property var clickedFunc
implicitHeight: 56
hoverEnabled: true
background: Rectangle {
id: background_border
color: "transparent"
border.color: root.activeFocus ? root.borderFocusedColor : "transparent"
border.width: root.activeFocus ? root.borderFocusedWidth : "transparent"
id: background
anchors.fill: parent
radius: 16
color: {
if (root.enabled) {
if (root.pressed) {
return pressedColor
}
return root.hovered ? hoveredColor : defaultColor
} else {
return disabledColor
}
}
border.color: borderColor
border.width: borderWidth
Behavior on color {
PropertyAnimation { duration: 200 }
}
Rectangle {
id: background
visible: root.squareLeftSide
anchors.fill: background_border
anchors.margins: root.activeFocus ? 2: 0
z: 1
radius: 16
width: parent.radius
height: parent.radius
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
color: {
if (root.enabled) {
if (root.pressed) {
@@ -57,53 +67,24 @@ Button {
return disabledColor
}
}
border.color: root.activeFocus ? "transparent" : borderColor
border.width: root.activeFocus ? 0 : borderWidth
Behavior on color {
PropertyAnimation { duration: 200 }
}
Rectangle {
visible: root.squareLeftSide
z: 1
width: parent.radius
height: parent.radius
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
color: {
if (root.enabled) {
if (root.pressed) {
return pressedColor
}
return root.hovered ? hoveredColor : defaultColor
} else {
return disabledColor
}
}
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
}
}
MouseArea {
anchors.fill: background_border
anchors.fill: background
enabled: false
cursorShape: Qt.PointingHandCursor
}
contentItem: Item {
anchors.fill: background_border
anchors.fill: background
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.centerIn: parent
@@ -133,22 +114,4 @@ 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

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

View File

@@ -1,241 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "TextTypes"
Item {
id: root
readonly property string drawerExpanded: "expanded"
readonly property string drawerCollapsed: "collapsed"
readonly property bool isOpened: drawerContent.state === root.drawerExpanded || (drawerContent.state === root.drawerCollapsed && dragArea.drag.active === true)
readonly property bool isClosed: drawerContent.state === root.drawerCollapsed && dragArea.drag.active === false
readonly property bool isExpanded: drawerContent.state === root.drawerExpanded
readonly property bool isCollapsed: drawerContent.state === root.drawerCollapsed
property Component collapsedContent
property Component expandedContent
property string defaultColor: "#1C1D21"
property string borderColor: "#2C2D30"
property real expandedHeight
property real collapsedHeight: 0
signal entered
signal exited
signal pressed(bool pressed, bool entered)
signal aboutToHide
signal aboutToShow
signal close
signal open
signal closed
signal opened
Connections {
target: root
function onClose() {
if (isCollapsed) {
return
}
aboutToHide()
drawerContent.state = root.drawerCollapsed
closed()
}
function onOpen() {
if (isExpanded) {
return
}
aboutToShow()
drawerContent.state = root.drawerExpanded
opened()
}
}
/** Set once based on first implicit height change once all children are layed out */
Component.onCompleted: {
if (root.isCollapsed && root.collapsedHeight == 0) {
root.collapsedHeight = drawerContent.implicitHeight
}
}
Rectangle {
id: background
anchors.fill: parent
color: root.isCollapsed ? "transparent" : Qt.rgba(14/255, 14/255, 17/255, 0.8)
Behavior on color {
PropertyAnimation { duration: 200 }
}
}
MouseArea {
id: emptyArea
anchors.fill: parent
enabled: root.isExpanded
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,23 +36,19 @@ Item {
property int rootButtonTextBottomMargin: 16
property real drawerHeight: 0.9
property Item drawerParent
property Component listView
signal open
signal close
property alias menuVisible: menu.visible
implicitWidth: rootButtonContent.implicitWidth
implicitHeight: rootButtonContent.implicitHeight
onOpen: {
menu.open()
rootButtonBackground.border.color = rootButtonPressedBorderColor
}
onClose: {
menu.close()
rootButtonBackground.border.color = rootButtonDefaultBorderColor
onMenuVisibleChanged: {
if (menuVisible) {
rootButtonBackground.border.color = rootButtonPressedBorderColor
} else {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
}
}
onEnabledChanged: {
@@ -137,21 +133,21 @@ Item {
hoverEnabled: root.enabled ? true : false
onEntered: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.border.color = rootButtonHoveredBorderColor
rootButtonBackground.color = rootButtonBackgroundHoveredColor
}
}
onExited: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.border.color = rootButtonDefaultBorderColor
rootButtonBackground.color = rootButtonBackgroundColor
}
}
onPressed: {
if (menu.isClosed) {
if (menu.visible === false) {
rootButtonBackground.color = pressed ? rootButtonBackgroundPressedColor : entered ? rootButtonHoveredBorderColor : rootButtonDefaultBorderColor
}
}
@@ -160,68 +156,60 @@ Item {
if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") {
rootButtonClickedFunction()
} else {
menu.open()
menu.visible = true
}
}
}
DrawerType2 {
DrawerType {
id: menu
parent: drawerParent
width: parent.width
height: parent.height * drawerHeight
anchors.fill: parent
expandedHeight: drawerParent.height * drawerHeight
ColumnLayout {
id: header
expandedContent: Item {
id: container
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
implicitHeight: menu.expandedHeight
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
root.menuVisible = false
}
}
}
ColumnLayout {
id: header
FlickableType {
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() {
menu.close()
}
}
}
spacing: 16
FlickableType {
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
Column {
id: col
anchors.top: parent.top
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16
headerText: root.headerText
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
width: parent.width
}
headerText: root.headerText
width: parent.width
}
Loader {
id: listViewLoader
sourceComponent: root.listView
}
Loader {
id: listViewLoader
sourceComponent: root.listView
}
}
}

View File

@@ -7,8 +7,6 @@ Item {
property StackView stackView: StackView.view
property var defaultActiveFocusItem: null
// MouseArea {
// id: globalMouseArea
// z: 99
@@ -21,17 +19,4 @@ Item {
// mouse.accepted = false
// }
// }
// Set a timer to set focus after a short delay
Timer {
id: timer
interval: 100 // Milliseconds
onTriggered: {
if (defaultActiveFocusItem) {
defaultActiveFocusItem.forceActiveFocus()
}
}
repeat: false // Stop the timer after one trigger
running: true // Start the timer
}
}

View File

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

View File

@@ -69,7 +69,6 @@ Item {
TextField {
id: textField
activeFocusOnTab: false
enabled: root.textFieldEditable
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
@@ -143,7 +142,7 @@ Item {
Layout.preferredWidth: content.implicitHeight
squareLeftSide: true
clickedFunc: function() {
onClicked: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
@@ -187,12 +186,4 @@ Item {
function getBackgroundBorderColor(noneFocusedColor) {
return textField.focus ? root.borderFocusedColor : noneFocusedColor
}
Keys.onEnterPressed: {
KeyNavigation.tab.forceActiveFocus();
}
Keys.onReturnPressed: {
KeyNavigation.tab.forceActiveFocus();
}
}

View File

@@ -18,355 +18,484 @@ import "../Components"
PageType {
id: root
property string defaultColor: "#1C1D21"
property string borderColor: "#2C2D30"
Connections {
target: PageController
function onRestorePageHomeState(isContainerInstalled) {
drawer.open()
buttonContent.state = "expanded"
if (isContainerInstalled) {
containersDropDown.rootButtonClickedFunction()
}
}
function onForceCloseDrawer() {
buttonContent.state = "collapsed"
}
}
MouseArea {
anchors.fill: parent
enabled: buttonContent.state === "expanded"
onClicked: {
buttonContent.state = "collapsed"
}
}
Item {
anchors.fill: parent
anchors.bottomMargin: drawer.collapsedHeight
anchors.bottomMargin: buttonContent.collapsedHeight
ConnectButton {
anchors.centerIn: parent
}
}
MouseArea {
id: dragArea
DrawerType2 {
id: drawer
anchors.fill: parent
anchors.fill: buttonBackground
cursorShape: buttonContent.state === "collapsed" ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
collapsedContent: ColumnLayout {
DividerType {
Layout.topMargin: 10
Layout.fillWidth: false
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
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 }
}
}
RowLayout {
ImageButtonType {
id: collapsedButtonChevron
Layout.leftMargin: 8
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
imageColor: "#d7d8db"
icon.width: 18
icon.height: 18
backgroundRadius: 16
horizontalPadding: 4
topPadding: 4
bottomPadding: 3
onClicked: {
if (buttonContent.state === "collapsed") {
buttonContent.state = "expanded"
}
}
}
}
LabelTextType {
id: collapsedServerMenuDescription
Layout.bottomMargin: 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: buttonContent.collapsedVisibility
text: ServersModel.defaultServerDescriptionCollapsed
}
ColumnLayout {
id: serversMenuHeader
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Layout.fillWidth: true
visible: buttonContent.expandedVisibility
Header1TextType {
Layout.fillWidth: true
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.leftMargin: 16
Layout.rightMargin: 16
spacing: 0
Connections {
target: drawer
function onEntered() {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
}
function onExited() {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
}
function onPressed(pressed, entered) {
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
}
}
Header1TextType {
id: collapsedButtonHeader
Layout.maximumWidth: drawer.width - 48 - 18 - 12 // todo
maximumLineCount: 2
elide: Qt.ElideRight
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
}
ImageButtonType {
id: collapsedButtonChevron
Layout.leftMargin: 8
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
imageColor: "#d7d8db"
icon.width: 18
icon.height: 18
backgroundRadius: 16
horizontalPadding: 4
topPadding: 4
bottomPadding: 3
onClicked: {
if (drawer.isCollapsed) {
drawer.open()
}
}
}
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
}
LabelTextType {
id: collapsedServerMenuDescription
Layout.bottomMargin: 44
id: expandedServersMenuDescription
Layout.bottomMargin: 24
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionExpanded
}
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionCollapsed
}
spacing: 8
}
expandedContent: Item {
id: serverMenuContainer
DropDownType {
id: containersDropDown
implicitHeight: root.height * 0.9
rootButtonImageColor: "#0E0E11"
rootButtonBackgroundColor: "#D7D8DB"
rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
rootButtonHoveredBorderColor: "transparent"
rootButtonDefaultBorderColor: "transparent"
rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8
Component.onCompleted: {
drawer.expandedHeight = serverMenuContainer.implicitHeight
}
text: ServersModel.defaultContainerName
textColor: "#0E0E11"
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
ColumnLayout {
id: serversMenuHeader
anchors.top: parent.top
anchors.right: parent.right
anchors.left: parent.left
Header1TextType {
Layout.fillWidth: true
Layout.topMargin: 14
Layout.leftMargin: 16
Layout.rightMargin: 16
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
}
LabelTextType {
id: expandedServersMenuDescription
Layout.bottomMargin: 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
}
Component.onCompleted: updateContainersModelFilters()
}
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 48
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Servers")
}
}
Flickable {
id: serversContainer
anchors.top: serversMenuHeader.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.topMargin: 16
contentHeight: col.height + col.anchors.bottomMargin
implicitHeight: parent.height - serversMenuHeader.implicitHeight
clip: true
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversContainer.height >= serversContainer.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 32
spacing: 16
ButtonGroup {
id: serversRadioButtonGroup
rootButtonClickedFunction: function() {
ServersModel.currentlyProcessedIndex = serversMenuContent.currentIndex
containersDropDown.menuVisible = true
}
ListView {
id: serversMenuContent
width: parent.width
height: serversMenuContent.contentItem.height
model: ServersModel
currentIndex: ServersModel.defaultIndex
listView: HomeContainersListView {
rootWidth: root.width
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
function onCurrentlyProcessedServerIndexChanged() {
updateContainersModelFilters()
}
}
clip: true
interactive: false
function updateContainersModelFilters() {
if (ServersModel.isCurrentlyProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
}
delegate: Item {
id: menuContentDelegate
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
}
property variant delegateData: model
Component.onCompleted: updateContainersModelFilters()
}
}
}
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 48
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: buttonContent.expandedVisibility
ColumnLayout {
id: serverRadioButtonContent
headerText: qsTr("Servers")
}
}
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Flickable {
id: serversContainer
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
Layout.fillWidth: true
Layout.topMargin: 16
contentHeight: col.implicitHeight
implicitHeight: root.height - (root.height * 0.1) - serversMenuHeader.implicitHeight - 52 //todo 52 is tabbar height
visible: buttonContent.expandedVisibility
clip: true
spacing: 0
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversContainer.height >= serversContainer.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
RowLayout {
VerticalRadioButton {
id: serverRadioButton
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
Layout.fillWidth: true
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
text: name
descriptionText: {
var fullDescription = ""
if (hasWriteAccess) {
if (SettingsController.isAmneziaDnsEnabled()
&& ServersModel.isAmneziaDnsContainerInstalled(index)) {
fullDescription += "Amnezia DNS | "
}
} else {
if (containsAmneziaDns) {
fullDescription += "Amnezia DNS | "
}
}
spacing: 16
return fullDescription += serverDescription
}
ButtonGroup {
id: serversRadioButtonGroup
}
checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected
ListView {
id: serversMenuContent
width: parent.width
height: serversMenuContent.contentItem.height
ButtonGroup.group: serversRadioButtonGroup
model: ServersModel
currentIndex: ServersModel.defaultIndex
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
}
}
serversMenuContent.currentIndex = index
clip: true
interactive: false
ServersModel.currentlyProcessedIndex = index
ServersModel.defaultIndex = index
}
delegate: Item {
id: menuContentDelegate
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
property variant delegateData: model
ImageButtonType {
image: "qrc:/images/controls/settings.svg"
imageColor: "#D7D8DB"
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
implicitWidth: 56
implicitHeight: 56
ColumnLayout {
id: serverRadioButtonContent
z: 1
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
onClicked: function() {
ServersModel.currentlyProcessedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
drawer.close()
}
}
}
spacing: 0
RowLayout {
VerticalRadioButton {
id: serverRadioButton
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
text: name
descriptionText: {
var fullDescription = ""
if (hasWriteAccess) {
if (SettingsController.isAmneziaDnsEnabled()
&& ServersModel.isAmneziaDnsContainerInstalled(index)) {
fullDescription += "Amnezia DNS | "
}
} else {
if (containsAmneziaDns) {
fullDescription += "Amnezia DNS | "
}
}
return fullDescription += serverDescription
}
checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected
ButtonGroup.group: serversRadioButtonGroup
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
serversMenuContent.currentIndex = index
ServersModel.currentlyProcessedIndex = index
ServersModel.defaultIndex = index
}
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
ImageButtonType {
image: "qrc:/images/controls/settings.svg"
imageColor: "#D7D8DB"
implicitWidth: 56
implicitHeight: 56
z: 1
onClicked: function() {
ServersModel.currentlyProcessedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
buttonContent.state = "collapsed"
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
}
}
}

View File

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

View File

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

View File

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

View File

@@ -90,77 +90,71 @@ PageType {
DividerType {}
DrawerType2 {
DrawerType {
id: configContentDrawer
expandedHeight: root.height * 0.9
width: parent.width
height: parent.height * 0.9
parent: root
anchors.fill: parent
BackButtonType {
id: backButton
expandedContent: Item {
implicitHeight: configContentDrawer.expandedHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.close()
}
backButtonFunction: function() {
configContentDrawer.visible = false
}
}
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
FlickableType {
anchors.top: backButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
ColumnLayout {
id: configContent
ColumnLayout {
id: configContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Connection options %1").arg(protocolName)
}
headerText: qsTr("Connection options %1").arg(protocolName)
}
TextArea {
id: configText
TextArea {
id: configText
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
padding: 0
leftPadding: 0
height: 24
padding: 0
leftPadding: 0
height: 24
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
color: "#D7D8DB"
selectionColor: "#633303"
selectedTextColor: "#D7D8DB"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
text: rawConfig
text: rawConfig
wrapMode: Text.Wrap
wrapMode: Text.Wrap
background: Rectangle {
color: "transparent"
}
background: Rectangle {
color: "transparent"
}
}
}
@@ -181,19 +175,20 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
questionDrawer.descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
MouseArea {
@@ -205,5 +200,9 @@ PageType {
DividerType {}
}
QuestionDrawer {
id: questionDrawer
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -117,6 +117,10 @@ PageType {
}
}
SelectLanguageDrawer {
id: selectLanguageDrawer
}
DividerType {}
@@ -139,33 +143,30 @@ PageType {
text: qsTr("Reset settings and remove all data from the application")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Reset settings and remove all data from the application?")
var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Reset settings and remove all data from the application?")
questionDrawer.descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
SettingsController.clearSettings()
PageController.replaceStartPage()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
SelectLanguageDrawer {
id: selectLanguageDrawer
width: root.width
height: root.height
}
}

View File

@@ -88,7 +88,7 @@ PageType {
text: qsTr("Make a backup")
clickedFunc: function() {
onClicked: {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN.backup"
@@ -121,7 +121,7 @@ PageType {
text: qsTr("Restore from backup")
clickedFunc: function() {
onClicked: {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
@@ -133,19 +133,24 @@ PageType {
}
function restoreBackup(filePath) {
var headerText = qsTr("Import settings from a backup file?")
var descriptionText = qsTr("All current settings will be reset");
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Import settings from a backup file?")
questionDrawer.descriptionText = qsTr("All current settings will be reset");
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
QuestionDrawer {
id: questionDrawer
}
}

View File

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

View File

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

View File

@@ -92,20 +92,21 @@ PageType {
descriptionText: qsTr("May be needed when changing other settings")
clickedFunction: function() {
var headerText = qsTr("Clear cached profiles?")
var descriptionText = qsTr("")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Clear cached profiles?")
questionDrawer.descriptionText = qsTr("")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
SettingsController.clearCachedProfiles()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -139,12 +140,13 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to reboot the server?")
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Do you want to reboot the server?")
questionDrawer.descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
@@ -152,10 +154,10 @@ PageType {
InstallController.rebootCurrentlyProcessedServer()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -170,12 +172,13 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to remove the server from application?")
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Do you want to remove the server from application?")
questionDrawer.descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
@@ -183,10 +186,10 @@ PageType {
InstallController.removeCurrentlyProcessedServer()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -200,22 +203,23 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to clear server from Amnezia software?")
var descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Do you want to clear server from Amnezia software?")
questionDrawer.descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.removeAllContainers()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
@@ -231,26 +235,31 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Do you want to reset API config?")
var descriptionText = ""
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Do you want to reset API config?")
questionDrawer.descriptionText = ""
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
ApiController.clearApiConfig()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
DividerType {
visible: ServersModel.isCurrentlyProcessedServerFromApi()
}
QuestionDrawer {
id: questionDrawer
}
}
}
}

View File

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

View File

@@ -113,19 +113,20 @@ PageType {
textColor: "#EB5757"
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName())
questionDrawer.descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
MouseArea {
@@ -137,9 +138,9 @@ PageType {
DividerType {}
}
}
QuestionDrawer {
id: questionDrawer
QuestionDrawer {
id: questionDrawer
}
}
}

View File

@@ -20,8 +20,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: website_ip_field.textField
property bool pageEnabled: {
return !ConnectionController.isConnected && !ServersModel.isDefaultServerFromApi()
}
@@ -123,7 +121,6 @@ PageType {
Layout.rightMargin: 16
drawerHeight: 0.4375
drawerParent: root
enabled: root.pageEnabled
@@ -138,7 +135,7 @@ PageType {
clickedFunction: function() {
selector.text = selectedText
selector.close()
selector.menuVisible = false
if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) {
SitesModel.routeMode = root.routeModesModel[currentIndex].type
}
@@ -205,21 +202,26 @@ PageType {
rightImageColor: "#D7D8DB"
clickedFunction: function() {
var headerText = qsTr("Remove ") + url + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
questionDrawer.headerText = qsTr("Remove ") + url + "?"
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
SitesController.removeSite(index)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.visible = true
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
}
@@ -247,8 +249,6 @@ PageType {
anchors.bottomMargin: 24
TextFieldWithHeaderType {
id: website_ip_field
Layout.fillWidth: true
textFieldPlaceholderText: qsTr("website or IP")
@@ -275,155 +275,151 @@ PageType {
}
}
DrawerType2 {
DrawerType {
id: moreActionsDrawer
anchors.fill: parent
expandedHeight: parent.height * 0.4375
width: parent.width
height: parent.height * 0.4375
expandedContent: ColumnLayout {
id: moreActionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import / Export Sites")
}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Import")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
importSitesDrawer.open()
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Save site list")
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "amnezia_sites.json"
} else {
fileName = SystemController.getFileName(qsTr("Save sites"),
qsTr("Sites files (*.json)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_sites",
true,
".json")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
SitesController.exportSites(fileName)
moreActionsDrawer.close()
PageController.showBusyIndicator(false)
}
}
}
DividerType {}
}
}
DrawerType2 {
id: importSitesDrawer
anchors.fill: parent
expandedHeight: parent.height * 0.4375
expandedContent: Item {
implicitHeight: importSitesDrawer.expandedHeight
BackButtonType {
id: importSitesDrawerBackButton
FlickableType {
anchors.fill: parent
contentHeight: moreActionsDrawerContent.height
ColumnLayout {
id: moreActionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
importSitesDrawer.close()
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import / Export Sites")
}
}
FlickableType {
anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
LabelWithButtonType {
Layout.fillWidth: true
contentHeight: importSitesDrawerContent.height
text: qsTr("Import")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
ColumnLayout {
id: importSitesDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import a list of sites")
clickedFunction: function() {
importSitesDrawer.open()
}
}
LabelWithButtonType {
Layout.fillWidth: true
DividerType {}
text: qsTr("Replace site list")
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Save site list")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "amnezia_sites.json"
} else {
fileName = SystemController.getFileName(qsTr("Save sites"),
qsTr("Sites files (*.json)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_sites",
true,
".json")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
SitesController.exportSites(fileName)
moreActionsDrawer.close()
PageController.showBusyIndicator(false)
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Add imported sites to existing ones")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false)
}
}
}
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.close()
moreActionsDrawer.close()
}
DividerType {}
}
DividerType {}
}
}
}
QuestionDrawer {
id: questionDrawer
DrawerType {
id: importSitesDrawer
width: parent.width
height: parent.height * 0.4375
BackButtonType {
id: importSitesDrawerBackButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
importSitesDrawer.close()
}
}
FlickableType {
anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: importSitesDrawerContent.height
ColumnLayout {
id: importSitesDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import a list of sites")
}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Replace site list")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Add imported sites to existing ones")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false)
}
}
}
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.close()
moreActionsDrawer.close()
}
DividerType {}
}
}
}
}

View File

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

View File

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

View File

@@ -165,7 +165,7 @@ PageType {
text: qsTr("Cancel installation")
clickedFunc: function() {
onClicked: {
InstallController.cancelInstallation()
PageController.showBusyIndicator(true)
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,8 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: clientNameTextField.textField
enum ConfigType {
AmneziaConnection,
OpenVpn,
@@ -43,6 +41,8 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.needCloseButton = false
shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true)
@@ -80,6 +80,11 @@ PageType {
}
PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true
}
function onExportErrorOccurred(errorMessage) {
@@ -124,7 +129,7 @@ PageType {
FlickableType {
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height + 10
contentHeight: content.height
ColumnLayout {
id: content
@@ -149,15 +154,14 @@ PageType {
shareFullAccessDrawer.open()
}
DrawerType2 {
DrawerType {
id: shareFullAccessDrawer
parent: root
width: root.width
height: root.height * 0.45
anchors.fill: parent
expandedHeight: root.height * 0.45
expandedContent: ColumnLayout {
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -260,8 +264,6 @@ PageType {
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: shareButton
}
DropDownType {
@@ -274,7 +276,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
descriptionText: qsTr("Server")
headerText: qsTr("Server")
@@ -304,7 +305,7 @@ PageType {
serverSelector.severSelectorIndexChanged()
}
serverSelector.close()
serverSelector.menuVisible = false
}
Component.onCompleted: {
@@ -327,7 +328,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.5
drawerParent: root
descriptionText: qsTr("Protocol")
headerText: qsTr("Protocol")
@@ -358,7 +358,7 @@ PageType {
clickedFunction: function() {
handler()
protocolSelector.close()
protocolSelector.menuVisible = false
}
Connections {
@@ -423,7 +423,6 @@ PageType {
Layout.topMargin: 16
drawerHeight: 0.4375
drawerParent: root
visible: accessTypeSelector.currentIndex === 0
enabled: root.connectionTypesModel.length > 1
@@ -447,7 +446,7 @@ PageType {
clickedFunction: function() {
exportTypeSelector.text = selectedText
exportTypeSelector.currentIndex = currentIndex
exportTypeSelector.close()
exportTypeSelector.menuVisible = false
}
Component.onCompleted: {
@@ -457,9 +456,11 @@ PageType {
}
}
BasicButtonType {
id: shareButton
ShareConnectionDrawer {
id: shareConnectionDrawer
}
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 40
@@ -469,7 +470,7 @@ PageType {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
clickedFunc: function(){
onClicked: {
if (clientNameTextField.textFieldText !== "") {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
}
@@ -560,15 +561,13 @@ PageType {
DividerType {}
DrawerType2 {
DrawerType {
id: clientInfoDrawer
parent: root
width: root.width
height: root.height * 0.5
anchors.fill: parent
expandedHeight: root.height * 0.5
expandedContent: ColumnLayout {
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -599,33 +598,30 @@ PageType {
text: qsTr("Rename")
clickedFunc: function() {
onClicked: function() {
clientNameEditDrawer.open()
}
DrawerType2 {
DrawerType {
id: clientNameEditDrawer
parent: root
width: root.width
height: root.height * 0.35
anchors.fill: parent
expandedHeight: root.height * 0.35
onVisibleChanged: {
if (clientNameEditDrawer.visible) {
clientNameEditor.textField.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: clientNameEditDrawer
function onOpened() {
clientNameEditor.textField.forceActiveFocus()
}
}
TextFieldWithHeaderType {
id: clientNameEditor
Layout.fillWidth: true
@@ -633,18 +629,14 @@ PageType {
textFieldText: clientName
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
clickedFunc: function() {
onClicked: {
if (clientNameEditor.textFieldText === "") {
return
}
@@ -676,20 +668,21 @@ PageType {
text: qsTr("Revoke")
clickedFunc: function() {
var headerText = qsTr("Revoke the config for a user - %1?").arg(clientName)
var descriptionText = qsTr("The user will no longer be able to connect to your server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
onClicked: function() {
questionDrawer.headerText = qsTr("Revoke the config for a user - %1?").arg(clientName)
questionDrawer.descriptionText = qsTr("The user will no longer be able to connect to your server.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
questionDrawer.yesButtonFunction = function() {
questionDrawer.close()
clientInfoDrawer.close()
root.revokeConfig(index)
}
var noButtonFunction = function() {
questionDrawer.noButtonFunction = function() {
questionDrawer.close()
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
questionDrawer.open()
}
}
}
@@ -697,15 +690,12 @@ PageType {
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onPressed: function(mouse) {

View File

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

View File

@@ -20,16 +20,22 @@ PageType {
function onGoToPageHome() {
tabBar.setCurrentIndex(0)
tabBarStackView.goToTabBarPage(PageEnum.PageHome)
PageController.updateDrawerRootPage(PageEnum.PageHome)
}
function onGoToPageSettings() {
tabBar.setCurrentIndex(2)
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
PageController.updateDrawerRootPage(PageEnum.PageSettings)
}
function onGoToPageViewConfig() {
var pagePath = PageController.getPagePath(PageEnum.PageSetupWizardViewConfig)
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
PageController.updateDrawerRootPage(PageEnum.PageSetupWizardViewConfig)
}
function onShowBusyIndicator(visible) {
@@ -38,13 +44,15 @@ PageType {
tabBar.enabled = !visible
}
// function onShowTopCloseButton(visible) {
// topCloseButton.visible = visible
// }
function onEnableTabBar(enabled) {
tabBar.enabled = enabled
}
function onClosePage() {
tabBar.isServerInfoShow = tabBarStackView.currentItem.objectName !== PageController.getPagePath(PageEnum.PageSettingsServerInfo)
if (tabBarStackView.depth <= 1) {
return
}
@@ -53,14 +61,13 @@ PageType {
function onGoToPage(page, slide) {
var pagePath = PageController.getPagePath(page)
if (slide) {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
} else {
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.Immediate)
}
tabBar.isServerInfoShow = page === PageEnum.PageSettingsServerInfo || tabBar.isServerInfoShow
PageController.updateDrawerRootPage(page)
}
function onGoToStartPage() {
@@ -114,6 +121,14 @@ PageType {
}
}
Connections {
target: ApiController
function onErrorOccurred(errorMessage) {
PageController.showErrorMessage(errorMessage)
}
}
StackViewType {
id: tabBarStackView
@@ -131,7 +146,8 @@ PageType {
var pagePath = PageController.getPagePath(page)
tabBarStackView.clear(StackView.Immediate)
tabBarStackView.replace(pagePath, { "objectName" : pagePath }, StackView.Immediate)
tabBar.isServerInfoShow = false
PageController.updateDrawerRootPage(page)
}
Component.onCompleted: {
@@ -139,13 +155,17 @@ 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
@@ -176,7 +196,7 @@ PageType {
}
TabImageButtonType {
isSelected: tabBar.isServerInfoShow ? false : tabBar.currentIndex === 0
isSelected: tabBar.currentIndex === 0
image: "qrc:/images/controls/home.svg"
onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageHome)
@@ -210,7 +230,7 @@ PageType {
}
TabImageButtonType {
isSelected: tabBar.isServerInfoShow ? true : tabBar.currentIndex === 2
isSelected: tabBar.currentIndex === 2
image: "qrc:/images/controls/settings-2.svg"
onClicked: {
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
@@ -233,6 +253,13 @@ PageType {
z: 1
}
// TopCloseButtonType {
// id: topCloseButton
// x: tabBarStackView.width - topCloseButton.buttonWidth - topCloseButton.rightPadding
// z: 1
// }
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection

View File

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