Compare commits

..

59 Commits

Author SHA1 Message Date
Cyril Anisimov 829d11bae6 refactor OpenVpnSettings page for correct focus 2025-08-02 15:45:54 +02:00
Cyril Anisimov 54b5f4cbed refactor OpenVpnConfigModel to use QObject instead of QAbstractListModel 2025-08-02 15:45:49 +02:00
Cyril Anisimov 82beb05741 fix PageSetupWizardApiServicesList 2025-08-02 15:11:46 +02:00
Cyril Anisimov e0eb18d0f3 update HomeSplitTunnelingDrawer 2025-08-02 15:11:46 +02:00
Cyril Anisimov 36dc2fd05d update HomeContainersListView 2025-08-02 15:11:46 +02:00
Cyril Anisimov 80418e8ae6 update SelectLanguageDrawer 2025-08-02 15:11:46 +02:00
Cyril Anisimov 29772cc174 update InstalledAppsDrawer 2025-08-02 15:11:46 +02:00
Cyril Anisimov 1ecbd2dc92 update SettingsContainersListView 2025-08-02 15:11:46 +02:00
Cyril Anisimov d320faa4b7 update ServersListView 2025-08-02 15:11:46 +02:00
Cyril Anisimov f515eb82be remove references to FlickableType in BasicButtonType.qml 2025-08-02 15:07:56 +02:00
Cyril Anisimov 243b988209 remove references to FlickableType in CardWithIconsType.qml 2025-08-02 15:07:56 +02:00
Cyril Anisimov fd8dfef176 remove references to FlickableType in CheckBoxType 2025-08-02 15:07:56 +02:00
Cyril Anisimov 60f32f7b0d remove references to FlickableType in SwitcherType 2025-08-02 15:07:56 +02:00
Cyril Anisimov 810756eda8 remove references to FlickableType in TextFieldWithHeaderType 2025-08-02 15:07:56 +02:00
Cyril Anisimov 9e805635c3 remove references to Flickable in TextAreaWithFooterType 2025-08-02 15:07:56 +02:00
Cyril Anisimov a6f52bfd90 remove references to Flickable in TextAreaType.qml 2025-08-02 15:07:56 +02:00
Cyril Anisimov b0722cabd7 replace ListView with ListViewType in ListViewWithRadioButtonType.qml and remove unnecessary properties 2025-08-02 15:07:56 +02:00
Cyril Anisimov af252a36ab remove useless key navigation handlers from ListViewType 2025-08-02 15:07:56 +02:00
Cyril Anisimov 1cefde84d6 remove Flickable references in LabelWithButtonType 2025-08-02 15:07:56 +02:00
Cyril Anisimov 36ed95aa33 update PageDevMenu 2025-08-02 15:07:55 +02:00
Cyril Anisimov e6b9d1dcda replace FlickableType with ListViewType in PageDeinstalling 2025-08-02 15:07:55 +02:00
Cyril Anisimov 9d4d493095 replace FlickableType with ListViewType in PageShareFullAccess 2025-08-02 15:07:55 +02:00
Cyril Anisimov 53a466d7d7 replace FlickableType with ListViewType in PageProtocolXraySettings 2025-08-02 15:03:09 +02:00
Cyril Anisimov af425eff42 replace FlickableType with ListViewType in PageProtocolWireGuardSettings 2025-08-02 15:03:08 +02:00
Cyril Anisimov 9ffeedffae replace FlickableType with ListViewType in PageProtocolWireGuardClientSettings 2025-08-02 14:28:59 +02:00
Cyril Anisimov bcdf6eec41 replace FlickableType with ListViewType in PageProtocolShadowSocksSettings 2025-08-02 14:28:59 +02:00
Cyril Anisimov a1c380127a replace FlickableType with ListViewType in PageProtocolRaw 2025-08-02 14:28:59 +02:00
Cyril Anisimov b8890db314 replace FlickableType with ListViewType in PageProtocolCloakSettings 2025-08-02 14:28:59 +02:00
Cyril Anisimov 0b30c854c5 update PageProtocolAwgSettings 2025-08-02 14:28:59 +02:00
Cyril Anisimov c34bdf0983 update PageProtocolAwgClientSettings 2025-08-02 14:28:59 +02:00
Cyril Anisimov 521a78f1a3 replace FlickableType with ListViewType in PageSetupWizardViewConfig 2025-08-02 14:28:59 +02:00
Cyril Anisimov ca224b22fa replace FlickableType with ListViewType in PageSetupWizardTextKey 2025-08-02 14:28:59 +02:00
Cyril Anisimov 9817ad6daf replace FlickableType with ListViewType in PageSetupWizardProtocolSettings 2025-08-02 14:28:59 +02:00
Cyril Anisimov f814b875d1 replace ListView with ListViewType in PageSetupWizardProtocols 2025-08-02 14:28:59 +02:00
Cyril Anisimov b5856386ee replace FlickableType with ListViewType in PageSetupWizardInstalling 2025-08-02 14:28:59 +02:00
Cyril Anisimov 41da88fee3 replace FlickableType with ListViewType in PageSetupWizardEasy 2025-08-02 14:28:59 +02:00
Cyril Anisimov 02ec0f72c7 replace ListView with ListViewType in PageSetupWizardCredentials 2025-08-02 14:06:02 +02:00
Cyril Anisimov 28270ff269 replace ListView with ListViewType in PageSetupWizardConfigSource 2025-08-02 14:06:02 +02:00
Cyril Anisimov 11e54ed12e update PageSetupWizardApiServicesList 2025-08-02 14:06:02 +02:00
Cyril Anisimov 3315675c11 replace FlickableType with ListViewType in PageSetupWizardApiServiceInfo 2025-08-02 13:57:55 +02:00
Cyril Anisimov 23700ed914 replace FlickableType with ListViewType in PageServiceTorWebsiteSettings 2025-08-02 13:46:18 +02:00
Cyril Anisimov f15c2daa4c update PageServiceSocksProxySettings 2025-08-02 13:46:18 +02:00
Cyril Anisimov 0e0500b3f3 update PageServiceSftpSettings 2025-08-02 13:46:18 +02:00
Cyril Anisimov 73e3cb197a replace FlickableType with ListViewType in PageServiceDnsSettings 2025-08-02 13:46:18 +02:00
Cyril Anisimov 7b4a94dd3d replace ListView with ListViewType in PageSettingsSplitTunneling 2025-08-02 13:46:18 +02:00
Cyril Anisimov 9e30039eaa update PageSettingsServersList 2025-08-02 13:41:18 +02:00
Cyril Anisimov 59a39719fd update structure of PageSettingsServerProtocol 2025-08-02 13:41:18 +02:00
Cyril Anisimov cc7e6c651b replace FlickableType with ListViewType in PageSettingsServerData 2025-08-02 13:41:18 +02:00
Cyril Anisimov fbd5b0a20b replace FlickableType with ListViewType in PageSettingsLogging 2025-08-02 13:41:18 +02:00
Cyril Anisimov 405bd70267 replace FlickableType with ListViewType in PageSettingsDns 2025-08-02 13:41:18 +02:00
Cyril Anisimov 04ee62ea90 replace FlickableType with ListViewType in PageSettingsConnection 2025-08-02 13:41:18 +02:00
Cyril Anisimov ad119d5de5 replace FlickableType with ListViewType in PageSettingsBackup 2025-08-02 13:41:18 +02:00
Cyril Anisimov 1a08b24cb8 replace FlickableType with ListViewType in PageSettingsAppSplitTunneling and adjust layout for better structure 2025-08-02 13:41:18 +02:00
Cyril Anisimov 73f94e1277 replace FlickableType with ListViewType in PageSettingsApplication and update layout structure 2025-08-02 13:41:18 +02:00
Cyril Anisimov b0fb3491ca replace Flickable with ListViewType in drawer in PageSettingsApiNativeConfigs 2025-08-02 13:41:17 +02:00
Cyril Anisimov 62770f4c04 reorganize PageSettingsAbout for improved structure 2025-08-02 13:41:17 +02:00
Cyril Anisimov 2b0faca362 replace FlickableType with ListViewType in PageSettings 2025-08-02 13:41:17 +02:00
Cyril Anisimov 5533ce56d7 remove parentFlickable from PageShare 2025-08-02 13:41:17 +02:00
Cyril Anisimov a7e812f6b2 change position view mode 2025-08-02 13:41:17 +02:00
17 changed files with 629 additions and 474 deletions
+5 -5
View File
@@ -9,17 +9,17 @@
### [English]([https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md](https://github.com/amnezia-vpn/amnezia-client/tree/dev?tab=readme-ov-file#)) | [Русский](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md)
[Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
[Amnezia](https://amnezia.org) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
[![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org)
### [Website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
> [!TIP]
> If the [Amnezia website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror).
> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org ).
<a href="https://amnezia.org/en/downloads?utm_source=github&utm_campaign=amnezia_button-readme-en"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/en/downloads&utm_source=github&utm_campaign=amnezia_button-readme-en-mirrow"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
+4 -4
View File
@@ -6,16 +6,16 @@
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
[AmneziaVPN](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
[AmneziaVPN](https://amnezia.org) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
[![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org)
### [Сайт](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
### [Сайт](https://amnezia.org) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
> [!TIP]
> Если [сайт Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror).
> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org).
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/ru/downloads&utm_source=github&utm_campaign=amnezia_button-readme-ru-mirror"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
+1 -1
View File
@@ -245,10 +245,10 @@ void CoreController::initNotificationHandler()
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
&ConnectionController::closeConnection);
connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
#endif
auto* trayHandler = qobject_cast<SystemTrayNotificationHandler*>(m_notificationHandler.get());
connect(this, &CoreController::websiteUrlChanged, trayHandler, &SystemTrayNotificationHandler::updateWebsiteUrl);
#endif
}
void CoreController::updateTranslator(const QLocale &locale)
+1 -3
View File
@@ -5,9 +5,7 @@
#include <QQmlContext>
#include <QThread>
#ifndef Q_OS_ANDROID
#include "ui/systemtray_notificationhandler.h"
#endif
#include "ui/systemtray_notificationhandler.h"
#include "ui/controllers/api/apiConfigsController.h"
#include "ui/controllers/api/apiSettingsController.h"
+1 -1
View File
@@ -1,7 +1,7 @@
FROM alpine:3.15
LABEL maintainer="AmneziaVPN"
ARG XRAY_RELEASE="v25.8.3"
ARG XRAY_RELEASE="v1.8.6"
RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz
RUN apk --update upgrade --no-cache
+107 -76
View File
@@ -2,72 +2,128 @@
#include "protocols/protocols_defs.h"
OpenVpnConfigModel::OpenVpnConfigModel(QObject *parent) : QAbstractListModel(parent)
OpenVpnConfigModel::OpenVpnConfigModel(QObject *parent)
: QObject(parent)
{
}
int OpenVpnConfigModel::rowCount(const QModelIndex &parent) const
QString OpenVpnConfigModel::subnetAddress() const
{
Q_UNUSED(parent);
return 1;
return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress);
}
bool OpenVpnConfigModel::setData(const QModelIndex &index, const QVariant &value, int role)
void OpenVpnConfigModel::setSubnetAddress(const QString &subnetAddress)
{
if (!index.isValid() || index.row() < 0 || index.row() >= ContainerProps::allContainers().size()) {
return false;
}
switch (role) {
case Roles::SubnetAddressRole: m_protocolConfig.insert(amnezia::config_key::subnet_address, value.toString()); break;
case Roles::TransportProtoRole: m_protocolConfig.insert(config_key::transport_proto, value.toString()); break;
case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break;
case Roles::AutoNegotiateEncryprionRole: m_protocolConfig.insert(config_key::ncp_disable, !value.toBool()); break;
case Roles::HashRole: m_protocolConfig.insert(config_key::hash, value.toString()); break;
case Roles::CipherRole: m_protocolConfig.insert(config_key::cipher, value.toString()); break;
case Roles::TlsAuthRole: m_protocolConfig.insert(config_key::tls_auth, value.toBool()); break;
case Roles::BlockDnsRole: m_protocolConfig.insert(config_key::block_outside_dns, value.toBool()); break;
case Roles::AdditionalClientCommandsRole: m_protocolConfig.insert(config_key::additional_client_config, value.toString()); break;
case Roles::AdditionalServerCommandsRole: m_protocolConfig.insert(config_key::additional_server_config, value.toString()); break;
}
emit dataChanged(index, index, QList { role });
return true;
m_protocolConfig.insert(amnezia::config_key::subnet_address, subnetAddress);
}
QVariant OpenVpnConfigModel::data(const QModelIndex &index, int role) const
QString OpenVpnConfigModel::transportProto() const
{
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) {
return false;
}
return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto);
}
switch (role) {
case Roles::SubnetAddressRole:
return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress);
case Roles::TransportProtoRole:
return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto);
case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort);
case Roles::AutoNegotiateEncryprionRole:
return !m_protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
case Roles::HashRole: return m_protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash);
case Roles::CipherRole: return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher);
case Roles::TlsAuthRole: return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
case Roles::BlockDnsRole:
return m_protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns);
case Roles::AdditionalClientCommandsRole:
return m_protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig);
case Roles::AdditionalServerCommandsRole:
return m_protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig);
case Roles::IsPortEditable: return m_container == DockerContainer::OpenVpn ? true : false;
case Roles::IsTransportProtoEditable: return m_container == DockerContainer::OpenVpn ? true : false;
case Roles::HasRemoveButton: return m_container == DockerContainer::OpenVpn ? true : false;
}
return QVariant();
void OpenVpnConfigModel::setTransportProto(const QString &transportProto)
{
m_protocolConfig.insert(config_key::transport_proto, transportProto);
}
QString OpenVpnConfigModel::port() const
{
return m_protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort);
}
void OpenVpnConfigModel::setPort(const QString &port)
{
m_protocolConfig.insert(config_key::port, port);
}
bool OpenVpnConfigModel::autoNegotiateEncryption() const
{
return !m_protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
}
void OpenVpnConfigModel::setAutoNegotiateEncryption(bool enabled)
{
m_protocolConfig.insert(config_key::ncp_disable, !enabled);
}
QString OpenVpnConfigModel::hash() const
{
return m_protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash);
}
void OpenVpnConfigModel::setHash(const QString &hash)
{
m_protocolConfig.insert(config_key::hash, hash);
}
QString OpenVpnConfigModel::cipher() const
{
return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher);
}
void OpenVpnConfigModel::setCipher(const QString &cipher)
{
m_protocolConfig.insert(config_key::cipher, cipher);
}
bool OpenVpnConfigModel::tlsAuth() const
{
return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
}
void OpenVpnConfigModel::setTlsAuth(bool enabled)
{
m_protocolConfig.insert(config_key::tls_auth, enabled);
}
bool OpenVpnConfigModel::blockDns() const
{
return m_protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns);
}
void OpenVpnConfigModel::setBlockDns(bool enabled)
{
m_protocolConfig.insert(config_key::block_outside_dns, enabled);
}
QString OpenVpnConfigModel::additionalClientCommands() const
{
return m_protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig);
}
void OpenVpnConfigModel::setAdditionalClientCommands(const QString &commands)
{
m_protocolConfig.insert(config_key::additional_client_config, commands);
}
QString OpenVpnConfigModel::additionalServerCommands() const
{
return m_protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig);
}
void OpenVpnConfigModel::setAdditionalServerCommands(const QString &commands)
{
m_protocolConfig.insert(config_key::additional_server_config, commands);
}
bool OpenVpnConfigModel::isPortEditable() const
{
return m_container == DockerContainer::OpenVpn;
}
bool OpenVpnConfigModel::isTransportProtoEditable() const
{
return m_container == DockerContainer::OpenVpn;
}
bool OpenVpnConfigModel::hasRemoveButton() const
{
return m_container == DockerContainer::OpenVpn;
}
void OpenVpnConfigModel::updateModel(const QJsonObject &config)
{
beginResetModel();
m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
m_fullConfig = config;
@@ -100,8 +156,6 @@ void OpenVpnConfigModel::updateModel(const QJsonObject &config)
m_protocolConfig.insert(
config_key::additional_server_config,
protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig));
endResetModel();
}
QJsonObject OpenVpnConfigModel::getConfig()
@@ -109,26 +163,3 @@ QJsonObject OpenVpnConfigModel::getConfig()
m_fullConfig.insert(config_key::openvpn, m_protocolConfig);
return m_fullConfig;
}
QHash<int, QByteArray> OpenVpnConfigModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[SubnetAddressRole] = "subnetAddress";
roles[TransportProtoRole] = "transportProto";
roles[PortRole] = "port";
roles[AutoNegotiateEncryprionRole] = "autoNegotiateEncryprion";
roles[HashRole] = "hash";
roles[CipherRole] = "cipher";
roles[TlsAuthRole] = "tlsAuth";
roles[BlockDnsRole] = "blockDns";
roles[AdditionalClientCommandsRole] = "additionalClientCommands";
roles[AdditionalServerCommandsRole] = "additionalServerCommands";
roles[IsPortEditable] = "isPortEditable";
roles[IsTransportProtoEditable] = "isTransportProtoEditable";
roles[HasRemoveButton] = "hasRemoveButton";
return roles;
}
+70 -27
View File
@@ -1,47 +1,90 @@
#ifndef OPENVPNCONFIGMODEL_H
#define OPENVPNCONFIGMODEL_H
#include <QAbstractListModel>
#include <QObject>
#include <QJsonObject>
#include "containers/containers_defs.h"
class OpenVpnConfigModel : public QAbstractListModel
class OpenVpnConfigModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString subnetAddress READ subnetAddress WRITE setSubnetAddress NOTIFY subnetAddressChanged)
Q_PROPERTY(QString transportProto READ transportProto WRITE setTransportProto NOTIFY transportProtoChanged)
Q_PROPERTY(QString port READ port WRITE setPort NOTIFY portChanged)
Q_PROPERTY(bool autoNegotiateEncryption READ autoNegotiateEncryption WRITE setAutoNegotiateEncryption NOTIFY autoNegotiateEncryptionChanged)
Q_PROPERTY(QString hash READ hash WRITE setHash NOTIFY hashChanged)
Q_PROPERTY(QString cipher READ cipher WRITE setCipher NOTIFY cipherChanged)
Q_PROPERTY(bool tlsAuth READ tlsAuth WRITE setTlsAuth NOTIFY tlsAuthChanged)
Q_PROPERTY(bool blockDns READ blockDns WRITE setBlockDns NOTIFY blockDnsChanged)
Q_PROPERTY(QString additionalClientCommands READ additionalClientCommands WRITE setAdditionalClientCommands NOTIFY additionalClientCommandsChanged)
Q_PROPERTY(QString additionalServerCommands READ additionalServerCommands WRITE setAdditionalServerCommands NOTIFY additionalServerCommandsChanged)
Q_PROPERTY(bool isPortEditable READ isPortEditable NOTIFY isPortEditableChanged)
Q_PROPERTY(bool isTransportProtoEditable READ isTransportProtoEditable NOTIFY isTransportProtoEditableChanged)
Q_PROPERTY(bool hasRemoveButton READ hasRemoveButton NOTIFY hasRemoveButtonChanged)
public:
enum Roles {
SubnetAddressRole = Qt::UserRole + 1,
TransportProtoRole,
PortRole,
AutoNegotiateEncryprionRole,
HashRole,
CipherRole,
TlsAuthRole,
BlockDnsRole,
AdditionalClientCommandsRole,
AdditionalServerCommandsRole,
IsPortEditable,
IsTransportProtoEditable,
HasRemoveButton
};
explicit OpenVpnConfigModel(QObject *parent = nullptr);
~OpenVpnConfigModel() override = default;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
OpenVpnConfigModel(const OpenVpnConfigModel &) = delete;
OpenVpnConfigModel &operator=(const OpenVpnConfigModel &) = delete;
OpenVpnConfigModel(OpenVpnConfigModel &&) = delete;
OpenVpnConfigModel &operator=(OpenVpnConfigModel &&) = delete;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QString subnetAddress() const;
void setSubnetAddress(const QString &subnetAddress);
QString transportProto() const;
void setTransportProto(const QString &transportProto);
QString port() const;
void setPort(const QString &port);
bool autoNegotiateEncryption() const;
void setAutoNegotiateEncryption(bool enabled);
QString hash() const;
void setHash(const QString &hash);
QString cipher() const;
void setCipher(const QString &cipher);
bool tlsAuth() const;
void setTlsAuth(bool enabled);
bool blockDns() const;
void setBlockDns(bool enabled);
QString additionalClientCommands() const;
void setAdditionalClientCommands(const QString &commands);
QString additionalServerCommands() const;
void setAdditionalServerCommands(const QString &commands);
bool isPortEditable() const;
bool isTransportProtoEditable() const;
bool hasRemoveButton() const;
Q_INVOKABLE QJsonObject getConfig();
signals:
void subnetAddressChanged(const QString &);
void transportProtoChanged(const QString &);
void portChanged(const QString &);
void autoNegotiateEncryptionChanged(bool);
void hashChanged(const QString &);
void cipherChanged(const QString &);
void tlsAuthChanged(bool);
void blockDnsChanged(bool);
void additionalClientCommandsChanged(const QString &);
void additionalServerCommandsChanged(const QString &);
void isPortEditableChanged(bool);
void isTransportProtoEditableChanged(bool);
void hasRemoveButtonChanged(bool);
public slots:
void updateModel(const QJsonObject &config);
QJsonObject getConfig();
protected:
QHash<int, QByteArray> roleNames() const override;
private:
DockerContainer m_container;
@@ -34,7 +34,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.top: backButtonLayout.bottom
anchors.bottom: saveButton.top
anchors.right: parent.right
anchors.left: parent.left
@@ -37,7 +37,7 @@ PageType {
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -24,9 +24,9 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) {
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
@@ -46,345 +46,417 @@ PageType {
width: listView.width
BaseHeaderType {
id: header
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("OpenVPN Settings")
headerText: qsTr("OpenVPN settings")
}
}
model: OpenVpnConfigModel
model: ListModel {
ListElement { type: "subnetHeader" }
ListElement { type: "networkProtocolText" }
ListElement { type: "protoSelector" }
ListElement { type: "portTextField" }
ListElement { type: "encryptionSection" }
ListElement { type: "checkboxSection" }
ListElement { type: "clientCommands" }
ListElement { type: "serverCommands" }
}
delegate: ColumnLayout {
delegate: DelegateChooser {
role: "type"
DelegateChoice {
// property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
roleValue: "subnetHeader"
ColumnLayout {
width: listView.width
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("VPN address subnet")
textField.text: OpenVpnConfigModel.subnetAddress
textField.onEditingFinished: {
if (textField.text !== OpenVpnConfigModel.subnetAddress) {
OpenVpnConfigModel.subnetAddress = textField.text
}
}
}
}
}
DelegateChoice {
roleValue: "networkProtocolText"
ColumnLayout {
width: listView.width
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Network protocol")
}
}
}
DelegateChoice {
roleValue: "protoSelector"
ColumnLayout {
width: listView.width
TransportProtoSelector {
id: transportProtoSelector
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
rootWidth: root.width
enabled: OpenVpnConfigModel.isTransportProtoEditable
currentIndex: {
return OpenVpnConfigModel.transportProto === "tcp" ? 1 : 0
}
onCurrentIndexChanged: {
if (OpenVpnConfigModel.transportProto === "tcp" && currentIndex === 0) {
OpenVpnConfigModel.transportProto = "udp"
} else if (OpenVpnConfigModel.transportProto === "udp" && currentIndex === 1) {
OpenVpnConfigModel.transportProto = "tcp"
}
}
}
}
}
DelegateChoice {
roleValue: "portTextField"
ColumnLayout {
width: listView.width
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: OpenVpnConfigModel.isPortEditable
headerText: qsTr("Port")
textField.text: OpenVpnConfigModel.port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== OpenVpnConfigModel.port) {
OpenVpnConfigModel.port = textField.text
}
}
}
}
}
DelegateChoice {
roleValue: "encryptionSection"
ColumnLayout {
width: listView.width
SwitcherType {
id: autoNegotiateEncryprionSwitcher
Layout.fillWidth: true
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Auto-negotiate encryption")
checked: OpenVpnConfigModel.autoNegotiateEncryption
onCheckedChanged: {
if (checked !== OpenVpnConfigModel.autoNegotiateEncryprion) {
OpenVpnConfigModel.autoNegotiateEncryprion = checked
}
}
}
DropDownType {
id: hashDropDown
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked
descriptionText: qsTr("Hash")
headerText: qsTr("Hash")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: hashListView
rootWidth: root.width
model: ListModel {
ListElement { name : qsTr("SHA512") }
ListElement { name : qsTr("SHA384") }
ListElement { name : qsTr("SHA256") }
ListElement { name : qsTr("SHA3-512") }
ListElement { name : qsTr("SHA3-384") }
ListElement { name : qsTr("SHA3-256") }
ListElement { name : qsTr("whirlpool") }
ListElement { name : qsTr("BLAKE2b512") }
ListElement { name : qsTr("BLAKE2s256") }
ListElement { name : qsTr("SHA1") }
}
clickedFunction: function() {
hashDropDown.text = selectedText
OpenVpnConfigModel.hash = hashDropDown.text
hashDropDown.closeTriggered()
}
Component.onCompleted: {
hashDropDown.text = OpenVpnConfigModel.hash
for (var i = 0; i < hashListView.model.count; i++) {
if (hashListView.model.get(i).name === hashDropDown.text) {
currentIndex = i
}
}
}
}
}
DropDownType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
rootWidth: root.width
model: ListModel {
ListElement { name : qsTr("AES-256-GCM") }
ListElement { name : qsTr("AES-192-GCM") }
ListElement { name : qsTr("AES-128-GCM") }
ListElement { name : qsTr("AES-256-CBC") }
ListElement { name : qsTr("AES-192-CBC") }
ListElement { name : qsTr("AES-128-CBC") }
ListElement { name : qsTr("ChaCha20-Poly1305") }
ListElement { name : qsTr("ARIA-256-CBC") }
ListElement { name : qsTr("CAMELLIA-256-CBC") }
ListElement { name : qsTr("none") }
}
clickedFunction: function() {
cipherDropDown.text = selectedText
OpenVpnConfigModel.cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
cipherDropDown.text = OpenVpnConfigModel.cipher
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
currentIndex = i
}
}
}
}
}
}
}
DelegateChoice {
roleValue: "checkboxSection"
ColumnLayout {
width: listView.width
Rectangle {
id: contentRect
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.preferredHeight: checkboxLayout.implicitHeight
color: AmneziaStyle.color.onyxBlack
radius: 16
ColumnLayout {
id: checkboxLayout
anchors.fill: parent
CheckBoxType {
id: tlsAuthCheckBox
Layout.fillWidth: true
text: qsTr("TLS auth")
checked: OpenVpnConfigModel.tlsAuth
onCheckedChanged: {
if (checked !== OpenVpnConfigModel.tlsAuth) {
console.log("tlsAuth changed to: " + checked)
OpenVpnConfigModel.tlsAuth = checked
}
}
}
DividerType {}
CheckBoxType {
id: blockDnsCheckBox
Layout.fillWidth: true
text: qsTr("Block DNS requests outside of VPN")
checked: OpenVpnConfigModel.blockDns
onCheckedChanged: {
if (checked !== OpenVpnConfigModel.blockDns) {
OpenVpnConfigModel.blockDns = checked
}
}
}
}
}
}
}
DelegateChoice {
roleValue: "clientCommands"
ColumnLayout {
width: listView.width
SwitcherType {
id: additionalClientCommandsSwitcher
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
checked: OpenVpnConfigModel.additionalClientCommands !== ""
text: qsTr("Additional client configuration commands")
onCheckedChanged: {
if (!checked) {
OpenVpnConfigModel.additionalClientCommands = ""
}
// listView.positionViewAtIndex(index, ListView.Beginning)
}
}
TextAreaType {
id: additionalClientCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalClientCommandsSwitcher.checked
textAreaText: OpenVpnConfigModel.additionalClientCommands
placeholderText: qsTr("Commands:")
textArea.onEditingFinished: {
if (OpenVpnConfigModel.additionalClientCommands !== textAreaText) {
OpenVpnConfigModel.additionalClientCommands = textAreaText
}
}
}
}
}
DelegateChoice {
roleValue: "serverCommands"
ColumnLayout {
width: listView.width
SwitcherType {
id: additionalServerCommandsSwitcher
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
checked: OpenVpnConfigModel.additionalServerCommands !== ""
text: qsTr("Additional server configuration commands")
onCheckedChanged: {
if (!checked) {
OpenVpnConfigModel.additionalServerCommands = ""
}
// listView.positionViewAtIndex(index, ListView.Beginning)
}
}
TextAreaType {
id: additionalServerCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalServerCommandsSwitcher.checked
textAreaText: OpenVpnConfigModel.additionalServerCommands
placeholderText: qsTr("Commands:")
textArea.onEditingFinished: {
if (OpenVpnConfigModel.additionalServerCommands !== textAreaText) {
OpenVpnConfigModel.additionalServerCommands = textAreaText
}
}
}
}
}
}
footer: ColumnLayout {
width: listView.width
spacing: 0
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: listView.enabled
headerText: qsTr("VPN address subnet")
textField.text: subnetAddress
textField.onEditingFinished: {
if (textField.text !== subnetAddress) {
subnetAddress = textField.text
}
}
checkEmptyText: true
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Network protocol")
}
TransportProtoSelector {
id: transportProtoSelector
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
rootWidth: root.width
enabled: isTransportProtoEditable
currentIndex: {
return transportProto === "tcp" ? 1 : 0
}
onCurrentIndexChanged: {
if (transportProto === "tcp" && currentIndex === 0) {
transportProto = "udp"
} else if (transportProto === "udp" && currentIndex === 1) {
transportProto = "tcp"
}
}
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: listView.enabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
SwitcherType {
id: autoNegotiateEncryprionSwitcher
Layout.fillWidth: true
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Auto-negotiate encryption")
checked: autoNegotiateEncryprion
onCheckedChanged: {
if (checked !== autoNegotiateEncryprion) {
autoNegotiateEncryprion = checked
}
}
}
DropDownType {
id: hashDropDown
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked
descriptionText: qsTr("Hash")
headerText: qsTr("Hash")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: hashListView
rootWidth: root.width
model: ListModel {
ListElement { name : qsTr("SHA512") }
ListElement { name : qsTr("SHA384") }
ListElement { name : qsTr("SHA256") }
ListElement { name : qsTr("SHA3-512") }
ListElement { name : qsTr("SHA3-384") }
ListElement { name : qsTr("SHA3-256") }
ListElement { name : qsTr("whirlpool") }
ListElement { name : qsTr("BLAKE2b512") }
ListElement { name : qsTr("BLAKE2s256") }
ListElement { name : qsTr("SHA1") }
}
clickedFunction: function() {
hashDropDown.text = selectedText
hash = hashDropDown.text
hashDropDown.closeTriggered()
}
Component.onCompleted: {
hashDropDown.text = hash
for (var i = 0; i < hashListView.model.count; i++) {
if (hashListView.model.get(i).name === hashDropDown.text) {
currentIndex = i
}
}
}
}
}
DropDownType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
rootWidth: root.width
model: ListModel {
ListElement { name : qsTr("AES-256-GCM") }
ListElement { name : qsTr("AES-192-GCM") }
ListElement { name : qsTr("AES-128-GCM") }
ListElement { name : qsTr("AES-256-CBC") }
ListElement { name : qsTr("AES-192-CBC") }
ListElement { name : qsTr("AES-128-CBC") }
ListElement { name : qsTr("ChaCha20-Poly1305") }
ListElement { name : qsTr("ARIA-256-CBC") }
ListElement { name : qsTr("CAMELLIA-256-CBC") }
ListElement { name : qsTr("none") }
}
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
cipherDropDown.text = cipher
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
currentIndex = i
}
}
}
}
}
Rectangle {
id: contentRect
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.preferredHeight: checkboxLayout.implicitHeight
color: AmneziaStyle.color.onyxBlack
radius: 16
ColumnLayout {
id: checkboxLayout
anchors.fill: parent
CheckBoxType {
id: tlsAuthCheckBox
Layout.fillWidth: true
text: qsTr("TLS auth")
checked: tlsAuth
onCheckedChanged: {
if (checked !== tlsAuth) {
console.log("tlsAuth changed to: " + checked)
tlsAuth = checked
}
}
}
DividerType {}
CheckBoxType {
id: blockDnsCheckBox
Layout.fillWidth: true
text: qsTr("Block DNS requests outside of VPN")
checked: blockDns
onCheckedChanged: {
if (checked !== blockDns) {
blockDns = checked
}
}
}
}
}
SwitcherType {
id: additionalClientCommandsSwitcher
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
checked: additionalClientCommands !== ""
text: qsTr("Additional client configuration commands")
onCheckedChanged: {
if (!checked) {
additionalClientCommands = ""
}
}
}
TextAreaType {
id: additionalClientCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalClientCommandsSwitcher.checked
textAreaText: additionalClientCommands
placeholderText: qsTr("Commands:")
textArea.onEditingFinished: {
if (additionalClientCommands !== textAreaText) {
additionalClientCommands = textAreaText
}
}
}
SwitcherType {
id: additionalServerCommandsSwitcher
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
checked: additionalServerCommands !== ""
text: qsTr("Additional server configuration commands")
onCheckedChanged: {
if (!checked) {
additionalServerCommands = ""
}
}
}
TextAreaType {
id: additionalServerCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalServerCommandsSwitcher.checked
textAreaText: additionalServerCommands
placeholderText: qsTr("Commands:")
textArea.onEditingFinished: {
if (additionalServerCommands !== textAreaText) {
additionalServerCommands = textAreaText
}
}
}
BasicButtonType {
id: saveButton
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
@@ -393,7 +465,7 @@ PageType {
Layout.rightMargin: 16
enabled: vpnAddressSubnetTextField.errorText === "" &&
portTextField.errorText === ""
portTextField.errorText === ""
text: qsTr("Save")
@@ -66,6 +66,8 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("VPN address subnet")
textField.text: subnetAddress
@@ -85,6 +87,8 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
+4
View File
@@ -43,6 +43,8 @@ PageType {
LabelWithButtonType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: isVisible
@@ -66,6 +68,8 @@ PageType {
visible: GC.isDesktop()
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Close application")
leftImageSource: "qrc:/images/controls/x-circle.svg"
@@ -71,7 +71,6 @@ PageType {
text: countryName
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
hideDescription: isWorkerExpired ? true : false
descriptionColor: AmneziaStyle.color.vibrantRed
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
@@ -187,13 +187,7 @@ PageType {
iconPath: "qrc:/images/controls/alert-circle.svg"
visible: {
for (let i = 0; i < ApiCountryModel.count; ++i) {
if (ApiCountryModel.get(i).isWorkerExpired)
return true;
}
return false;
}
visible: ApiAccountInfoModel.data("hasExpiredWorker")
}
LabelWithButtonType {
+11 -7
View File
@@ -66,13 +66,6 @@ PageType {
text: qsTr("If AmneziaDNS is not used or installed")
}
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
spacing: 16
TextFieldWithHeaderType {
id: primaryDns
@@ -103,6 +96,13 @@ PageType {
regularExpression: InstallController.ipAddressRegExp()
}
}
}
model: 1 // fake model to force the ListView to be created without a model
spacing: 16
delegate: ColumnLayout {
width: listView.width
BasicButtonType {
id: restoreDefaultButton
@@ -139,6 +139,10 @@ PageType {
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
footer: ColumnLayout {
width: listView.width
BasicButtonType {
id: saveButton
@@ -18,8 +18,6 @@ PageType {
signal lastItemTabClickedSignal()
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
Connections {
target: InstallController
@@ -61,13 +59,15 @@ PageType {
target: ServersModel
function onProcessedServerIndexChanged() {
root.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
}
}
ListViewType {
id: listView
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
anchors.fill: parent
model: serverActions
@@ -107,7 +107,7 @@ PageType {
QtObject {
id: check
property bool isVisible: root.isServerWithWriteAccess
property bool isVisible: true
readonly property string title: qsTr("Check the server for previously installed Amnezia services")
readonly property string description: qsTr("Add them to the application if they were not displayed")
readonly property var tColor: AmneziaStyle.color.paleGray
@@ -121,7 +121,7 @@ PageType {
QtObject {
id: reboot
property bool isVisible: root.isServerWithWriteAccess
property bool isVisible: true
readonly property string title: qsTr("Reboot server")
readonly property string description: ""
readonly property var tColor: AmneziaStyle.color.vibrantRed
@@ -181,7 +181,7 @@ PageType {
QtObject {
id: clear
property bool isVisible: root.isServerWithWriteAccess
property bool isVisible: true
readonly property string title: qsTr("Clear server from Amnezia software")
readonly property string description: ""
readonly property var tColor: AmneziaStyle.color.vibrantRed
@@ -240,7 +240,7 @@ PageType {
QtObject {
id: switch_to_premium
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
readonly property string title: qsTr("Switch to the new Amnezia Premium subscription")
readonly property string description: ""
readonly property var tColor: AmneziaStyle.color.vibrantRed
@@ -161,4 +161,10 @@ PageType {
}
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
anchors.fill: parent
}
}