This commit is contained in:
Cyril Anisimov 2025-06-24 19:34:56 +03:00 committed by GitHub
commit 4c2eb95374
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 6513 additions and 6772 deletions

View file

@ -37,7 +37,7 @@ void ListViewFocusController::viewAtCurrentIndex() const
} }
case Section::Delegate: { case Section::Delegate: {
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index
Q_ARG(int, 2)); // PositionMode (0 = Visible) Q_ARG(int, 6)); // PositionMode (0 = Beginning; 1 = Center; 2 = End; 3 = Visible; 4 = Contain; 5 = SnapPosition)
break; break;
} }
case Section::Footer: { case Section::Footer: {
@ -207,6 +207,7 @@ void ListViewFocusController::focusNextItem()
m_focusedItemIndex++; m_focusedItemIndex++;
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex)); m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
m_focusedItem->forceActiveFocus(Qt::TabFocusReason); m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
qDebug() << "Next focus is set to item: " << m_focusedItem;
} }
void ListViewFocusController::focusPreviousItem() void ListViewFocusController::focusPreviousItem()
@ -238,6 +239,7 @@ void ListViewFocusController::resetFocusChain()
m_focusChain.clear(); m_focusChain.clear();
m_focusedItem = nullptr; m_focusedItem = nullptr;
m_focusedItemIndex = -1; m_focusedItemIndex = -1;
qDebug() << "Focus chain was reset";
} }
void ListViewFocusController::reloadFocusChain() void ListViewFocusController::reloadFocusChain()

View file

@ -2,72 +2,128 @@
#include "protocols/protocols_defs.h" #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;
}
bool OpenVpnConfigModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
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;
}
QVariant OpenVpnConfigModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) {
return false;
}
switch (role) {
case Roles::SubnetAddressRole:
return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress); 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::setSubnetAddress(const QString &subnetAddress)
{
m_protocolConfig.insert(amnezia::config_key::subnet_address, subnetAddress);
}
QString OpenVpnConfigModel::transportProto() const
{
return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto);
}
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) void OpenVpnConfigModel::updateModel(const QJsonObject &config)
{ {
beginResetModel();
m_container = ContainerProps::containerFromString(config.value(config_key::container).toString()); m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
m_fullConfig = config; m_fullConfig = config;
@ -100,8 +156,6 @@ void OpenVpnConfigModel::updateModel(const QJsonObject &config)
m_protocolConfig.insert( m_protocolConfig.insert(
config_key::additional_server_config, config_key::additional_server_config,
protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig)); protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig));
endResetModel();
} }
QJsonObject OpenVpnConfigModel::getConfig() QJsonObject OpenVpnConfigModel::getConfig()
@ -109,26 +163,3 @@ QJsonObject OpenVpnConfigModel::getConfig()
m_fullConfig.insert(config_key::openvpn, m_protocolConfig); m_fullConfig.insert(config_key::openvpn, m_protocolConfig);
return m_fullConfig; 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;
}

View file

@ -1,47 +1,90 @@
#ifndef OPENVPNCONFIGMODEL_H #ifndef OPENVPNCONFIGMODEL_H
#define OPENVPNCONFIGMODEL_H #define OPENVPNCONFIGMODEL_H
#include <QAbstractListModel> #include <QObject>
#include <QJsonObject> #include <QJsonObject>
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
class OpenVpnConfigModel : public QAbstractListModel class OpenVpnConfigModel : public QObject
{ {
Q_OBJECT 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: public:
enum Roles {
SubnetAddressRole = Qt::UserRole + 1,
TransportProtoRole,
PortRole,
AutoNegotiateEncryprionRole,
HashRole,
CipherRole,
TlsAuthRole,
BlockDnsRole,
AdditionalClientCommandsRole,
AdditionalServerCommandsRole,
IsPortEditable,
IsTransportProtoEditable,
HasRemoveButton
};
explicit OpenVpnConfigModel(QObject *parent = nullptr); 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; QString subnetAddress() const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 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: public slots:
void updateModel(const QJsonObject &config); void updateModel(const QJsonObject &config);
QJsonObject getConfig();
protected:
QHash<int, QByteArray> roleNames() const override;
private: private:
DockerContainer m_container; DockerContainer m_container;

View file

@ -10,8 +10,7 @@ import ProtocolEnum 1.0
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
ListViewType {
ListView {
id: menuContent id: menuContent
property var rootWidth property var rootWidth
@ -21,13 +20,6 @@ ListView {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
clip: true
snapMode: ListView.SnapToItem
ScrollBar.vertical: ScrollBarType {}
property bool isFocusable: true
ButtonGroup { ButtonGroup {
id: containersRadioButtonGroup id: containersRadioButtonGroup
} }

View file

@ -57,7 +57,7 @@ DrawerType2 {
headerText: qsTr("Choose application") headerText: qsTr("Choose application")
} }
ListView { ListViewType {
id: listView id: listView
Layout.fillWidth: true Layout.fillWidth: true
@ -66,11 +66,6 @@ DrawerType2 {
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
clip: true
interactive: true
property bool isFocusable: true
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxyInstalledAppsModel id: proxyInstalledAppsModel
sourceModel: installedAppsModel sourceModel: installedAppsModel
@ -81,20 +76,14 @@ DrawerType2 {
} }
} }
ScrollBar.vertical: ScrollBarType {}
ButtonGroup { ButtonGroup {
id: buttonGroup id: buttonGroup
} }
delegate: Item { delegate: ColumnLayout {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent id: delegateContent
anchors.fill: parent width: listView.width
RowLayout { RowLayout {
CheckBoxType { CheckBoxType {
@ -121,7 +110,6 @@ DrawerType2 {
} }
} }
} }
}
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: searchField id: searchField

View file

@ -49,7 +49,7 @@ DrawerType2 {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButtonLayout.bottom anchors.top: backButtonLayout.bottom
@ -57,14 +57,8 @@ DrawerType2 {
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
property bool isFocusable: true
property int selectedIndex: LanguageModel.currentLanguageIndex property int selectedIndex: LanguageModel.currentLanguageIndex
clip: true
reuseItems: true
ScrollBar.vertical: ScrollBarType {}
model: LanguageModel model: LanguageModel
ButtonGroup { ButtonGroup {

View file

@ -15,7 +15,7 @@ import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Config" import "../Config"
ListView { ListViewType {
id: root id: root
property int selectedIndex: ServersModel.defaultIndex property int selectedIndex: ServersModel.defaultIndex
@ -28,10 +28,6 @@ ListView {
model: ServersModel model: ServersModel
ScrollBar.vertical: ScrollBarType {}
property bool isFocusable: true
Connections { Connections {
target: ServersModel target: ServersModel
function onDefaultServerIndexChanged(serverIndex) { function onDefaultServerIndexChanged(serverIndex) {
@ -39,9 +35,6 @@ ListView {
} }
} }
clip: true
reuseItems: true
delegate: Item { delegate: Item {
id: menuContentDelegate id: menuContentDelegate
objectName: "menuContentDelegate" objectName: "menuContentDelegate"

View file

@ -13,29 +13,16 @@ import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
ListView { ListViewType {
id: root id: root
width: parent.width
height: root.contentItem.height
clip: true
reuseItems: true
property bool isFocusable: false
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent anchors.fill: parent
delegate: ColumnLayout {
width: root.width
LabelWithButtonType { LabelWithButtonType {
id: containerRadioButton Layout.fillWidth: true
implicitWidth: parent.width
text: name text: name
descriptionText: description descriptionText: description
@ -87,4 +74,3 @@ ListView {
DividerType {} DividerType {}
} }
} }
}

View file

@ -53,7 +53,7 @@ DrawerType2 {
headerText: root.headerText headerText: root.headerText
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: header.bottom anchors.top: header.bottom
@ -61,14 +61,7 @@ DrawerType2 {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
property bool isFocusable: true model: 1 // fake model to force the ListView to be created without a model
ScrollBar.vertical: ScrollBarType {}
model: 1
clip: true
reuseItems: true
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -185,9 +178,21 @@ DrawerType2 {
Connections { Connections {
target: copyNativeConfigStringButton target: copyNativeConfigStringButton
function onClicked() { function onClicked() {
nativeConfigString.selectAll() const headerItem = configListView.headerItem;
nativeConfigString.copy() if (!headerItem) {
nativeConfigString.select(0, 0) console.error("Failed to copy: header item not found in ListView")
return
}
const nativeConfigStringItem = configListView.findChildWithObjectName(headerItem.children, "nativeConfigString");
if (!nativeConfigStringItem) {
console.error("Failed to copy: nativeConfigString item not found in ListView")
return
}
nativeConfigStringItem.selectAll()
nativeConfigStringItem.copy()
nativeConfigStringItem.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
} }
} }
@ -195,11 +200,22 @@ DrawerType2 {
Connections { Connections {
target: copyConfigTextButton target: copyConfigTextButton
function onClicked() { function onClicked() {
configText.selectAll() const headerItem = configListView.headerItem;
configText.copy() if (!headerItem) {
configText.select(0, 0) console.error("Failed to copy: header item not found in ListView")
return
}
const configTextItem = configListView.findChildWithObjectName(headerItem.children, "configText");
if (!configTextItem) {
console.error("Failed to copy: configText item not found in ListView")
return
}
configTextItem.selectAll()
configTextItem.copy()
configTextItem.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
header.forceActiveFocus()
} }
} }
@ -214,30 +230,37 @@ DrawerType2 {
backButtonFunction: function() { configContentDrawer.closeTriggered() } backButtonFunction: function() { configContentDrawer.closeTriggered() }
} }
FlickableType { ListViewType {
id: configListView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
ColumnLayout { model: 1 // fake model to force the ListView to be created without a model
id: configContent
anchors.fill: parent header: ColumnLayout {
anchors.rightMargin: 16 width: configListView.width
anchors.leftMargin: 16
Header2Type { Header2Type {
id: configContentHeader id: configContentHeader
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: root.configContentHeaderText headerText: root.configContentHeaderText
} }
TextField { TextField {
id: nativeConfigString id: nativeConfigString
objectName: "nativeConfigString"
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: false visible: false
text: ExportController.nativeConfigString text: ExportController.nativeConfigString
@ -248,10 +271,13 @@ DrawerType2 {
TextArea { TextArea {
id: configText id: configText
objectName: "configText"
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.bottomMargin: 16 Layout.bottomMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
padding: 0 padding: 0
leftPadding: 0 leftPadding: 0

View file

@ -29,8 +29,6 @@ Button {
property bool squareLeftSide: false property bool squareLeftSide: false
property FlickableType parentFlickable
property var clickedFunc property var clickedFunc
property alias buttonTextLabel: buttonText property alias buttonTextLabel: buttonText
@ -65,14 +63,6 @@ Button {
hoverEnabled: true hoverEnabled: true
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(this)
}
}
}
background: Rectangle { background: Rectangle {
id: focusBorder id: focusBorder

View file

@ -27,8 +27,6 @@ Button {
property alias focusItem: rightImage property alias focusItem: rightImage
property FlickableType parentFlickable
hoverEnabled: true hoverEnabled: true
background: Rectangle { background: Rectangle {
@ -44,22 +42,6 @@ Button {
} }
} }
function ensureVisible(item) {
if (item.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
onFocusChanged: {
ensureVisible(root)
}
focusItem.onFocusChanged: {
root.ensureVisible(focusItem)
}
contentItem: Item { contentItem: Item {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right

View file

@ -34,13 +34,30 @@ CheckBox {
property string imageSource: "qrc:/images/controls/check.svg" property string imageSource: "qrc:/images/controls/check.svg"
property var parentFlickable property bool isFocusable: true
onFocusChanged: {
if (root.activeFocus) { Keys.onTabPressed: {
if (root.parentFlickable) { FocusController.nextKeyTabItem()
root.parentFlickable.ensureVisible(root)
} }
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
} }
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
} }
hoverEnabled: enabled ? true : false hoverEnabled: enabled ? true : false

View file

@ -9,6 +9,7 @@ import "TextTypes"
Item { Item {
id: root id: root
// property alias focusObjectName: eyeImage.objectName
property string text property string text
property int textMaximumLineCount: 2 property int textMaximumLineCount: 2
property int textElide: Qt.ElideRight property int textElide: Qt.ElideRight
@ -25,7 +26,6 @@ Item {
property alias rightButton: rightImage property alias rightButton: rightImage
property alias eyeButton: eyeImage property alias eyeButton: eyeImage
property FlickableType parentFlickable
property string textColor: AmneziaStyle.color.paleGray property string textColor: AmneziaStyle.color.paleGray
property string textDisabledColor: AmneziaStyle.color.mutedGray property string textDisabledColor: AmneziaStyle.color.mutedGray
@ -70,25 +70,6 @@ Item {
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
Connections {
target: rightImage
function onFocusChanged() {
if (rightImage.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor

View file

@ -6,33 +6,16 @@ ListView {
property bool isFocusable: true property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {} ScrollBar.vertical: ScrollBarType {}
clip: true clip: true
reuseItems: true reuseItems: true
snapMode: ListView.SnapToItem
function findChildWithObjectName(items, name) {
for (var i = 0; i < items.length; ++i) {
if (items[i].objectName === name)
return items[i];
}
return null;
}
} }

View file

@ -6,7 +6,7 @@ import Style 1.0
import "TextTypes" import "TextTypes"
ListView { ListViewType {
id: root id: root
property var rootWidth property var rootWidth
@ -25,13 +25,6 @@ ListView {
width: rootWidth width: rootWidth
height: root.contentItem.height height: root.contentItem.height
clip: true
reuseItems: true
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
ButtonGroup { ButtonGroup {
id: buttonGroup id: buttonGroup
} }

View file

@ -64,16 +64,6 @@ Switch {
hoverEnabled: enabled ? true : false hoverEnabled: enabled ? true : false
focusPolicy: Qt.TabFocus focusPolicy: Qt.TabFocus
property FlickableType parentFlickable: null
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
indicator: Rectangle { indicator: Rectangle {
id: switcher id: switcher

View file

@ -21,15 +21,6 @@ Rectangle {
border.color: getBorderColor(borderNormalColor) border.color: getBorderColor(borderNormalColor)
radius: 16 radius: 16
property FlickableType parentFlickable: null
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
MouseArea { MouseArea {
id: parentMouse id: parentMouse
anchors.fill: parent anchors.fill: parent
@ -54,6 +45,32 @@ Rectangle {
anchors.topMargin: 16 anchors.topMargin: 16
anchors.bottomMargin: 16 anchors.bottomMargin: 16
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
color: AmneziaStyle.color.paleGray color: AmneziaStyle.color.paleGray
selectionColor: AmneziaStyle.color.richBrown selectionColor: AmneziaStyle.color.richBrown
selectedTextColor: AmneziaStyle.color.paleGray selectedTextColor: AmneziaStyle.color.paleGray

View file

@ -31,15 +31,6 @@ Rectangle {
border.color: getBorderColor(borderNormalColor) border.color: getBorderColor(borderNormalColor)
radius: 16 radius: 16
property FlickableType parentFlickable: null
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
MouseArea { MouseArea {
id: parentMouse id: parentMouse
anchors.fill: parent anchors.fill: parent

View file

@ -37,19 +37,6 @@ Item {
implicitWidth: content.implicitWidth implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight implicitHeight: content.implicitHeight
property FlickableType parentFlickable
Connections {
target: textField
function onFocusChanged() {
if (textField.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
}
ColumnLayout { ColumnLayout {
id: content id: content
anchors.fill: parent anchors.fill: parent

View file

@ -20,7 +20,9 @@ PageType {
SortFilterProxyModel { SortFilterProxyModel {
id: proxyServersModel id: proxyServersModel
sourceModel: ServersModel sourceModel: ServersModel
filters: [ filters: [
ValueFilter { ValueFilter {
roleName: "isCurrentlyProcessed" roleName: "isCurrentlyProcessed"
@ -29,36 +31,23 @@ PageType {
] ]
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.fill: parent anchors.fill: parent
contentHeight: content.height
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 16 spacing: 16
Repeater {
model: proxyServersModel model: proxyServersModel
delegate: Item {
implicitWidth: parent.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout { delegate: ColumnLayout {
id: delegateContent width: listView.width
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Removing services from %1").arg(name) headerText: qsTr("Removing services from %1").arg(name)
} }
@ -68,6 +57,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
Timer { Timer {
id: timer id: timer
@ -84,12 +75,11 @@ PageType {
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Usually it takes no more than 5 minutes") text: qsTr("Usually it takes no more than 5 minutes")
} }
} }
} }
} }
}
}
}

View file

@ -25,23 +25,17 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
BaseHeaderType { BaseHeaderType {
id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
@ -50,16 +44,14 @@ PageType {
} }
} }
model: 1 model: 1 // fake model to force the ListView to be created without a model
clip: true
spacing: 16 spacing: 16
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: passwordTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
@ -87,8 +79,6 @@ PageType {
width: listView.width width: listView.width
SwitcherType { SwitcherType {
id: switcher
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.rightMargin: 16 Layout.rightMargin: 16

View file

@ -30,77 +30,41 @@ PageType {
} }
} }
ListView { ListViewType {
id: listview id: listView
anchors.top: backButtonLayout.bottom anchors.top: backButtonLayout.bottom
anchors.bottom: saveButton.top anchors.bottom: saveButton.top
width: parent.width width: parent.width
clip: true
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
model: AwgConfigModel model: AwgConfigModel
delegate: Item { delegate: ColumnLayout {
id: delegateItem width: listView.width
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === "" && property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" && junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" && junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" junkPacketCountTextField.errorText === ""
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0 spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("AmneziaWG settings") headerText: qsTr("AmneziaWG settings")
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: mtuTextField id: mtuTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("MTU") headerText: qsTr("MTU")
textField.text: clientMtu textField.text: clientMtu
@ -112,13 +76,15 @@ PageType {
} }
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: junkPacketCountTextField id: junkPacketCountTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jc - Junk packet count" headerText: "Jc - Junk packet count"
textField.text: clientJunkPacketCount textField.text: clientJunkPacketCount
@ -131,14 +97,15 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: junkPacketMinSizeTextField id: junkPacketMinSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jmin - Junk packet minimum size" headerText: "Jmin - Junk packet minimum size"
textField.text: clientJunkPacketMinSize textField.text: clientJunkPacketMinSize
@ -151,14 +118,15 @@ PageType {
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField id: junkPacketMaxSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jmax - Junk packet maximum size" headerText: "Jmax - Junk packet maximum size"
textField.text: clientJunkPacketMaxSize textField.text: clientJunkPacketMaxSize
@ -177,14 +145,19 @@ PageType {
Header2TextType { Header2TextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Server settings") text: qsTr("Server settings")
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: portTextField id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -194,8 +167,11 @@ PageType {
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: initPacketJunkSizeTextField id: initPacketJunkSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -205,8 +181,11 @@ PageType {
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField id: responsePacketJunkSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -216,8 +195,11 @@ PageType {
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField id: initPacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -227,8 +209,11 @@ PageType {
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField id: responsePacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -238,8 +223,11 @@ PageType {
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -249,8 +237,11 @@ PageType {
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField id: transportPacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -259,7 +250,6 @@ PageType {
} }
} }
} }
}
BasicButtonType { BasicButtonType {
id: saveButton id: saveButton
@ -273,18 +263,17 @@ PageType {
anchors.rightMargin: 16 anchors.rightMargin: 16
anchors.leftMargin: 16 anchors.leftMargin: 16
enabled: listview.currentItem.isSaveButtonEnabled enabled: listView.currentItem.isSaveButtonEnabled
text: qsTr("Save") text: qsTr("Save")
onActiveFocusChanged: { onActiveFocusChanged: {
if(activeFocus) { if(activeFocus) {
listview.positionViewAtEnd() listView.positionViewAtEnd()
} }
} }
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?") var headerText = qsTr("Save settings?")
var descriptionText = qsTr("Only the settings for this device will be changed") var descriptionText = qsTr("Only the settings for this device will be changed")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
@ -299,11 +288,9 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig()) InstallController.updateContainer(AwgConfigModel.getConfig())
} }
var noButtonFunction = function() {
if (!GC.isMobile()) { var noButtonFunction = function() {}
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }

View file

@ -33,66 +33,30 @@ PageType {
} }
} }
ListView { ListViewType {
id: listview id: listView
property bool isFocusable: true
anchors.top: backButtonLayout.bottom anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
clip: true
model: AwgConfigModel model: AwgConfigModel
delegate: Item { delegate: ColumnLayout {
id: delegateItem id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight width: listView.width
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0 spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("AmneziaWG settings") headerText: qsTr("AmneziaWG settings")
} }
@ -102,6 +66,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled enabled: delegateItem.isEnabled
@ -121,6 +87,8 @@ PageType {
id: portTextField id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled enabled: delegateItem.isEnabled
@ -142,6 +110,8 @@ PageType {
id: junkPacketCountTextField id: junkPacketCountTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jc - Junk packet count") headerText: qsTr("Jc - Junk packet count")
textField.text: serverJunkPacketCount textField.text: serverJunkPacketCount
@ -164,6 +134,8 @@ PageType {
id: junkPacketMinSizeTextField id: junkPacketMinSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jmin - Junk packet minimum size") headerText: qsTr("Jmin - Junk packet minimum size")
textField.text: serverJunkPacketMinSize textField.text: serverJunkPacketMinSize
@ -182,6 +154,8 @@ PageType {
id: junkPacketMaxSizeTextField id: junkPacketMaxSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jmax - Junk packet maximum size") headerText: qsTr("Jmax - Junk packet maximum size")
textField.text: serverJunkPacketMaxSize textField.text: serverJunkPacketMaxSize
@ -200,6 +174,8 @@ PageType {
id: initPacketJunkSizeTextField id: initPacketJunkSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("S1 - Init packet junk size") headerText: qsTr("S1 - Init packet junk size")
textField.text: serverInitPacketJunkSize textField.text: serverInitPacketJunkSize
@ -224,6 +200,8 @@ PageType {
id: responsePacketJunkSizeTextField id: responsePacketJunkSizeTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("S2 - Response packet junk size") headerText: qsTr("S2 - Response packet junk size")
textField.text: serverResponsePacketJunkSize textField.text: serverResponsePacketJunkSize
@ -248,6 +226,8 @@ PageType {
id: initPacketMagicHeaderTextField id: initPacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H1 - Init packet magic header") headerText: qsTr("H1 - Init packet magic header")
textField.text: serverInitPacketMagicHeader textField.text: serverInitPacketMagicHeader
@ -266,6 +246,8 @@ PageType {
id: responsePacketMagicHeaderTextField id: responsePacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H2 - Response packet magic header") headerText: qsTr("H2 - Response packet magic header")
textField.text: serverResponsePacketMagicHeader textField.text: serverResponsePacketMagicHeader
@ -284,6 +266,8 @@ PageType {
id: transportPacketMagicHeaderTextField id: transportPacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H4 - Transport packet magic header") headerText: qsTr("H4 - Transport packet magic header")
textField.text: serverTransportPacketMagicHeader textField.text: serverTransportPacketMagicHeader
@ -302,6 +286,8 @@ PageType {
id: underloadPacketMagicHeaderTextField id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H3 - Underload packet magic header") headerText: qsTr("H3 - Underload packet magic header")
textField.text: serverUnderloadPacketMagicHeader textField.text: serverUnderloadPacketMagicHeader
@ -322,6 +308,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: underloadPacketMagicHeaderTextField.errorText === "" && enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
transportPacketMagicHeaderTextField.errorText === "" && transportPacketMagicHeaderTextField.errorText === "" &&
@ -339,13 +327,11 @@ PageType {
onActiveFocusChanged: { onActiveFocusChanged: {
if(activeFocus) { if(activeFocus) {
listview.positionViewAtEnd() listView.positionViewAtEnd()
} }
} }
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
if (delegateItem.isEnabled) { if (delegateItem.isEnabled) {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text, if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
transportPacketMagicHeaderTextField.textField.text, transportPacketMagicHeaderTextField.textField.text,
@ -376,15 +362,12 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig()) InstallController.updateContainer(AwgConfigModel.getConfig())
} }
var noButtonFunction = function() {
if (!GC.isMobile()) { var noButtonFunction = function() {}
saveRestartButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
} }
} }
} }
}

View file

@ -16,77 +16,57 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Column {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
}
enabled: ServersModel.isProcessedServerHasWriteAccess() ListViewType {
id: listView
ListView { anchors.top: backButton.bottom
id: listview anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
property int selectedIndex: 0 property int selectedIndex: 0
width: parent.width enabled: ServersModel.isProcessedServerHasWriteAccess()
height: listview.contentItem.height
clip: true header: ColumnLayout {
reuseItems: true
model: CloakConfigModel width: listView.width
delegate: Item {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias trafficFromField: trafficFromField
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Cloak settings") headerText: qsTr("Cloak settings")
} }
}
model: CloakConfigModel
delegate: ColumnLayout {
width: listView.width
property alias trafficFromField: trafficFromField
spacing: 0
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: trafficFromField id: trafficFromField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Disguised as traffic from") headerText: qsTr("Disguised as traffic from")
textField.text: site textField.text: site
@ -111,6 +91,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Port") headerText: qsTr("Port")
textField.text: port textField.text: port
@ -126,8 +108,11 @@ PageType {
DropDownType { DropDownType {
id: cipherDropDown id: cipherDropDown
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
descriptionText: qsTr("Cipher") descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher") headerText: qsTr("Cipher")
@ -171,12 +156,12 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Save") text: qsTr("Save")
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return return
@ -189,6 +174,3 @@ PageType {
} }
} }
} }
}
}
}

View file

@ -17,158 +17,190 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Column {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
enabled: ServersModel.isProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView { header: ColumnLayout {
id: listview width: listView.width
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: OpenVpnConfigModel
delegate: Item {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("OpenVPN settings") headerText: qsTr("OpenVPN settings")
} }
}
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: DelegateChooser {
role: "type"
DelegateChoice {
// property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
roleValue: "subnetHeader"
ColumnLayout {
width: listView.width
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: vpnAddressSubnetTextField id: vpnAddressSubnetTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("VPN address subnet") headerText: qsTr("VPN address subnet")
textField.text: subnetAddress textField.text: OpenVpnConfigModel.subnetAddress
parentFlickable: fl
textField.onEditingFinished: { textField.onEditingFinished: {
if (textField.text !== subnetAddress) { if (textField.text !== OpenVpnConfigModel.subnetAddress) {
subnetAddress = textField.text OpenVpnConfigModel.subnetAddress = textField.text
} }
} }
} }
}
}
DelegateChoice {
roleValue: "networkProtocolText"
ColumnLayout {
width: listView.width
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Network protocol") text: qsTr("Network protocol")
} }
}
}
DelegateChoice {
roleValue: "protoSelector"
ColumnLayout {
width: listView.width
TransportProtoSelector { TransportProtoSelector {
id: transportProtoSelector id: transportProtoSelector
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
rootWidth: root.width rootWidth: root.width
enabled: isTransportProtoEditable enabled: OpenVpnConfigModel.isTransportProtoEditable
currentIndex: { currentIndex: {
return transportProto === "tcp" ? 1 : 0 return OpenVpnConfigModel.transportProto === "tcp" ? 1 : 0
} }
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (transportProto === "tcp" && currentIndex === 0) { if (OpenVpnConfigModel.transportProto === "tcp" && currentIndex === 0) {
transportProto = "udp" OpenVpnConfigModel.transportProto = "udp"
} else if (transportProto === "udp" && currentIndex === 1) { } else if (OpenVpnConfigModel.transportProto === "udp" && currentIndex === 1) {
transportProto = "tcp" OpenVpnConfigModel.transportProto = "tcp"
} }
} }
} }
}
}
DelegateChoice {
roleValue: "portTextField"
ColumnLayout {
width: listView.width
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: portTextField id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
parentFlickable: fl Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: isPortEditable enabled: OpenVpnConfigModel.isPortEditable
headerText: qsTr("Port") headerText: qsTr("Port")
textField.text: port textField.text: OpenVpnConfigModel.port
textField.maximumLength: 5 textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 } textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: { textField.onEditingFinished: {
if (textField.text !== port) { if (textField.text !== OpenVpnConfigModel.port) {
port = textField.text OpenVpnConfigModel.port = textField.text
} }
} }
} }
}
}
DelegateChoice {
roleValue: "encryptionSection"
ColumnLayout {
width: listView.width
SwitcherType { SwitcherType {
id: autoNegotiateEncryprionSwitcher id: autoNegotiateEncryprionSwitcher
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
parentFlickable: fl Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Auto-negotiate encryption") text: qsTr("Auto-negotiate encryption")
checked: autoNegotiateEncryprion checked: OpenVpnConfigModel.autoNegotiateEncryption
onCheckedChanged: { onCheckedChanged: {
if (checked !== autoNegotiateEncryprion) { if (checked !== OpenVpnConfigModel.autoNegotiateEncryprion) {
autoNegotiateEncryprion = checked OpenVpnConfigModel.autoNegotiateEncryprion = checked
} }
} }
} }
DropDownType { DropDownType {
id: hashDropDown id: hashDropDown
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked enabled: !autoNegotiateEncryprionSwitcher.checked
@ -197,12 +229,12 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
hashDropDown.text = selectedText hashDropDown.text = selectedText
hash = hashDropDown.text OpenVpnConfigModel.hash = hashDropDown.text
hashDropDown.closeTriggered() hashDropDown.closeTriggered()
} }
Component.onCompleted: { Component.onCompleted: {
hashDropDown.text = hash hashDropDown.text = OpenVpnConfigModel.hash
for (var i = 0; i < hashListView.model.count; i++) { for (var i = 0; i < hashListView.model.count; i++) {
if (hashListView.model.get(i).name === hashDropDown.text) { if (hashListView.model.get(i).name === hashDropDown.text) {
@ -215,8 +247,11 @@ PageType {
DropDownType { DropDownType {
id: cipherDropDown id: cipherDropDown
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked enabled: !autoNegotiateEncryprionSwitcher.checked
@ -245,12 +280,12 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
cipherDropDown.text = selectedText cipherDropDown.text = selectedText
cipher = cipherDropDown.text OpenVpnConfigModel.cipher = cipherDropDown.text
cipherDropDown.closeTriggered() cipherDropDown.closeTriggered()
} }
Component.onCompleted: { Component.onCompleted: {
cipherDropDown.text = cipher cipherDropDown.text = OpenVpnConfigModel.cipher
for (var i = 0; i < cipherListView.model.count; i++) { for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) { if (cipherListView.model.get(i).name === cipherDropDown.text) {
@ -260,41 +295,42 @@ PageType {
} }
} }
} }
}
}
DelegateChoice {
roleValue: "checkboxSection"
ColumnLayout {
width: listView.width
Rectangle { Rectangle {
id: contentRect id: contentRect
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.preferredHeight: checkboxLayout.implicitHeight Layout.preferredHeight: checkboxLayout.implicitHeight
color: AmneziaStyle.color.onyxBlack color: AmneziaStyle.color.onyxBlack
radius: 16 radius: 16
Connections {
target: tlsAuthCheckBox
enabled: !GC.isMobile()
function onFocusChanged() {
if (tlsAuthCheckBox.activeFocus) {
fl.ensureVisible(contentRect)
}
}
}
ColumnLayout { ColumnLayout {
id: checkboxLayout id: checkboxLayout
anchors.fill: parent anchors.fill: parent
CheckBoxType { CheckBoxType {
id: tlsAuthCheckBox id: tlsAuthCheckBox
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("TLS auth") text: qsTr("TLS auth")
checked: tlsAuth checked: OpenVpnConfigModel.tlsAuth
onCheckedChanged: { onCheckedChanged: {
if (checked !== tlsAuth) { if (checked !== OpenVpnConfigModel.tlsAuth) {
console.log("tlsAuth changed to: " + checked) console.log("tlsAuth changed to: " + checked)
tlsAuth = checked OpenVpnConfigModel.tlsAuth = checked
} }
} }
} }
@ -303,89 +339,121 @@ PageType {
CheckBoxType { CheckBoxType {
id: blockDnsCheckBox id: blockDnsCheckBox
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Block DNS requests outside of VPN") text: qsTr("Block DNS requests outside of VPN")
checked: blockDns checked: OpenVpnConfigModel.blockDns
onCheckedChanged: { onCheckedChanged: {
if (checked !== blockDns) { if (checked !== OpenVpnConfigModel.blockDns) {
blockDns = checked OpenVpnConfigModel.blockDns = checked
} }
} }
} }
} }
} }
}
}
DelegateChoice {
roleValue: "clientCommands"
ColumnLayout {
width: listView.width
SwitcherType { SwitcherType {
id: additionalClientCommandsSwitcher id: additionalClientCommandsSwitcher
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
parentFlickable: fl Layout.leftMargin: 16
Layout.rightMargin: 16
checked: additionalClientCommands !== "" checked: OpenVpnConfigModel.additionalClientCommands !== ""
text: qsTr("Additional client configuration commands") text: qsTr("Additional client configuration commands")
onCheckedChanged: { onCheckedChanged: {
if (!checked) { if (!checked) {
additionalClientCommands = "" OpenVpnConfigModel.additionalClientCommands = ""
} }
// listView.positionViewAtIndex(index, ListView.Beginning)
} }
} }
TextAreaType { TextAreaType {
id: additionalClientCommandsTextArea id: additionalClientCommandsTextArea
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalClientCommandsSwitcher.checked visible: additionalClientCommandsSwitcher.checked
parentFlickable: fl textAreaText: OpenVpnConfigModel.additionalClientCommands
textAreaText: additionalClientCommands
placeholderText: qsTr("Commands:") placeholderText: qsTr("Commands:")
textArea.onEditingFinished: { textArea.onEditingFinished: {
if (additionalClientCommands !== textAreaText) { if (OpenVpnConfigModel.additionalClientCommands !== textAreaText) {
additionalClientCommands = textAreaText OpenVpnConfigModel.additionalClientCommands = textAreaText
} }
} }
} }
}
}
DelegateChoice {
roleValue: "serverCommands"
ColumnLayout {
width: listView.width
SwitcherType { SwitcherType {
id: additionalServerCommandsSwitcher id: additionalServerCommandsSwitcher
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
parentFlickable: fl Layout.leftMargin: 16
Layout.rightMargin: 16
checked: additionalServerCommands !== "" checked: OpenVpnConfigModel.additionalServerCommands !== ""
text: qsTr("Additional server configuration commands") text: qsTr("Additional server configuration commands")
onCheckedChanged: { onCheckedChanged: {
if (!checked) { if (!checked) {
additionalServerCommands = "" OpenVpnConfigModel.additionalServerCommands = ""
} }
// listView.positionViewAtIndex(index, ListView.Beginning)
} }
} }
TextAreaType { TextAreaType {
id: additionalServerCommandsTextArea id: additionalServerCommandsTextArea
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalServerCommandsSwitcher.checked visible: additionalServerCommandsSwitcher.checked
textAreaText: additionalServerCommands textAreaText: OpenVpnConfigModel.additionalServerCommands
placeholderText: qsTr("Commands:") placeholderText: qsTr("Commands:")
parentFlickable: fl
textArea.onEditingFinished: { textArea.onEditingFinished: {
if (additionalServerCommands !== textAreaText) { if (OpenVpnConfigModel.additionalServerCommands !== textAreaText) {
additionalServerCommands = textAreaText OpenVpnConfigModel.additionalServerCommands = textAreaText
} }
} }
} }
}
}
}
footer: ColumnLayout {
width: listView.width
BasicButtonType { BasicButtonType {
id: saveRestartButton id: saveRestartButton
@ -393,13 +461,12 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Save") text: qsTr("Save")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return return
@ -412,6 +479,3 @@ PageType {
} }
} }
} }
}
}
}

View file

@ -19,69 +19,53 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: header id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
listView.positionViewAtBeginning()
} }
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
} }
} }
FlickableType {
id: fl
anchors.top: header.bottom
anchors.left: parent.left
anchors.right: parent.right
contentHeight: content.height
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
ListView {
id: listView
width: parent.width
height: contentItem.height
clip: true
interactive: false
model: ProtocolsModel model: ProtocolsModel
activeFocusOnTab: true delegate: ColumnLayout {
focus: true width: listView.width
delegate: Item {
implicitWidth: parent.width
implicitHeight: delegateContent.implicitHeight
property alias focusItem: button
ColumnLayout {
id: delegateContent
anchors.fill: parent
LabelWithButtonType { LabelWithButtonType {
id: button id: button
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Show connection options") text: qsTr("Show connection options")
@ -110,7 +94,7 @@ PageType {
implicitHeight: configContentDrawer.expandedHeight implicitHeight: configContentDrawer.expandedHeight
BackButtonType { BackButtonType {
id: backButton1 id: drawerBackButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
@ -122,36 +106,41 @@ PageType {
} }
} }
FlickableType { ListViewType {
anchors.top: backButton1.bottom id: drawerListView
anchors.left: parent.left
anchors.right: parent.right anchors.top: drawerBackButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin anchors.right: parent.right
anchors.left: parent.left
ColumnLayout { header: ColumnLayout {
id: configContent width: drawerListView.width
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type { Header2Type {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Connection options %1").arg(protocolName) headerText: qsTr("Connection options %1").arg(protocolName)
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: drawerListView.width
TextArea { TextArea {
id: configText id: configText
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.bottomMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16
padding: 0 padding: 0
leftPadding: 0
height: 24 height: 24
color: AmneziaStyle.color.paleGray color: AmneziaStyle.color.paleGray
@ -175,8 +164,9 @@ PageType {
} }
} }
} }
}
} footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: removeButton id: removeButton
@ -198,11 +188,7 @@ PageType {
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer() InstallController.removeProcessedContainer()
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }

View file

@ -16,70 +16,42 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Column {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
enabled: ServersModel.isProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: ShadowSocksConfigModel model: ShadowSocksConfigModel
delegate: Item { delegate: ColumnLayout {
implicitWidth: listview.width width: listView.width
implicitHeight: col.implicitHeight
property var focusItemId: portTextField.enabled ?
portTextField :
cipherDropDown.enabled ?
cipherDropDown :
saveRestartButton
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0 spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Shadowsocks settings") headerText: qsTr("Shadowsocks settings")
} }
@ -89,6 +61,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: isPortEditable enabled: isPortEditable
@ -106,8 +80,11 @@ PageType {
DropDownType { DropDownType {
id: cipherDropDown id: cipherDropDown
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: isCipherEditable enabled: isCipherEditable
@ -154,14 +131,14 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: isPortEditable | isCipherEditable enabled: isPortEditable | isCipherEditable
text: qsTr("Save") text: qsTr("Save")
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return return
@ -174,6 +151,3 @@ PageType {
} }
} }
} }
}
}
}

View file

@ -16,77 +16,43 @@ import "../Components"
PageType { PageType {
id: root id: root
Item {
id: focusItem
onFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
KeyNavigation.tab: listview.currentItem.mtuTextField.textField
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin
Column {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
ListView { onFocusChanged: {
id: listview if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
width: parent.width ListViewType {
height: listview.contentItem.height id: listView
clip: true anchors.top: backButton.bottom
interactive: false anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
model: WireGuardConfigModel model: WireGuardConfigModel
delegate: Item { delegate: ColumnLayout {
id: delegateItem width: listView.width
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias mtuTextField: mtuTextField property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === "" property bool isSaveButtonEnabled: mtuTextField.errorText === ""
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0 spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("WG settings") headerText: qsTr("WG settings")
} }
@ -95,6 +61,8 @@ PageType {
id: mtuTextField id: mtuTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("MTU") headerText: qsTr("MTU")
textField.text: clientMtu textField.text: clientMtu
@ -106,12 +74,13 @@ PageType {
} }
} }
checkEmptyText: true checkEmptyText: true
KeyNavigation.tab: saveButton
} }
Header2TextType { Header2TextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Server settings") text: qsTr("Server settings")
} }
@ -120,6 +89,8 @@ PageType {
id: portTextField id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false enabled: false
@ -127,29 +98,24 @@ PageType {
textField.text: port textField.text: port
} }
} }
}
} footer: ColumnLayout {
} width: listView.width
}
BasicButtonType { BasicButtonType {
id: saveButton id: saveButton
anchors.right: root.right Layout.fillWidth: true
anchors.left: root.left Layout.topMargin: 24
anchors.bottom: root.bottom Layout.bottomMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
anchors.topMargin: 24 enabled: listView.currentItem.isSaveButtonEnabled
anchors.bottomMargin: 24
anchors.rightMargin: 16
anchors.leftMargin: 16
enabled: listview.currentItem.isSaveButtonEnabled
text: qsTr("Save") text: qsTr("Save")
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?") var headerText = qsTr("Save settings?")
var descriptionText = qsTr("Only the settings for this device will be changed") var descriptionText = qsTr("Only the settings for this device will be changed")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
@ -164,12 +130,10 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(WireGuardConfigModel.getConfig()) InstallController.updateContainer(WireGuardConfigModel.getConfig())
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
if (!GC.isMobile()) {
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
} }
}
}

View file

@ -16,76 +16,55 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Column {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
enabled: ServersModel.isProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: WireGuardConfigModel model: WireGuardConfigModel
delegate: Item { delegate: ColumnLayout {
id: delegateItem width: listView.width
property alias focusItemId: vpnAddressSubnetTextField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
implicitWidth: listview.width
implicitHeight: col.implicitHeight
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0 spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("WG settings") headerText: qsTr("WG settings")
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: vpnAddressSubnetTextField id: vpnAddressSubnetTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled enabled: delegateItem.isEnabled
@ -105,6 +84,8 @@ PageType {
id: portTextField id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled enabled: delegateItem.isEnabled
@ -124,9 +105,12 @@ PageType {
BasicButtonType { BasicButtonType {
id: saveButton id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: portTextField.errorText === "" && enabled: portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === "" vpnAddressSubnetTextField.errorText === ""
@ -164,6 +148,3 @@ PageType {
} }
} }
} }
}
}
}

View file

@ -17,73 +17,48 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType {
id: backButton
}
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: XrayConfigModel model: XrayConfigModel
delegate: Item { delegate: ColumnLayout {
width: listView.width
property alias focusItemId: textFieldWithHeaderType.textField property alias focusItemId: textFieldWithHeaderType.textField
implicitWidth: listview.width
implicitHeight: col.implicitHeight
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0 spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("XRay settings") headerText: qsTr("XRay settings")
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: textFieldWithHeaderType id: textFieldWithHeaderType
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Disguised as traffic from") headerText: qsTr("Disguised as traffic from")
textField.text: site textField.text: site
@ -107,6 +82,8 @@ PageType {
id: portTextField id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled enabled: delegateItem.isEnabled
@ -126,15 +103,16 @@ PageType {
BasicButtonType { BasicButtonType {
id: saveButton id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Save") text: qsTr("Save")
onClicked: { onClicked: {
forceActiveFocus()
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return return
@ -142,16 +120,11 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(XrayConfigModel.getConfig()) InstallController.updateContainer(XrayConfigModel.getConfig())
focusItem.forceActiveFocus()
} }
Keys.onEnterPressed: basicButton.clicked() Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: basicButton.clicked() Keys.onReturnPressed: saveButton.clicked()
} }
} }
} }
} }
}
}
}

View file

@ -16,50 +16,47 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
ColumnLayout {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.bottomMargin: 24
headerText: "AmneziaDNS" headerText: "AmneziaDNS"
descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") + descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") +
qsTr("The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab.") qsTr("The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab.")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: removeButton Layout.fillWidth: true
Layout.leftMargin: 16
Layout.topMargin: 24 Layout.rightMargin: 16
width: parent.width
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: AmneziaStyle.color.vibrantRed textColor: AmneziaStyle.color.vibrantRed
@ -73,17 +70,12 @@ PageType {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
&& SettingsController.isAmneziaDnsEnabled()) { && SettingsController.isAmneziaDnsEnabled()) {
PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server")) PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server"))
} else } else {
{
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer() InstallController.removeProcessedContainer()
} }
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
if (!GC.isMobile()) {
removeButton.rightButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }

View file

@ -24,64 +24,35 @@ PageType {
} }
} }
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Column {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
enabled: ServersModel.isProcessedServerHasWriteAccess() enabled: ServersModel.isProcessedServerHasWriteAccess()
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: SftpConfigModel model: SftpConfigModel
onFocusChanged: { delegate: ColumnLayout {
if (focus) { width: listView.width
listview.currentItem.listViewFocusItem.forceActiveFocus()
}
}
delegate: Item {
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias listViewFocusItem: hostLabel.rightButton
ColumnLayout {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0 spacing: 0
@ -95,10 +66,11 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: hostLabel id: hostLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
parentFlickable: fl Layout.rightMargin: 16
text: qsTr("Host") text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName") descriptionText: ServersModel.getProcessedServerData("hostName")
@ -111,69 +83,63 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
LabelWithButtonType { LabelWithButtonType {
id: portLabel id: portLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Port") text: qsTr("Port")
descriptionText: port descriptionText: port
descriptionOnTop: true descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg" rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
LabelWithButtonType { LabelWithButtonType {
id: usernameLabel id: usernameLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("User name") text: qsTr("User name")
descriptionText: username descriptionText: username
descriptionOnTop: true descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg" rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
LabelWithButtonType { LabelWithButtonType {
id: passwordLabel id: passwordLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Password") text: qsTr("Password")
descriptionText: password descriptionText: password
descriptionOnTop: true descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg" rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray rightImageColor: AmneziaStyle.color.paleGray
@ -182,14 +148,12 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
BasicButtonType { BasicButtonType {
id: mountButton id: mountButton
visible: !GC.isMobile() visible: !GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -205,8 +169,6 @@ PageType {
textColor: AmneziaStyle.color.paleGray textColor: AmneziaStyle.color.paleGray
borderWidth: 1 borderWidth: 1
parentFlickable: fl
text: qsTr("Mount folder on device") text: qsTr("Mount folder on device")
clickedFunc: function() { clickedFunc: function() {
@ -246,7 +208,6 @@ PageType {
return str return str
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
@ -256,6 +217,7 @@ PageType {
BasicButtonType { BasicButtonType {
id: detailedInstructionsButton id: detailedInstructionsButton
Layout.topMargin: 16 Layout.topMargin: 16
Layout.bottomMargin: 16 Layout.bottomMargin: 16
Layout.leftMargin: 8 Layout.leftMargin: 8
@ -269,8 +231,6 @@ PageType {
text: qsTr("Detailed instructions") text: qsTr("Detailed instructions")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") // Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
} }
@ -278,6 +238,3 @@ PageType {
} }
} }
} }
}
}
}

View file

@ -25,55 +25,33 @@ PageType {
} }
} }
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
listView.positionViewAtBeginning()
}
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: listview.implicitHeight anchors.right: parent.right
anchors.left: parent.left
ListView {
id: listview
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
model: Socks5ProxyConfigModel model: Socks5ProxyConfigModel
onFocusChanged: { delegate: ColumnLayout {
if (focus) { width: listView.width
listview.currentItem.focusItemId.forceActiveFocus()
}
}
delegate: Item {
implicitWidth: listview.width
implicitHeight: content.implicitHeight
property alias focusItemId: hostLabel.rightButton
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0 spacing: 0
@ -86,11 +64,10 @@ PageType {
} }
LabelWithButtonType { LabelWithButtonType {
id: hostLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.rightMargin: 16
parentFlickable: fl Layout.bottomMargin: 16
text: qsTr("Host") text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName") descriptionText: ServersModel.getProcessedServerData("hostName")
@ -103,69 +80,57 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
LabelWithButtonType { LabelWithButtonType {
id: portLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("Port") text: qsTr("Port")
descriptionText: port descriptionText: port
descriptionOnTop: true descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg" rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
LabelWithButtonType { LabelWithButtonType {
id: usernameLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("User name") text: qsTr("User name")
descriptionText: username descriptionText: username
descriptionOnTop: true descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg" rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
LabelWithButtonType { LabelWithButtonType {
id: passwordLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("Password") text: qsTr("Password")
descriptionText: password descriptionText: password
descriptionOnTop: true descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg" rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray rightImageColor: AmneziaStyle.color.paleGray
@ -174,9 +139,6 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
@ -219,6 +181,8 @@ PageType {
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("SOCKS5 settings") headerText: qsTr("SOCKS5 settings")
} }
@ -228,7 +192,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
parentFlickable: fl Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Port") headerText: qsTr("Port")
textField.text: port textField.text: port
@ -248,7 +213,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
parentFlickable: fl Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Username") headerText: qsTr("Username")
textField.placeholderText: "username" textField.placeholderText: "username"
@ -270,7 +236,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
parentFlickable: fl Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Password") headerText: qsTr("Password")
textField.placeholderText: "password" textField.placeholderText: "password"
@ -299,12 +266,11 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.rightMargin: 16
text: qsTr("Change connection settings") text: qsTr("Change connection settings")
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
if (!portTextField.textField.acceptableInput) { if (!portTextField.textField.acceptableInput) {
portTextField.errorText = qsTr("The port must be in the range of 1 to 65535") portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
return return
@ -340,12 +306,9 @@ PageType {
text: qsTr("Change connection settings") text: qsTr("Change connection settings")
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
changeSettingsDrawer.openTriggered() changeSettingsDrawer.openTriggered()
} }
} }
} }
} }
} }
}
}

View file

@ -25,34 +25,25 @@ PageType {
} }
} }
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType { BackButtonType {
id: backButton id: backButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
ColumnLayout {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
}
spacing: 0 ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -61,11 +52,19 @@ PageType {
headerText: qsTr("Tor website settings") headerText: qsTr("Tor website settings")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: websiteName id: websiteName
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.bottomMargin: 24
text: qsTr("Website address") text: qsTr("Website address")
descriptionText: { descriptionText: {
@ -83,15 +82,16 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
} }
} }
} }
footer: ColumnLayout {
width: listView.width
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16

View file

@ -14,130 +14,62 @@ import "../Config"
PageType { PageType {
id: root id: root
FlickableType { ListViewType {
id: fl id: listView
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout { anchors.fill: parent
id: content
anchors.top: parent.top header: ColumnLayout {
anchors.left: parent.left width: listView.width
anchors.right: parent.right
spacing: 0
BaseHeaderType { BaseHeaderType {
id: header id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
headerText: qsTr("Settings") headerText: qsTr("Settings")
} }
}
model: settingsEntries
delegate: ColumnLayout {
width: listView.width
spacing: 0
LabelWithButtonType { LabelWithButtonType {
id: account
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Servers") visible: isVisible
text: title
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/server.svg" leftImageSource: leftImagePath
clickedFunction: function() { clickedFunction: clickedHandler
PageController.goToPage(PageEnum.PageSettingsServersList)
}
}
DividerType {}
LabelWithButtonType {
id: connection
Layout.fillWidth: true
text: qsTr("Connection")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/radio.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsConnection)
}
}
DividerType {}
LabelWithButtonType {
id: application
Layout.fillWidth: true
text: qsTr("Application")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/app.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsApplication)
}
}
DividerType {}
LabelWithButtonType {
id: backup
Layout.fillWidth: true
text: qsTr("Backup")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/save.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
}
DividerType {}
LabelWithButtonType {
id: about
Layout.fillWidth: true
text: qsTr("About AmneziaVPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/amnezia.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAbout)
}
}
DividerType {}
LabelWithButtonType {
id: devConsole
visible: SettingsController.isDevModeEnabled
Layout.fillWidth: true
text: qsTr("Dev console")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/bug.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageDevMenu)
}
} }
DividerType { DividerType {
visible: SettingsController.isDevModeEnabled visible: isVisible
} }
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: close id: close
visible: GC.isDesktop() visible: GC.isDesktop()
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: about.height Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Close application") text: qsTr("Close application")
leftImageSource: "qrc:/images/controls/x-circle.svg" leftImageSource: "qrc:/images/controls/x-circle.svg"
@ -149,8 +81,87 @@ PageType {
} }
DividerType { DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: GC.isDesktop() visible: GC.isDesktop()
} }
} }
} }
property list<QtObject> settingsEntries: [
servers,
connection,
application,
backup,
about,
devConsole
]
QtObject {
id: servers
property string title: qsTr("Servers")
readonly property string leftImagePath: "qrc:/images/controls/server.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsServersList)
}
}
QtObject {
id: connection
property string title: qsTr("Connection")
readonly property string leftImagePath: "qrc:/images/controls/radio.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsConnection)
}
}
QtObject {
id: application
property string title: qsTr("Application")
readonly property string leftImagePath: "qrc:/images/controls/app.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsApplication)
}
}
QtObject {
id: backup
property string title: qsTr("Backup")
readonly property string leftImagePath: "qrc:/images/controls/save.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
}
QtObject {
id: about
property string title: qsTr("About AmneziaVPN")
readonly property string leftImagePath: "qrc:/images/controls/amnezia.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsAbout)
}
}
QtObject {
id: devConsole
property string title: qsTr("Dev console")
readonly property string leftImagePath: "qrc:/images/controls/bug.svg"
property bool isVisible: SettingsController.isDevModeEnabled
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageDevMenu)
}
}
} }

View file

@ -29,58 +29,7 @@ PageType {
} }
} }
QtObject { ListViewType {
id: telegramGroup
readonly property string title: qsTr("Telegram group")
readonly property string description: qsTr("To discuss features")
readonly property string imageSource: "qrc:/images/controls/telegram.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
}
}
QtObject {
id: mail
readonly property string title: qsTr("support@amnezia.org")
readonly property string description: qsTr("For reviews and bug reports")
readonly property string imageSource: "qrc:/images/controls/mail.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
}
}
QtObject {
id: github
readonly property string title: qsTr("GitHub")
readonly property string description: qsTr("Discover the source code")
readonly property string imageSource: "qrc:/images/controls/github.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
}
}
QtObject {
id: website
readonly property string title: qsTr("Website")
readonly property string description: qsTr("Visit official website")
readonly property string imageSource: "qrc:/images/controls/amnezia.svg"
readonly property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
property list<QtObject> contacts: [
telegramGroup,
mail,
github,
website
]
ListView {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
@ -88,38 +37,6 @@ PageType {
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
model: contacts
clip: true
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -170,6 +87,8 @@ PageType {
} }
} }
model: contacts
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
@ -257,4 +176,55 @@ PageType {
} }
} }
} }
QtObject {
id: telegramGroup
readonly property string title: qsTr("Telegram group")
readonly property string description: qsTr("To discuss features")
readonly property string imageSource: "qrc:/images/controls/telegram.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
}
}
QtObject {
id: mail
readonly property string title: qsTr("support@amnezia.org")
readonly property string description: qsTr("For reviews and bug reports")
readonly property string imageSource: "qrc:/images/controls/mail.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
}
}
QtObject {
id: github
readonly property string title: qsTr("GitHub")
readonly property string description: qsTr("Discover the source code")
readonly property string imageSource: "qrc:/images/controls/github.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
}
}
QtObject {
id: website
readonly property string title: qsTr("Website")
readonly property string description: qsTr("Visit official website")
readonly property string imageSource: "qrc:/images/controls/amnezia.svg"
readonly property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
property list<QtObject> contacts: [
telegramGroup,
mail,
github,
website
]
} }

View file

@ -22,22 +22,28 @@ PageType {
property string configExtension: ".conf" property string configExtension: ".conf"
property string configCaption: qsTr("Save AmneziaVPN config") property string configCaption: qsTr("Save AmneziaVPN config")
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
}
ListViewType { ListViewType {
id: listView id: listView
anchors.fill: parent anchors.top: backButton.bottom
anchors.topMargin: 20 anchors.bottom: parent.bottom
anchors.bottomMargin: 24 anchors.right: parent.right
anchors.left: parent.left
model: ApiCountryModel model: ApiCountryModel
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
BackButtonType {
id: backButton
}
BaseHeaderType { BaseHeaderType {
id: header id: header
@ -104,30 +110,34 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: drawerListView
anchors.top: moreOptionsDrawerBackButton.bottom anchors.top: moreOptionsDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: moreOptionsDrawerContent.height
ColumnLayout {
id: moreOptionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
header: ColumnLayout {
width: drawerListView.width
Header2Type { Header2Type {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file") headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: drawerListView.width
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Generate a new configuration file") text: qsTr("Generate a new configuration file")
descriptionText: qsTr("The previously created one will stop working") descriptionText: qsTr("The previously created one will stop working")
@ -138,9 +148,16 @@ PageType {
} }
DividerType {} DividerType {}
}
footer: ColumnLayout {
width: drawerListView.width
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Revoke the current configuration file") text: qsTr("Revoke the current configuration file")
clickedFunction: function() { clickedFunction: function() {
@ -212,8 +229,7 @@ PageType {
} }
moreOptionsDrawer.closeTriggered() moreOptionsDrawer.closeTriggered()
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }

View file

@ -50,6 +50,7 @@ PageType {
readonly property string name: qsTr("Only the apps from the list should have access via VPN") readonly property string name: qsTr("Only the apps from the list should have access via VPN")
readonly property int type: routeMode.onlyForwardApps readonly property int type: routeMode.onlyForwardApps
} }
QtObject { QtObject {
id: allExceptApps id: allExceptApps
@ -146,24 +147,14 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: listView
anchors.top: header.bottom anchors.top: header.bottom
anchors.topMargin: 16 anchors.bottom: addAppButton.top
contentHeight: col.implicitHeight + addAppButton.implicitHeight + addAppButton.anchors.bottomMargin + addAppButton.anchors.topMargin
enabled: root.pageEnabled
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
ListView {
id: apps
width: parent.width
height: apps.contentItem.height
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxyAppSplitTunnelingModel id: proxyAppSplitTunnelingModel
sourceModel: AppSplitTunnelingModel sourceModel: AppSplitTunnelingModel
@ -177,23 +168,15 @@ PageType {
] ]
} }
clip: true delegate: ColumnLayout {
interactive: false width: listView.width
delegate: Item {
implicitWidth: apps.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: appPath text: appPath
rightImageSource: "qrc:/images/controls/trash.svg" rightImageSource: "qrc:/images/controls/trash.svg"
rightImageColor: AmneziaStyle.color.paleGray rightImageColor: AmneziaStyle.color.paleGray
@ -216,9 +199,6 @@ PageType {
DividerType {} DividerType {}
} }
} }
}
}
}
Rectangle { Rectangle {
anchors.fill: addAppButton anchors.fill: addAppButton

View file

@ -23,20 +23,16 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
spacing: 0 header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -45,9 +41,17 @@ PageType {
headerText: qsTr("Application") headerText: qsTr("Application")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
SwitcherType { SwitcherType {
id: switcher id: switcherAllowScreenshots
visible: GC.isMobile() visible: GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -61,10 +65,6 @@ PageType {
SettingsController.toggleScreenshotsEnabled(checked) SettingsController.toggleScreenshotsEnabled(checked)
} }
} }
// KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
// labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
parentFlickable: fl
} }
DividerType { DividerType {
@ -73,15 +73,15 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonNotification id: labelWithButtonNotification
visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Enable notifications") text: qsTr("Enable notifications")
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar") descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
SettingsController.requestNotificationPermission() SettingsController.requestNotificationPermission()
} }
@ -93,6 +93,7 @@ PageType {
SwitcherType { SwitcherType {
id: switcherAutoStart id: switcherAutoStart
visible: !GC.isMobile() visible: !GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -101,8 +102,6 @@ PageType {
text: qsTr("Auto start") text: qsTr("Auto start")
descriptionText: qsTr("Launch the application every time the device is starts") descriptionText: qsTr("Launch the application every time the device is starts")
parentFlickable: fl
checked: SettingsController.isAutoStartEnabled() checked: SettingsController.isAutoStartEnabled()
onCheckedChanged: { onCheckedChanged: {
if (checked !== SettingsController.isAutoStartEnabled()) { if (checked !== SettingsController.isAutoStartEnabled()) {
@ -117,6 +116,7 @@ PageType {
SwitcherType { SwitcherType {
id: switcherAutoConnect id: switcherAutoConnect
visible: !GC.isMobile() visible: !GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -125,8 +125,6 @@ PageType {
text: qsTr("Auto connect") text: qsTr("Auto connect")
descriptionText: qsTr("Connect to VPN on app start") descriptionText: qsTr("Connect to VPN on app start")
parentFlickable: fl
checked: SettingsController.isAutoConnectEnabled() checked: SettingsController.isAutoConnectEnabled()
onCheckedChanged: { onCheckedChanged: {
if (checked !== SettingsController.isAutoConnectEnabled()) { if (checked !== SettingsController.isAutoConnectEnabled()) {
@ -141,6 +139,7 @@ PageType {
SwitcherType { SwitcherType {
id: switcherStartMinimized id: switcherStartMinimized
visible: !GC.isMobile() visible: !GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -149,8 +148,6 @@ PageType {
text: qsTr("Start minimized") text: qsTr("Start minimized")
descriptionText: qsTr("Launch application minimized") descriptionText: qsTr("Launch application minimized")
parentFlickable: fl
checked: SettingsController.isStartMinimizedEnabled() checked: SettingsController.isStartMinimizedEnabled()
onCheckedChanged: { onCheckedChanged: {
if (checked !== SettingsController.isStartMinimizedEnabled()) { if (checked !== SettingsController.isStartMinimizedEnabled()) {
@ -162,17 +159,21 @@ PageType {
DividerType { DividerType {
visible: !GC.isMobile() visible: !GC.isMobile()
} }
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonLanguage id: labelWithButtonLanguage
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Language") text: qsTr("Language")
descriptionText: LanguageModel.currentLanguageName descriptionText: LanguageModel.currentLanguageName
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
selectLanguageDrawer.openTriggered() selectLanguageDrawer.openTriggered()
} }
@ -182,14 +183,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonLogging id: labelWithButtonLogging
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Logging") text: qsTr("Logging")
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled") descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsLogging) PageController.goToPage(PageEnum.PageSettingsLogging)
} }
@ -199,14 +199,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonReset id: labelWithButtonReset
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Reset settings and remove all data from the application") text: qsTr("Reset settings and remove all data from the application")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: AmneziaStyle.color.vibrantRed textColor: AmneziaStyle.color.vibrantRed
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
var headerText = qsTr("Reset settings and remove all data from the application?") 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 descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")

View file

@ -43,33 +43,43 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16 header: ColumnLayout {
width: listView.width
spacing: 16 spacing: 16
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Back up your configuration") headerText: qsTr("Back up your configuration")
descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.") descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
spacing: 16
WarningType { WarningType {
Layout.topMargin: 16
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
textString: qsTr("The backup will contain your passwords and private keys for all servers added " + textString: qsTr("The backup will contain your passwords and private keys for all servers added " +
"to AmneziaVPN. Keep this information in a secure place.") "to AmneziaVPN. Keep this information in a secure place.")
@ -79,13 +89,14 @@ PageType {
BasicButtonType { BasicButtonType {
id: makeBackupButton id: makeBackupButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 14 Layout.topMargin: 14
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Make a backup") text: qsTr("Make a backup")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
var fileName = "" var fileName = ""
if (GC.isMobile()) { if (GC.isMobile()) {
@ -108,8 +119,11 @@ PageType {
BasicButtonType { BasicButtonType {
id: restoreBackupButton id: restoreBackupButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: -8 Layout.topMargin: -8
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite hoveredColor: AmneziaStyle.color.translucentWhite
@ -120,8 +134,6 @@ PageType {
text: qsTr("Restore from backup") text: qsTr("Restore from backup")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
var filePath = SystemController.getFileName(qsTr("Open backup file"), var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)")) qsTr("Backup files (*.backup)"))

View file

@ -23,19 +23,18 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
@ -43,9 +42,17 @@ PageType {
headerText: qsTr("Connection") headerText: qsTr("Connection")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
SwitcherType { SwitcherType {
id: amneziaDnsSwitch id: amneziaDnsSwitch
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
@ -64,14 +71,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: dnsServersButton id: dnsServersButton
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("DNS servers") text: qsTr("DNS servers")
descriptionText: qsTr("When AmneziaDNS is not used or installed") descriptionText: qsTr("When AmneziaDNS is not used or installed")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsDns) PageController.goToPage(PageEnum.PageSettingsDns)
} }
@ -81,14 +87,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: splitTunnelingButton id: splitTunnelingButton
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Site-based split tunneling") text: qsTr("Site-based split tunneling")
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN") descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling) PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
} }
@ -96,8 +101,15 @@ PageType {
DividerType {} DividerType {}
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: splitTunnelingButton2 id: splitTunnelingButton2
visible: root.isAppSplitTinnelingEnabled visible: root.isAppSplitTinnelingEnabled
Layout.fillWidth: true Layout.fillWidth: true
@ -106,8 +118,6 @@ PageType {
descriptionText: qsTr("Allows you to use the VPN only for certain Apps") descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
} }
@ -127,8 +137,6 @@ PageType {
descriptionText: qsTr("Blocks network connections without VPN") descriptionText: qsTr("Blocks network connections without VPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsKillSwitch) PageController.goToPage(PageEnum.PageSettingsKillSwitch)
} }

View file

@ -21,13 +21,21 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height anchors.right: parent.right
anchors.left: parent.left
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
@ -39,25 +47,23 @@ PageType {
} }
} }
ColumnLayout { header: ColumnLayout {
id: content width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16 spacing: 16
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("DNS servers") headerText: qsTr("DNS servers")
} }
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("If AmneziaDNS is not used or installed") text: qsTr("If AmneziaDNS is not used or installed")
} }
@ -65,6 +71,9 @@ PageType {
id: primaryDns id: primaryDns
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Primary DNS") headerText: qsTr("Primary DNS")
textField.text: SettingsController.primaryDns textField.text: SettingsController.primaryDns
@ -77,6 +86,9 @@ PageType {
id: secondaryDns id: secondaryDns
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Secondary DNS") headerText: qsTr("Secondary DNS")
textField.text: SettingsController.secondaryDns textField.text: SettingsController.secondaryDns
@ -84,10 +96,21 @@ PageType {
regularExpression: InstallController.ipAddressRegExp() 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 { BasicButtonType {
id: restoreDefaultButton id: restoreDefaultButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite hoveredColor: AmneziaStyle.color.translucentWhite
@ -116,11 +139,16 @@ PageType {
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
}
footer: ColumnLayout {
width: listView.width
BasicButtonType { BasicButtonType {
id: saveButton id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16
text: qsTr("Save") text: qsTr("Save")
@ -136,5 +164,4 @@ PageType {
} }
} }
} }
} }

View file

@ -25,7 +25,7 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
@ -33,10 +33,6 @@ PageType {
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -101,8 +97,7 @@ PageType {
} }
model: logTypes model: logTypes
clip: true
reuseItems: true
snapMode: ListView.SnapOneItem snapMode: ListView.SnapOneItem
delegate: ColumnLayout { delegate: ColumnLayout {

View file

@ -18,10 +18,6 @@ PageType {
signal lastItemTabClickedSignal() signal lastItemTabClickedSignal()
onFocusChanged: content.isServerWithWriteAccess ?
labelWithButton.forceActiveFocus() :
labelWithButton3.forceActiveFocus()
Connections { Connections {
target: InstallController target: InstallController
@ -63,53 +59,73 @@ PageType {
target: ServersModel target: ServersModel
function onProcessedServerIndexChanged() { function onProcessedServerIndexChanged() {
content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
anchors.fill: parent
model: serverActions
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: labelWithButton
visible: content.isServerWithWriteAccess
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Check the server for previously installed Amnezia services") visible: isVisible
descriptionText: qsTr("Add them to the application if they were not displayed")
text: title
descriptionText: description
textColor: tColor
clickedFunction: function() { clickedFunction: function() {
clickedHandler()
}
}
DividerType {
visible: isVisible
}
}
}
property list<QtObject> serverActions: [
check,
reboot,
remove,
clear,
reset,
switch_to_premium,
]
QtObject {
id: check
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
readonly property var clickedHandler: function() {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
InstallController.scanServerForInstalledContainers() InstallController.scanServerForInstalledContainers()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
} }
DividerType { QtObject {
visible: content.isServerWithWriteAccess id: reboot
}
LabelWithButtonType { property bool isVisible: true
id: labelWithButton2 readonly property string title: qsTr("Reboot server")
visible: content.isServerWithWriteAccess readonly property string description: ""
Layout.fillWidth: true readonly property var tColor: AmneziaStyle.color.vibrantRed
readonly property var clickedHandler: function() {
text: qsTr("Reboot server")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Do you want to reboot the server?") 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 descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
@ -123,32 +139,23 @@ PageType {
InstallController.rebootProcessedServer() InstallController.rebootProcessedServer()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
} }
var noButtonFunction = function() { var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton2.forceActiveFocus()
}
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType { QtObject {
visible: content.isServerWithWriteAccess id: remove
}
LabelWithButtonType { property bool isVisible: true
id: labelWithButton3 readonly property string title: qsTr("Remove server from application")
Layout.fillWidth: true readonly property string description: ""
readonly property var tColor: AmneziaStyle.color.vibrantRed
text: qsTr("Remove server from application") readonly property var clickedHandler: function() {
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Do you want to remove the server from application?") 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 descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
@ -162,31 +169,23 @@ PageType {
InstallController.removeProcessedServer() InstallController.removeProcessedServer()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
} }
var noButtonFunction = function() { var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton3.forceActiveFocus()
}
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType {} QtObject {
id: clear
LabelWithButtonType { property bool isVisible: true
id: labelWithButton4 readonly property string title: qsTr("Clear server from Amnezia software")
visible: content.isServerWithWriteAccess readonly property string description: ""
Layout.fillWidth: true readonly property var tColor: AmneziaStyle.color.vibrantRed
readonly property var clickedHandler: function() {
text: qsTr("Clear server from Amnezia software")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Do you want to clear server from Amnezia software?") var headerText = qsTr("Do you want to clear server from Amnezia software?")
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.") var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
@ -199,33 +198,23 @@ PageType {
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeAllContainers() InstallController.removeAllContainers()
} }
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
} }
var noButtonFunction = function() { var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton4.forceActiveFocus()
}
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType { QtObject {
visible: content.isServerWithWriteAccess id: reset
}
LabelWithButtonType { property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
id: labelWithButton5 readonly property string title: qsTr("Reset API config")
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") readonly property string description: ""
Layout.fillWidth: true readonly property var tColor: AmneziaStyle.color.vibrantRed
readonly property var clickedHandler: function() {
text: qsTr("Reset API config")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Do you want to reset API config?") var headerText = qsTr("Do you want to reset API config?")
var descriptionText = "" var descriptionText = ""
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
@ -239,42 +228,25 @@ PageType {
InstallController.removeApiConfig(ServersModel.processedIndex) InstallController.removeApiConfig(ServersModel.processedIndex)
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
} }
var noButtonFunction = function() { var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType { QtObject {
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") id: switch_to_premium
}
LabelWithButtonType { property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
id: labelWithButton6 readonly property string title: qsTr("Switch to the new Amnezia Premium subscription")
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") readonly property string description: ""
Layout.fillWidth: true readonly property var tColor: AmneziaStyle.color.vibrantRed
readonly property var clickedHandler: function() {
text: qsTr("Switch to the new Amnezia Premium subscription")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
PageController.goToPageHome() PageController.goToPageHome()
ApiPremV1MigrationController.showMigrationDrawer() ApiPremV1MigrationController.showMigrationDrawer()
} }
} }
DividerType {
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
}
}
}
} }

View file

@ -21,19 +21,26 @@ PageType {
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex()) property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
ColumnLayout { BackButtonType {
id: header id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType {
id: backButton
} }
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
@ -42,50 +49,14 @@ PageType {
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
} }
ListView {
id: protocols
Layout.fillWidth: true
height: protocols.contentItem.height
clip: true
interactive: true
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
} }
model: ProtocolsModel model: ProtocolsModel
delegate: Item { delegate: ColumnLayout {
implicitWidth: protocols.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent id: delegateContent
anchors.fill: parent width: listView.width
property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess() property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
@ -157,10 +128,10 @@ PageType {
visible: delegateContent.isServerSettingsVisible visible: delegateContent.isServerSettingsVisible
} }
} }
}
footer: ColumnLayout { footer: ColumnLayout {
width: header.width
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: clearCacheButton id: clearCacheButton
@ -188,10 +159,8 @@ PageType {
InstallController.clearCachedProfile() InstallController.clearCachedProfile()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
var noButtonFunction = function() { var noButtonFunction = function() {
// if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
// }
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@ -205,10 +174,6 @@ PageType {
} }
DividerType { DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: root.isClearCacheVisible visible: root.isClearCacheVisible
} }
@ -239,9 +204,7 @@ PageType {
} }
} }
var noButtonFunction = function() { var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@ -255,15 +218,8 @@ PageType {
} }
DividerType { DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ServersModel.isProcessedServerHasWriteAccess() visible: ServersModel.isProcessedServerHasWriteAccess()
} }
} }
} }
} }
}

View file

@ -40,25 +40,20 @@ PageType {
} }
} }
ListView { ListViewType {
id: servers id: servers
objectName: "servers" objectName: "servers"
width: parent.width width: parent.width
anchors.top: header.bottom anchors.top: header.bottom
anchors.topMargin: 16 anchors.topMargin: 16
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: 500
property bool isFocusable: true
model: ServersModel model: ServersModel
clip: true
reuseItems: true
delegate: Item { delegate: Item {
implicitWidth: servers.width implicitWidth: servers.width
implicitHeight: delegateContent.implicitHeight implicitHeight: delegateContent.implicitHeight

View file

@ -161,7 +161,7 @@ PageType {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: header.bottom anchors.top: header.bottom
@ -172,8 +172,6 @@ PageType {
enabled: root.pageEnabled enabled: root.pageEnabled
property bool isFocusable: true
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxySitesModel id: proxySitesModel
sourceModel: SitesModel sourceModel: SitesModel
@ -193,13 +191,7 @@ PageType {
] ]
} }
clip: true
reuseItems: true
delegate: ColumnLayout { delegate: ColumnLayout {
id: delegateContent
width: listView.width width: listView.width
LabelWithButtonType { LabelWithButtonType {
@ -236,7 +228,6 @@ PageType {
} }
} }
Rectangle { Rectangle {
anchors.fill: addSiteButton anchors.fill: addSiteButton
anchors.bottomMargin: -24 anchors.bottomMargin: -24
@ -376,20 +367,16 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: importSitesDrawerListView
anchors.top: importSitesDrawerBackButton.bottom anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: importSitesDrawerContent.height header: ColumnLayout {
width: importSitesDrawerListView.width
ColumnLayout {
id: importSitesDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type { Header2Type {
Layout.fillWidth: true Layout.fillWidth: true
@ -397,34 +384,58 @@ PageType {
headerText: qsTr("Import a list of sites") headerText: qsTr("Import a list of sites")
} }
}
model: importOptions
delegate: ColumnLayout {
width: importSitesDrawerListView.width
LabelWithButtonType { LabelWithButtonType {
id: importSitesButton2
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Replace site list") text: title
clickedFunction: function() { clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"), clickedHandler()
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
} }
} }
DividerType {} DividerType {}
}
}
}
}
LabelWithButtonType { property list<QtObject> importOptions: [
id: importSitesButton3 replaceOption,
Layout.fillWidth: true addOption,
text: qsTr("Add imported sites to existing ones") ]
clickedFunction: function() { QtObject {
id: replaceOption
readonly property string title: qsTr("Replace site list")
readonly property var clickedHandler: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"), var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)")) qsTr("Sites files (*.json)"))
if (fileName !== "") { if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false) root.importSites(fileName, true)
}
}
}
QtObject {
id: addOption
readonly property string title: qsTr("Add imported sites to existing ones")
readonly property var clickedHandler: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
root.importSites(fileName, false)
} }
} }
} }
@ -436,10 +447,4 @@ PageType {
importSitesDrawer.closeTriggered() importSitesDrawer.closeTriggered()
moreActionsDrawer.closeTriggered() moreActionsDrawer.closeTriggered()
} }
DividerType {}
}
}
}
}
} }

View file

@ -15,25 +15,31 @@ import "../Components"
PageType { PageType {
id: root id: root
FlickableType { BackButtonType {
id: fl id: backButton
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin
ColumnLayout {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
spacing: 0 onFocusChanged: {
if (this.activeFocus) {
BackButtonType { listView.positionViewAtBeginning()
id: backButton
Layout.topMargin: 20
} }
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -45,53 +51,28 @@ PageType {
headerText: ApiServicesModel.getSelectedServiceData("name") headerText: ApiServicesModel.getSelectedServiceData("name")
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
} }
}
model: inputFields
spacing: 0
delegate: ColumnLayout {
width: listView.width
LabelWithImageType { LabelWithImageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
imageSource: "qrc:/images/controls/map-pin.svg" imageSource: imagePath
leftText: qsTr("For the region") leftText: lText
rightText: ApiServicesModel.getSelectedServiceData("region") rightText: rText
}
} }
LabelWithImageType { footer: ColumnLayout {
Layout.fillWidth: true width: listView.width
Layout.margins: 16
imageSource: "qrc:/images/controls/tag.svg" spacing: 0
leftText: qsTr("Price")
rightText: ApiServicesModel.getSelectedServiceData("price")
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
imageSource: "qrc:/images/controls/history.svg"
leftText: qsTr("Work period")
rightText: ApiServicesModel.getSelectedServiceData("timeLimit")
visible: rightText !== ""
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
imageSource: "qrc:/images/controls/gauge.svg"
leftText: qsTr("Speed")
rightText: ApiServicesModel.getSelectedServiceData("speed")
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
imageSource: "qrc:/images/controls/info.svg"
leftText: qsTr("Features")
rightText: ""
}
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
@ -113,20 +94,15 @@ PageType {
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
} }
} }
}
}
BasicButtonType { BasicButtonType {
id: continueButton id: continueButton
anchors.right: parent.right Layout.fillWidth: true
anchors.left: parent.left Layout.topMargin: 32
anchors.bottom: parent.bottom Layout.bottomMargin: 32
Layout.leftMargin: 16
anchors.topMargin: 32 Layout.rightMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.bottomMargin: 32
text: qsTr("Connect") text: qsTr("Connect")
@ -144,3 +120,58 @@ PageType {
} }
} }
} }
}
property list<QtObject> inputFields: [
region,
price,
timeLimit,
speed,
features
]
QtObject {
id: region
readonly property string imagePath: "qrc:/images/controls/map-pin.svg"
readonly property string lText: qsTr("For the region")
readonly property string rText: ApiServicesModel.getSelectedServiceData("region")
property bool isVisible: true
}
QtObject {
id: price
readonly property string imagePath: "qrc:/images/controls/tag.svg"
readonly property string lText: qsTr("Price")
readonly property string rText: ApiServicesModel.getSelectedServiceData("price")
property bool isVisible: true
}
QtObject {
id: timeLimit
readonly property string imagePath: "qrc:/images/controls/history.svg"
readonly property string lText: qsTr("Work period")
readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit")
property bool isVisible: rText !== ""
}
QtObject {
id: speed
readonly property string imagePath: "qrc:/images/controls/gauge.svg"
readonly property string lText: qsTr("Speed")
readonly property string rText: ApiServicesModel.getSelectedServiceData("speed")
property bool isVisible: true
}
QtObject {
id: features
readonly property string imagePath: "qrc:/images/controls/info.svg"
readonly property string lText: qsTr("Features")
readonly property string rText: ""
property bool isVisible: true
}
}

View file

@ -40,7 +40,7 @@ PageType {
} }
} }
ListView { ListViewType {
id: servicesListView id: servicesListView
anchors.top: header.bottom anchors.top: header.bottom
@ -48,17 +48,11 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.topMargin: 16 anchors.topMargin: 16
spacing: 0 spacing: 0
property bool isFocusable: true
clip: true
reuseItems: true
model: ApiServicesModel model: ApiServicesModel
ScrollBar.vertical: ScrollBarType {}
delegate: Item { delegate: Item {
implicitWidth: servicesListView.width implicitWidth: servicesListView.width
implicitHeight: delegateContent.implicitHeight implicitHeight: delegateContent.implicitHeight

View file

@ -27,21 +27,13 @@ PageType {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.fill: parent anchors.fill: parent
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
model: variants model: variants
clip: true
reuseItems: true
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width

View file

@ -28,41 +28,14 @@ PageType {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -78,8 +51,6 @@ PageType {
model: inputFields model: inputFields
spacing: 16 spacing: 16
clip: true
reuseItems: true
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width

View file

@ -20,6 +20,7 @@ PageType {
SortFilterProxyModel { SortFilterProxyModel {
id: proxyContainersModel id: proxyContainersModel
sourceModel: ContainersModel sourceModel: ContainersModel
filters: [ filters: [
ValueFilter { ValueFilter {
@ -42,68 +43,59 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ButtonGroup {
id: fl id: buttonGroup
}
ListViewType {
id: listView
property int dockerContainer
property int containerDefaultPort
property int containerDefaultTransportProto
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + setupLaterButton.anchors.bottomMargin
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16 spacing: 16
header: ColumnLayout {
id: content
width: listView.width
spacing: 16 spacing: 16
BaseHeaderType { BaseHeaderType {
id: header id: header
implicitWidth: parent.width Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerTextMaximumLineCount: 10 headerTextMaximumLineCount: 10
headerText: qsTr("Choose Installation Type") headerText: qsTr("Choose Installation Type")
} }
ButtonGroup {
id: buttonGroup
} }
ListView {
id: containers
width: parent.width
height: containers.contentItem.height
spacing: 16
currentIndex: 0
clip: true
interactive: false
model: proxyContainersModel model: proxyContainersModel
currentIndex: 0
property int dockerContainer delegate: ColumnLayout {
property int containerDefaultPort
property int containerDefaultTransportProto
property bool isFocusable: true width: listView.width
delegate: Item {
implicitWidth: containers.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
CardType { CardType {
id: card id: card
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: easySetupHeader headerText: easySetupHeader
bodyText: easySetupDescription bodyText: easySetupDescription
@ -111,33 +103,35 @@ PageType {
ButtonGroup.group: buttonGroup ButtonGroup.group: buttonGroup
onClicked: function() { onClicked: function() {
checked = true
isEasySetup = true isEasySetup = true
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
containers.dockerContainer = dockerContainer listView.dockerContainer = dockerContainer
containers.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto) listView.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
containers.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto) listView.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
}
} }
Keys.onReturnPressed: this.clicked()
Keys.onEnterPressed: this.clicked()
} }
} }
Component.onCompleted: { footer: ColumnLayout {
var item = containers.itemAtIndex(containers.currentIndex)
if (item !== null) { width: listView.width
var button = item.children[0].children[0] spacing: 16
button.checked = true
button.clicked()
}
}
}
DividerType { DividerType {
implicitWidth: parent.width Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
} }
CardType { CardType {
implicitWidth: parent.width Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Manual") headerText: qsTr("Manual")
bodyText: qsTr("Choose a VPN protocol") bodyText: qsTr("Choose a VPN protocol")
@ -146,25 +140,29 @@ PageType {
onClicked: function() { onClicked: function() {
isEasySetup = false isEasySetup = false
checked = true
} }
Keys.onReturnPressed: this.clicked()
Keys.onEnterPressed: this.clicked()
} }
BasicButtonType { BasicButtonType {
id: continueButton id: continueButton
implicitWidth: parent.width Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Continue") text: qsTr("Continue")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
if (root.isEasySetup) { if (root.isEasySetup) {
ContainersModel.setProcessedContainerIndex(containers.dockerContainer) ContainersModel.setProcessedContainerIndex(listView.dockerContainer)
PageController.goToPage(PageEnum.PageSetupWizardInstalling) PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.install(containers.dockerContainer, InstallController.install(listView.dockerContainer,
containers.containerDefaultPort, listView.containerDefaultPort,
containers.containerDefaultTransportProto) listView.containerDefaultTransportProto)
} else { } else {
PageController.goToPage(PageEnum.PageSetupWizardProtocols) PageController.goToPage(PageEnum.PageSetupWizardProtocols)
} }
@ -174,9 +172,11 @@ PageType {
BasicButtonType { BasicButtonType {
id: setupLaterButton id: setupLaterButton
implicitWidth: parent.width Layout.fillWidth: true
anchors.topMargin: 8 Layout.topMargin: 8
anchors.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite hoveredColor: AmneziaStyle.color.translucentWhite
@ -185,9 +185,6 @@ PageType {
textColor: AmneziaStyle.color.paleGray textColor: AmneziaStyle.color.paleGray
borderWidth: 1 borderWidth: 1
Keys.onTabPressed: lastItemTabClicked(focusItem)
parentFlickable: fl
visible: { visible: {
if (PageController.isTriggeredByConnectButton()) { if (PageController.isTriggeredByConnectButton()) {
PageController.setTriggeredByConnectButton(false) PageController.setTriggeredByConnectButton(false)
@ -205,5 +202,15 @@ PageType {
} }
} }
} }
Component.onCompleted: {
var item = listView.itemAtIndex(listView.currentIndex)
if (item !== null) {
var button = item.children[0]
button.checked = true
button.clicked()
} }
} }
}
}

View file

@ -85,42 +85,23 @@ PageType {
] ]
} }
FlickableType { ListViewType {
id: listView
anchors.fill: parent anchors.fill: parent
contentHeight: content.height
Column {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 16
ListView {
id: container
width: parent.width
height: container.contentItem.height
currentIndex: -1 currentIndex: -1
clip: true
interactive: false
model: proxyContainersModel model: proxyContainersModel
delegate: Item { delegate: ColumnLayout {
implicitWidth: container.width width: listView.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Installing") headerText: qsTr("Installing")
descriptionText: name descriptionText: name
@ -131,6 +112,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
Timer { Timer {
id: timer id: timer
@ -149,6 +132,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
text: root.progressBarText text: root.progressBarText
} }
@ -158,6 +143,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: root.isCancelButtonVisible visible: root.isCancelButtonVisible
@ -171,6 +158,3 @@ PageType {
} }
} }
} }
}
}
}

View file

@ -29,77 +29,42 @@ PageType {
] ]
} }
FlickableType { BackButtonType {
anchors.fill: parent id: backButton
contentHeight: content.height
Column {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
ListView {
id: processedContainerListView
width: parent.width
height: contentItem.height
currentIndex: -1 currentIndex: -1
clip: true
interactive: false
model: proxyContainersModel model: proxyContainersModel
property bool isFocusable: true delegate: ColumnLayout {
width: listView.width
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
delegate: Item {
implicitWidth: processedContainerListView.width
implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height
property alias port:port
ColumnLayout {
id: delegateContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
BackButtonType {
id: backButton
Layout.topMargin: 20
Layout.rightMargin: -16
Layout.leftMargin: -16
}
BaseHeaderType { BaseHeaderType {
id: header id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Installing %1").arg(name) headerText: qsTr("Installing %1").arg(name)
descriptionText: description descriptionText: description
@ -109,7 +74,8 @@ PageType {
id: showDetailsButton id: showDetailsButton
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: -8 Layout.rightMargin: 16
Layout.leftMargin: 16
implicitHeight: 32 implicitHeight: 32
@ -120,7 +86,6 @@ PageType {
textColor: AmneziaStyle.color.goldenApricot textColor: AmneziaStyle.color.goldenApricot
text: qsTr("More detailed") text: qsTr("More detailed")
KeyNavigation.tab: transportProtoSelector
clickedFunc: function() { clickedFunc: function() {
showDetailsDrawer.openTriggered() showDetailsDrawer.openTriggered()
@ -149,39 +114,40 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: fl id: showDetailsListView
anchors.top: showDetailsBackButton.bottom anchors.top: showDetailsBackButton.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: {
var emptySpaceHeight = parent.height - showDetailsBackButton.implicitHeight - showDetailsBackButton.anchors.topMargin
return (showDetailsDrawerContent.height > emptySpaceHeight) ?
showDetailsDrawerContent.height : emptySpaceHeight
}
ColumnLayout { header: ColumnLayout {
id: showDetailsDrawerContent width: showDetailsListView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type { Header2Type {
id: showDetailsDrawerHeader id: showDetailsDrawerHeader
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: name headerText: name
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: showDetailsListView.width
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.bottomMargin: 16 Layout.bottomMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: detailedDescription text: detailedDescription
textFormat: Text.MarkdownText textFormat: Text.MarkdownText
@ -189,14 +155,22 @@ PageType {
Rectangle { Rectangle {
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: 16
Layout.rightMargin: 16
color: AmneziaStyle.color.transparent color: AmneziaStyle.color.transparent
} }
}
footer: ColumnLayout {
width: showDetailsListView.width
BasicButtonType { BasicButtonType {
id: showDetailsCloseButton id: showDetailsCloseButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.bottomMargin: 32 Layout.bottomMargin: 32
parentFlickable: fl Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Close") text: qsTr("Close")
@ -213,6 +187,8 @@ PageType {
id: transportProtoHeader id: transportProtoHeader
Layout.topMargin: 16 Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
text: qsTr("Network protocol") text: qsTr("Network protocol")
} }
@ -221,6 +197,9 @@ PageType {
id: transportProtoSelector id: transportProtoSelector
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
rootWidth: root.width rootWidth: root.width
} }
@ -229,6 +208,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Port") headerText: qsTr("Port")
textField.maximumLength: 5 textField.maximumLength: 5
@ -237,6 +218,9 @@ PageType {
Rectangle { Rectangle {
Layout.fillHeight: true Layout.fillHeight: true
Layout.rightMargin: 16
Layout.leftMargin: 16
color: AmneziaStyle.color.transparent color: AmneziaStyle.color.transparent
} }
@ -245,6 +229,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.bottomMargin: 32 Layout.bottomMargin: 32
Layout.rightMargin: 16
Layout.leftMargin: 16
text: qsTr("Install") text: qsTr("Install")
@ -279,6 +265,3 @@ PageType {
} }
} }
} }
}
}
}

View file

@ -44,17 +44,13 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -72,9 +68,8 @@ PageType {
} }
model: proxyContainersModel model: proxyContainersModel
clip: true
spacing: 0 spacing: 0
reuseItems: true
snapMode: ListView.SnapToItem snapMode: ListView.SnapToItem
delegate: ColumnLayout { delegate: ColumnLayout {
@ -88,8 +83,8 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function () { clickedFunction: function () {
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index)) ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index));
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings);
} }
} }

View file

@ -13,25 +13,31 @@ import "../Config"
PageType { PageType {
id: root id: root
FlickableType { BackButtonType {
id: fl id: backButton
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20
spacing: 16 onFocusChanged: {
if (this.activeFocus) {
BackButtonType { listView.positionViewAtBeginning()
id: backButton
Layout.topMargin: 20
} }
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -41,6 +47,13 @@ PageType {
headerText: qsTr("Connection key") headerText: qsTr("Connection key")
descriptionText: qsTr("A line that starts with vpn://...") descriptionText: qsTr("A line that starts with vpn://...")
} }
}
spacing: 16
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: textKey id: textKey
@ -60,17 +73,18 @@ PageType {
} }
} }
} }
}
footer: ColumnLayout {
width: listView.width
BasicButtonType { BasicButtonType {
id: continueButton id: continueButton
anchors.bottom: parent.bottom Layout.fillWidth: true
anchors.left: parent.left Layout.rightMargin: 16
anchors.right: parent.right Layout.leftMargin: 16
anchors.rightMargin: 16 Layout.topMargin: 16
anchors.leftMargin: 16 Layout.bottomMargin: 32
anchors.bottomMargin: 32
text: qsTr("Continue") text: qsTr("Continue")
@ -81,3 +95,5 @@ PageType {
} }
} }
} }
}
}

View file

@ -46,27 +46,29 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + connectButton.implicitHeight
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 16 anchors.left: parent.left
anchors.leftMargin: 16
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("New connection") headerText: qsTr("New connection")
} }
RowLayout { RowLayout {
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
spacing: 8 spacing: 8
visible: fileName.text !== "" visible: fileName.text !== ""
@ -88,7 +90,9 @@ PageType {
BasicButtonType { BasicButtonType {
id: showContentButton id: showContentButton
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: -8 Layout.leftMargin: 16
Layout.rightMargin: 16
implicitHeight: 32 implicitHeight: 32
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
@ -99,8 +103,6 @@ PageType {
text: showContent ? qsTr("Collapse content") : qsTr("Show content") text: showContent ? qsTr("Collapse content") : qsTr("Show content")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
showContent = !showContent showContent = !showContent
} }
@ -108,16 +110,28 @@ PageType {
CheckBoxType { CheckBoxType {
id: cloakingCheckBox id: cloakingCheckBox
objectName: "cloakingCheckBox"
visible: ImportController.isNativeWireGuardConfig() visible: ImportController.isNativeWireGuardConfig()
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider.") text: qsTr("Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider.")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
WarningType { WarningType {
Layout.topMargin: 16
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
textString: ImportController.getMaliciousWarningText() textString: ImportController.getMaliciousWarningText()
textFormat: Qt.RichText textFormat: Qt.RichText
@ -130,8 +144,10 @@ PageType {
} }
WarningType { WarningType {
Layout.topMargin: 16
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
textString: qsTr("Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data.") textString: qsTr("Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data.")
@ -140,7 +156,10 @@ PageType {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 48 Layout.bottomMargin: 48
Layout.rightMargin: 16
Layout.leftMargin: 16
implicitHeight: configContent.implicitHeight implicitHeight: configContent.implicitHeight
@ -161,31 +180,34 @@ PageType {
} }
} }
} }
}
Rectangle { footer: ColumnLayout {
anchors.fill: columnContent width: listView.width
anchors.bottomMargin: -24
color: AmneziaStyle.color.midnightBlack
opacity: 0.8
}
ColumnLayout {
id: columnContent
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
BasicButtonType { BasicButtonType {
id: connectButton id: connectButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 32 Layout.bottomMargin: 32
Layout.rightMargin: 16
Layout.leftMargin: 16
text: qsTr("Connect") text: qsTr("Connect")
clickedFunc: function() { clickedFunc: function() {
if (cloakingCheckBox.checked) { const headerItem = listView.headerItem;
if (!headerItem) {
console.error("Header item not found in ListView")
return
}
const cloakingCheckBoxItem = listView.findChildWithObjectName(headerItem.children, "cloakingCheckBox");
if (!cloakingCheckBoxItem) {
console.error("cloakingCheckBox not found")
return
}
if (cloakingCheckBoxItem.checked) {
ImportController.processNativeWireGuardConfig() ImportController.processNativeWireGuardConfig()
} }
ImportController.importConfig() ImportController.importConfig()
@ -193,3 +215,4 @@ PageType {
} }
} }
} }
}

View file

@ -520,9 +520,6 @@ PageType {
text: qsTr("Share") text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg" leftImageSource: "qrc:/images/controls/share-2.svg"
parentFlickable: a
clickedFunc: function(){ clickedFunc: function(){
if (clientNameTextField.textField.text !== "") { if (clientNameTextField.textField.text !== "") {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type) ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)

View file

@ -25,27 +25,29 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
} }
FlickableType { ListViewType {
id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left
anchors.rightMargin: 16 header: ColumnLayout {
anchors.leftMargin: 16 width: listView.width
spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 24 Layout.topMargin: 24
headerText: qsTr("Full access to the server and VPN") headerText: qsTr("Full access to the server and VPN")
@ -53,6 +55,8 @@ PageType {
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
@ -63,11 +67,14 @@ PageType {
DropDownType { DropDownType {
id: serverSelector id: serverSelector
objectName: "serverSelector"
signal severSelectorIndexChanged signal severSelectorIndexChanged
property int currentIndex: 0 property int currentIndex: 0
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 16 Layout.topMargin: 16
drawerHeight: 0.4375 drawerHeight: 0.4375
@ -117,11 +124,20 @@ PageType {
} }
} }
} }
}
model: 1 // fake model to force the ListView to be created without a model
spacing: 0
delegate: ColumnLayout {
width: listView.width
BasicButtonType { BasicButtonType {
id: shareButton id: shareButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Share") text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg" leftImageSource: "qrc:/images/controls/share-2.svg"
@ -137,8 +153,22 @@ PageType {
ExportController.generateFullAccessConfig() ExportController.generateFullAccessConfig()
} }
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text const headerItem = listView.headerItem;
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text if (!headerItem) {
PageController.showBusyIndicator(false)
console.error("Failed to share: header item not found in ListView")
return
}
const serverSelectorItem = listView.findChildWithObjectName(headerItem.children, "serverSelector");
if (!serverSelectorItem) {
PageController.showBusyIndicator(false)
console.error("Failed to share: serverSelector item not found in ListView")
return
}
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelectorItem.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelectorItem.text
shareConnectionDrawer.openTriggered() shareConnectionDrawer.openTriggered()