Compare commits

..

2 Commits

Author SHA1 Message Date
Mykola Baibuz e08b62df40 Fix work wth PKCS12 TempFile 2024-08-20 22:46:51 +03:00
Mykola Baibuz 90912f9231 Fix Windows IPsec 2024-07-26 00:55:13 +03:00
65 changed files with 1769 additions and 1486 deletions
+2 -2
View File
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.6.1.0
project(${PROJECT} VERSION 4.6.0.4
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 56)
set(APP_ANDROID_VERSION_CODE 55)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
-6
View File
@@ -11,9 +11,6 @@
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<!-- for TV -->
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<!-- The following comment will be replaced upon deployment with default features based on the dependencies
of the application. Remove the comment if you do not require these default features. -->
@@ -34,11 +31,9 @@
android:label="-- %%INSERT_APP_NAME%% --"
android:icon="@mipmap/icon"
android:roundIcon="@mipmap/icon_round"
android:banner="@mipmap/ic_banner"
android:theme="@style/NoActionBar"
android:fullBackupContent="@xml/backup_content"
android:dataExtractionRules="@xml/data_extraction_rules"
android:hasFragileUserData="false"
tools:targetApi="s">
<activity
@@ -52,7 +47,6 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<intent-filter>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_banner_background"/>
<foreground android:drawable="@mipmap/ic_banner_foreground"/>
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_banner_background">#1E1E1F</color>
</resources>
@@ -1,7 +1,6 @@
package org.amnezia.vpn
import android.Manifest
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.NotificationManager
import android.content.BroadcastReceiver
@@ -231,10 +230,7 @@ class AmneziaActivity : QtActivity() {
override fun onStop() {
Log.d(TAG, "Stop Amnezia activity")
doUnbindService()
mainScope.launch {
qtInitialized.await()
QtAndroidController.onServiceDisconnected()
}
QtAndroidController.onServiceDisconnected()
super.onStop()
}
@@ -546,7 +542,7 @@ class AmneziaActivity : QtActivity() {
}
}.also {
startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
onAny = {
onSuccess = {
val uri = it?.data?.toString() ?: ""
Log.d(TAG, "Open file: $uri")
mainScope.launch {
@@ -560,12 +556,8 @@ class AmneziaActivity : QtActivity() {
}
@Suppress("unused")
@SuppressLint("UnsupportedChromeOsCameraSystemFeature")
fun isCameraPresent(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
@Suppress("unused")
fun isOnTv(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
@Suppress("unused")
fun startQrCodeReader() {
Log.v(TAG, "Start camera")
@@ -88,24 +88,16 @@ class NetworkState(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val numberAttempts = 3
var attemptCount = 0
while(true) {
try {
try {
connectivityManager.requestNetwork(networkRequest, networkCallback, handler)
} catch (e: SecurityException) {
Log.e(TAG, "Failed to bind network listener: $e")
// Android 11 bug: https://issuetracker.google.com/issues/175055271
if (e.message?.startsWith("Package android does not belong to") == true) {
delay(1000)
connectivityManager.requestNetwork(networkRequest, networkCallback, handler)
break
} catch (e: SecurityException) {
Log.e(TAG, "Failed to bind network listener: $e")
// Android 11 bug: https://issuetracker.google.com/issues/175055271
if (e.message?.startsWith("Package android does not belong to") == true) {
if (++attemptCount > numberAttempts) {
throw e
}
delay(1000)
continue
} else {
throw e
}
} else {
throw e
}
}
} else {
@@ -119,21 +119,18 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString,
if (!m_settings->isSitesSplitTunnelingEnabled()) {
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
#endif
config.append("block-ipv6\n");
} else if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
// no redirect-gateway
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
#ifndef Q_OS_ANDROID
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
#endif
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
#endif
config.append("block-ipv6\n");
}
}
+1 -1
View File
@@ -96,7 +96,7 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{ DockerContainer::Awg, "AmneziaWG" },
{ DockerContainer::Xray, "XRay" },
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
{ DockerContainer::SSXray, "Shadowsocks"},
{ DockerContainer::SSXray, "ShadowSocks"},
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
@@ -179,11 +179,6 @@ bool AndroidController::isCameraPresent()
return callActivityMethod<jboolean>("isCameraPresent", "()Z");
}
bool AndroidController::isOnTv()
{
return callActivityMethod<jboolean>("isOnTv", "()Z");
}
void AndroidController::startQrReaderActivity()
{
callActivityMethod("startQrCodeReader", "()V");
@@ -35,7 +35,6 @@ public:
void saveFile(const QString &fileName, const QString &data);
QString openFile(const QString &filter);
bool isCameraPresent();
bool isOnTv();
void startQrReaderActivity();
void setSaveLogs(bool enabled);
void exportLogsFile(const QString &fileName);
+47 -43
View File
@@ -10,6 +10,7 @@
#include "ikev2_vpn_protocol_windows.h"
#include "utilities.h"
static Ikev2Protocol* self = nullptr;
static std::mutex rasDialFuncMutex;
@@ -80,10 +81,10 @@ void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE
case RASCS_AuthNotify:
//qDebug()<<__FUNCTION__ << __LINE__;
if (dwError != 0) {
//qDebug() << "have error" << dwError;
qDebug() << "have error" << dwError;
setConnectionState(Vpn::ConnectionState::Disconnected);
} else {
//qDebug() << "RASCS_AuthNotify but no error" << dwError;
qDebug() << "RASCS_AuthNotify but no error" << dwError;
}
break;
case RASCS_AuthRetry:
@@ -179,11 +180,13 @@ ErrorCode Ikev2Protocol::start()
QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8());
setConnectionState(Vpn::ConnectionState::Connecting);
QTemporaryFile certFile;
certFile.setAutoRemove(false);
certFile.open();
certFile.write(cert);
certFile.close();
QTemporaryFile * certFile = new QTemporaryFile;
certFile->setAutoRemove(false);
certFile->open();
QString m_filename = certFile->fileName();
certFile->write(cert);
certFile->close();
delete certFile;
{
auto certInstallProcess = IpcClient::CreatePrivilegedProcess();
@@ -193,19 +196,19 @@ ErrorCode Ikev2Protocol::start()
return ErrorCode::AmneziaServiceConnectionFailed;
}
certInstallProcess->waitForSource(1000);
certInstallProcess->waitForSource();
if (!certInstallProcess->isInitialized()) {
qWarning() << "IpcProcess replica is not connected!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
certInstallProcess->setProgram(PermittedProcess::CertUtil);
QStringList arguments({"-f" , "-importpfx",
"-p", m_config[config_key::password].toString(),
certFile.fileName(), "NoExport"
});
certInstallProcess->setArguments(arguments);
QStringList arguments({"-f", "-importpfx", "-p", m_config[config_key::password].toString(),
QDir::toNativeSeparators(m_filename), "NoExport"
});
certInstallProcess->setArguments(arguments);
certInstallProcess->start();
}
// /*
@@ -219,40 +222,40 @@ ErrorCode Ikev2Protocol::start()
}
{
{
if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
qDebug() <<"Can't create the VPN connect";
}
}
}
{
if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
qDebug() <<"Can't create the VPN connect";
}
}
}
{
auto adapterConfigProcess = new QProcess;
{
QProcess adapterConfigProcess;
adapterConfigProcess.setProgram("powershell");
QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
"-ConnectionName '%1' "
"-AuthenticationTransformConstants GCMAES128 "
"-CipherTransformConstants GCMAES128 "
"-EncryptionMethod AES256 "
"-IntegrityCheckMethod SHA256 "
"-PfsGroup None "
"-DHGroup Group14 "
"-PassThru -Force\"")
.arg(tunnelName());
adapterConfigProcess->setProgram("powershell");
QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
"-ConnectionName '%1' "
"-AuthenticationTransformConstants GCMAES128 "
"-CipherTransformConstants GCMAES128 "
"-EncryptionMethod AES256 "
"-IntegrityCheckMethod SHA256 "
"-PfsGroup None "
"-DHGroup Group14 "
"-PassThru -Force\"")
.arg(tunnelName());
adapterConfigProcess->setNativeArguments(arguments);
adapterConfigProcess.setNativeArguments(arguments);
adapterConfigProcess->start();
adapterConfigProcess->waitForFinished(5000);
adapterConfigProcess.start();
adapterConfigProcess.waitForFinished(5000);
}
//*/
{
if (!connect_to_vpn(tunnelName())) {
qDebug()<<"We can't connect to VPN";
}
//*/
{
if (!connect_to_vpn(tunnelName())) {
qDebug()<<"We can't connect to VPN";
}
}
//setConnectionState(Connecting);
return ErrorCode::NoError;
}
//setConnectionState(Connecting);
return ErrorCode::NoError;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
@@ -299,6 +302,7 @@ bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){
auto ret = RasDial(NULL, NULL, &RasDialParams, 0,
&RasDialFuncCallback,
&hRasConn);
if (ret == ERROR_SUCCESS){
return true;
}
+2 -2
View File
@@ -65,14 +65,14 @@ QString ProtocolProps::transportProtoToString(TransportProto proto, Proto p)
QMap<amnezia::Proto, QString> ProtocolProps::protocolHumanNames()
{
return { { Proto::OpenVpn, "OpenVPN" },
{ Proto::ShadowSocks, "Shadowsocks" },
{ Proto::ShadowSocks, "ShadowSocks" },
{ Proto::Cloak, "Cloak" },
{ Proto::WireGuard, "WireGuard" },
{ Proto::Awg, "AmneziaWG" },
{ Proto::Ikev2, "IKEv2" },
{ Proto::L2tp, "L2TP" },
{ Proto::Xray, "XRay" },
{ Proto::SSXray, "Shadowsocks"},
{ Proto::SSXray, "ShadowSocks"},
{ Proto::TorWebSite, "Website in Tor network" },
-1
View File
@@ -236,6 +236,5 @@
<file>server_scripts/socks5_proxy/Dockerfile</file>
<file>server_scripts/socks5_proxy/configure_container.sh</file>
<file>server_scripts/socks5_proxy/start.sh</file>
<file>ui/qml/Controls2/FocusChainType.qml</file>
</qresource>
</RCC>
File diff suppressed because it is too large Load Diff
@@ -14,71 +14,74 @@ DrawerType2 {
width: parent.width
height: parent.height
expandedContent: FocusChainType {
focus: root.visible
focusTabBarOnLastItem: false
expandedContent: ColumnLayout {
id: content
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Component.onCompleted: {
root.expandedHeight = content.implicitHeight + 32
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Add new connection")
}
// Item {
// id: focusItem
// KeyNavigation.tab: ip.rightButton
// }
LabelWithButtonType {
id: ip
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Configure your server")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.close()
}
// KeyNavigation.tab: qrCode.rightButton
}
DividerType {}
LabelWithButtonType {
id: qrCode
Layout.fillWidth: true
text: qsTr("Open config file, key or QR code")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.close()
}
// KeyNavigation.tab: focusItem
}
DividerType {}
Component.onCompleted: {
root.expandedHeight = content.implicitHeight + 32
}
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Add new connection")
}
Item {
id: focusItem
KeyNavigation.tab: ip.rightButton
}
LabelWithButtonType {
id: ip
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Configure your server")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.close()
}
KeyNavigation.tab: qrCode.rightButton
}
DividerType {}
LabelWithButtonType {
id: qrCode
Layout.fillWidth: true
text: qsTr("Open config file, key or QR code")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.close()
}
KeyNavigation.tab: focusItem
}
DividerType {}
}
}
@@ -16,109 +16,103 @@ DrawerType2 {
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedContent: FocusChainType {
focus: root.visible
focusTabBarOnLastItem: false
expandedContent: ColumnLayout {
id: content
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
// onActiveFocusChanged: {
// if (activeFocus) {
// focusItem.forceActiveFocus()
// }
// }
// Connections {
// target: root
// enabled: !GC.isMobile()
// function onOpened() {
// focusItem.forceActiveFocus()
// }
// }
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Split tunneling")
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
LabelWithButtonType {
id: splitTunnelingSwitch
Layout.fillWidth: true
Layout.topMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
headerText: qsTr("Split tunneling")
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
}
text: qsTr("Split tunneling on the server")
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
Item {
id: focusItem
KeyNavigation.tab: splitTunnelingSwitch.visible ? splitTunnelingSwitch : siteBasedSplitTunnelingSwitch.rightButton
}
// KeyNavigation.tab: siteBasedSplitTunnelingSwitch.visible ? siteBasedSplitTunnelingSwitch.rightButton : focusItem
LabelWithButtonType {
id: splitTunnelingSwitch
Layout.fillWidth: true
Layout.topMargin: 16
clickedFunction: function() {
// PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
// root.close()
}
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
text: qsTr("Split tunneling on the server")
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: siteBasedSplitTunnelingSwitch.visible ? siteBasedSplitTunnelingSwitch.rightButton : focusItem
clickedFunction: function() {
// PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
// root.close()
}
}
DividerType {
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
DividerType {
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")
}
LabelWithButtonType {
id: siteBasedSplitTunnelingSwitch
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Site-based split tunneling")
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: appSplitTunnelingSwitch.visible ?
appSplitTunnelingSwitch.rightButton :
focusItem
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
root.close()
}
}
LabelWithButtonType {
id: siteBasedSplitTunnelingSwitch
Layout.fillWidth: true
Layout.topMargin: 16
DividerType {
}
text: qsTr("Site-based split tunneling")
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
LabelWithButtonType {
id: appSplitTunnelingSwitch
visible: isAppSplitTinnelingEnabled
// KeyNavigation.tab: appSplitTunnelingSwitch.visible ?
// appSplitTunnelingSwitch.rightButton :
// focusItem
Layout.fillWidth: true
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
root.close()
}
text: qsTr("App-based split tunneling")
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: focusItem
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
root.close()
}
}
DividerType {
}
LabelWithButtonType {
id: appSplitTunnelingSwitch
visible: isAppSplitTinnelingEnabled
Layout.fillWidth: true
text: qsTr("App-based split tunneling")
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
// KeyNavigation.tab: focusItem
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
root.close()
}
}
DividerType {
visible: isAppSplitTinnelingEnabled
}
DividerType {
visible: isAppSplitTinnelingEnabled
}
}
}
+7 -1
View File
@@ -4,7 +4,7 @@ import Qt5Compat.GraphicalEffects
import Style 1.0
FocusScope {
Item {
id: root
property string backButtonImage: "qrc:/images/controls/arrow-left.svg"
@@ -15,6 +15,12 @@ FocusScope {
visible: backButtonImage !== ""
onActiveFocusChanged: {
if (activeFocus) {
backButton.forceActiveFocus()
}
}
RowLayout {
id: content
+1 -2
View File
@@ -20,8 +20,7 @@ Menu {
MenuItem {
text: qsTr("&Paste")
shortcut: StandardKey.Paste
// Fix calling paste from clipboard when launching app on android
enabled: Qt.platform.os === "android" ? true : textObj.canPaste
enabled: textObj.canPaste
onTriggered: textObj.paste()
}
+1 -47
View File
@@ -4,10 +4,9 @@ import QtQuick.Layouts
import Style 1.0
import "../Config"
import "TextTypes"
FocusScope {
Item {
id: root
readonly property string drawerExpanded: "expanded"
@@ -41,50 +40,6 @@ FocusScope {
signal closed
signal opened
onClosed: {
if (GC.isMobile()) {
return
}
// if (parent && parent instanceof PageType) {
// parent.focusItem_.forceActiveFocus()
// }
// tabBarStackView.currentItem.focusItem_.forceActiveFocus()
// PageController.forceStackActiveFocus()
}
// onOpened: {
// if (GC.isMobile()) {
// return
// }
// if (root.expandedContent) {
// expandedLoader.item.forceActiveFocus()
// }
// }
onActiveFocusChanged: {
if (GC.isMobile()) {
return
}
if (root.activeFocus && !root.isOpened && root.collapsedContent) {
collapsedLoader.item.forceActiveFocus()
}
}
onOpened: {
if (isOpened) {
if (drawerContent.state === root.drawerExpanded) {
expandedLoader.item.forceActiveFocus()
} else {
collapsedLoader.item.forceActiveFocus()
}
}
}
Connections {
target: PageController
@@ -220,7 +175,6 @@ FocusScope {
Item {
id: drawerContent
focus: true
Drag.active: dragArea.drag.active
anchors.right: root.right
anchors.left: root.left
-131
View File
@@ -1,131 +0,0 @@
import QtQuick
import "../Config"
import "../Components"
FocusScope {
id: root
property bool focusTabBarOnLastItem: true
property alias focusItem_: focusItem
QtObject {
id: internal
property var firstActiveFocusItem: null
property var focusChain: []
}
onVisibleChanged: {
focusItem_.focus = true
}
function getChildren(parent) {
for (var i = 0; i < parent.children.length; i++) {
var child = parent.children[i]
if (child.children) {
getChildren(child)
}
}
}
function isFocusableItem(item) {
if (!item || !item.visible || !item.enabled) {
return false
}
return item instanceof BasicButtonType ||
item instanceof ConnectButton ||
item instanceof LabelWithButtonType ||
item instanceof SwitcherType ||
item instanceof ImageButtonType ||
item instanceof TextFieldWithHeaderType ||
item instanceof BackButtonType ||
item instanceof HorizontalRadioButton ||
item instanceof DrawerType2 && !item.isOpened && item.collapsedContent
}
function getFocusChain(parent) {
let focusChain = []
for (var i = 0; i < parent.children.length; i++) {
var child = parent.children[i]
if (child instanceof DropDownType ||
child instanceof HomeSplitTunnelingDrawer ||
child instanceof ConnectionTypeSelectionDrawer
) {
continue
}
if (isFocusableItem(child)) {
focusChain.push(child)
continue
}
if (child.children) {
focusChain = focusChain.concat(getFocusChain(child))
}
}
return focusChain
}
Component.onCompleted: {
internal.focusChain = getFocusChain(root)
if (internal.focusChain.length === 0) {
return
}
for (let i = 0; i < internal.focusChain.length; i++) {
internal.focusChain[i].KeyNavigation.tab = internal.focusChain[(i + 1) % internal.focusChain.length]
internal.focusChain[i].KeyNavigation.backtab = internal.focusChain[(i + internal.focusChain.length - 1) % internal.focusChain.length]
}
internal.firstActiveFocusItem = internal.focusChain[0]
const lastItem = internal.focusChain[internal.focusChain.length - 1]
lastItem.Keys.onTabPressed.connect(function() {
lastItemTabClicked(lastItem)
})
for (let j = 0; j < internal.focusChain.length; j++) {
if (internal.focusChain[j] instanceof TextFieldWithHeaderType) {
internal.focusChain[j].forceActiveFocus()
break
}
}
}
Item {
id: focusItem
focus: true
Keys.onTabPressed: {
if (internal.firstActiveFocusItem) {
internal.firstActiveFocusItem.focus = true
internal.firstActiveFocusItem.forceActiveFocus()
}
}
}
function lastItemTabClicked() {
focusItem.focus = true
if (GC.isMobile()) {
return
}
if (focusTabBarOnLastItem) {
PageController.forceTabBarActiveFocus()
}
if (lastItem && lastItem.parentFlickable) {
lastItem.parentFlickable.contentY = 0
}
}
}
@@ -43,17 +43,25 @@ Item {
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
onActiveFocusChanged: {
onFocusChanged: {
if (root.activeFocus) {
if (rightImage.visible) {
rightImage.forceActiveFocus()
}
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
Connections {
target: rightImage
function onFocusChanged() {
if (rightImage.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
@@ -243,7 +251,6 @@ Item {
hoverEnabled: false
image: rightImageSource
imageColor: rightImageColor
// focus: visible
visible: rightImageSource ? true : false
Layout.alignment: Qt.AlignRight
@@ -270,7 +277,6 @@ Item {
id: background
anchors.fill: root
color: AmneziaStyle.color.transparent
visible: !rightImageSource
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
border.width: root.activeFocus ? root.borderFocusedWidth : 0
+36 -16
View File
@@ -1,19 +1,37 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "../Config"
import "../Components"
FocusChainType {
Item {
id: root
property StackView stackView: StackView.view
// onVisibleChanged: {
// if (visible && !GC.isMobile()) {
// timer.start()
// }
// }
property var defaultActiveFocusItem: null
onVisibleChanged: {
if (visible && !GC.isMobile()) {
timer.start()
}
}
function lastItemTabClicked(focusItem) {
if (GC.isMobile()) {
return
}
if (focusItem) {
focusItem.forceActiveFocus()
PageController.forceTabBarActiveFocus()
} else {
if (defaultActiveFocusItem) {
defaultActiveFocusItem.forceActiveFocus()
}
PageController.forceTabBarActiveFocus()
}
}
// MouseArea {
// id: globalMouseArea
@@ -29,13 +47,15 @@ FocusChainType {
// }
// Set a timer to set focus after a short delay
// Timer {
// id: timer
// interval: 100 // Milliseconds
// onTriggered: {
// focusItem.forceActiveFocus()
// }
// repeat: false // Stop the timer after one trigger
// running: !GC.isMobile() // Start the timer
// }
Timer {
id: timer
interval: 100 // Milliseconds
onTriggered: {
if (defaultActiveFocusItem) {
defaultActiveFocusItem.forceActiveFocus()
}
}
repeat: false // Stop the timer after one trigger
running: !GC.isMobile() // Start the timer
}
}
@@ -19,7 +19,6 @@ TabButton {
property var clickedFunc
focus: true
hoverEnabled: true
focusPolicy: Qt.TabFocus
@@ -6,7 +6,7 @@ import Style 1.0
import "TextTypes"
FocusScope {
Item {
id: root
property string headerText
@@ -40,17 +40,16 @@ FocusScope {
implicitHeight: content.implicitHeight
property FlickableType parentFlickable
// Connections {
// target: textField
// function onFocusChanged() {
// if (textField.activeFocus) {
// if (root.parentFlickable) {
// root.parentFlickable.ensureVisible(root)
// }
// }
// }
// }
Connections {
target: textField
function onFocusChanged() {
if (textField.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
}
ColumnLayout {
id: content
@@ -86,7 +85,6 @@ FocusScope {
TextField {
id: textField
activeFocusOnTab: false
focus: true
enabled: root.textFieldEditable
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
@@ -121,7 +119,6 @@ FocusScope {
}
onActiveFocusChanged: {
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
if (checkEmptyText && textFieldText === "") {
errorText = qsTr("The field can't be empty")
}
@@ -139,6 +136,9 @@ FocusScope {
textObj: textField
}
onFocusChanged: {
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
}
}
}
}
@@ -199,7 +199,7 @@ FocusScope {
}
function getBackgroundBorderColor(noneFocusedColor) {
return textField.activeFocus ? root.borderFocusedColor : noneFocusedColor
return textField.focus ? root.borderFocusedColor : noneFocusedColor
}
Keys.onEnterPressed: {
+418 -419
View File
@@ -18,7 +18,8 @@ import "../Components"
PageType {
id: root
focus: true
defaultActiveFocusItem: focusItem
Connections {
target: PageController
@@ -31,7 +32,7 @@ PageType {
}
}
FocusScope {
Item {
anchors.fill: parent
anchors.bottomMargin: drawer.collapsedHeight
@@ -40,6 +41,12 @@ PageType {
anchors.topMargin: 34
anchors.bottomMargin: 34
Item {
id: focusItem
KeyNavigation.tab: loggingButton.visible ?
loggingButton :
connectButton
}
BasicButtonType {
id: loggingButton
@@ -61,9 +68,8 @@ PageType {
Keys.onEnterPressed: loggingButton.clicked()
Keys.onReturnPressed: loggingButton.clicked()
// activeFocusOnTab: true
// KeyNavigation.tab: connectButton
KeyNavigation.tab: connectButton
onClicked: {
PageController.goToPage(PageEnum.PageSettingsLogging)
@@ -72,10 +78,9 @@ PageType {
ConnectButton {
id: connectButton
activeFocusOnTab: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
// KeyNavigation.tab: splitTunnelingButton
KeyNavigation.tab: splitTunnelingButton
}
BasicButtonType {
@@ -111,7 +116,7 @@ PageType {
Keys.onEnterPressed: splitTunnelingButton.clicked()
Keys.onReturnPressed: splitTunnelingButton.clicked()
// KeyNavigation.tab: drawer
KeyNavigation.tab: drawer
onClicked: {
homeSplitTunnelingDrawer.open()
@@ -121,426 +126,420 @@ PageType {
id: homeSplitTunnelingDrawer
parent: root
// onClosed: {
// if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
// }
// }
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
}
}
}
}
DrawerType2 {
id: drawer
objectName: "drawer"
anchors.fill: parent
focus: true
// collapsedContent: FocusScope {
// id: collapsed123
// focus: true
// implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
// Component.onCompleted: {
// drawer.expandedHeight = implicitHeight
// }
// // Connections {
// // target: drawer
// // enabled: !GC.isMobile()
// // function onActiveFocusChanged() {
// // if (drawer.activeFocus && !drawer.isOpened) {
// // collapsed123.forceActiveFocus()
// // // collapsedButtonChevron.forceActiveFocus()
// // }
// // }
// // }
// ColumnLayout {
// id: collapsed
// anchors.left: parent.left
// anchors.right: parent.right
// Component.onCompleted: {
// drawer.collapsedHeight = collapsed.implicitHeight
// }
// DividerType {
// Layout.topMargin: 10
// Layout.fillWidth: false
// Layout.preferredWidth: 20
// Layout.preferredHeight: 2
// Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
// }
// RowLayout {
// Layout.topMargin: 14
// Layout.leftMargin: 24
// Layout.rightMargin: 24
// Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
// spacing: 0
// Connections {
// target: drawer
// function onEntered() {
// if (drawer.isCollapsed) {
// collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
// collapsedButtonHeader.opacity = 0.8
// } else {
// collapsedButtonHeader.opacity = 1
// }
// }
// function onExited() {
// if (drawer.isCollapsed) {
// collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
// collapsedButtonHeader.opacity = 1
// } else {
// collapsedButtonHeader.opacity = 1
// }
// }
// function onPressed(pressed, entered) {
// if (drawer.isCollapsed) {
// collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
// collapsedButtonHeader.opacity = 0.7
// } else {
// collapsedButtonHeader.opacity = 1
// }
// }
// }
// Header1TextType {
// id: collapsedButtonHeader
// Layout.maximumWidth: drawer.width - 48 - 18 - 12
// maximumLineCount: 2
// elide: Qt.ElideRight
// text: ServersModel.defaultServerName
// horizontalAlignment: Qt.AlignHCenter
// Behavior on opacity {
// PropertyAnimation { duration: 200 }
// }
// }
// ImageButtonType {
// id: collapsedButtonChevron
// Layout.leftMargin: 8
// visible: drawer.isCollapsed
// hoverEnabled: false
// image: "qrc:/images/controls/chevron-down.svg"
// imageColor: AmneziaStyle.color.white
// icon.width: 18
// icon.height: 18
// backgroundRadius: 16
// horizontalPadding: 4
// topPadding: 4
// bottomPadding: 3
// Keys.onEnterPressed: collapsedButtonChevron.clicked()
// Keys.onReturnPressed: collapsedButtonChevron.clicked()
// // Keys.onTabPressed: lastItemTabClicked()
// focus: true
// onClicked: {
// if (drawer.isCollapsed) {
// drawer.open()
// focusItem1.forceActiveFocus()
// }
// }
// }
// }
// LabelTextType {
// id: collapsedServerMenuDescription
// Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
// Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
// text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
// }
// }
// // Connections {
// // target: drawer
// // enabled: !GC.isMobile()
// // function onIsCollapsedChanged() {
// // if (!drawer.isCollapsed) {
// // focusItem1.forceActiveFocus()
// // }
// // }
// // }
// ColumnLayout {
// id: serversMenuHeader
// anchors.top: collapsed.bottom
// anchors.right: parent.right
// anchors.left: parent.left
// RowLayout {
// Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
// focus: false
// spacing: 8
// visible: !ServersModel.isDefaultServerFromApi
// Item {
// id: focusItem1
// KeyNavigation.tab: serversMenuContent /*containersDropDown*/
// }
// // DropDownType {
// // id: containersDropDown
// // rootButtonImageColor: AmneziaStyle.color.black
// // rootButtonBackgroundColor: AmneziaStyle.color.white
// // rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
// // rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
// // rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
// // rootButtonDefaultBorderColor: AmneziaStyle.color.transparent
// // rootButtonTextTopMargin: 8
// // rootButtonTextBottomMargin: 8
// // text: ServersModel.defaultServerDefaultContainerName
// // textColor: AmneziaStyle.color.black
// // headerText: qsTr("VPN protocol")
// // headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
// // rootButtonClickedFunction: function() {
// // containersDropDown.open()
// // }
// // drawerParent: root
// // KeyNavigation.tab: serversMenuContent
// // listView: HomeContainersListView {
// // id: containersListView
// // rootWidth: root.width
// // // onVisibleChanged: {
// // // if (containersDropDown.visible && !GC.isMobile()) {
// // // focusItem1.forceActiveFocus()
// // // }
// // // }
// // Connections {
// // target: ServersModel
// // function onDefaultServerIndexChanged() {
// // updateContainersModelFilters()
// // }
// // }
// // function updateContainersModelFilters() {
// // if (ServersModel.isDefaultServerHasWriteAccess()) {
// // proxyDefaultServerContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
// // } else {
// // proxyDefaultServerContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
// // }
// // }
// // model: SortFilterProxyModel {
// // id: proxyDefaultServerContainersModel
// // sourceModel: DefaultServerContainersModel
// // sorters: [
// // RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
// // ]
// // }
// // Component.onCompleted: updateContainersModelFilters()
// // }
// // }
// }
// Header2Type {
// Layout.fillWidth: true
// Layout.topMargin: 48
// Layout.leftMargin: 16
// Layout.rightMargin: 16
// headerText: qsTr("Servers")
// }
// }
// ButtonGroup {
// id: serversRadioButtonGroup
// }
// ListView {
// id: serversMenuContent
// anchors.top: serversMenuHeader.bottom
// anchors.right: parent.right
// anchors.left: parent.left
// anchors.bottom: parent.bottom
// anchors.topMargin: 16
// model: ServersModel
// currentIndex: ServersModel.defaultIndex
// ScrollBar.vertical: ScrollBar {
// id: scrollBar
// policy: serversMenuContent.height >= serversMenuContent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
// }
// activeFocusOnTab: true
// focus: true
// property int focusItemIndex: 0
// onActiveFocusChanged: {
// if (activeFocus) {
// serversMenuContent.focusItemIndex = 0
// serversMenuContent.itemAtIndex(focusItemIndex).forceActiveFocus()
// }
// }
// onFocusItemIndexChanged: {
// const focusedElement = serversMenuContent.itemAtIndex(focusItemIndex)
// if (focusedElement) {
// if (focusedElement.y + focusedElement.height > serversMenuContent.height) {
// serversMenuContent.contentY = focusedElement.y + focusedElement.height - serversMenuContent.height
// } else {
// serversMenuContent.contentY = 0
// }
// }
// }
// Keys.onUpPressed: scrollBar.decrease()
// Keys.onDownPressed: scrollBar.increase()
// Connections {
// target: drawer
// enabled: !GC.isMobile()
// function onIsCollapsedChanged() {
// if (drawer.isCollapsed) {
// const item = serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex)
// if (item) { item.serverRadioButtonProperty.focus = false }
// }
// }
// }
// Connections {
// target: ServersModel
// function onDefaultServerIndexChanged(serverIndex) {
// serversMenuContent.currentIndex = serverIndex
// }
// }
// clip: true
// delegate: Item {
// id: menuContentDelegate
// property variant delegateData: model
// property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
// implicitWidth: serversMenuContent.width
// implicitHeight: serverRadioButtonContent.implicitHeight
// onActiveFocusChanged: {
// if (activeFocus) {
// serverRadioButton.forceActiveFocus()
// }
// }
// ColumnLayout {
// id: serverRadioButtonContent
// anchors.fill: parent
// anchors.rightMargin: 16
// anchors.leftMargin: 16
// spacing: 0
// RowLayout {
// Layout.fillWidth: true
// VerticalRadioButton {
// id: serverRadioButton
// Layout.fillWidth: true
// text: name
// descriptionText: serverDescription
// checked: index === serversMenuContent.currentIndex
// checkable: !ConnectionController.isConnected
// ButtonGroup.group: serversRadioButtonGroup
// onClicked: {
// if (ConnectionController.isConnected) {
// PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
// return
// }
// serversMenuContent.currentIndex = index
// ServersModel.defaultIndex = index
// }
// MouseArea {
// anchors.fill: serverRadioButton
// cursorShape: Qt.PointingHandCursor
// enabled: false
// }
// Keys.onTabPressed: serverInfoButton.forceActiveFocus()
// Keys.onEnterPressed: serverRadioButton.clicked()
// Keys.onReturnPressed: serverRadioButton.clicked()
// KeyNavigation.tab: serverInfoButton
// }
// ImageButtonType {
// id: serverInfoButton
// image: "qrc:/images/controls/settings.svg"
// imageColor: AmneziaStyle.color.white
// implicitWidth: 56
// implicitHeight: 56
// z: 1
// Keys.onTabPressed: {
// if (serversMenuContent.focusItemIndex < serversMenuContent.count - 1) {
// serversMenuContent.focusItemIndex++
// serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex).forceActiveFocus()
// } else {
// focusItem1.forceActiveFocus()
// serversMenuContent.contentY = 0
// }
// }
// Keys.onEnterPressed: serverInfoButton.clicked()
// Keys.onReturnPressed: serverInfoButton.clicked()
// onClicked: function() {
// ServersModel.processedIndex = index
// PageController.goToPage(PageEnum.PageSettingsServerInfo)
// drawer.close()
// }
// }
// }
// DividerType {
// Layout.fillWidth: true
// Layout.leftMargin: 0
// Layout.rightMargin: 0
// }
// }
// }
// }
// }
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
collapsedContent: Item {
implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
Component.onCompleted: {
drawer.expandedHeight = implicitHeight
}
Connections {
target: drawer
enabled: !GC.isMobile()
function onActiveFocusChanged() {
if (drawer.activeFocus && !drawer.isOpened) {
collapsedButtonChevron.forceActiveFocus()
}
}
}
ColumnLayout {
id: collapsed
anchors.left: parent.left
anchors.right: parent.right
Component.onCompleted: {
drawer.collapsedHeight = collapsed.implicitHeight
}
DividerType {
Layout.topMargin: 10
Layout.fillWidth: false
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
RowLayout {
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 0
Connections {
target: drawer
function onEntered() {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
} else {
collapsedButtonHeader.opacity = 1
}
}
function onExited() {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
} else {
collapsedButtonHeader.opacity = 1
}
}
function onPressed(pressed, entered) {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
} else {
collapsedButtonHeader.opacity = 1
}
}
}
Header1TextType {
id: collapsedButtonHeader
Layout.maximumWidth: drawer.width - 48 - 18 - 12
maximumLineCount: 2
elide: Qt.ElideRight
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
KeyNavigation.tab: tabBar
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
}
ImageButtonType {
id: collapsedButtonChevron
Layout.leftMargin: 8
visible: drawer.isCollapsed
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
imageColor: AmneziaStyle.color.white
icon.width: 18
icon.height: 18
backgroundRadius: 16
horizontalPadding: 4
topPadding: 4
bottomPadding: 3
Keys.onEnterPressed: collapsedButtonChevron.clicked()
Keys.onReturnPressed: collapsedButtonChevron.clicked()
Keys.onTabPressed: lastItemTabClicked()
onClicked: {
if (drawer.isCollapsed) {
drawer.open()
}
}
}
}
LabelTextType {
id: collapsedServerMenuDescription
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
}
}
Connections {
target: drawer
enabled: !GC.isMobile()
function onIsCollapsedChanged() {
if (!drawer.isCollapsed) {
focusItem1.forceActiveFocus()
}
}
}
ColumnLayout {
id: serversMenuHeader
anchors.top: collapsed.bottom
anchors.right: parent.right
anchors.left: parent.left
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8
visible: !ServersModel.isDefaultServerFromApi
Item {
id: focusItem1
KeyNavigation.tab: containersDropDown
}
DropDownType {
id: containersDropDown
rootButtonImageColor: AmneziaStyle.color.black
rootButtonBackgroundColor: AmneziaStyle.color.white
rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
rootButtonDefaultBorderColor: AmneziaStyle.color.transparent
rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8
text: ServersModel.defaultServerDefaultContainerName
textColor: AmneziaStyle.color.black
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() {
containersDropDown.open()
}
drawerParent: root
KeyNavigation.tab: serversMenuContent
listView: HomeContainersListView {
id: containersListView
rootWidth: root.width
onVisibleChanged: {
if (containersDropDown.visible && !GC.isMobile()) {
focusItem1.forceActiveFocus()
}
}
Connections {
target: ServersModel
function onDefaultServerIndexChanged() {
updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isDefaultServerHasWriteAccess()) {
proxyDefaultServerContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyDefaultServerContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
}
model: SortFilterProxyModel {
id: proxyDefaultServerContainersModel
sourceModel: DefaultServerContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
}
Component.onCompleted: updateContainersModelFilters()
}
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 48
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Servers")
}
}
ButtonGroup {
id: serversRadioButtonGroup
}
ListView {
id: serversMenuContent
anchors.top: serversMenuHeader.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.topMargin: 16
model: ServersModel
currentIndex: ServersModel.defaultIndex
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversMenuContent.height >= serversMenuContent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
activeFocusOnTab: true
focus: true
property int focusItemIndex: 0
onActiveFocusChanged: {
if (activeFocus) {
serversMenuContent.focusItemIndex = 0
serversMenuContent.itemAtIndex(focusItemIndex).forceActiveFocus()
}
}
onFocusItemIndexChanged: {
const focusedElement = serversMenuContent.itemAtIndex(focusItemIndex)
if (focusedElement) {
if (focusedElement.y + focusedElement.height > serversMenuContent.height) {
serversMenuContent.contentY = focusedElement.y + focusedElement.height - serversMenuContent.height
} else {
serversMenuContent.contentY = 0
}
}
}
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
Connections {
target: drawer
enabled: !GC.isMobile()
function onIsCollapsedChanged() {
if (drawer.isCollapsed) {
const item = serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex)
if (item) { item.serverRadioButtonProperty.focus = false }
}
}
}
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
}
}
clip: true
delegate: Item {
id: menuContentDelegate
property variant delegateData: model
property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
serverRadioButton.forceActiveFocus()
}
}
ColumnLayout {
id: serverRadioButtonContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
RowLayout {
Layout.fillWidth: true
VerticalRadioButton {
id: serverRadioButton
Layout.fillWidth: true
text: name
descriptionText: serverDescription
checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected
ButtonGroup.group: serversRadioButtonGroup
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
serversMenuContent.currentIndex = index
ServersModel.defaultIndex = index
}
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
Keys.onTabPressed: serverInfoButton.forceActiveFocus()
Keys.onEnterPressed: serverRadioButton.clicked()
Keys.onReturnPressed: serverRadioButton.clicked()
}
ImageButtonType {
id: serverInfoButton
image: "qrc:/images/controls/settings.svg"
imageColor: AmneziaStyle.color.white
implicitWidth: 56
implicitHeight: 56
z: 1
Keys.onTabPressed: {
if (serversMenuContent.focusItemIndex < serversMenuContent.count - 1) {
serversMenuContent.focusItemIndex++
serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex).forceActiveFocus()
} else {
focusItem1.forceActiveFocus()
serversMenuContent.contentY = 0
}
}
Keys.onEnterPressed: serverInfoButton.clicked()
Keys.onReturnPressed: serverInfoButton.clicked()
onClicked: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
drawer.close()
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
}
}
}
}
}
}
}
@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
Item {
id: focusItem
onFocusChanged: {
@@ -15,7 +15,12 @@ import "../Components"
PageType {
id: root
// defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -178,6 +183,7 @@ PageType {
Layout.bottomMargin: 24
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
@@ -17,7 +17,7 @@ import "../Components"
PageType {
id: root
// defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
Item {
id: focusItem
+10 -2
View File
@@ -19,6 +19,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@@ -115,7 +122,7 @@ PageType {
onClosed: {
if (!GC.isMobile()) {
// defaultActiveFocusItem.forceActiveFocus()
defaultActiveFocusItem.forceActiveFocus()
}
}
@@ -219,6 +226,7 @@ PageType {
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: AmneziaStyle.color.red
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
@@ -231,7 +239,7 @@ PageType {
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
focusItem.forceActiveFocus()
}
}
@@ -15,9 +15,9 @@ import "../Components"
PageType {
id: root
// defaultActiveFocusItem: listview.currentItem.focusItemId.enabled ?
// listview.currentItem.focusItemId.textField :
// focusItem
defaultActiveFocusItem: listview.currentItem.focusItemId.enabled ?
listview.currentItem.focusItemId.textField :
focusItem
Item {
id: focusItem
@@ -15,6 +15,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Item {
id: focusItem
KeyNavigation.tab: backButton
@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Item {
id: focusItem
KeyNavigation.tab: backButton
@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: InstallController
@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Connections {
target: InstallController
@@ -17,6 +17,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: InstallController
+11 -7
View File
@@ -13,6 +13,8 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: header
FlickableType {
id: fl
anchors.top: parent.top
@@ -36,6 +38,8 @@ PageType {
Layout.leftMargin: 16
headerText: qsTr("Settings")
KeyNavigation.tab: account.rightButton
}
LabelWithButtonType {
@@ -51,7 +55,7 @@ PageType {
PageController.goToPage(PageEnum.PageSettingsServersList)
}
// KeyNavigation.tab: connection.rightButton
KeyNavigation.tab: connection.rightButton
}
DividerType {}
@@ -68,7 +72,7 @@ PageType {
PageController.goToPage(PageEnum.PageSettingsConnection)
}
// KeyNavigation.tab: application.rightButton
KeyNavigation.tab: application.rightButton
}
DividerType {}
@@ -85,7 +89,7 @@ PageType {
PageController.goToPage(PageEnum.PageSettingsApplication)
}
// KeyNavigation.tab: backup.rightButton
KeyNavigation.tab: backup.rightButton
}
DividerType {}
@@ -102,7 +106,7 @@ PageType {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
// KeyNavigation.tab: about.rightButton
KeyNavigation.tab: about.rightButton
}
DividerType {}
@@ -118,7 +122,7 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAbout)
}
// KeyNavigation.tab: close
KeyNavigation.tab: close
}
@@ -132,9 +136,9 @@ PageType {
text: qsTr("Close application")
leftImageSource: "qrc:/images/controls/x-circle.svg"
isLeftImageHoverEnabled: false
isLeftImageHoverEnabled: false
// Keys.onTabPressed: lastItemTabClicked()
Keys.onTabPressed: lastItemTabClicked(header)
clickedFunction: function() {
PageController.closeApplication()
+20 -4
View File
@@ -14,6 +14,19 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
onFocusChanged: {
if (focusItem.activeFocus) {
fl.contentY = 0
}
}
}
BackButtonType {
id: backButton
@@ -21,6 +34,8 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: telegramButton
}
FlickableType {
@@ -91,7 +106,7 @@ PageType {
descriptionText: qsTr("To discuss features")
leftImageSource: "qrc:/images/controls/telegram.svg"
// KeyNavigation.tab: mailButton
KeyNavigation.tab: mailButton
parentFlickable: fl
clickedFunction: function() {
@@ -109,7 +124,7 @@ PageType {
descriptionText: qsTr("For reviews and bug reports")
leftImageSource: "qrc:/images/controls/mail.svg"
// KeyNavigation.tab: githubButton
KeyNavigation.tab: githubButton
parentFlickable: fl
clickedFunction: function() {
@@ -126,7 +141,7 @@ PageType {
text: qsTr("GitHub")
leftImageSource: "qrc:/images/controls/github.svg"
// KeyNavigation.tab: websiteButton
KeyNavigation.tab: websiteButton
parentFlickable: fl
clickedFunction: function() {
@@ -180,7 +195,7 @@ PageType {
text: qsTr("Check for updates")
// KeyNavigation.tab: privacyPolicyButton
KeyNavigation.tab: privacyPolicyButton
parentFlickable: fl
clickedFunc: function() {
@@ -203,6 +218,7 @@ PageType {
text: qsTr("Privacy Policy")
Keys.onTabPressed: lastItemTabClicked()
parentFlickable: fl
clickedFunc: function() {
@@ -21,6 +21,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
property bool pageEnabled
Component.onCompleted: {
@@ -64,6 +66,11 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@@ -75,6 +82,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: switcher
}
RowLayout {
@@ -95,6 +103,10 @@ PageType {
enabled: root.pageEnabled
KeyNavigation.tab: selector.enabled ?
selector :
searchField.textField
checked: AppSplitTunnelingModel.isTunnelingEnabled
onToggled: {
AppSplitTunnelingModel.toggleSplitTunneling(checked)
@@ -118,6 +130,8 @@ PageType {
enabled: Qt.platform.os === "android" && root.pageEnabled
KeyNavigation.tab: searchField.textField
listView: ListViewWithRadioButtonType {
rootWidth: root.width
@@ -253,6 +267,7 @@ PageType {
textFieldPlaceholderText: qsTr("application name")
buttonImageSource: "qrc:/images/controls/plus.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
rightButtonClickedOnEnter: true
clickedFunc: function() {
@@ -14,6 +14,18 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
onFocusChanged: {
if (focusItem.activeFocus) {
fl.contentY = 0
}
}
}
BackButtonType {
id: backButton
@@ -23,7 +35,7 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 20
// KeyNavigation.tab: GC.isMobile() ? switcher : switcherAutoStart
KeyNavigation.tab: GC.isMobile() ? switcher : switcherAutoStart
}
FlickableType {
@@ -65,8 +77,8 @@ PageType {
}
}
// KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
// labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
parentFlickable: fl
}
@@ -83,7 +95,7 @@ PageType {
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
// KeyNavigation.tab: labelWithButtonLanguage.rightButton
KeyNavigation.tab: labelWithButtonLanguage.rightButton
parentFlickable: fl
clickedFunction: function() {
@@ -105,7 +117,7 @@ PageType {
text: qsTr("Auto start")
descriptionText: qsTr("Launch the application every time the device is starts")
// KeyNavigation.tab: switcherAutoConnect
KeyNavigation.tab: switcherAutoConnect
parentFlickable: fl
checked: SettingsController.isAutoStartEnabled()
@@ -130,7 +142,7 @@ PageType {
text: qsTr("Auto connect")
descriptionText: qsTr("Connect to VPN on app start")
// KeyNavigation.tab: switcherStartMinimized
KeyNavigation.tab: switcherStartMinimized
parentFlickable: fl
checked: SettingsController.isAutoConnectEnabled()
@@ -155,7 +167,7 @@ PageType {
text: qsTr("Start minimized")
descriptionText: qsTr("Launch application minimized")
// KeyNavigation.tab: labelWithButtonLanguage.rightButton
KeyNavigation.tab: labelWithButtonLanguage.rightButton
parentFlickable: fl
checked: SettingsController.isStartMinimizedEnabled()
@@ -178,7 +190,7 @@ PageType {
descriptionText: LanguageModel.currentLanguageName
rightImageSource: "qrc:/images/controls/chevron-right.svg"
// KeyNavigation.tab: labelWithButtonLogging.rightButton
KeyNavigation.tab: labelWithButtonLogging.rightButton
parentFlickable: fl
clickedFunction: function() {
@@ -196,7 +208,7 @@ PageType {
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
// KeyNavigation.tab: labelWithButtonReset.rightButton
KeyNavigation.tab: labelWithButtonReset.rightButton
parentFlickable: fl
clickedFunction: function() {
@@ -214,6 +226,9 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: AmneziaStyle.color.red
Keys.onTabPressed: lastItemTabClicked()
parentFlickable: fl
clickedFunction: function() {
var headerText = qsTr("Reset settings and remove all data from the application?")
var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
@@ -230,12 +245,12 @@ PageType {
}
if (!GC.isMobile()) {
// root.defaultActiveFocusItem.forceActiveFocus()
root.defaultActiveFocusItem.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
// root.defaultActiveFocusItem.forceActiveFocus()
root.defaultActiveFocusItem.forceActiveFocus()
}
}
+10 -3
View File
@@ -17,6 +17,8 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: SettingsController
@@ -35,6 +37,11 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -43,7 +50,7 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 20
// KeyNavigation.tab: makeBackupButton
KeyNavigation.tab: makeBackupButton
}
FlickableType {
@@ -106,7 +113,7 @@ PageType {
}
}
// KeyNavigation.tab: restoreBackupButton
KeyNavigation.tab: restoreBackupButton
}
BasicButtonType {
@@ -131,7 +138,7 @@ PageType {
}
}
// Keys.onTabPressed: lastItemTabClicked()
Keys.onTabPressed: lastItemTabClicked()
}
}
}
@@ -11,8 +11,15 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: focusItem
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -21,7 +28,7 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 20
// KeyNavigation.tab: amneziaDnsSwitch
KeyNavigation.tab: amneziaDnsSwitch
}
FlickableType {
@@ -60,7 +67,7 @@ PageType {
}
}
// KeyNavigation.tab: dnsServersButton.rightButton
KeyNavigation.tab: dnsServersButton.rightButton
}
DividerType {}
@@ -77,7 +84,7 @@ PageType {
PageController.goToPage(PageEnum.PageSettingsDns)
}
// KeyNavigation.tab: splitTunnelingButton.rightButton
KeyNavigation.tab: splitTunnelingButton.rightButton
}
DividerType {}
@@ -159,7 +166,7 @@ PageType {
}
}
// Keys.onTabPressed: lastItemTabClicked()
Keys.onTabPressed: lastItemTabClicked()
}
DividerType {
+5 -3
View File
@@ -14,6 +14,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: primaryDns.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
@@ -27,7 +29,7 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 20
// KeyNavigation.tab: root.defaultActiveFocusItem
KeyNavigation.tab: root.defaultActiveFocusItem
}
FlickableType {
@@ -122,12 +124,12 @@ PageType {
PageController.showNotificationMessage(qsTr("Settings have been reset"))
if (!GC.isMobile()) {
// defaultActiveFocusItem.forceActiveFocus()
defaultActiveFocusItem.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
// defaultActiveFocusItem.forceActiveFocus()
defaultActiveFocusItem.forceActiveFocus()
}
}
+19 -6
View File
@@ -28,6 +28,13 @@ disabled after 14 days, and all log files will be deleted.")
}
}
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -35,6 +42,8 @@ disabled after 14 days, and all log files will be deleted.")
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: switcher
}
FlickableType {
@@ -70,6 +79,7 @@ disabled after 14 days, and all log files will be deleted.")
text: qsTr("Save logs")
checked: SettingsController.isLoggingEnabled
KeyNavigation.tab: openFolderButton
onCheckedChanged: {
if (checked !== SettingsController.isLoggingEnabled) {
SettingsController.isLoggingEnabled = checked
@@ -93,6 +103,7 @@ disabled after 14 days, and all log files will be deleted.")
implicitHeight: 56
image: "qrc:/images/controls/folder-open.svg"
KeyNavigation.tab: saveButton
onClicked: SettingsController.openLogsFolder()
Keys.onReturnPressed: openFolderButton.clicked()
@@ -120,6 +131,7 @@ disabled after 14 days, and all log files will be deleted.")
implicitHeight: 56
image: "qrc:/images/controls/save.svg"
KeyNavigation.tab: clearButton
Keys.onReturnPressed: saveButton.clicked()
Keys.onEnterPressed: saveButton.clicked()
@@ -164,6 +176,7 @@ disabled after 14 days, and all log files will be deleted.")
implicitHeight: 56
image: "qrc:/images/controls/delete.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
Keys.onReturnPressed: clearButton.clicked()
Keys.onEnterPressed: clearButton.clicked()
@@ -177,14 +190,14 @@ disabled after 14 days, and all log files will be deleted.")
SettingsController.clearLogs()
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs have been cleaned up"))
// if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
// }
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
var noButtonFunction = function() {
// if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
// }
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@@ -19,6 +19,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: PageController
@@ -21,6 +21,8 @@ PageType {
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
@@ -17,6 +17,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@@ -28,7 +35,7 @@ PageType {
BackButtonType {
id: backButton
// KeyNavigation.tab: servers
KeyNavigation.tab: servers
}
HeaderType {
@@ -62,8 +69,8 @@ PageType {
clip: true
interactive: false
// activeFocusOnTab: true
// focus: true
activeFocusOnTab: true
focus: true
Keys.onTabPressed: {
if (currentIndex < servers.count - 1) {
servers.incrementCurrentIndex()
@@ -86,11 +93,11 @@ PageType {
implicitWidth: servers.width
implicitHeight: delegateContent.implicitHeight
// onFocusChanged: {
// if (focus) {
// server.rightButton.forceActiveFocus()
// }
// }
onFocusChanged: {
if (focus) {
server.rightButton.forceActiveFocus()
}
}
ColumnLayout {
id: delegateContent
@@ -23,6 +23,8 @@ PageType {
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
defaultActiveFocusItem: searchField.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
@@ -358,11 +360,11 @@ PageType {
anchors.fill: parent
expandedHeight: parent.height * 0.4375
// onClosed: {
// if (root.defaultActiveFocusItem && !GC.isMobile()) {
// root.defaultActiveFocusItem.forceActiveFocus()
// }
// }
onClosed: {
if (root.defaultActiveFocusItem && !GC.isMobile()) {
root.defaultActiveFocusItem.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
id: moreActionsDrawerContent
@@ -22,6 +22,8 @@ PageType {
}
}
defaultActiveFocusItem: focusItem
FlickableType {
id: fl
anchors.top: parent.top
@@ -37,9 +39,15 @@ PageType {
spacing: 0
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
Layout.topMargin: 20
KeyNavigation.tab: fileButton.rightButton
}
HeaderType {
@@ -70,6 +78,8 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/folder-open.svg"
KeyNavigation.tab: qrButton.visible ? qrButton.rightButton : textButton.rightButton
clickedFunction: function() {
var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" :
"Config files (*.vpn *.ovpn *.conf *.json)"
@@ -93,6 +103,8 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/qr-code.svg"
KeyNavigation.tab: textButton.rightButton
clickedFunction: function() {
ImportController.startDecodingQr()
if (Qt.platform.os === "ios") {
@@ -113,6 +125,8 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/text-cursor.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardTextKey)
}
@@ -12,6 +12,13 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: hostname.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -19,6 +26,8 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: hostname.textField
}
FlickableType {
@@ -58,7 +67,7 @@ PageType {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
// KeyNavigation.stab: username.textField
KeyNavigation.tab: username.textField
}
TextFieldWithHeaderType {
@@ -72,7 +81,7 @@ PageType {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
// KeyNavigation.tab: secretData.textField
KeyNavigation.tab: secretData.textField
}
TextFieldWithHeaderType {
@@ -94,7 +103,7 @@ PageType {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
// KeyNavigation.tab: continueButton
KeyNavigation.tab: continueButton
}
BasicButtonType {
@@ -105,7 +114,7 @@ PageType {
text: qsTr("Continue")
// Keys.onTabPressed: lastItemTabClicked()
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
@@ -17,6 +17,7 @@ PageType {
id: root
property bool isEasySetup: true
defaultActiveFocusItem: focusItem
SortFilterProxyModel {
id: proxyContainersModel
@@ -33,6 +34,14 @@ PageType {
}
}
Item {
id: focusItem
implicitWidth: 1
implicitHeight: 54
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -40,6 +49,8 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: continueButton
}
FlickableType {
@@ -152,6 +163,7 @@ PageType {
implicitWidth: parent.width
text: qsTr("Continue")
KeyNavigation.tab: setupLaterButton
parentFlickable: fl
clickedFunc: function() {
@@ -181,6 +193,7 @@ PageType {
textColor: AmneziaStyle.color.white
borderWidth: 1
Keys.onTabPressed: lastItemTabClicked(focusItem)
parentFlickable: fl
visible: {
@@ -13,6 +13,7 @@ import "../Config"
PageType {
id: root
Component.onCompleted: PageController.disableTabBar(true)
Component.onDestruction: PageController.disableTabBar(false)
@@ -113,7 +113,7 @@ PageType {
parent: root
onClosed: {
if (!GC.isMobile()) {
// defaultActiveFocusItem.forceActiveFocus()
defaultActiveFocusItem.forceActiveFocus()
}
}
@@ -263,7 +263,8 @@ PageType {
clickedFunc: function() {
if (!port.textField.acceptableInput &&
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite") {
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" &&
ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") {
port.errorText = qsTr("The port must be in the range of 1 to 65535")
return
}
@@ -288,10 +289,10 @@ PageType {
transportProtoSelector.visible = protocolSelectorVisible
transportProtoHeader.visible = protocolSelectorVisible
// if (port.visible && port.enabled)
// defaultActiveFocusItem = port.textField
// else
// defaultActiveFocusItem = focusItem
if (port.visible && port.enabled)
defaultActiveFocusItem = port.textField
else
defaultActiveFocusItem = focusItem
}
}
}
@@ -14,6 +14,13 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
+15 -8
View File
@@ -13,10 +13,11 @@ import "../Components"
PageType {
id: root
objectName: "PageStart"
property bool isControlsDisabled: false
defaultActiveFocusItem: focusItem
Connections {
target: PageController
@@ -138,6 +139,11 @@ PageType {
qsTr(" Helps you access blocked content without revealing your privacy, even to VPN providers.")
}
Item {
id: focusItem
KeyNavigation.tab: startButton
}
BasicButtonType {
id: startButton
Layout.fillWidth: true
@@ -150,6 +156,8 @@ PageType {
clickedFunc: function() {
connectionTypeSelection.open()
}
KeyNavigation.tab: startButton2
}
BasicButtonType {
@@ -171,6 +179,8 @@ PageType {
clickedFunc: function() {
Qt.openUrlExternally(qsTr("https://amnezia.org/instructions/0_starter-guide"))
}
Keys.onTabPressed: lastItemTabClicked(focusItem)
}
}
}
@@ -178,12 +188,9 @@ PageType {
ConnectionTypeSelectionDrawer {
id: connectionTypeSelection
// onClosed: {
// PageController.forceTabBarActiveFocus()
// root.defaultActiveFocusItem.forceActiveFocus()
// PageController.forceStackActiveFocus()
// startButton2.forceActiveFocus()
// }
onClosed: {
PageController.forceTabBarActiveFocus()
root.defaultActiveFocusItem.forceActiveFocus()
}
}
}
@@ -12,6 +12,14 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: textKey.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
FlickableType {
id: fl
anchors.top: parent.top
@@ -30,6 +38,7 @@ PageType {
BackButtonType {
id: backButton
Layout.topMargin: 20
KeyNavigation.tab: textKey.textField
}
HeaderType {
@@ -57,6 +66,8 @@ PageType {
textField.text = ""
textField.paste()
}
KeyNavigation.tab: continueButton
}
}
}
@@ -72,6 +83,7 @@ PageType {
anchors.bottomMargin: 32
text: qsTr("Continue")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
if (ImportController.extractConfigFromData(textKey.textFieldText)) {
@@ -16,6 +16,13 @@ PageType {
property bool showContent: false
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -23,6 +30,8 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: showContentButton
}
Connections {
@@ -183,6 +192,8 @@ PageType {
anchors.rightMargin: 16
anchors.leftMargin: 16
Keys.onTabPressed: lastItemTabClicked(focusItem)
BasicButtonType {
id: connectButton
Layout.fillWidth: true
+18 -16
View File
@@ -18,6 +18,8 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: clientNameTextField.textField
enum ConfigType {
AmneziaConnection,
OpenVpn,
@@ -152,7 +154,7 @@ PageType {
}
FlickableType {
id: fl
id: a
anchors.top: parent.top
anchors.bottom: parent.bottom
@@ -175,7 +177,7 @@ PageType {
KeyNavigation.tab: header.actionButton
onFocusChanged: {
if (focusItem.activeFocus) {
fl.contentY = 0
a.contentY = 0
}
}
}
@@ -286,7 +288,7 @@ PageType {
implicitWidth: (root.width - 32) / 2
text: qsTr("Connection")
// KeyNavigation.tab: usersRadioButton
KeyNavigation.tab: usersRadioButton
onClicked: {
accessTypeSelector.currentIndex = 0
@@ -303,7 +305,7 @@ PageType {
implicitWidth: (root.width - 32) / 2
text: qsTr("Users")
// KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? clientNameTextField.textField : serverSelector
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? clientNameTextField.textField : serverSelector
onClicked: {
accessTypeSelector.currentIndex = 1
@@ -341,7 +343,7 @@ PageType {
checkEmptyText: true
// KeyNavigation.tab: serverSelector
KeyNavigation.tab: serverSelector
}
@@ -407,7 +409,7 @@ PageType {
}
}
// KeyNavigation.tab: protocolSelector
KeyNavigation.tab: protocolSelector
}
DropDownType {
@@ -507,11 +509,11 @@ PageType {
}
}
// KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ?
// exportTypeSelector :
// isSearchBarVisible ?
// searchTextField.textField :
// usersHeader.actionButton
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ?
exportTypeSelector :
isSearchBarVisible ?
searchTextField.textField :
usersHeader.actionButton
}
DropDownType {
@@ -575,7 +577,7 @@ PageType {
Keys.onTabPressed: lastItemTabClicked(focusItem)
parentFlickable:fl
parentFlickable: a
clickedFunc: function(){
if (clientNameTextField.textFieldText !== "") {
@@ -721,10 +723,10 @@ PageType {
onCurrentIndexChanged: {
if (currentItem) {
if (currentItem.y < fl.contentY) {
fl.contentY = currentItem.y
} else if (currentItem.y + currentItem.height + clientsListView.y > fl.contentY + fl.height) {
fl.contentY = currentItem.y + clientsListView.y + currentItem.height - fl.height
if (currentItem.y < a.contentY) {
a.contentY = currentItem.y
} else if (currentItem.y + currentItem.height + clientsListView.y > a.contentY + a.height) {
a.contentY = currentItem.y + clientsListView.y + currentItem.height - a.height
}
}
}
@@ -18,6 +18,13 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -25,6 +32,8 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: serverSelector
}
FlickableType {
@@ -76,6 +85,8 @@ PageType {
descriptionText: qsTr("Server")
headerText: qsTr("Server")
KeyNavigation.tab: shareButton
listView: ListViewWithRadioButtonType {
id: serverSelectorListView
@@ -126,6 +137,8 @@ PageType {
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
+6 -23
View File
@@ -12,9 +12,11 @@ import "../Controls2/TextTypes"
import "../Config"
import "../Components"
FocusScope {
PageType {
id: root
defaultActiveFocusItem: homeTabButton
property bool isControlsDisabled: false
property bool isTabBarDisabled: false
@@ -86,7 +88,7 @@ FocusScope {
function onForceTabBarActiveFocus() {
homeTabButton.focus = true
homeTabButton.forceActiveFocus()
tabBar.forceActiveFocus()
}
function onForceStackActiveFocus() {
@@ -166,27 +168,12 @@ FocusScope {
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: tabBar.top
focus: true
width: parent.width
height: root.height - tabBar.implicitHeight
enabled: !root.isControlsDisabled
// onActiveFocusChanged: {
// if (currentItem) {
// currentItem.forceActiveFocus()
// }
// }
// KeyNavigation.tab: homeTabButton
// Keys.onTabPressed: tabBarStackView.currentItem.lastItemTabClicked()
// onCurrentItemChanged: {
// if (currentItem) {
// currentItem.forceActiveFocus()
// }
// }
function goToTabBarPage(page) {
connectionTypeSelection.close()
@@ -227,8 +214,8 @@ FocusScope {
startY: 0
PathLine { x: width; y: 0 }
PathLine { x: width; y: tabBar.height - 1 }
PathLine { x: 0; y: tabBar.height - 1 }
PathLine { x: width; y: height - 1 }
PathLine { x: 0; y: height - 1 }
PathLine { x: 0; y: 0 }
strokeWidth: 1
@@ -249,8 +236,6 @@ FocusScope {
}
KeyNavigation.tab: shareTabButton
KeyNavigation.backtab: tabBarStackView
Keys.onEnterPressed: this.clicked()
Keys.onReturnPressed: this.clicked()
}
@@ -304,8 +289,6 @@ FocusScope {
}
Keys.onTabPressed: PageController.forceStackActiveFocus()
// KeysNavigation.tab: tabBarStackView.currentItem
}
}
+2 -8
View File
@@ -11,7 +11,7 @@ import "Config"
import "Controls2"
import "Components"
Window {
Window {
id: root
objectName: "mainWindow"
visible: true
@@ -25,16 +25,12 @@ Window {
color: AmneziaStyle.color.black
onClosing: function() {
// console.debug("QML onClosing signal")
console.debug("QML onClosing signal")
PageController.closeWindow()
}
title: "AmneziaVPN"
onActiveFocusItemChanged: {
console.debug("onActiveFocusItemChanged", activeFocusItem)
}
StackViewType {
id: rootStackView
@@ -224,8 +220,6 @@ Window {
id: questionDrawer
anchors.fill: parent
onClosed: PageController.forceStackActiveFocus()
}
}