Compare commits

..

2 Commits

Author SHA1 Message Date
Mykola Baibuz e0abd3f9dc XRay Linux firewall rules 2024-12-30 13:21:45 +02:00
Mykola Baibuz c0ea38db61 bugfix: check for Linux firewall install before use it 2024-12-30 12:24:27 +02:00
129 changed files with 3821 additions and 4332 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.8.3.0
project(${PROJECT} VERSION 4.8.2.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 2072)
set(APP_ANDROID_VERSION_CODE 2071)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
-2
View File
@@ -146,7 +146,6 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h
${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.h
${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.h
)
# Mozilla headres
@@ -198,7 +197,6 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.cpp
${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.cpp
)
# Mozilla sources
-3
View File
@@ -404,9 +404,6 @@ void AmneziaApplication::initControllers()
m_pageController.reset(new PageController(m_serversModel, m_settings));
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
m_focusController.reset(new FocusController(m_engine, this));
m_engine->rootContext()->setContextProperty("FocusController", m_focusController.get());
m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_clientManagementModel,
m_apiServicesModel, m_settings));
m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
-2
View File
@@ -19,7 +19,6 @@
#include "ui/controllers/exportController.h"
#include "ui/controllers/importController.h"
#include "ui/controllers/installController.h"
#include "ui/controllers/focusController.h"
#include "ui/controllers/pageController.h"
#include "ui/controllers/settingsController.h"
#include "ui/controllers/sitesController.h"
@@ -125,7 +124,6 @@ private:
#endif
QScopedPointer<ConnectionController> m_connectionController;
QScopedPointer<FocusController> m_focusController;
QScopedPointer<PageController> m_pageController;
QScopedPointer<InstallController> m_installController;
QScopedPointer<ImportController> m_importController;
-7
View File
@@ -91,13 +91,6 @@
android:exported="false"
android:theme="@style/Translucent" />
<activity android:name=".TvFilePicker"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:taskAffinity=""
android:exported="false"
android:theme="@style/Translucent" />
<activity
android:name=".ImportConfigActivity"
android:excludeFromRecents="true"
@@ -0,0 +1,5 @@
<?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: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

-2
View File
@@ -23,6 +23,4 @@
<string name="notificationSettingsDialogTitle">Настройки уведомлений</string>
<string name="notificationSettingsDialogMessage">Для показа уведомлений необходимо включить уведомления в системных настройках</string>
<string name="openNotificationSettings">Открыть настройки уведомлений</string>
<string name="tvNoFileBrowser">Пожалуйста, установите приложение для просмотра файлов</string>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_banner_background">#1E1E1F</color>
</resources>
-2
View File
@@ -23,6 +23,4 @@
<string name="notificationSettingsDialogTitle">Notification settings</string>
<string name="notificationSettingsDialogMessage">To show notifications, you must enable notifications in the system settings</string>
<string name="openNotificationSettings">Open notification settings</string>
<string name="tvNoFileBrowser">Please install a file management utility to browse files</string>
</resources>
@@ -4,7 +4,6 @@ import android.Manifest
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.NotificationManager
import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Intent
@@ -13,7 +12,6 @@ import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.net.VpnService
import android.os.Build
import android.os.Bundle
@@ -22,13 +20,8 @@ import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.os.ParcelFileDescriptor
import android.os.SystemClock
import android.provider.OpenableColumns
import android.provider.Settings
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager.LayoutParams
import android.webkit.MimeTypeMap
import android.widget.Toast
@@ -37,7 +30,6 @@ import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE
import kotlin.coroutines.CoroutineContext
import kotlin.text.RegexOption.IGNORE_CASE
import AppListProvider
import kotlinx.coroutines.CompletableDeferred
@@ -79,7 +71,6 @@ class AmneziaActivity : QtActivity() {
private var isInBoundState = false
private var notificationStateReceiver: BroadcastReceiver? = null
private lateinit var vpnServiceMessenger: IpcMessenger
private var pfd: ParcelFileDescriptor? = null
private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>()
private val permissionRequestHandlers = mutableMapOf<Int, PermissionRequestHandler>()
@@ -523,25 +514,21 @@ class AmneziaActivity : QtActivity() {
type = "text/*"
putExtra(Intent.EXTRA_TITLE, fileName)
}.also {
try {
startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
onSuccess = {
it?.data?.let { uri ->
Log.v(TAG, "Save file to $uri")
try {
contentResolver.openOutputStream(uri)?.use { os ->
os.bufferedWriter().use { it.write(data) }
}
} catch (e: IOException) {
Log.e(TAG, "Failed to save file $uri: $e")
// todo: send error to Qt
startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
onSuccess = {
it?.data?.let { uri ->
Log.v(TAG, "Save file to $uri")
try {
contentResolver.openOutputStream(uri)?.use { os ->
os.bufferedWriter().use { it.write(data) }
}
} catch (e: IOException) {
Log.e(TAG, "Failed to save file $uri: $e")
// todo: send error to Qt
}
}
))
} catch (_: ActivityNotFoundException) {
Toast.makeText(this@AmneziaActivity, "Unsupported", Toast.LENGTH_LONG).show()
}
}
))
}
}
}
@@ -550,46 +537,35 @@ class AmneziaActivity : QtActivity() {
fun openFile(filter: String?) {
Log.v(TAG, "Open file with filter: $filter")
mainScope.launch {
val intent = if (!isOnTv()) {
val mimeTypes = if (!filter.isNullOrEmpty()) {
val extensionRegex = "\\*\\.([a-z0-9]+)".toRegex(IGNORE_CASE)
val mime = MimeTypeMap.getSingleton()
extensionRegex.findAll(filter).map {
it.groups[1]?.value?.let { mime.getMimeTypeFromExtension(it) } ?: "*/*"
}.toSet()
} else emptySet()
val mimeTypes = if (!filter.isNullOrEmpty()) {
val extensionRegex = "\\*\\.([a-z0-9]+)".toRegex(IGNORE_CASE)
val mime = MimeTypeMap.getSingleton()
extensionRegex.findAll(filter).map {
it.groups[1]?.value?.let { mime.getMimeTypeFromExtension(it) } ?: "*/*"
}.toSet()
} else emptySet()
Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
Log.v(TAG, "File mimyType filter: $mimeTypes")
if ("*/*" in mimeTypes) {
type = "*/*"
} else {
when (mimeTypes.size) {
1 -> type = mimeTypes.first()
Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
Log.v(TAG, "File mimyType filter: $mimeTypes")
if ("*/*" in mimeTypes) {
type = "*/*"
} else {
when (mimeTypes.size) {
1 -> type = mimeTypes.first()
in 2..Int.MAX_VALUE -> {
type = "*/*"
putExtra(EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
}
else -> type = "*/*"
in 2..Int.MAX_VALUE -> {
type = "*/*"
putExtra(EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
}
else -> type = "*/*"
}
}
} else {
Intent(this@AmneziaActivity, TvFilePicker::class.java)
}
try {
startActivityForResult(intent, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
}.also {
startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
onAny = {
if (isOnTv() && it?.hasExtra("activityNotFound") == true) {
showNoFileBrowserAlertDialog()
}
val uri = it?.data?.apply {
grantUriPermission(packageName, this, Intent.FLAG_GRANT_READ_URI_PERMISSION)
}?.toString() ?: ""
val uri = it?.data?.toString() ?: ""
Log.v(TAG, "Open file: $uri")
mainScope.launch {
qtInitialized.await()
@@ -597,68 +573,10 @@ class AmneziaActivity : QtActivity() {
}
}
))
} catch (_: ActivityNotFoundException) {
showNoFileBrowserAlertDialog()
mainScope.launch {
qtInitialized.await()
QtAndroidController.onFileOpened("")
}
}
}
}
private fun showNoFileBrowserAlertDialog() {
AlertDialog.Builder(this)
.setMessage(R.string.tvNoFileBrowser)
.setCancelable(false)
.setPositiveButton(android.R.string.ok) { _, _ ->
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://webstoreredirect")))
} catch (_: Throwable) {}
}
.show()
}
@Suppress("unused")
fun getFd(fileName: String): Int {
Log.v(TAG, "Get fd for $fileName")
return blockingCall {
try {
pfd = contentResolver.openFileDescriptor(Uri.parse(fileName), "r")
pfd?.fd ?: -1
} catch (e: Exception) {
Log.e(TAG, "Failed to get fd: $e")
-1
}
}
}
@Suppress("unused")
fun closeFd() {
Log.v(TAG, "Close fd")
mainScope.launch {
pfd?.close()
pfd = null
}
}
@Suppress("unused")
fun getFileName(uri: String): String {
Log.v(TAG, "Get file name for uri: $uri")
return blockingCall {
try {
contentResolver.query(Uri.parse(uri), arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
if (cursor.moveToFirst() && !cursor.isNull(0)) {
return@blockingCall cursor.getString(0) ?: ""
}
}
} catch (e: Exception) {
Log.e(TAG, "Failed to get file name: $e")
}
""
}
}
@Suppress("unused")
@SuppressLint("UnsupportedChromeOsCameraSystemFeature")
fun isCameraPresent(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
@@ -803,50 +721,6 @@ class AmneziaActivity : QtActivity() {
}
}
// method to workaround Qt's problem with calling the keyboard on TVs
@Suppress("unused")
fun sendTouch(x: Float, y: Float) {
Log.v(TAG, "Send touch: $x, $y")
blockingCall {
findQtWindow(window.decorView)?.let {
Log.v(TAG, "Send touch to $it")
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN))
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP))
}
}
}
private fun findQtWindow(view: View): View? {
Log.v(TAG, "findQtWindow: process $view")
if (view::class.simpleName == "QtWindow") return view
else if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val result = findQtWindow(view.getChildAt(i))
if (result != null) return result
}
return null
} else return null
}
private fun createEvent(x: Float, y: Float, eventTime: Long, action: Int): MotionEvent =
MotionEvent.obtain(
eventTime,
eventTime,
action,
1,
arrayOf(MotionEvent.PointerProperties().apply {
id = 0
toolType = MotionEvent.TOOL_TYPE_FINGER
}),
arrayOf(MotionEvent.PointerCoords().apply {
this.x = x
this.y = y
pressure = 1f
size = 1f
}),
0, 0, 1.0f, 1.0f, 0, 0, 0,0
)
// workaround for a bug in Qt that causes the mouse click event not to be handled
// also disable right-click, as it causes the application to crash
private var lastButtonState = 0
@@ -896,7 +770,6 @@ class AmneziaActivity : QtActivity() {
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
Log.v(TAG, "dispatchTouch: $ev")
if (ev != null && ev.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
return handleMouseEvent(ev) { super.dispatchTouchEvent(it) }
}
@@ -911,13 +784,6 @@ class AmneziaActivity : QtActivity() {
/**
* Utils methods
*/
private fun <T> blockingCall(
context: CoroutineContext = Dispatchers.Main.immediate,
block: suspend () -> T
) = runBlocking {
mainScope.async(context) { block() }.await()
}
companion object {
private fun actionCodeToString(actionCode: Int): String =
when (actionCode) {
@@ -1,45 +0,0 @@
package org.amnezia.vpn
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import org.amnezia.vpn.util.Log
private const val TAG = "TvFilePicker"
class TvFilePicker : ComponentActivity() {
private val fileChooseResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) {
setResult(RESULT_OK, Intent().apply { data = it })
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.v(TAG, "onCreate")
getFile()
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Log.v(TAG, "onNewIntent")
getFile()
}
private fun getFile() {
try {
Log.v(TAG, "getFile")
fileChooseResultLauncher.launch("*/*")
} catch (_: ActivityNotFoundException) {
Log.w(TAG, "Activity not found")
setResult(RESULT_CANCELED, Intent().apply { putExtra("activityNotFound", true) })
finish()
} catch (e: Exception) {
Log.e(TAG, "Failed to get file: $e")
setResult(RESULT_CANCELED)
finish()
}
}
}
@@ -120,7 +120,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
}
}
QString subnetIp = containerConfig.value(m_protocolName).toObject().value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
QString subnetIp = containerConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
{
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
if (l.isEmpty()) {
+3 -9
View File
@@ -346,9 +346,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
}
if (container == DockerContainer::Awg) {
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|| (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
if ((oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort))
|| (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)
!= newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount))
@@ -372,10 +370,8 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
}
if (container == DockerContainer::WireGuard) {
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|| (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
if (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort))
return true;
}
@@ -611,8 +607,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({ { "$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() } });
// Amnezia wireguard vars
vars.append({ { "$AWG_SUBNET_IP",
amneziaWireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) } });
vars.append({ { "$AWG_SERVER_PORT", amneziaWireguarConfig.value(config_key::port).toString(protocols::awg::defaultPort) } });
vars.append({ { "$JUNK_PACKET_COUNT", amneziaWireguarConfig.value(config_key::junkPacketCount).toString() } });
-5
View File
@@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 13V19C18 19.5304 17.7893 20.0391 17.4142 20.4142C17.0391 20.7893 16.5304 21 16 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V8C3 7.46957 3.21071 6.96086 3.58579 6.58579C3.96086 6.21071 4.46957 6 5 6H11" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 3H21V9" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 14L21 3" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 644 B

@@ -163,7 +163,9 @@ QString AndroidController::openFile(const QString &filter)
QString fileName;
connect(this, &AndroidController::fileOpened, this,
[&fileName, &wait](const QString &uri) {
fileName = uri;
qDebug() << "Android event: file opened; uri:" << uri;
fileName = QQmlFile::urlToLocalFileOrQrc(uri);
qDebug() << "Android opened filename:" << fileName;
wait.quit();
},
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
@@ -173,25 +175,6 @@ QString AndroidController::openFile(const QString &filter)
return fileName;
}
int AndroidController::getFd(const QString &fileName)
{
return callActivityMethod<jint>("getFd", "(Ljava/lang/String;)I",
QJniObject::fromString(fileName).object<jstring>());
}
void AndroidController::closeFd()
{
callActivityMethod("closeFd", "()V");
}
QString AndroidController::getFileName(const QString &uri)
{
auto fileName = callActivityMethod<jstring, jstring>("getFileName", "(Ljava/lang/String;)Ljava/lang/String;",
QJniObject::fromString(uri).object<jstring>());
QJniEnvironment env;
return AndroidUtils::convertJString(env.jniEnv(), fileName.object<jstring>());
}
bool AndroidController::isCameraPresent()
{
return callActivityMethod<jboolean>("isCameraPresent", "()Z");
@@ -304,11 +287,6 @@ bool AndroidController::requestAuthentication()
return result;
}
void AndroidController::sendTouch(float x, float y)
{
callActivityMethod("sendTouch", "(FF)V", x, y);
}
// Moving log processing to the Android side
jclass AndroidController::log;
jmethodID AndroidController::logDebug;
@@ -34,9 +34,6 @@ public:
void resetLastServer(int serverIndex);
void saveFile(const QString &fileName, const QString &data);
QString openFile(const QString &filter);
int getFd(const QString &fileName);
void closeFd();
QString getFileName(const QString &uri);
bool isCameraPresent();
bool isOnTv();
void startQrReaderActivity();
@@ -51,7 +48,6 @@ public:
bool isNotificationPermissionGranted();
void requestNotificationPermission();
bool requestAuthentication();
void sendTouch(float x, float y);
static bool initLogging();
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);
+19 -16
View File
@@ -1,6 +1,7 @@
#include "xrayprotocol.h"
#include "utilities.h"
#include "containers/containers_defs.h"
#include "core/networkUtilities.h"
#include <QCryptographicHash>
@@ -21,8 +22,9 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent):
XrayProtocol::~XrayProtocol()
{
qDebug() << "XrayProtocol::~XrayProtocol()";
XrayProtocol::stop();
QThread::msleep(200);
m_xrayProcess.close();
}
ErrorCode XrayProtocol::start()
@@ -34,6 +36,10 @@ ErrorCode XrayProtocol::start()
return lastError();
}
if (Utils::processIsRunning(Utils::executable(xrayExecPath(), true))) {
Utils::killProcessByName(Utils::executable(xrayExecPath(), true));
}
#ifdef QT_DEBUG
m_xrayCfgFile.setAutoRemove(false);
#endif
@@ -48,16 +54,9 @@ ErrorCode XrayProtocol::start()
qDebug().noquote() << "XrayProtocol::start()"
<< xrayExecPath() << args.join(" ");
m_xrayProcess.setProcessChannelMode(QProcess::MergedChannels);
m_xrayProcess.setProgram(xrayExecPath());
if (Utils::processIsRunning(Utils::executable("xray", false))) {
qDebug().noquote() << "kill previos xray";
Utils::killProcessByName(Utils::executable("xray", false));
}
m_xrayProcess.setArguments(args);
connect(&m_xrayProcess, &QProcess::readyReadStandardOutput, this, [this]() {
@@ -69,9 +68,13 @@ ErrorCode XrayProtocol::start()
connect(&m_xrayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
qDebug().noquote() << "XrayProtocol finished, exitCode, exitStatus" << exitCode << exitStatus;
setConnectionState(Vpn::ConnectionState::Disconnected);
if ((exitStatus != QProcess::NormalExit) || (exitCode != 0)) {
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
emit setConnectionState(Vpn::ConnectionState::Error);
if (exitStatus != QProcess::NormalExit) {
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
stop();
}
if (exitCode != 0) {
emit protocolError(amnezia::ErrorCode::InternalError);
stop();
}
});
@@ -174,14 +177,14 @@ void XrayProtocol::stop()
IpcClient::Interface()->StartRoutingIpv6();
#endif
qDebug() << "XrayProtocol::stop()";
m_xrayProcess.disconnect();
m_xrayProcess.kill();
m_xrayProcess.waitForFinished(3000);
m_xrayProcess.terminate();
if (m_t2sProcess) {
m_t2sProcess->stop();
}
setConnectionState(Vpn::ConnectionState::Disconnected);
#ifdef Q_OS_WIN
Utils::signalCtrl(m_xrayProcess.processId(), CTRL_C_EVENT);
#endif
}
QString XrayProtocol::xrayExecPath()
+194 -198
View File
@@ -1,229 +1,225 @@
<RCC>
<qresource prefix="/">
<file>fonts/pt-root-ui_vf.ttf</file>
<file>images/amneziaBigLogo.png</file>
<file>images/AmneziaVPN.png</file>
<file>images/controls/alert-circle.svg</file>
<file>images/controls/amnezia.svg</file>
<file>images/controls/app.svg</file>
<file>images/controls/archive-restore.svg</file>
<file>images/controls/arrow-left.svg</file>
<file>images/controls/arrow-right.svg</file>
<file>images/controls/bug.svg</file>
<file>images/controls/check.svg</file>
<file>images/controls/chevron-down.svg</file>
<file>images/controls/chevron-right.svg</file>
<file>images/controls/chevron-up.svg</file>
<file>images/controls/close.svg</file>
<file>images/controls/copy.svg</file>
<file>images/controls/delete.svg</file>
<file>images/controls/download.svg</file>
<file>images/controls/edit-3.svg</file>
<file>images/controls/eye-off.svg</file>
<file>images/controls/eye.svg</file>
<file>images/controls/external-link.svg</file>
<file>images/controls/file-check-2.svg</file>
<file>images/controls/file-cog-2.svg</file>
<file>images/controls/folder-open.svg</file>
<file>images/controls/folder-search-2.svg</file>
<file>images/controls/gauge.svg</file>
<file>images/controls/github.svg</file>
<file>images/controls/help-circle.svg</file>
<file>images/controls/history.svg</file>
<file>images/controls/home.svg</file>
<file>images/controls/info.svg</file>
<file>images/controls/mail.svg</file>
<file>images/controls/map-pin.svg</file>
<file>images/controls/more-vertical.svg</file>
<file>images/controls/plus.svg</file>
<file>images/controls/qr-code.svg</file>
<file>images/controls/radio-button-inner-circle-pressed.png</file>
<file>images/controls/radio-button-inner-circle.png</file>
<file>images/controls/radio-button-pressed.svg</file>
<file>images/controls/radio-button.svg</file>
<file>images/controls/radio.svg</file>
<file>images/controls/refresh-cw.svg</file>
<file>images/controls/save.svg</file>
<file>images/controls/scan-line.svg</file>
<file>images/controls/search.svg</file>
<file>images/controls/server.svg</file>
<file>images/controls/settings-2.svg</file>
<file>images/controls/settings.svg</file>
<file>images/controls/share-2.svg</file>
<file>images/controls/split-tunneling.svg</file>
<file>images/controls/tag.svg</file>
<file>images/controls/telegram.svg</file>
<file>images/controls/text-cursor.svg</file>
<file>images/controls/trash.svg</file>
<file>images/controls/x-circle.svg</file>
<file>images/tray/active.png</file>
<file>images/tray/default.png</file>
<file>images/tray/error.png</file>
<file>server_scripts/awg/configure_container.sh</file>
<file>server_scripts/awg/Dockerfile</file>
<file>server_scripts/awg/run_container.sh</file>
<file>server_scripts/awg/start.sh</file>
<file>server_scripts/awg/template.conf</file>
<file>server_scripts/build_container.sh</file>
<file>server_scripts/check_connection.sh</file>
<file>server_scripts/check_server_is_busy.sh</file>
<file>server_scripts/check_user_in_sudo.sh</file>
<file>server_scripts/dns/configure_container.sh</file>
<file>server_scripts/dns/Dockerfile</file>
<file>server_scripts/dns/run_container.sh</file>
<file>server_scripts/install_docker.sh</file>
<file>server_scripts/ipsec/configure_container.sh</file>
<file>server_scripts/ipsec/Dockerfile</file>
<file>server_scripts/ipsec/mobileconfig.plist</file>
<file>server_scripts/ipsec/run_container.sh</file>
<file>server_scripts/ipsec/start.sh</file>
<file>server_scripts/ipsec/strongswan.profile</file>
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
<file>images/AmneziaVPN.png</file>
<file>server_scripts/remove_container.sh</file>
<file>server_scripts/setup_host_firewall.sh</file>
<file>server_scripts/openvpn_cloak/Dockerfile</file>
<file>server_scripts/openvpn_cloak/run_container.sh</file>
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
<file>server_scripts/openvpn_cloak/start.sh</file>
<file>server_scripts/openvpn_cloak/template.ovpn</file>
<file>server_scripts/install_docker.sh</file>
<file>server_scripts/build_container.sh</file>
<file>server_scripts/prepare_host.sh</file>
<file>server_scripts/check_connection.sh</file>
<file>server_scripts/remove_all_containers.sh</file>
<file>server_scripts/openvpn_cloak/run_container.sh</file>
<file>server_scripts/openvpn/configure_container.sh</file>
<file>server_scripts/openvpn/run_container.sh</file>
<file>server_scripts/openvpn/template.ovpn</file>
<file>server_scripts/openvpn/Dockerfile</file>
<file>server_scripts/openvpn/start.sh</file>
<file>server_scripts/openvpn_shadowsocks/configure_container.sh</file>
<file>server_scripts/openvpn_shadowsocks/Dockerfile</file>
<file>server_scripts/openvpn_shadowsocks/run_container.sh</file>
<file>server_scripts/openvpn_shadowsocks/start.sh</file>
<file>server_scripts/openvpn_shadowsocks/template.ovpn</file>
<file>server_scripts/openvpn/configure_container.sh</file>
<file>server_scripts/openvpn/Dockerfile</file>
<file>server_scripts/openvpn/run_container.sh</file>
<file>server_scripts/openvpn/start.sh</file>
<file>server_scripts/openvpn/template.ovpn</file>
<file>server_scripts/prepare_host.sh</file>
<file>server_scripts/remove_all_containers.sh</file>
<file>server_scripts/remove_container.sh</file>
<file>server_scripts/setup_host_firewall.sh</file>
<file>server_scripts/sftp/configure_container.sh</file>
<file>server_scripts/sftp/Dockerfile</file>
<file>server_scripts/sftp/run_container.sh</file>
<file>server_scripts/socks5_proxy/configure_container.sh</file>
<file>server_scripts/socks5_proxy/Dockerfile</file>
<file>server_scripts/socks5_proxy/run_container.sh</file>
<file>server_scripts/socks5_proxy/start.sh</file>
<file>server_scripts/website_tor/configure_container.sh</file>
<file>server_scripts/website_tor/Dockerfile</file>
<file>server_scripts/website_tor/run_container.sh</file>
<file>server_scripts/wireguard/configure_container.sh</file>
<file>server_scripts/wireguard/Dockerfile</file>
<file>server_scripts/wireguard/run_container.sh</file>
<file>server_scripts/wireguard/start.sh</file>
<file>server_scripts/wireguard/template.conf</file>
<file>server_scripts/website_tor/configure_container.sh</file>
<file>server_scripts/website_tor/run_container.sh</file>
<file>ui/qml/Config/GlobalConfig.qml</file>
<file>ui/qml/Config/qmldir</file>
<file>server_scripts/check_server_is_busy.sh</file>
<file>server_scripts/dns/configure_container.sh</file>
<file>server_scripts/dns/Dockerfile</file>
<file>server_scripts/dns/run_container.sh</file>
<file>server_scripts/sftp/configure_container.sh</file>
<file>server_scripts/sftp/Dockerfile</file>
<file>server_scripts/sftp/run_container.sh</file>
<file>server_scripts/ipsec/configure_container.sh</file>
<file>server_scripts/ipsec/Dockerfile</file>
<file>server_scripts/ipsec/run_container.sh</file>
<file>server_scripts/ipsec/start.sh</file>
<file>server_scripts/ipsec/mobileconfig.plist</file>
<file>server_scripts/ipsec/strongswan.profile</file>
<file>server_scripts/website_tor/Dockerfile</file>
<file>server_scripts/check_user_in_sudo.sh</file>
<file>ui/qml/Controls2/BasicButtonType.qml</file>
<file>ui/qml/Controls2/TextFieldWithHeaderType.qml</file>
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
<file>images/controls/arrow-right.svg</file>
<file>images/controls/chevron-right.svg</file>
<file>ui/qml/Controls2/ImageButtonType.qml</file>
<file>ui/qml/Controls2/CardType.qml</file>
<file>ui/qml/Controls2/CheckBoxType.qml</file>
<file>images/controls/check.svg</file>
<file>ui/qml/Controls2/DropDownType.qml</file>
<file>ui/qml/Pages2/PageSetupWizardStart.qml</file>
<file>ui/qml/main2.qml</file>
<file>images/amneziaBigLogo.png</file>
<file>ui/qml/Controls2/FlickableType.qml</file>
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>
<file>ui/qml/Controls2/HeaderType.qml</file>
<file>images/controls/arrow-left.svg</file>
<file>ui/qml/Pages2/PageSetupWizardProtocols.qml</file>
<file>ui/qml/Pages2/PageSetupWizardEasy.qml</file>
<file>images/controls/chevron-down.svg</file>
<file>images/controls/chevron-up.svg</file>
<file>ui/qml/Controls2/TextTypes/ParagraphTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/Header2TextType.qml</file>
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
<file>ui/qml/Controls2/SwitcherType.qml</file>
<file>ui/qml/Controls2/TabButtonType.qml</file>
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
<file>images/controls/folder-open.svg</file>
<file>images/controls/qr-code.svg</file>
<file>images/controls/text-cursor.svg</file>
<file>ui/qml/Pages2/PageSetupWizardTextKey.qml</file>
<file>ui/qml/Pages2/PageStart.qml</file>
<file>ui/qml/Controls2/TabImageButtonType.qml</file>
<file>images/controls/home.svg</file>
<file>images/controls/settings-2.svg</file>
<file>images/controls/share-2.svg</file>
<file>ui/qml/Pages2/PageHome.qml</file>
<file>ui/qml/Pages2/PageSettingsServersList.qml</file>
<file>ui/qml/Pages2/PageShare.qml</file>
<file>ui/qml/Controls2/TextTypes/Header1TextType.qml</file>
<file>ui/qml/Controls2/TextTypes/LabelTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/ButtonTextType.qml</file>
<file>ui/qml/Controls2/Header2Type.qml</file>
<file>images/controls/plus.svg</file>
<file>ui/qml/Components/ConnectButton.qml</file>
<file>images/controls/download.svg</file>
<file>ui/qml/Controls2/ProgressBarType.qml</file>
<file>ui/qml/Components/ConnectionTypeSelectionDrawer.qml</file>
<file>ui/qml/Components/HomeContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/CaptionTextType.qml</file>
<file>images/controls/settings.svg</file>
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
<file>ui/qml/Controls2/PageType.qml</file>
<file>ui/qml/Controls2/PopupType.qml</file>
<file>images/controls/edit-3.svg</file>
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
<file>ui/qml/Controls2/DividerType.qml</file>
<file>ui/qml/Controls2/StackViewType.qml</file>
<file>ui/qml/Pages2/PageSettings.qml</file>
<file>images/controls/amnezia.svg</file>
<file>images/controls/app.svg</file>
<file>images/controls/radio.svg</file>
<file>images/controls/save.svg</file>
<file>images/controls/server.svg</file>
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
<file>ui/qml/Pages2/PageSettingsServerServices.qml</file>
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
<file>images/controls/file-cog-2.svg</file>
<file>ui/qml/Components/QuestionDrawer.qml</file>
<file>ui/qml/Pages2/PageDeinstalling.qml</file>
<file>ui/qml/Controls2/BackButtonType.qml</file>
<file>ui/qml/Pages2/PageSettingsServerProtocol.qml</file>
<file>ui/qml/Components/TransportProtoSelector.qml</file>
<file>ui/qml/Controls2/ListViewWithRadioButtonType.qml</file>
<file>images/controls/radio-button.svg</file>
<file>images/controls/radio-button-inner-circle.png</file>
<file>images/controls/radio-button-pressed.svg</file>
<file>images/controls/radio-button-inner-circle-pressed.png</file>
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
<file>ui/qml/Pages2/PageSettingsApplication.qml</file>
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
<file>images/controls/delete.svg</file>
<file>ui/qml/Pages2/PageSettingsAbout.qml</file>
<file>images/controls/github.svg</file>
<file>images/controls/mail.svg</file>
<file>images/controls/telegram.svg</file>
<file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file>
<file>ui/qml/Filters/ContainersModelFilters.qml</file>
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
<file>ui/qml/Controls2/BusyIndicatorType.qml</file>
<file>ui/qml/Pages2/PageProtocolOpenVpnSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
<file>images/controls/copy.svg</file>
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
<file>images/controls/eye.svg</file>
<file>images/controls/eye-off.svg</file>
<file>ui/qml/Pages2/PageSettingsSplitTunneling.qml</file>
<file>ui/qml/Controls2/ContextMenuType.qml</file>
<file>ui/qml/Controls2/TextAreaType.qml</file>
<file>images/controls/trash.svg</file>
<file>images/controls/more-vertical.svg</file>
<file>ui/qml/Controls2/ListViewWithLabelsType.qml</file>
<file>ui/qml/Pages2/PageServiceDnsSettings.qml</file>
<file>ui/qml/Controls2/TopCloseButtonType.qml</file>
<file>images/controls/x-circle.svg</file>
<file>ui/qml/Pages2/PageProtocolAwgSettings.qml</file>
<file>server_scripts/awg/template.conf</file>
<file>server_scripts/awg/start.sh</file>
<file>server_scripts/awg/configure_container.sh</file>
<file>server_scripts/awg/run_container.sh</file>
<file>server_scripts/awg/Dockerfile</file>
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>images/controls/close.svg</file>
<file>images/controls/search.svg</file>
<file>server_scripts/xray/configure_container.sh</file>
<file>server_scripts/xray/Dockerfile</file>
<file>server_scripts/xray/run_container.sh</file>
<file>server_scripts/xray/start.sh</file>
<file>server_scripts/xray/template.json</file>
<file>ui/qml/Components/AdLabel.qml</file>
<file>ui/qml/Components/ConnectButton.qml</file>
<file>ui/qml/Components/ConnectionTypeSelectionDrawer.qml</file>
<file>ui/qml/Components/HomeContainersListView.qml</file>
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
<file>ui/qml/Components/InstalledAppsDrawer.qml</file>
<file>ui/qml/Components/QuestionDrawer.qml</file>
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
<file>ui/qml/Components/ServersListView.qml</file>
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
<file>ui/qml/Components/TransportProtoSelector.qml</file>
<file>ui/qml/Config/GlobalConfig.qml</file>
<file>ui/qml/Config/qmldir</file>
<file>ui/qml/Controls2/BackButtonType.qml</file>
<file>ui/qml/Controls2/BasicButtonType.qml</file>
<file>ui/qml/Controls2/BusyIndicatorType.qml</file>
<file>ui/qml/Controls2/CardType.qml</file>
<file>ui/qml/Controls2/CardWithIconsType.qml</file>
<file>ui/qml/Controls2/CheckBoxType.qml</file>
<file>ui/qml/Controls2/ContextMenuType.qml</file>
<file>ui/qml/Controls2/DividerType.qml</file>
<file>ui/qml/Controls2/DrawerType2.qml</file>
<file>ui/qml/Controls2/DropDownType.qml</file>
<file>ui/qml/Controls2/FlickableType.qml</file>
<file>ui/qml/Controls2/Header2Type.qml</file>
<file>ui/qml/Controls2/HeaderType.qml</file>
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
<file>ui/qml/Controls2/ImageButtonType.qml</file>
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
<file>ui/qml/Controls2/LabelWithImageType.qml</file>
<file>ui/qml/Controls2/ListViewWithLabelsType.qml</file>
<file>ui/qml/Controls2/ListViewWithRadioButtonType.qml</file>
<file>ui/qml/Controls2/PageType.qml</file>
<file>ui/qml/Controls2/PopupType.qml</file>
<file>ui/qml/Controls2/ProgressBarType.qml</file>
<file>ui/qml/Controls2/ScrollBarType.qml</file>
<file>ui/qml/Controls2/StackViewType.qml</file>
<file>ui/qml/Controls2/SwitcherType.qml</file>
<file>ui/qml/Controls2/TabButtonType.qml</file>
<file>ui/qml/Controls2/TabImageButtonType.qml</file>
<file>ui/qml/Controls2/TextAreaType.qml</file>
<file>ui/qml/Controls2/TextAreaWithFooterType.qml</file>
<file>ui/qml/Controls2/TextFieldWithHeaderType.qml</file>
<file>ui/qml/Controls2/TextTypes/ButtonTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/CaptionTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/Header1TextType.qml</file>
<file>ui/qml/Controls2/TextTypes/Header2TextType.qml</file>
<file>ui/qml/Controls2/TextTypes/LabelTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
<file>ui/qml/Controls2/TextTypes/ParagraphTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file>
<file>ui/qml/Controls2/TopCloseButtonType.qml</file>
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
<file>ui/qml/Controls2/WarningType.qml</file>
<file>ui/qml/Filters/ContainersModelFilters.qml</file>
<file>ui/qml/main2.qml</file>
<file>ui/qml/Modules/Style/AmneziaStyle.qml</file>
<file>ui/qml/Modules/Style/qmldir</file>
<file>ui/qml/Pages2/PageDeinstalling.qml</file>
<file>ui/qml/Pages2/PageDevMenu.qml</file>
<file>ui/qml/Pages2/PageHome.qml</file>
<file>ui/qml/Pages2/PageProtocolAwgSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolOpenVpnSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolWireGuardSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
<file>ui/qml/Pages2/PageServiceDnsSettings.qml</file>
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
<file>ui/qml/Pages2/PageServiceSocksProxySettings.qml</file>
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
<file>ui/qml/Pages2/PageSettings.qml</file>
<file>ui/qml/Pages2/PageSettingsAbout.qml</file>
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
<file>ui/qml/Pages2/PageSettingsApiServerInfo.qml</file>
<file>ui/qml/Pages2/PageSettingsApplication.qml</file>
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
<file>images/controls/split-tunneling.svg</file>
<file>ui/qml/Controls2/DrawerType2.qml</file>
<file>ui/qml/Pages2/PageSettingsAppSplitTunneling.qml</file>
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
<file>ui/qml/Pages2/PageSettingsServerProtocol.qml</file>
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
<file>ui/qml/Pages2/PageSettingsServerServices.qml</file>
<file>ui/qml/Pages2/PageSettingsServersList.qml</file>
<file>ui/qml/Pages2/PageSettingsSplitTunneling.qml</file>
<file>ui/qml/Components/InstalledAppsDrawer.qml</file>
<file>images/controls/alert-circle.svg</file>
<file>images/controls/file-check-2.svg</file>
<file>ui/qml/Controls2/WarningType.qml</file>
<file>fonts/pt-root-ui_vf.ttf</file>
<file>ui/qml/Modules/Style/qmldir</file>
<file>ui/qml/Modules/Style/AmneziaStyle.qml</file>
<file>ui/qml/Pages2/PageServiceSocksProxySettings.qml</file>
<file>server_scripts/socks5_proxy/run_container.sh</file>
<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/Pages2/PageProtocolAwgClientSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>
<file>ui/qml/Pages2/PageSetupWizardEasy.qml</file>
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
<file>ui/qml/Pages2/PageSetupWizardProtocols.qml</file>
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
<file>ui/qml/Pages2/PageSetupWizardStart.qml</file>
<file>ui/qml/Pages2/PageSetupWizardTextKey.qml</file>
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
<file>ui/qml/Pages2/PageShare.qml</file>
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>ui/qml/Pages2/PageStart.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
<file>ui/qml/Controls2/CardWithIconsType.qml</file>
<file>images/controls/tag.svg</file>
<file>images/controls/history.svg</file>
<file>images/controls/gauge.svg</file>
<file>images/controls/map-pin.svg</file>
<file>ui/qml/Controls2/LabelWithImageType.qml</file>
<file>images/controls/info.svg</file>
<file>ui/qml/Controls2/TextAreaWithFooterType.qml</file>
<file>images/controls/scan-line.svg</file>
<file>images/controls/folder-search-2.svg</file>
<file>ui/qml/Pages2/PageSettingsApiServerInfo.qml</file>
<file>images/controls/bug.svg</file>
<file>ui/qml/Pages2/PageDevMenu.qml</file>
<file>images/controls/refresh-cw.svg</file>
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
<file>images/controls/archive-restore.svg</file>
<file>images/controls/help-circle.svg</file>
</qresource>
<qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file>
@@ -12,7 +12,7 @@ echo $WIREGUARD_PSK > /opt/amnezia/awg/wireguard_psk.key
cat > /opt/amnezia/awg/wg0.conf <<EOF
[Interface]
PrivateKey = $WIREGUARD_SERVER_PRIVATE_KEY
Address = $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR
Address = $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR
ListenPort = $AWG_SERVER_PORT
Jc = $JUNK_PACKET_COUNT
Jmin = $JUNK_PACKET_MIN_SIZE
+4 -4
View File
@@ -17,12 +17,12 @@ iptables -A FORWARD -i wg0 -j ACCEPT
iptables -A OUTPUT -o wg0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i wg0 -o eth0 -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i wg0 -o eth1 -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i wg0 -o eth0 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i wg0 -o eth1 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth1 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth1 -j MASQUERADE
tail -f /dev/null
-10
View File
@@ -538,13 +538,3 @@ void Settings::toggleDevGatewayEnv(bool enabled)
{
m_isDevGatewayEnv = enabled;
}
bool Settings::isHomeAdLabelVisible()
{
return value("Conf/homeAdLabelVisible", true).toBool();
}
void Settings::disableHomeAdLabel()
{
setValue("Conf/homeAdLabelVisible", false);
}
-3
View File
@@ -222,9 +222,6 @@ public:
bool isDevGatewayEnv();
void toggleDevGatewayEnv(bool enabled);
bool isHomeAdLabelVisible();
void disableHomeAdLabel();
signals:
void saveLogsChanged(bool enabled);
void screenshotsEnabledChanged(bool enabled);
-209
View File
@@ -1,209 +0,0 @@
#include "focusController.h"
#include "utils/qmlUtils.h"
#include <QQmlApplicationEngine>
#include <QQuickWindow>
FocusController::FocusController(QQmlApplicationEngine *engine, QObject *parent)
: QObject { parent },
m_engine { engine },
m_focusChain {},
m_focusedItem { nullptr },
m_rootObjects {},
m_defaultFocusItem { nullptr },
m_lvfc { nullptr }
{
QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated, this, [this](QObject *object, const QUrl &url) {
QQuickItem *newDefaultFocusItem = object->findChild<QQuickItem *>("defaultFocusItem");
if (newDefaultFocusItem && m_defaultFocusItem != newDefaultFocusItem) {
m_defaultFocusItem = newDefaultFocusItem;
}
});
QObject::connect(this, &FocusController::focusedItemChanged, this,
[this]() { m_focusedItem->forceActiveFocus(Qt::TabFocusReason); });
}
void FocusController::nextKeyTabItem()
{
nextItem(Direction::Forward);
}
void FocusController::previousKeyTabItem()
{
nextItem(Direction::Backward);
}
void FocusController::nextKeyUpItem()
{
nextItem(Direction::Backward);
}
void FocusController::nextKeyDownItem()
{
nextItem(Direction::Forward);
}
void FocusController::nextKeyLeftItem()
{
nextItem(Direction::Backward);
}
void FocusController::nextKeyRightItem()
{
nextItem(Direction::Forward);
}
void FocusController::setFocusItem(QQuickItem *item)
{
if (m_focusedItem != item) {
m_focusedItem = item;
}
emit focusedItemChanged();
}
void FocusController::setFocusOnDefaultItem()
{
setFocusItem(m_defaultFocusItem);
}
void FocusController::pushRootObject(QObject *object)
{
m_rootObjects.push(object);
dropListView();
// setFocusOnDefaultItem();
}
void FocusController::dropRootObject(QObject *object)
{
if (m_rootObjects.empty()) {
return;
}
if (m_rootObjects.top() == object) {
m_rootObjects.pop();
dropListView();
setFocusOnDefaultItem();
} else {
qWarning() << "===>> TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
}
}
void FocusController::resetRootObject()
{
m_rootObjects.clear();
}
void FocusController::reload(Direction direction)
{
m_focusChain.clear();
QObject *rootObject = (m_rootObjects.empty() ? m_engine->rootObjects().value(0) : m_rootObjects.top());
if (!rootObject) {
qCritical() << "No ROOT OBJECT found!";
resetRootObject();
dropListView();
return;
}
m_focusChain.append(FocusControl::getSubChain(rootObject));
std::sort(m_focusChain.begin(), m_focusChain.end(),
direction == Direction::Forward ? FocusControl::isLess : FocusControl::isMore);
if (m_focusChain.empty()) {
qWarning() << "Focus chain is empty!";
resetRootObject();
dropListView();
return;
}
}
void FocusController::nextItem(Direction direction)
{
reload(direction);
if (m_lvfc && FocusControl::isListView(m_focusedItem)) {
direction == Direction::Forward ? focusNextListViewItem() : focusPreviousListViewItem();
return;
}
if (m_focusChain.empty()) {
qWarning() << "There are no items to navigate";
setFocusOnDefaultItem();
return;
}
auto focusedItemIndex = m_focusChain.indexOf(m_focusedItem);
if (focusedItemIndex == -1) {
focusedItemIndex = 0;
} else if (focusedItemIndex == (m_focusChain.size() - 1)) {
focusedItemIndex = 0;
} else {
focusedItemIndex++;
}
const auto focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(focusedItemIndex));
if (focusedItem == nullptr) {
qWarning() << "Failed to get item to focus on. Setting focus on default";
setFocusOnDefaultItem();
return;
}
if (FocusControl::isListView(focusedItem)) {
m_lvfc = new ListViewFocusController(focusedItem, this);
m_focusedItem = focusedItem;
if (direction == Direction::Forward) {
m_lvfc->nextDelegate();
focusNextListViewItem();
} else {
m_lvfc->previousDelegate();
focusPreviousListViewItem();
}
return;
}
setFocusItem(focusedItem);
}
void FocusController::focusNextListViewItem()
{
m_lvfc->reloadFocusChain();
if (m_lvfc->isLastFocusItemInListView() || m_lvfc->isReturnNeeded()) {
dropListView();
nextItem(Direction::Forward);
return;
} else if (m_lvfc->isLastFocusItemInDelegate()) {
m_lvfc->resetFocusChain();
m_lvfc->nextDelegate();
}
m_lvfc->focusNextItem();
}
void FocusController::focusPreviousListViewItem()
{
m_lvfc->reloadFocusChain();
if (m_lvfc->isFirstFocusItemInListView() || m_lvfc->isReturnNeeded()) {
dropListView();
nextItem(Direction::Backward);
return;
} else if (m_lvfc->isFirstFocusItemInDelegate()) {
m_lvfc->resetFocusChain();
m_lvfc->previousDelegate();
}
m_lvfc->focusPreviousItem();
}
void FocusController::dropListView()
{
if (m_lvfc) {
delete m_lvfc;
m_lvfc = nullptr;
}
}
-57
View File
@@ -1,57 +0,0 @@
#ifndef FOCUSCONTROLLER_H
#define FOCUSCONTROLLER_H
#include "ui/controllers/listViewFocusController.h"
#include <QQmlApplicationEngine>
/*!
* \brief The FocusController class makes focus control more straightforward
* \details Focus is handled only for visible and enabled items which have
* `isFocused` property from top left to bottom right.
* \note There are items handled differently (e.g. ListView)
*/
class FocusController : public QObject
{
Q_OBJECT
public:
explicit FocusController(QQmlApplicationEngine *engine, QObject *parent = nullptr);
~FocusController() override = default;
Q_INVOKABLE void nextKeyTabItem();
Q_INVOKABLE void previousKeyTabItem();
Q_INVOKABLE void nextKeyUpItem();
Q_INVOKABLE void nextKeyDownItem();
Q_INVOKABLE void nextKeyLeftItem();
Q_INVOKABLE void nextKeyRightItem();
Q_INVOKABLE void setFocusItem(QQuickItem *item);
Q_INVOKABLE void setFocusOnDefaultItem();
Q_INVOKABLE void pushRootObject(QObject *object);
Q_INVOKABLE void dropRootObject(QObject *object);
Q_INVOKABLE void resetRootObject();
private:
enum class Direction {
Forward,
Backward,
};
void reload(Direction direction);
void nextItem(Direction direction);
void focusNextListViewItem();
void focusPreviousListViewItem();
void dropListView();
QQmlApplicationEngine *m_engine; // Pointer to engine to get root object
QList<QObject *> m_focusChain; // List of current objects to be focused
QQuickItem *m_focusedItem; // Pointer to the active focus item
QStack<QObject *> m_rootObjects; // Pointer to stack of roots for focus chain
QQuickItem *m_defaultFocusItem;
ListViewFocusController *m_lvfc; // ListView focus manager
signals:
void focusedItemChanged();
};
#endif // FOCUSCONTROLLER_H
+10 -12
View File
@@ -9,7 +9,6 @@
#include "core/errorstrings.h"
#include "core/serialization/serialization.h"
#include "systemController.h"
#include "utilities.h"
#ifdef Q_OS_ANDROID
@@ -77,18 +76,17 @@ ImportController::ImportController(const QSharedPointer<ServersModel> &serversMo
bool ImportController::extractConfigFromFile(const QString &fileName)
{
QString data;
if (!SystemController::readFile(fileName, data)) {
emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
return false;
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
QString data = file.readAll();
m_configFileName = QFileInfo(file.fileName()).fileName();
return extractConfigFromData(data);
}
m_configFileName = QFileInfo(QFile(fileName).fileName()).fileName();
#ifdef Q_OS_ANDROID
if (m_configFileName.isEmpty()) {
m_configFileName = AndroidController::instance()->getFileName(fileName);
}
#endif
return extractConfigFromData(data);
emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
return false;
}
bool ImportController::extractConfigFromData(QString data)
@@ -1,309 +0,0 @@
#include "listViewFocusController.h"
#include "utils/qmlUtils.h"
#include <QQuickWindow>
ListViewFocusController::ListViewFocusController(QQuickItem *listView, QObject *parent)
: QObject { parent },
m_listView { listView },
m_focusChain {},
m_currentSection { Section::Default },
m_header { nullptr },
m_footer { nullptr },
m_focusedItem { nullptr },
m_focusedItemIndex { -1 },
m_delegateIndex { 0 },
m_isReturnNeeded { false },
m_currentSectionString { "Default", "Header", "Delegate", "Footer" }
{
QVariant headerItemProperty = m_listView->property("headerItem");
m_header = headerItemProperty.canConvert<QQuickItem *>() ? headerItemProperty.value<QQuickItem *>() : nullptr;
QVariant footerItemProperty = m_listView->property("footerItem");
m_footer = footerItemProperty.canConvert<QQuickItem *>() ? footerItemProperty.value<QQuickItem *>() : nullptr;
}
ListViewFocusController::~ListViewFocusController()
{
}
void ListViewFocusController::viewAtCurrentIndex() const
{
switch (m_currentSection) {
case Section::Default: [[fallthrough]];
case Section::Header: {
QMetaObject::invokeMethod(m_listView, "positionViewAtBeginning");
break;
}
case Section::Delegate: {
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index
Q_ARG(int, 2)); // PositionMode (0 = Visible)
break;
}
case Section::Footer: {
QMetaObject::invokeMethod(m_listView, "positionViewAtEnd");
break;
}
}
}
int ListViewFocusController::size() const
{
return m_listView->property("count").toInt();
}
int ListViewFocusController::currentIndex() const
{
return m_delegateIndex;
}
void ListViewFocusController::setDelegateIndex(int index)
{
m_delegateIndex = index;
m_listView->setProperty("currentIndex", index);
}
void ListViewFocusController::nextDelegate()
{
switch (m_currentSection) {
case Section::Default: {
if (hasHeader()) {
m_currentSection = Section::Header;
viewAtCurrentIndex();
break;
}
[[fallthrough]];
}
case Section::Header: {
if (size() > 0) {
m_currentSection = Section::Delegate;
viewAtCurrentIndex();
break;
}
[[fallthrough]];
}
case Section::Delegate:
if (m_delegateIndex < (size() - 1)) {
setDelegateIndex(m_delegateIndex + 1);
viewAtCurrentIndex();
break;
} else if (hasFooter()) {
m_currentSection = Section::Footer;
viewAtCurrentIndex();
break;
}
[[fallthrough]];
case Section::Footer: {
m_isReturnNeeded = true;
m_currentSection = Section::Default;
viewAtCurrentIndex();
break;
}
default: {
qCritical() << "Current section is invalid!";
break;
}
}
}
void ListViewFocusController::previousDelegate()
{
switch (m_currentSection) {
case Section::Default: {
if (hasFooter()) {
m_currentSection = Section::Footer;
break;
}
[[fallthrough]];
}
case Section::Footer: {
if (size() > 0) {
m_currentSection = Section::Delegate;
setDelegateIndex(size() - 1);
break;
}
[[fallthrough]];
}
case Section::Delegate: {
if (m_delegateIndex > 0) {
setDelegateIndex(m_delegateIndex - 1);
break;
} else if (hasHeader()) {
m_currentSection = Section::Header;
break;
}
[[fallthrough]];
}
case Section::Header: {
m_isReturnNeeded = true;
m_currentSection = Section::Default;
break;
}
default: {
qCritical() << "Current section is invalid!";
break;
}
}
}
void ListViewFocusController::decrementIndex()
{
m_delegateIndex--;
}
QQuickItem *ListViewFocusController::itemAtIndex(const int index) const
{
QQuickItem *item { nullptr };
QMetaObject::invokeMethod(m_listView, "itemAtIndex", Q_RETURN_ARG(QQuickItem *, item), Q_ARG(int, index));
return item;
}
QQuickItem *ListViewFocusController::currentDelegate() const
{
QQuickItem *result { nullptr };
switch (m_currentSection) {
case Section::Default: {
qWarning() << "No elements...";
break;
}
case Section::Header: {
result = m_header;
break;
}
case Section::Delegate: {
result = itemAtIndex(m_delegateIndex);
break;
}
case Section::Footer: {
result = m_footer;
break;
}
}
return result;
}
QQuickItem *ListViewFocusController::focusedItem() const
{
return m_focusedItem;
}
void ListViewFocusController::focusNextItem()
{
if (m_isReturnNeeded) {
return;
}
reloadFocusChain();
if (m_focusChain.empty()) {
qWarning() << "No elements found in the delegate. Going to next delegate...";
nextDelegate();
focusNextItem();
return;
}
m_focusedItemIndex++;
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
}
void ListViewFocusController::focusPreviousItem()
{
if (m_isReturnNeeded) {
return;
}
if (m_focusChain.empty()) {
qInfo() << "Empty focusChain with current delegate: " << currentDelegate() << "Scanning for elements...";
reloadFocusChain();
}
if (m_focusChain.empty()) {
qWarning() << "No elements found in the delegate. Going to next delegate...";
previousDelegate();
focusPreviousItem();
return;
}
if (m_focusedItemIndex == -1) {
m_focusedItemIndex = m_focusChain.size();
}
m_focusedItemIndex--;
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
}
void ListViewFocusController::resetFocusChain()
{
m_focusChain.clear();
m_focusedItem = nullptr;
m_focusedItemIndex = -1;
}
void ListViewFocusController::reloadFocusChain()
{
m_focusChain = FocusControl::getItemsChain(currentDelegate());
}
bool ListViewFocusController::isFirstFocusItemInDelegate() const
{
return m_focusedItem && (m_focusedItem == m_focusChain.first());
}
bool ListViewFocusController::isLastFocusItemInDelegate() const
{
return m_focusedItem && (m_focusedItem == m_focusChain.last());
}
bool ListViewFocusController::hasHeader() const
{
return m_header && !FocusControl::getItemsChain(m_header).isEmpty();
}
bool ListViewFocusController::hasFooter() const
{
return m_footer && !FocusControl::getItemsChain(m_footer).isEmpty();
}
bool ListViewFocusController::isFirstFocusItemInListView() const
{
switch (m_currentSection) {
case Section::Footer: {
return isFirstFocusItemInDelegate() && !hasHeader() && (size() == 0);
}
case Section::Delegate: {
return isFirstFocusItemInDelegate() && (m_delegateIndex == 0) && !hasHeader();
}
case Section::Header: {
isFirstFocusItemInDelegate();
}
case Section::Default: {
return true;
}
default: qWarning() << "Wrong section"; return true;
}
}
bool ListViewFocusController::isLastFocusItemInListView() const
{
switch (m_currentSection) {
case Section::Default: {
return !hasHeader() && (size() == 0) && !hasFooter();
}
case Section::Header: {
return isLastFocusItemInDelegate() && (size() == 0) && !hasFooter();
}
case Section::Delegate: {
return isLastFocusItemInDelegate() && (m_delegateIndex == size() - 1) && !hasFooter();
}
case Section::Footer: {
return isLastFocusItemInDelegate();
}
default: qWarning() << "Wrong section"; return true;
}
}
bool ListViewFocusController::isReturnNeeded() const
{
return m_isReturnNeeded;
}
@@ -1,70 +0,0 @@
#ifndef LISTVIEWFOCUSCONTROLLER_H
#define LISTVIEWFOCUSCONTROLLER_H
#include <QList>
#include <QObject>
#include <QQuickItem>
#include <QSharedPointer>
#include <QStack>
/*!
* \brief The ListViewFocusController class manages the focus of elements in ListView
* \details This class object moving focus to ListView's controls since ListView stores
* it's data implicitly and it could be got one by one.
*
* This class was made to store as less as possible data getting it from QML
* when it's needed.
*/
class ListViewFocusController : public QObject
{
Q_OBJECT
public:
explicit ListViewFocusController(QQuickItem *listView, QObject *parent = nullptr);
~ListViewFocusController();
void nextDelegate();
void previousDelegate();
void decrementIndex();
void focusNextItem();
void focusPreviousItem();
void resetFocusChain();
void reloadFocusChain();
bool isFirstFocusItemInListView() const;
bool isFirstFocusItemInDelegate() const;
bool isLastFocusItemInListView() const;
bool isLastFocusItemInDelegate() const;
bool isReturnNeeded() const;
private:
enum class Section {
Default,
Header,
Delegate,
Footer,
};
int size() const;
int currentIndex() const;
void setDelegateIndex(int index);
void viewAtCurrentIndex() const;
QQuickItem *itemAtIndex(const int index) const;
QQuickItem *currentDelegate() const;
QQuickItem *focusedItem() const;
bool hasHeader() const;
bool hasFooter() const;
QQuickItem *m_listView;
QList<QObject *> m_focusChain;
Section m_currentSection;
QQuickItem *m_header;
QQuickItem *m_footer;
QQuickItem *m_focusedItem; // Pointer to focused item on Delegate
qsizetype m_focusedItemIndex;
qsizetype m_delegateIndex;
bool m_isReturnNeeded;
QList<QString> m_currentSectionString;
};
#endif // LISTVIEWFOCUSCONTROLLER_H
+2 -16
View File
@@ -81,7 +81,7 @@ void PageController::keyPressEvent(Qt::Key key)
case Qt::Key_Escape: {
if (m_drawerDepth) {
emit closeTopDrawer();
decrementDrawerDepth();
setDrawerDepth(getDrawerDepth() - 1);
} else {
emit escapePressed();
}
@@ -142,25 +142,11 @@ void PageController::setDrawerDepth(const int depth)
}
}
int PageController::getDrawerDepth() const
int PageController::getDrawerDepth()
{
return m_drawerDepth;
}
int PageController::incrementDrawerDepth()
{
return ++m_drawerDepth;
}
int PageController::decrementDrawerDepth()
{
if (m_drawerDepth == 0) {
return m_drawerDepth;
} else {
return --m_drawerDepth;
}
}
void PageController::onShowErrorMessage(ErrorCode errorCode)
{
const auto fullErrorMessage = errorString(errorCode);
+4 -3
View File
@@ -100,9 +100,7 @@ public slots:
void closeApplication();
void setDrawerDepth(const int depth);
int getDrawerDepth() const;
int incrementDrawerDepth();
int decrementDrawerDepth();
int getDrawerDepth();
private slots:
void onShowErrorMessage(amnezia::ErrorCode errorCode);
@@ -137,6 +135,9 @@ signals:
void escapePressed();
void closeTopDrawer();
void forceTabBarActiveFocus();
void forceStackActiveFocus();
private:
QSharedPointer<ServersModel> m_serversModel;
+7 -14
View File
@@ -131,8 +131,12 @@ void SettingsController::backupAppConfig(const QString &fileName)
void SettingsController::restoreAppConfig(const QString &fileName)
{
QByteArray data;
SystemController::readFile(fileName, data);
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
restoreAppConfigFromData(data);
}
@@ -320,15 +324,4 @@ bool SettingsController::isOnTv()
#else
return false;
#endif
}
bool SettingsController::isHomeAdLabelVisible()
{
return m_settings->isHomeAdLabelVisible();
}
void SettingsController::disableHomeAdLabel()
{
m_settings->disableHomeAdLabel();
emit isHomeAdLabelVisibleChanged(false);
}
}
@@ -29,8 +29,6 @@ public:
Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged)
Q_PROPERTY(bool isDevGatewayEnv READ isDevGatewayEnv WRITE toggleDevGatewayEnv NOTIFY devGatewayEnvChanged)
Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged)
public slots:
void toggleAmneziaDns(bool enable);
bool isAmneziaDnsEnabled();
@@ -91,9 +89,6 @@ public slots:
bool isOnTv();
bool isHomeAdLabelVisible();
void disableHomeAdLabel();
signals:
void primaryDnsChanged();
void secondaryDnsChanged();
@@ -117,8 +112,6 @@ signals:
void gatewayEndpointChanged(const QString &endpoint);
void devGatewayEnvChanged(bool enabled);
void isHomeAdLabelVisibleChanged(bool visible);
private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
+4 -2
View File
@@ -82,12 +82,14 @@ void SitesController::removeSite(int index)
void SitesController::importSites(const QString &fileName, bool replaceExisting)
{
QByteArray jsonData;
if (!SystemController::readFile(fileName, jsonData)) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
emit errorOccurred(tr("Can't open file: %1").arg(fileName));
return;
}
QByteArray jsonData = file.readAll();
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
if (jsonDocument.isNull()) {
emit errorOccurred(tr("Failed to parse JSON data from file: %1").arg(fileName));
+1 -33
View File
@@ -24,7 +24,7 @@ SystemController::SystemController(const std::shared_ptr<Settings> &settings, QO
{
}
void SystemController::saveFile(const QString &fileName, const QString &data)
void SystemController::saveFile(QString fileName, const QString &data)
{
#if defined Q_OS_ANDROID
AndroidController::instance()->saveFile(fileName, data);
@@ -62,31 +62,6 @@ void SystemController::saveFile(const QString &fileName, const QString &data)
#endif
}
bool SystemController::readFile(const QString &fileName, QByteArray &data)
{
#ifdef Q_OS_ANDROID
int fd = AndroidController::instance()->getFd(fileName);
if (fd == -1) return false;
QFile file;
if(!file.open(fd, QIODevice::ReadOnly)) return false;
data = file.readAll();
AndroidController::instance()->closeFd();
#else
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) return false;
data = file.readAll();
#endif
return true;
}
bool SystemController::readFile(const QString &fileName, QString &data)
{
QByteArray byteArray;
if(!readFile(fileName, byteArray)) return false;
data = byteArray;
return true;
}
QString SystemController::getFileName(const QString &acceptLabel, const QString &nameFilter,
const QString &selectedFile, const bool isSaveMode, const QString &defaultSuffix)
{
@@ -159,10 +134,3 @@ bool SystemController::isAuthenticated()
return true;
#endif
}
void SystemController::sendTouch(float x, float y)
{
#ifdef Q_OS_ANDROID
AndroidController::instance()->sendTouch(x, y);
#endif
}
+1 -5
View File
@@ -11,9 +11,7 @@ class SystemController : public QObject
public:
explicit SystemController(const std::shared_ptr<Settings> &setting, QObject *parent = nullptr);
static void saveFile(const QString &fileName, const QString &data);
static bool readFile(const QString &fileName, QByteArray &data);
static bool readFile(const QString &fileName, QString &data);
static void saveFile(QString fileName, const QString &data);
public slots:
QString getFileName(const QString &acceptLabel, const QString &nameFilter, const QString &selectedFile = "",
@@ -22,8 +20,6 @@ public slots:
void setQmlRoot(QObject *qmlRoot);
bool isAuthenticated();
void sendTouch(float x, float y);
signals:
void fileDialogClosed(const bool isAccepted);
+2 -2
View File
@@ -70,7 +70,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
.arg(speed);
} else if (serviceType == serviceType::amneziaFree){
QString description = tr("VPN to access blocked sites in regions with high levels of Internet censorship. ");
if (!isServiceAvailable) {
if (isServiceAvailable) {
description += tr("<p><a style=\"color: #EB5757;\">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a>");
}
return description;
@@ -86,7 +86,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
}
case IsServiceAvailableRole: {
if (serviceType == serviceType::amneziaFree) {
if (!isServiceAvailable) {
if (isServiceAvailable) {
return false;
}
}
@@ -21,7 +21,6 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
}
switch (role) {
case Roles::SubnetAddressRole: m_serverProtocolConfig.insert(config_key::subnet_address, value.toString()); break;
case Roles::PortRole: m_serverProtocolConfig.insert(config_key::port, value.toString()); break;
case Roles::ClientMtuRole: m_clientProtocolConfig.insert(config_key::mtu, value.toString()); break;
@@ -59,7 +58,6 @@ QVariant AwgConfigModel::data(const QModelIndex &index, int role) const
}
switch (role) {
case Roles::SubnetAddressRole: return m_serverProtocolConfig.value(config_key::subnet_address).toString();
case Roles::PortRole: return m_serverProtocolConfig.value(config_key::port).toString();
case Roles::ClientMtuRole: return m_clientProtocolConfig.value(config_key::mtu);
@@ -94,7 +92,6 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
m_serverProtocolConfig.insert(config_key::transport_proto,
serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config);
m_serverProtocolConfig[config_key::subnet_address] = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
m_serverProtocolConfig[config_key::junkPacketCount] =
serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
@@ -171,7 +168,6 @@ QHash<int, QByteArray> AwgConfigModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[SubnetAddressRole] = "subnetAddress";
roles[PortRole] = "port";
roles[ClientMtuRole] = "clientMtu";
@@ -201,7 +197,6 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
subnetAddress = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
serverJunkPacketCount = serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
serverJunkPacketMinSize = serverProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
@@ -221,7 +216,7 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
{
if (subnetAddress != other.subnetAddress || port != other.port || serverJunkPacketCount != other.serverJunkPacketCount
if (port != other.port || serverJunkPacketCount != other.serverJunkPacketCount
|| serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize
|| serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize
|| serverInitPacketMagicHeader != other.serverInitPacketMagicHeader
+1 -3
View File
@@ -15,7 +15,6 @@ struct AwgConfig
{
AwgConfig(const QJsonObject &jsonConfig);
QString subnetAddress;
QString port;
QString clientMtu;
@@ -44,8 +43,7 @@ class AwgConfigModel : public QAbstractListModel
public:
enum Roles {
SubnetAddressRole = Qt::UserRole + 1,
PortRole,
PortRole = Qt::UserRole + 1,
ClientMtuRole,
ClientJunkPacketCountRole,
@@ -21,7 +21,6 @@ bool WireGuardConfigModel::setData(const QModelIndex &index, const QVariant &val
}
switch (role) {
case Roles::SubnetAddressRole: m_serverProtocolConfig.insert(config_key::subnet_address, value.toString()); break;
case Roles::PortRole: m_serverProtocolConfig.insert(config_key::port, value.toString()); break;
case Roles::ClientMtuRole: m_clientProtocolConfig.insert(config_key::mtu, value.toString()); break;
}
@@ -37,7 +36,6 @@ QVariant WireGuardConfigModel::data(const QModelIndex &index, int role) const
}
switch (role) {
case Roles::SubnetAddressRole: return m_serverProtocolConfig.value(config_key::subnet_address).toString();
case Roles::PortRole: return m_serverProtocolConfig.value(config_key::port).toString();
case Roles::ClientMtuRole: return m_clientProtocolConfig.value(config_key::mtu);
}
@@ -58,7 +56,6 @@ void WireGuardConfigModel::updateModel(const QJsonObject &config)
m_serverProtocolConfig.insert(config_key::transport_proto,
serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config);
m_serverProtocolConfig[config_key::subnet_address] = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::wireguard::defaultPort);
auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString();
@@ -99,7 +96,6 @@ QHash<int, QByteArray> WireGuardConfigModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[SubnetAddressRole] = "subnetAddress";
roles[PortRole] = "port";
roles[ClientMtuRole] = "clientMtu";
@@ -112,13 +108,12 @@ WgConfig::WgConfig(const QJsonObject &serverProtocolConfig)
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object();
clientMtu = clientProtocolConfig[config_key::mtu].toString(protocols::wireguard::defaultMtu);
subnetAddress = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
port = serverProtocolConfig.value(config_key::port).toString(protocols::wireguard::defaultPort);
}
bool WgConfig::hasEqualServerSettings(const WgConfig &other) const
{
if (subnetAddress != other.subnetAddress || port != other.port) {
if (port != other.port) {
return false;
}
return true;
@@ -10,7 +10,6 @@ struct WgConfig
{
WgConfig(const QJsonObject &jsonConfig);
QString subnetAddress;
QString port;
QString clientMtu;
@@ -25,8 +24,7 @@ class WireGuardConfigModel : public QAbstractListModel
public:
enum Roles {
SubnetAddressRole = Qt::UserRole + 1,
PortRole,
PortRole = Qt::UserRole + 1,
ClientMtuRole
};
-72
View File
@@ -1,72 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Shapes
import Qt5Compat.GraphicalEffects
import Style 1.0
import "../Config"
import "../Controls2"
import "../Controls2/TextTypes"
Rectangle {
id: root
property real contentHeight: ad.implicitHeight + ad.anchors.topMargin + ad.anchors.bottomMargin
border.width: 1
border.color: AmneziaStyle.color.goldenApricot
color: AmneziaStyle.color.transparent
radius: 13
visible: GC.isDesktop() && ServersModel.isDefaultServerFromApi
&& ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && SettingsController.isHomeAdLabelVisible
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/premium")
}
}
RowLayout {
id: ad
anchors.fill: parent
anchors.margins: 16
Image {
source: "qrc:/images/controls/amnezia.svg"
sourceSize: Qt.size(36, 36)
layer {
effect: ColorOverlay {
color: AmneziaStyle.color.paleGray
}
}
}
CaptionTextType {
Layout.fillWidth: true
Layout.rightMargin: 10
Layout.leftMargin: 10
text: qsTr("Amnezia Premium - for access to any website")
color: AmneziaStyle.color.pearlGray
lineHeight: 18
font.pixelSize: 15
}
ImageButtonType {
image: "qrc:/images/controls/close.svg"
imageColor: AmneziaStyle.color.paleGray
onClicked: function() {
SettingsController.disableHomeAdLabel()
}
}
}
}
@@ -16,32 +16,6 @@ Button {
property string connectedButtonColor: AmneziaStyle.color.goldenApricot
property bool buttonActiveFocus: activeFocus && (Qt.platform.os !== "android" || SettingsController.isOnTv())
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()
}
implicitWidth: 190
implicitHeight: 190
@@ -14,7 +14,7 @@ DrawerType2 {
width: parent.width
height: parent.height
expandedStateContent: ColumnLayout {
expandedContent: ColumnLayout {
id: content
anchors.top: parent.top
@@ -26,6 +26,14 @@ DrawerType2 {
root.expandedHeight = content.implicitHeight + 32
}
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
@@ -36,6 +44,11 @@ DrawerType2 {
headerText: qsTr("Add new connection")
}
Item {
id: focusItem
KeyNavigation.tab: ip.rightButton
}
LabelWithButtonType {
id: ip
Layout.fillWidth: true
@@ -46,8 +59,10 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.closeTriggered()
root.close()
}
KeyNavigation.tab: qrCode.rightButton
}
DividerType {}
@@ -61,8 +76,10 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.closeTriggered()
root.close()
}
KeyNavigation.tab: focusItem
}
DividerType {}
@@ -17,15 +17,55 @@ ListView {
property var rootWidth
property var selectedText
property bool a: true
width: rootWidth
height: contentItem.height
height: menuContent.contentItem.height
clip: true
snapMode: ListView.SnapToItem
interactive: false
ScrollBar.vertical: ScrollBarType {}
property FlickableType parentFlickable
property var lastItemTabClicked
property bool isFocusable: true
property int currentFocusIndex: 0
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
this.currentFocusIndex = 0
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
}
}
Keys.onTabPressed: {
if (currentFocusIndex < this.count - 1) {
currentFocusIndex += 1
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
} else {
currentFocusIndex = 0
if (lastItemTabClicked && typeof lastItemTabClicked === "function") {
lastItemTabClicked()
}
}
}
onVisibleChanged: {
if (visible) {
currentFocusIndex = 0
focusItem.forceActiveFocus()
}
}
Item {
id: focusItem
}
onCurrentFocusIndexChanged: {
if (parentFlickable) {
parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex))
}
}
ButtonGroup {
id: containersRadioButtonGroup
@@ -35,6 +75,12 @@ ListView {
implicitWidth: rootWidth
implicitHeight: content.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
containerRadioButton.forceActiveFocus()
}
}
ColumnLayout {
id: content
@@ -65,13 +111,13 @@ ListView {
}
if (checked) {
containersDropDown.closeTriggered()
containersDropDown.close()
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyDefaultServerContainersModel.mapToSource(index))
} else {
ContainersModel.setProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.closeTriggered()
containersDropDown.close()
}
}
@@ -16,7 +16,7 @@ DrawerType2 {
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedStateContent: ColumnLayout {
expandedContent: ColumnLayout {
id: content
anchors.top: parent.top
@@ -24,6 +24,14 @@ DrawerType2 {
anchors.right: parent.right
spacing: 0
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
@@ -35,6 +43,11 @@ DrawerType2 {
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
}
Item {
id: focusItem
KeyNavigation.tab: splitTunnelingSwitch.visible ? splitTunnelingSwitch : siteBasedSplitTunnelingSwitch.rightButton
}
LabelWithButtonType {
id: splitTunnelingSwitch
Layout.fillWidth: true
@@ -46,9 +59,11 @@ DrawerType2 {
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.closeTriggered()
// PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
// root.close()
}
}
@@ -65,9 +80,13 @@ DrawerType2 {
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.closeTriggered()
root.close()
}
}
@@ -84,9 +103,11 @@ DrawerType2 {
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: focusItem
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
root.closeTriggered()
root.close()
}
}
@@ -26,7 +26,7 @@ DrawerType2 {
id: installedAppsModel
}
expandedStateContent: Item {
expandedContent: Item {
id: container
implicitHeight: expandedHeight
@@ -43,7 +43,7 @@ DrawerType2 {
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.closeTriggered()
root.close()
}
}
@@ -69,8 +69,6 @@ DrawerType2 {
clip: true
interactive: true
property bool isFocusable: true
model: SortFilterProxyModel {
id: proxyInstalledAppsModel
sourceModel: installedAppsModel
@@ -81,7 +79,10 @@ DrawerType2 {
}
}
ScrollBar.vertical: ScrollBarType {}
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: ScrollBar.AlwaysOn
}
ButtonGroup {
id: buttonGroup
@@ -154,7 +155,7 @@ DrawerType2 {
PageController.showBusyIndicator(true)
AppSplitTunnelingController.addApps(installedAppsModel.getSelectedAppsInfo())
PageController.showBusyIndicator(false)
root.closeTriggered()
root.close()
}
}
}
+18 -1
View File
@@ -20,7 +20,7 @@ DrawerType2 {
property var yesButtonFunction
property var noButtonFunction
expandedStateContent: ColumnLayout {
expandedContent: ColumnLayout {
id: content
anchors.top: parent.top
@@ -33,6 +33,14 @@ DrawerType2 {
root.expandedHeight = content.implicitHeight + 32
}
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
@@ -51,6 +59,11 @@ DrawerType2 {
text: descriptionText
}
Item {
id: focusItem
KeyNavigation.tab: yesButton
}
BasicButtonType {
id: yesButton
Layout.fillWidth: true
@@ -65,6 +78,8 @@ DrawerType2 {
yesButtonFunction()
}
}
KeyNavigation.tab: noButton
}
BasicButtonType {
@@ -87,6 +102,8 @@ DrawerType2 {
noButtonFunction()
}
}
KeyNavigation.tab: focusItem
}
}
}
+161 -129
View File
@@ -11,7 +11,7 @@ import "../Config"
DrawerType2 {
id: root
expandedStateContent: Item {
expandedContent: Item {
id: container
implicitHeight: root.height * 0.9
@@ -20,6 +20,19 @@ DrawerType2 {
root.expandedHeight = container.implicitHeight
}
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -30,148 +43,167 @@ DrawerType2 {
BackButtonType {
id: backButton
Layout.fillWidth: true
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() { root.closeTriggered() }
}
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Choose language")
backButtonFunction: function() { root.close() }
KeyNavigation.tab: listView
}
}
ListView {
id: listView
FlickableType {
anchors.top: backButtonLayout.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
property bool isFocusable: true
property int selectedIndex: LanguageModel.currentLanguageIndex
ColumnLayout {
id: content
clip: true
reuseItems: true
anchors.fill: parent
ScrollBar.vertical: ScrollBarType {}
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
model: LanguageModel
ButtonGroup {
id: buttonGroup
}
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
RadioButton {
id: radioButton
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
hoverEnabled: 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()
}
indicator: Rectangle {
width: parent.width - 1
height: parent.height
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
border.width: radioButton.focus ? 1 : 0
Behavior on color {
PropertyAnimation { duration: 200 }
}
Behavior on border.color {
PropertyAnimation { duration: 200 }
}
}
RowLayout {
id: radioButtonContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
z: 1
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
width: 24
height: 24
Layout.rightMargin: 8
}
}
ButtonGroup.group: buttonGroup
checked: listView.selectedIndex === index
onClicked: {
listView.selectedIndex = index
LanguageModel.changeLanguage(languageIndex)
root.closeTriggered()
}
}
headerText: qsTr("Choose language")
}
Keys.onEnterPressed: radioButton.clicked()
Keys.onReturnPressed: radioButton.clicked()
ListView {
id: listView
Layout.fillWidth: true
height: listView.contentItem.height
clip: true
interactive: false
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
ButtonGroup {
id: buttonGroup
}
property int currentFocusIndex: 0
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
this.currentFocusIndex = 0
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
}
}
Keys.onTabPressed: {
if (currentFocusIndex < this.count - 1) {
currentFocusIndex += 1
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
} else {
listViewFocusItem.forceActiveFocus()
focusItem.forceActiveFocus()
}
}
Item {
id: listViewFocusItem
Keys.onTabPressed: {
root.forceActiveFocus()
}
}
onVisibleChanged: {
if (visible) {
listViewFocusItem.forceActiveFocus()
focusItem.forceActiveFocus()
}
}
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
radioButton.forceActiveFocus()
}
}
ColumnLayout {
id: delegateContent
anchors.fill: parent
RadioButton {
id: radioButton
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
hoverEnabled: true
indicator: Rectangle {
width: parent.width - 1
height: parent.height
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
border.width: radioButton.focus ? 1 : 0
Behavior on color {
PropertyAnimation { duration: 200 }
}
Behavior on border.color {
PropertyAnimation { duration: 200 }
}
}
RowLayout {
id: radioButtonContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
z: 1
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
width: 24
height: 24
Layout.rightMargin: 8
}
}
ButtonGroup.group: buttonGroup
checked: listView.currentIndex === index
onClicked: {
listView.currentIndex = index
LanguageModel.changeLanguage(languageIndex)
root.close()
}
}
}
Keys.onEnterPressed: radioButton.clicked()
Keys.onReturnPressed: radioButton.clicked()
}
}
}
}
}
@@ -1,126 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0
import ProtocolEnum 1.0
import ContainerProps 1.0
import ContainersModelFilters 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
ListView {
id: root
property int selectedIndex: ServersModel.defaultIndex
anchors.top: serversMenuHeader.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.topMargin: 16
model: ServersModel
ScrollBar.vertical: ScrollBarType {}
property bool isFocusable: true
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
root.selectedIndex = serverIndex
}
}
clip: true
reuseItems: true
delegate: Item {
id: menuContentDelegate
objectName: "menuContentDelegate"
property variant delegateData: model
property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
implicitWidth: root.width
implicitHeight: serverRadioButtonContent.implicitHeight
ColumnLayout {
id: serverRadioButtonContent
objectName: "serverRadioButtonContent"
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
RowLayout {
objectName: "serverRadioButtonRowLayout"
Layout.fillWidth: true
VerticalRadioButton {
id: serverRadioButton
objectName: "serverRadioButton"
Layout.fillWidth: true
text: name
descriptionText: serverDescription
checked: index === root.selectedIndex
checkable: !ConnectionController.isConnected
ButtonGroup.group: serversRadioButtonGroup
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
root.selectedIndex = index
ServersModel.defaultIndex = index
}
Keys.onEnterPressed: serverRadioButton.clicked()
Keys.onReturnPressed: serverRadioButton.clicked()
}
ImageButtonType {
id: serverInfoButton
objectName: "serverInfoButton"
image: "qrc:/images/controls/settings.svg"
imageColor: AmneziaStyle.color.paleGray
implicitWidth: 56
implicitHeight: 56
z: 1
onClicked: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
drawer.closeTriggered()
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
}
}
}
}
@@ -20,14 +20,47 @@ ListView {
height: root.contentItem.height
clip: true
reuseItems: true
interactive: false
property bool isFocusable: false
activeFocusOnTab: true
Keys.onTabPressed: {
if (currentIndex < this.count - 1) {
this.incrementCurrentIndex()
} else {
currentIndex = 0
lastItemTabClickedSignal()
}
}
onCurrentIndexChanged: {
if (visible) {
if (fl.contentHeight > fl.height) {
var item = this.currentItem
if (item.y < fl.height) {
fl.contentY = item.y
} else if (item.y + item.height > fl.contentY + fl.height) {
fl.contentY = item.y + item.height - fl.height
}
}
}
}
onVisibleChanged: {
if (visible) {
this.currentIndex = 0
}
}
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
containerRadioButton.rightButton.forceActiveFocus()
}
}
ColumnLayout {
id: delegateContent
@@ -36,9 +36,17 @@ DrawerType2 {
configFileName = "amnezia_config"
}
expandedStateContent: Item {
expandedContent: Item {
implicitHeight: root.expandedHeight
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
header.forceActiveFocus()
}
}
Header2Type {
id: header
anchors.top: parent.top
@@ -49,27 +57,24 @@ DrawerType2 {
anchors.rightMargin: 16
headerText: root.headerText
KeyNavigation.tab: shareButton
}
ListView {
id: listView
FlickableType {
anchors.top: header.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
contentHeight: content.height + 32
property bool isFocusable: true
ColumnLayout {
id: content
ScrollBar.vertical: ScrollBarType {}
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
model: 1
clip: true
reuseItems: true
header: ColumnLayout {
width: listView.width
anchors.leftMargin: 16
anchors.rightMargin: 16
visible: root.contentVisible
@@ -77,12 +82,12 @@ DrawerType2 {
id: shareButton
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg"
KeyNavigation.tab: copyConfigTextButton
clickedFunc: function() {
var fileName = ""
if (GC.isMobile()) {
@@ -106,8 +111,6 @@ DrawerType2 {
id: copyConfigTextButton
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
@@ -121,14 +124,14 @@ DrawerType2 {
Keys.onReturnPressed: { copyConfigTextButton.clicked() }
Keys.onEnterPressed: { copyConfigTextButton.clicked() }
KeyNavigation.tab: copyNativeConfigStringButton.visible ? copyNativeConfigStringButton : showSettingsButton
}
BasicButtonType {
id: copyNativeConfigStringButton
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: false
@@ -150,8 +153,6 @@ DrawerType2 {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
@@ -163,8 +164,10 @@ DrawerType2 {
text: qsTr("Show connection settings")
clickedFunc: function() {
configContentDrawer.openTriggered()
configContentDrawer.open()
}
KeyNavigation.tab: header
}
DrawerType2 {
@@ -175,11 +178,30 @@ DrawerType2 {
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedStateContent: Item {
onClosed: {
if (!GC.isMobile()) {
header.forceActiveFocus()
}
}
expandedContent: Item {
id: configContentContainer
implicitHeight: configContentDrawer.expandedHeight
Connections {
target: configContentDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
Connections {
target: copyNativeConfigStringButton
function onClicked() {
@@ -209,7 +231,9 @@ DrawerType2 {
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() { configContentDrawer.closeTriggered() }
backButtonFunction: function() { configContentDrawer.close() }
KeyNavigation.tab: focusItem
}
FlickableType {
@@ -278,10 +302,6 @@ DrawerType2 {
}
}
}
}
delegate: ColumnLayout {
width: listView.width
Rectangle {
id: qrCodeContainer
@@ -289,8 +309,6 @@ DrawerType2 {
Layout.fillWidth: true
Layout.preferredHeight: width
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ExportController.qrCodesCount > 0
@@ -302,32 +320,6 @@ DrawerType2 {
source: ExportController.qrCodesCount ? ExportController.qrCodes[0] : ""
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()
}
Timer {
property int index: 0
interval: 1000
@@ -354,8 +346,6 @@ DrawerType2 {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ExportController.qrCodesCount > 0
@@ -39,6 +39,8 @@ Rectangle {
implicitWidth: (rootWidth - 32) / 2
text: "UDP"
KeyNavigation.tab: tcpButton
onClicked: {
root.currentIndex = 0
}
+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
+2 -27
View File
@@ -35,35 +35,10 @@ Button {
property alias buttonTextLabel: buttonText
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()
}
implicitHeight: 56
hoverEnabled: true
focusPolicy: Qt.TabFocus
onFocusChanged: {
if (root.activeFocus) {
@@ -175,7 +150,7 @@ Button {
ButtonTextType {
id: buttonText
color: root.textColor
color: textColor
text: root.text
visible: root.text === "" ? false : true
+1 -30
View File
@@ -22,7 +22,6 @@ RadioButton {
property string pressedBorderColor: AmneziaStyle.color.softGoldenApricot
property string selectedBorderColor: AmneziaStyle.color.goldenApricot
property string defaultBodredColor: AmneziaStyle.color.transparent
property string focusBorderColor: AmneziaStyle.color.paleGray
property int borderWidth: 0
implicitWidth: content.implicitWidth
@@ -30,32 +29,6 @@ RadioButton {
hoverEnabled: 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()
}
indicator: Rectangle {
anchors.fill: parent
radius: 16
@@ -79,8 +52,6 @@ RadioButton {
return pressedBorderColor
} else if (root.checked) {
return selectedBorderColor
} else if (root.activeFocus) {
return focusBorderColor
}
}
return defaultBodredColor
@@ -88,7 +59,7 @@ RadioButton {
border.width: {
if (root.enabled) {
if(root.checked || root.activeFocus) {
if(root.checked) {
return 1
}
return root.pressed ? 1 : 0
+3 -27
View File
@@ -25,15 +25,10 @@ Button {
property real textOpacity: 1.0
property alias focusItem: rightImage
property FlickableType parentFlickable
hoverEnabled: true
background: Rectangle {
id: backgroundRect
anchors.fill: parent
radius: 16
@@ -44,31 +39,13 @@ Button {
}
}
function ensureVisible(item) {
if (item.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
onFocusChanged: {
ensureVisible(root)
}
focusItem.onFocusChanged: {
root.ensureVisible(focusItem)
}
contentItem: Item {
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: content.implicitHeight
RowLayout {
id: content
anchors.fill: parent
Image {
@@ -84,7 +61,6 @@ Button {
}
ColumnLayout {
ListItemTitleType {
text: root.headerText
visible: text !== ""
@@ -147,7 +123,6 @@ Button {
Rectangle {
id: rightImageBackground
anchors.fill: parent
radius: 12
color: "transparent"
@@ -156,9 +131,10 @@ Button {
PropertyAnimation { duration: 200 }
}
}
onClicked: {
root.clicked()
if (clickedFunction && typeof clickedFunction === "function") {
clickedFunction()
}
}
}
}
+69 -126
View File
@@ -9,14 +9,17 @@ import "TextTypes"
Item {
id: root
readonly property string drawerExpandedStateName: "expanded"
readonly property string drawerCollapsedStateName: "collapsed"
readonly property string drawerExpanded: "expanded"
readonly property string drawerCollapsed: "collapsed"
readonly property bool isOpened: isExpandedStateActive() || (isCollapsedStateActive() && (dragArea.drag.active === true))
readonly property bool isClosed: isCollapsedStateActive() && (dragArea.drag.active === false)
readonly property bool isOpened: drawerContent.state === root.drawerExpanded || (drawerContent.state === root.drawerCollapsed && dragArea.drag.active === true)
readonly property bool isClosed: drawerContent.state === root.drawerCollapsed && dragArea.drag.active === false
property Component collapsedStateContent
property Component expandedStateContent
readonly property bool isExpanded: drawerContent.state === root.drawerExpanded
readonly property bool isCollapsed: drawerContent.state === root.drawerCollapsed
property Component collapsedContent
property Component expandedContent
property string defaultColor: AmneziaStyle.color.onyxBlack
property string borderColor: AmneziaStyle.color.slateGray
@@ -26,41 +29,29 @@ Item {
property int depthIndex: 0
signal cursorEntered
signal cursorExited
signal entered
signal exited
signal pressed(bool pressed, bool entered)
signal aboutToHide
signal aboutToShow
signal closeTriggered
signal openTriggered
signal close
signal open
signal closed
signal opened
function isExpandedStateActive() {
return isStateActive(drawerExpandedStateName)
}
function isCollapsedStateActive() {
return isStateActive(drawerCollapsedStateName)
}
function isStateActive(stateName) {
return drawerContent.state === stateName
}
Connections {
target: PageController
function onCloseTopDrawer() {
if (depthIndex === PageController.getDrawerDepth()) {
if (isCollapsedStateActive()) {
if (isCollapsed) {
return
}
aboutToHide()
drawerContent.state = root.drawerCollapsedStateName
drawerContent.state = root.drawerCollapsed
depthIndex = 0
closed()
}
@@ -70,52 +61,30 @@ Item {
Connections {
target: root
function onCloseTriggered() {
if (isCollapsedStateActive()) {
function onClose() {
if (isCollapsed) {
return
}
aboutToHide()
drawerContent.state = root.drawerCollapsed
depthIndex = 0
PageController.setDrawerDepth(PageController.getDrawerDepth() - 1)
closed()
}
function onClosed() {
drawerContent.state = root.drawerCollapsedStateName
if (root.isCollapsedStateActive()) {
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
}
depthIndex = 0
PageController.decrementDrawerDepth()
FocusController.dropRootObject(root)
}
function onOpenTriggered() {
if (root.isExpandedStateActive()) {
function onOpen() {
if (isExpanded) {
return
}
root.aboutToShow()
aboutToShow()
root.opened()
}
function onOpened() {
drawerContent.state = root.drawerExpandedStateName
if (isExpandedStateActive()) {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
}
depthIndex = PageController.incrementDrawerDepth()
FocusController.pushRootObject(root)
drawerContent.state = root.drawerExpanded
depthIndex = PageController.getDrawerDepth() + 1
PageController.setDrawerDepth(depthIndex)
opened()
}
}
@@ -123,7 +92,7 @@ Item {
id: background
anchors.fill: parent
color: root.isCollapsedStateActive() ? AmneziaStyle.color.transparent : AmneziaStyle.color.translucentMidnightBlack
color: root.isCollapsed ? AmneziaStyle.color.transparent : AmneziaStyle.color.translucentMidnightBlack
Behavior on color {
PropertyAnimation { duration: 200 }
@@ -133,17 +102,18 @@ Item {
MouseArea {
id: emptyArea
anchors.fill: parent
enabled: root.isExpanded
visible: enabled
onClicked: {
root.closeTriggered()
root.close()
}
}
MouseArea {
id: dragArea
objectName: "dragArea"
anchors.fill: drawerContentBackground
cursorShape: root.isCollapsed ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
enabled: drawerContent.implicitHeight > 0
@@ -155,36 +125,35 @@ Item {
/** If drag area is released at any point other than min or max y, transition to the other state */
onReleased: {
if (isCollapsedStateActive() && drawerContent.y < dragArea.drag.maximumY) {
root.openTriggered()
if (root.isCollapsed && drawerContent.y < dragArea.drag.maximumY) {
root.open()
return
}
if (isExpandedStateActive() && drawerContent.y > dragArea.drag.minimumY) {
root.closeTriggered()
if (root.isExpanded && drawerContent.y > dragArea.drag.minimumY) {
root.close()
return
}
}
onEntered: {
root.cursorEntered()
root.entered()
}
onExited: {
root.cursorExited()
root.exited()
}
onPressedChanged: {
root.pressed(pressed, entered)
}
onClicked: {
if (isCollapsedStateActive()) {
root.openTriggered()
if (root.isCollapsed) {
root.open()
}
}
}
Rectangle {
id: drawerContentBackground
objectName: "drawerContentBackground"
anchors { left: drawerContent.left; right: drawerContent.right; top: drawerContent.top }
height: root.height
@@ -205,80 +174,53 @@ Item {
Item {
id: drawerContent
objectName: "drawerContent"
Drag.active: dragArea.drag.active
anchors.right: root.right
anchors.left: root.left
y: root.height - drawerContent.height
state: root.drawerCollapsed
state: root.drawerCollapsedStateName
implicitHeight: root.isCollapsed ? collapsedHeight : expandedHeight
onStateChanged: {
if (root.isCollapsed) {
var initialPageNavigationBarColor = PageController.getInitialPageNavigationBarColor()
if (initialPageNavigationBarColor !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(initialPageNavigationBarColor)
}
return
}
if (root.isExpanded) {
if (PageController.getInitialPageNavigationBarColor() !== 0xFF1C1D21) {
PageController.updateNavigationBarColor(0xFF1C1D21)
}
return
}
}
states: [
State {
name: root.drawerCollapsedStateName
name: root.drawerCollapsed
PropertyChanges {
target: drawerContent
implicitHeight: collapsedHeight
y: root.height - root.collapsedHeight
}
PropertyChanges {
target: background
color: AmneziaStyle.color.transparent
}
PropertyChanges {
target: dragArea
cursorShape: Qt.PointingHandCursor
}
PropertyChanges {
target: emptyArea
enabled: false
visible: false
}
PropertyChanges {
target: collapsedLoader
// visible: true
}
PropertyChanges {
target: expandedLoader
visible: false
}
},
State {
name: root.drawerExpandedStateName
name: root.drawerExpanded
PropertyChanges {
target: drawerContent
implicitHeight: expandedHeight
y: dragArea.drag.minimumY
}
PropertyChanges {
target: background
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
}
PropertyChanges {
target: dragArea
cursorShape: Qt.ArrowCursor
}
PropertyChanges {
target: emptyArea
enabled: true
visible: true
}
PropertyChanges {
target: collapsedLoader
// visible: false
}
PropertyChanges {
target: expandedLoader
visible: true
}
}
]
transitions: [
Transition {
from: root.drawerCollapsedStateName
to: root.drawerExpandedStateName
from: root.drawerCollapsed
to: root.drawerExpanded
PropertyAnimation {
target: drawerContent
properties: "y"
@@ -286,8 +228,8 @@ Item {
}
},
Transition {
from: root.drawerExpandedStateName
to: root.drawerCollapsedStateName
from: root.drawerExpanded
to: root.drawerCollapsed
PropertyAnimation {
target: drawerContent
properties: "y"
@@ -299,7 +241,7 @@ Item {
Loader {
id: collapsedLoader
sourceComponent: root.collapsedStateContent
sourceComponent: root.collapsedContent
anchors.right: parent.right
anchors.left: parent.left
@@ -308,7 +250,8 @@ Item {
Loader {
id: expandedLoader
sourceComponent: root.expandedStateContent
visible: root.isExpanded
sourceComponent: root.expandedContent
anchors.right: parent.right
anchors.left: parent.left
+87 -55
View File
@@ -45,56 +45,33 @@ Item {
property Item drawerParent
property Component listView
signal openTriggered
signal closeTriggered
signal open
signal close
readonly property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
function popupClosedFunc() {
if (!GC.isMobile()) {
this.forceActiveFocus()
}
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
property var parentFlickable
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
implicitWidth: rootButtonContent.implicitWidth
implicitHeight: rootButtonContent.implicitHeight
onOpenTriggered: {
menu.openTriggered()
onOpen: {
menu.open()
}
onCloseTriggered: {
menu.closeTriggered()
}
Keys.onEnterPressed: {
if (menu.isClosed) {
menu.openTriggered()
}
}
Keys.onReturnPressed: {
if (menu.isClosed) {
menu.openTriggered()
}
onClose: {
menu.close()
}
Rectangle {
@@ -196,7 +173,7 @@ Item {
if (rootButtonClickedFunction && typeof rootButtonClickedFunction === "function") {
rootButtonClickedFunction()
} else {
menu.openTriggered()
menu.open()
}
}
}
@@ -209,38 +186,93 @@ Item {
anchors.fill: parent
expandedHeight: drawerParent.height * drawerHeight
expandedStateContent: Item {
onClosed: {
root.popupClosedFunc()
}
expandedContent: Item {
id: container
implicitHeight: menu.expandedHeight
Connections {
target: menu
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
anchors.fill: parent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
BackButtonType {
id: backButton
backButtonImage: root.headerBackButtonImage
backButtonFunction: function() { menu.closeTriggered() }
backButtonFunction: function() { menu.close() }
KeyNavigation.tab: listViewLoader.item
}
}
Header2Type {
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
Layout.fillWidth: true
FlickableType {
id: flickable
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
headerText: root.headerText
}
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Loader {
id: listViewLoader
sourceComponent: root.listView
spacing: 16
Layout.fillHeight: true
Header2Type {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: root.headerText
width: parent.width
}
Loader {
id: listViewLoader
sourceComponent: root.listView
onLoaded: {
listViewLoader.item.parentFlickable = flickable
listViewLoader.item.lastItemTabClicked = function() {
focusItem.forceActiveFocus()
}
}
}
}
}
}
}
Keys.onEnterPressed: {
if (menu.isClosed) {
menu.open()
}
}
Keys.onReturnPressed: {
if (menu.isClosed) {
menu.open()
}
}
}
+2 -3
View File
@@ -7,11 +7,10 @@ Flickable {
function ensureVisible(item) {
if (item.y < fl.contentY) {
fl.contentY = item.y - 40 // 40 is a top margin
fl.contentY = item.y
} else if (item.y + item.height > fl.contentY + fl.height) {
fl.contentY = item.y + item.height - fl.height + 40 // 40 is a bottom margin
}
fl.returnToBounds()
}
clip: true
@@ -25,7 +24,7 @@ Flickable {
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
ScrollBar.vertical: ScrollBarType {
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: fl.height >= fl.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
+2
View File
@@ -19,6 +19,8 @@ Item {
property string descriptionText
focus: true
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
@@ -27,32 +27,6 @@ RadioButton {
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
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()
}
indicator: Rectangle {
anchors.fill: parent
radius: 16
+9 -26
View File
@@ -24,39 +24,22 @@ Button {
property int borderFocusedWidth: 1
hoverEnabled: true
focus: true
focusPolicy: Qt.TabFocus
icon.source: image
icon.color: root.enabled ? imageColor : disableImageColor
property bool isFocusable: true
property Flickable parentFlickable
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(this)
}
}
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
Keys.onEnterPressed: root.clicked()
Keys.onReturnPressed: root.clicked()
Behavior on icon.color {
PropertyAnimation { duration: 200 }
}
@@ -41,32 +41,6 @@ Item {
property bool descriptionOnTop: false
property bool hideDescription: true
property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
@@ -17,7 +17,7 @@ ListView {
property bool dividerVisible: false
property int selectedIndex: 0
currentIndex: 0
width: rootWidth
height: menuContent.contentItem.height
@@ -45,7 +45,7 @@ ListView {
rightImageSource: imageSource
clickedFunction: function() {
menuContent.selectedIndex = index
menuContent.currentIndex = index
menuContent.selectedText = name
if (menuContent.clickedFunction && typeof menuContent.clickedFunction === "function") {
menuContent.clickedFunction()
@@ -62,7 +62,7 @@ ListView {
}
Component.onCompleted: {
if (menuContent.selectedIndex === index) {
if (menuContent.currentIndex === index) {
menuContent.selectedText = name
}
}
@@ -20,134 +20,155 @@ ListView {
property var clickedFunction
property int selectedIndex: 0
currentIndex: 0
width: rootWidth
height: root.contentItem.height
clip: true
reuseItems: true
interactive: false
property bool isFocusable: true
property FlickableType parentFlickable
property var lastItemTabClicked
ScrollBar.vertical: ScrollBarType {}
property int currentFocusIndex: 0
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
this.currentFocusIndex = 0
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
}
}
Keys.onTabPressed: {
if (currentFocusIndex < this.count - 1) {
currentFocusIndex += 1
} else {
currentFocusIndex = 0
}
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
}
Item {
id: focusItem
Keys.onTabPressed: {
root.forceActiveFocus()
}
}
onVisibleChanged: {
if (visible) {
focusItem.forceActiveFocus()
}
}
onCurrentFocusIndexChanged: {
if (parentFlickable) {
parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex))
}
}
ButtonGroup {
id: buttonGroup
}
function triggerCurrentItem() {
var item = root.itemAtIndex(selectedIndex)
item.selectable.clicked()
var item = root.itemAtIndex(currentIndex)
var radioButton = item.children[0].children[0]
radioButton.clicked()
}
delegate: ColumnLayout {
id: content
property alias selectable: radioButton
delegate: Item {
implicitWidth: rootWidth
implicitHeight: content.implicitHeight
RadioButton {
id: radioButton
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
hoverEnabled: true
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
onActiveFocusChanged: {
if (activeFocus) {
radioButton.forceActiveFocus()
}
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
ColumnLayout {
id: content
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
anchors.fill: parent
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
RadioButton {
id: radioButton
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
hoverEnabled: true
indicator: Rectangle {
width: parent.width - 1
height: parent.height
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
border.width: radioButton.focus ? 1 : 0
indicator: Rectangle {
width: parent.width - 1
height: parent.height
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
border.width: radioButton.focus ? 1 : 0
Behavior on color {
PropertyAnimation { duration: 200 }
}
Behavior on border.color {
PropertyAnimation { duration: 200 }
Behavior on color {
PropertyAnimation { duration: 200 }
}
Behavior on border.color {
PropertyAnimation { duration: 200 }
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
MouseArea {
RowLayout {
id: radioButtonContent
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
RowLayout {
id: radioButtonContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
z: 1
z: 1
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: name
maximumLineCount: root.textMaximumLineCount
elide: root.textElide
text: name
maximumLineCount: root.textMaximumLineCount
elide: root.textElide
}
Image {
source: imageSource
visible: radioButton.checked
width: 24
height: 24
Layout.rightMargin: 8
}
}
Image {
source: imageSource
visible: radioButton.checked
ButtonGroup.group: buttonGroup
checked: root.currentIndex === index
width: 24
height: 24
Layout.rightMargin: 8
}
}
ButtonGroup.group: buttonGroup
checked: root.selectedIndex === index
onClicked: {
root.selectedIndex = index
root.selectedText = name
if (clickedFunction && typeof clickedFunction === "function") {
clickedFunction()
onClicked: {
root.currentIndex = index
root.selectedText = name
if (clickedFunction && typeof clickedFunction === "function") {
clickedFunction()
}
}
}
}
Component.onCompleted: {
if (root.selectedIndex === index) {
if (root.currentIndex === index) {
root.selectedText = name
}
}
+37 -5
View File
@@ -9,21 +9,53 @@ Item {
property StackView stackView: StackView.view
property var defaultActiveFocusItem: null
onVisibleChanged: {
if (visible) {
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
// z: 99
// anchors.fill: parent
// enabled: true
// onPressed: function(mouse) {
// forceActiveFocus()
// mouse.accepted = false
// }
// }
// Set a timer to set focus after a short delay
Timer {
id: timer
interval: 200 // Milliseconds
interval: 100 // Milliseconds
onTriggered: {
FocusController.resetRootObject()
FocusController.setFocusOnDefaultItem()
if (defaultActiveFocusItem) {
defaultActiveFocusItem.forceActiveFocus()
}
}
repeat: false // Stop the timer after one trigger
running: true // Start the timer
running: !GC.isMobile() // Start the timer
}
}
+8 -14
View File
@@ -5,7 +5,6 @@ import QtQuick.Layouts
import Style 1.0
import "TextTypes"
import "../Config"
Popup {
id: root
@@ -29,11 +28,11 @@ Popup {
}
onOpened: {
timer.start()
focusItem.forceActiveFocus()
}
onClosed: {
FocusController.dropRootObject(root)
PageController.forceStackActiveFocus()
}
background: Rectangle {
@@ -43,17 +42,6 @@ Popup {
radius: 4
}
Timer {
id: timer
interval: 200 // Milliseconds
onTriggered: {
FocusController.pushRootObject(root)
FocusController.setFocusItem(closeButton)
}
repeat: false // Stop the timer after one trigger
running: true // Start the timer
}
contentItem: Item {
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
@@ -84,6 +72,11 @@ Popup {
}
}
Item {
id: focusItem
KeyNavigation.tab: closeButton
}
BasicButtonType {
id: closeButton
visible: closeButtonVisible
@@ -99,6 +92,7 @@ Popup {
borderWidth: 0
text: qsTr("Close")
KeyNavigation.tab: focusItem
clickedFunc: function() {
root.close()
-11
View File
@@ -1,11 +0,0 @@
import QtQuick
import QtQuick.Controls
import "./"
import "../Controls2"
ScrollBar {
id: root
policy: parent.height >= parent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
+7 -36
View File
@@ -35,37 +35,10 @@ Switch {
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite
property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent
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()
}
hoverEnabled: enabled ? true : false
focusPolicy: Qt.TabFocus
property FlickableType parentFlickable: null
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
@@ -158,15 +131,13 @@ Switch {
enabled: false
}
Keys.onEnterPressed: event => handleSwitch(event)
Keys.onReturnPressed: event => handleSwitch(event)
Keys.onSpacePressed: event => handleSwitch(event)
Keys.onEnterPressed: {
root.checked = !root.checked
root.checkedChanged()
}
function handleSwitch(event) {
if (!event.isAutoRepeat) {
root.checked = !root.checked
root.checkedChanged()
}
event.accepted = true
Keys.onReturnPressed: {
root.checked = !root.checked
root.checkedChanged()
}
}
+1 -26
View File
@@ -17,35 +17,10 @@ TabButton {
property bool isSelected: false
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()
}
implicitHeight: 48
hoverEnabled: true
focusPolicy: Qt.TabFocus
background: Rectangle {
id: background
+2 -27
View File
@@ -14,38 +14,13 @@ TabButton {
property bool isSelected: false
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()
}
property string borderFocusedColor: AmneziaStyle.color.paleGray
property int borderFocusedWidth: 1
property var clickedFunc
hoverEnabled: true
focusPolicy: Qt.TabFocus
icon.source: image
icon.color: isSelected ? selectedColor : defaultColor
@@ -66,7 +41,7 @@ TabButton {
cursorShape: Qt.PointingHandCursor
enabled: false
}
Keys.onEnterPressed: {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
@@ -78,6 +78,9 @@ Rectangle {
placeholderText: root.placeholderText
text: root.text
KeyNavigation.tab: firstButton
onCursorVisibleChanged: {
if (textArea.cursorVisible) {
fl.interactive = true
@@ -40,7 +40,6 @@ Item {
implicitHeight: content.implicitHeight
property FlickableType parentFlickable
Connections {
target: textField
function onFocusChanged() {
@@ -85,16 +84,7 @@ Item {
TextField {
id: textField
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
activeFocusOnTab: false
enabled: root.textFieldEditable
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
@@ -219,9 +209,9 @@ Item {
clickedFunc()
}
// if (KeyNavigation.tab) {
// KeyNavigation.tab.forceActiveFocus();
// }
if (KeyNavigation.tab) {
KeyNavigation.tab.forceActiveFocus();
}
}
Keys.onReturnPressed: {
@@ -229,8 +219,8 @@ Item {
clickedFunc()
}
// if (KeyNavigation.tab) {
// KeyNavigation.tab.forceActiveFocus();
// }
if (KeyNavigation.tab) {
KeyNavigation.tab.forceActiveFocus();
}
}
}
@@ -28,33 +28,8 @@ RadioButton {
property string imageSource
property bool showImage
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()
}
hoverEnabled: true
focusPolicy: Qt.TabFocus
indicator: Rectangle {
id: background
@@ -26,6 +26,5 @@ QtObject {
readonly property color softGoldenApricot: Qt.rgba(251/255, 178/255, 106/255, 0.3)
readonly property color mistyGray: Qt.rgba(215/255, 216/255, 219/255, 0.8)
readonly property color cloudyGray: Qt.rgba(215/255, 216/255, 219/255, 0.65)
readonly property color pearlGray: '#EAEAEC'
}
}
+28 -24
View File
@@ -16,28 +16,40 @@ import "../Components"
PageType {
id: root
BackButtonType {
id: backButton
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType {
id: backButton
// KeyNavigation.tab: removeButton
}
}
ListView {
id: listView
anchors.top: backButton.bottom
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
contentHeight: content.implicitHeight
property bool isFocusable: true
ColumnLayout {
id: content
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout {
width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
HeaderType {
id: header
@@ -48,14 +60,7 @@ PageType {
headerText: "Dev menu"
}
}
model: 1
clip: true
spacing: 16
delegate: ColumnLayout {
width: listView.width
TextFieldWithHeaderType {
id: passwordTextField
@@ -64,6 +69,7 @@ PageType {
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
parentFlickable: fl
headerText: qsTr("Gateway endpoint")
textFieldText: SettingsController.gatewayEndpoint
@@ -80,19 +86,17 @@ PageType {
SettingsController.gatewayEndpoint = textFieldText
}
}
}
}
footer: ColumnLayout {
width: listView.width
// KeyNavigation.tab: saveButton
}
SwitcherType {
id: switcher
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.topMargin: 16
text: qsTr("Dev gateway environment")
checked: SettingsController.isDevGatewayEnv
+229 -68
View File
@@ -1,7 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import SortFilterProxyModel 0.2
@@ -20,13 +19,13 @@ import "../Components"
PageType {
id: root
Connections {
objectName: "pageControllerConnections"
defaultActiveFocusItem: focusItem
Connections {
target: PageController
function onRestorePageHomeState(isContainerInstalled) {
drawer.openTriggered()
drawer.open()
if (isContainerInstalled) {
containersDropDown.rootButtonClickedFunction()
}
@@ -34,32 +33,23 @@ PageType {
}
Item {
objectName: "homeColumnItem"
anchors.fill: parent
anchors.bottomMargin: drawer.collapsedHeight
ColumnLayout {
objectName: "homeColumnLayout"
anchors.fill: parent
anchors.topMargin: 12
anchors.bottomMargin: 16
anchors.topMargin: 34
anchors.bottomMargin: 34
AdLabel {
id: adLabel
Layout.fillWidth: true
Layout.preferredHeight: adLabel.contentHeight
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 22
Item {
id: focusItem
KeyNavigation.tab: loggingButton.visible ?
loggingButton :
connectButton
}
BasicButtonType {
id: loggingButton
objectName: "loggingButton"
property bool isLoggingEnabled: SettingsController.isLoggingEnabled
Layout.alignment: Qt.AlignHCenter
@@ -79,6 +69,8 @@ PageType {
Keys.onEnterPressed: loggingButton.clicked()
Keys.onReturnPressed: loggingButton.clicked()
KeyNavigation.tab: connectButton
onClicked: {
PageController.goToPage(PageEnum.PageSettingsLogging)
}
@@ -86,17 +78,16 @@ PageType {
ConnectButton {
id: connectButton
objectName: "connectButton"
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
KeyNavigation.tab: splitTunnelingButton
}
BasicButtonType {
id: splitTunnelingButton
objectName: "splitTunnelingButton"
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
Layout.bottomMargin: 34
leftPadding: 16
rightPadding: 16
@@ -125,37 +116,53 @@ PageType {
Keys.onEnterPressed: splitTunnelingButton.clicked()
Keys.onReturnPressed: splitTunnelingButton.clicked()
KeyNavigation.tab: drawer
onClicked: {
homeSplitTunnelingDrawer.openTriggered()
homeSplitTunnelingDrawer.open()
}
HomeSplitTunnelingDrawer {
id: homeSplitTunnelingDrawer
objectName: "homeSplitTunnelingDrawer"
parent: root
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
}
}
}
}
DrawerType2 {
id: drawer
objectName: "drawerProtocol"
anchors.fill: parent
collapsedStateContent: Item {
objectName: "ProtocolDrawerCollapsedContent"
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
objectName: "collapsedColumnLayout"
anchors.left: parent.left
anchors.right: parent.right
@@ -174,8 +181,6 @@ PageType {
}
RowLayout {
objectName: "rowLayout"
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
@@ -184,11 +189,9 @@ PageType {
spacing: 0
Connections {
objectName: "drawerConnections"
target: drawer
function onCursorEntered() {
if (drawer.isCollapsedStateActive) {
function onEntered() {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
} else {
@@ -196,8 +199,8 @@ PageType {
}
}
function onCursorExited() {
if (drawer.isCollapsedStateActive) {
function onExited() {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
} else {
@@ -206,7 +209,7 @@ PageType {
}
function onPressed(pressed, entered) {
if (drawer.isCollapsedStateActive) {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
} else {
@@ -217,8 +220,6 @@ PageType {
Header1TextType {
id: collapsedButtonHeader
objectName: "collapsedButtonHeader"
Layout.maximumWidth: drawer.width - 48 - 18 - 12
maximumLineCount: 2
@@ -227,6 +228,8 @@ PageType {
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
KeyNavigation.tab: tabBar
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
@@ -234,11 +237,10 @@ PageType {
ImageButtonType {
id: collapsedButtonChevron
objectName: "collapsedButtonChevron"
Layout.leftMargin: 8
visible: drawer.isCollapsedStateActive()
visible: drawer.isCollapsed
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
@@ -253,24 +255,25 @@ PageType {
Keys.onEnterPressed: collapsedButtonChevron.clicked()
Keys.onReturnPressed: collapsedButtonChevron.clicked()
Keys.onTabPressed: lastItemTabClicked()
onClicked: {
if (drawer.isCollapsedStateActive()) {
drawer.openTriggered()
if (drawer.isCollapsed) {
drawer.open()
}
}
}
}
RowLayout {
objectName: "rowLayoutLabel"
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.topMargin: 8
Layout.bottomMargin: drawer.isCollapsedStateActive ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16
spacing: 0
BasicButtonType {
enabled: (ServersModel.defaultServerImagePathCollapsed !== "") && drawer.isCollapsedStateActive
enabled: (ServersModel.defaultServerImagePathCollapsed !== "") && drawer.isCollapsed
hoverEnabled: enabled
implicitHeight: 36
@@ -288,9 +291,8 @@ PageType {
buttonTextLabel.font.pixelSize: 13
buttonTextLabel.font.weight: 400
text: drawer.isCollapsedStateActive ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
leftImageSource: ServersModel.defaultServerImagePathCollapsed
leftImageColor: ""
changeLeftImageSize: false
rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : ""
@@ -303,9 +305,18 @@ PageType {
}
}
Connections {
target: drawer
enabled: !GC.isMobile()
function onIsCollapsedChanged() {
if (!drawer.isCollapsed) {
focusItem1.forceActiveFocus()
}
}
}
ColumnLayout {
id: serversMenuHeader
objectName: "serversMenuHeader"
anchors.top: collapsed.bottom
anchors.right: parent.right
@@ -317,9 +328,13 @@ PageType {
visible: !ServersModel.isDefaultServerFromApi
Item {
id: focusItem1
KeyNavigation.tab: containersDropDown
}
DropDownType {
id: containersDropDown
objectName: "containersDropDown"
rootButtonImageColor: AmneziaStyle.color.midnightBlack
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
@@ -330,28 +345,28 @@ PageType {
rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8
enabled: drawer.isOpened
text: ServersModel.defaultServerDefaultContainerName
textColor: AmneziaStyle.color.midnightBlack
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() {
containersDropDown.openTriggered()
containersDropDown.open()
}
drawerParent: root
KeyNavigation.tab: serversMenuContent
listView: HomeContainersListView {
id: containersListView
objectName: "containersListView"
rootWidth: root.width
onVisibleChanged: {
if (containersDropDown.visible && !GC.isMobile()) {
focusItem1.forceActiveFocus()
}
}
Connections {
objectName: "rowLayoutConnections"
target: ServersModel
function onDefaultServerIndexChanged() {
@@ -393,21 +408,167 @@ PageType {
ButtonGroup {
id: serversRadioButtonGroup
objectName: "serversRadioButtonGroup"
}
ServersListView {
ListView {
id: serversMenuContent
objectName: "serversMenuContent"
isFocusable: false
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 }
}
}
}
// this item shouldn't be focused when drawer is closed
function onIsOpenedChanged() {
serversMenuContent.isFocusable = drawer.isOpened
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.paleGray
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,18 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.mtuTextField.textField
Item {
id: focusItem
onFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -27,235 +39,229 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.mtuTextField.textField
}
}
ListView {
id: listview
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: saveButton.top
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin
width: parent.width
Column {
id: content
clip: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
property bool isFocusable: true
ListView {
id: listview
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
width: parent.width
height: listview.contentItem.height
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
clip: true
interactive: false
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
model: AwgConfigModel
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === ""
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ColumnLayout {
id: col
model: AwgConfigModel
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
anchors.leftMargin: 16
anchors.rightMargin: 16
property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === ""
spacing: 0
ColumnLayout {
id: col
HeaderType {
Layout.fillWidth: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
headerText: qsTr("AmneziaWG settings")
}
anchors.leftMargin: 16
anchors.rightMargin: 16
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 40
spacing: 0
headerText: qsTr("MTU")
textFieldText: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
HeaderType {
Layout.fillWidth: true
textField.onEditingFinished: {
if (textFieldText !== clientMtu) {
clientMtu = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
headerText: qsTr("AmneziaWG settings")
}
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 40
headerText: "Jc - Junk packet count"
textFieldText: clientJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
headerText: qsTr("MTU")
textFieldText: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketCount) {
clientJunkPacketCount = textFieldText
}
}
textField.onEditingFinished: {
if (textFieldText !== clientMtu) {
clientMtu = textFieldText
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmin - Junk packet minimum size"
textFieldText: clientJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMinSize) {
clientJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmax - Junk packet maximum size"
textFieldText: clientJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMaxSize) {
clientJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
Keys.onTabPressed: saveButton.forceActiveFocus()
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Server settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 8
enabled: false
headerText: qsTr("Port")
textFieldText: port
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S1 - Init packet junk size"
textFieldText: serverInitPacketJunkSize
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S2 - Response packet junk size"
textFieldText: serverResponsePacketJunkSize
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H1 - Init packet magic header"
textFieldText: serverInitPacketMagicHeader
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H2 - Response packet magic header"
textFieldText: serverResponsePacketMagicHeader
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
enabled: false
headerText: "H3 - Underload packet magic header"
textFieldText: serverUnderloadPacketMagicHeader
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H4 - Transport packet magic header"
textFieldText: serverTransportPacketMagicHeader
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jc - Junk packet count"
textFieldText: clientJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketCount) {
clientJunkPacketCount = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmin - Junk packet minimum size"
textFieldText: clientJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMinSize) {
clientJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmax - Junk packet maximum size"
textFieldText: clientJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMaxSize) {
clientJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Server settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 8
enabled: false
headerText: qsTr("Port")
textFieldText: port
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S1 - Init packet junk size"
textFieldText: serverInitPacketJunkSize
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S2 - Response packet junk size"
textFieldText: serverResponsePacketJunkSize
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H1 - Init packet magic header"
textFieldText: serverInitPacketMagicHeader
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H2 - Response packet magic header"
textFieldText: serverResponsePacketMagicHeader
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H3 - Underload packet magic header"
textFieldText: serverUnderloadPacketMagicHeader
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H4 - Transport packet magic header"
textFieldText: serverTransportPacketMagicHeader
}
}
}
@@ -277,11 +283,7 @@ PageType {
text: qsTr("Save")
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
+313 -320
View File
@@ -2,8 +2,6 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtCore
import SortFilterProxyModel 0.2
import PageEnum 1.0
@@ -19,6 +17,18 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
Item {
id: focusItem
onFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -30,358 +40,341 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.portTextField.textField
}
}
ListView {
id: listview
property bool isFocusable: true
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
width: parent.width
Column {
id: content
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
ListView {
id: listview
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
width: parent.width
height: listview.contentItem.height
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
clip: true
interactive: false
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
model: AwgConfigModel
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
clip: true
property alias portTextField: portTextField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
model: AwgConfigModel
ColumnLayout {
id: col
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
anchors.leftMargin: 16
anchors.rightMargin: 16
ColumnLayout {
id: col
spacing: 0
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
HeaderType {
Layout.fillWidth: true
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
HeaderType {
Layout.fillWidth: true
headerText: qsTr("AmneziaWG settings")
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 40
enabled: delegateItem.isEnabled
headerText: qsTr("VPN address subnet")
textFieldText: subnetAddress
textField.onEditingFinished: {
if (textFieldText !== subnetAddress) {
subnetAddress = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textFieldText: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textFieldText !== port) {
port = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jc - Junk packet count")
textFieldText: serverJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText === "") {
textFieldText = "0"
headerText: qsTr("AmneziaWG settings")
}
if (textFieldText !== serverJunkPacketCount) {
serverJunkPacketCount = textFieldText
}
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
checkEmptyText: true
}
enabled: delegateItem.isEnabled
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Port")
textFieldText: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
parentFlickable: fl
headerText: qsTr("Jmin - Junk packet minimum size")
textFieldText: serverJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMinSize) {
serverJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jmax - Junk packet maximum size")
textFieldText: serverJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMaxSize) {
serverJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S1 - Init packet junk size")
textFieldText: serverInitPacketJunkSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketJunkSize) {
serverInitPacketJunkSize = textFieldText
}
}
checkEmptyText: true
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S2 - Response packet junk size")
textFieldText: serverResponsePacketJunkSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketJunkSize) {
serverResponsePacketJunkSize = textFieldText
}
}
checkEmptyText: true
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H1 - Init packet magic header")
textFieldText: serverInitPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketMagicHeader) {
serverInitPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H2 - Response packet magic header")
textFieldText: serverResponsePacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketMagicHeader) {
serverResponsePacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H4 - Transport packet magic header")
textFieldText: serverTransportPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverTransportPacketMagicHeader) {
serverTransportPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H3 - Underload packet magic header")
textFieldText: serverUnderloadPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverUnderloadPacketMagicHeader) {
serverUnderloadPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
transportPacketMagicHeaderTextField.errorText === "" &&
responsePacketMagicHeaderTextField.errorText === "" &&
initPacketMagicHeaderTextField.errorText === "" &&
responsePacketJunkSizeTextField.errorText === "" &&
initPacketJunkSizeTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" &&
portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === ""
text: qsTr("Save")
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
clickedFunc: function() {
forceActiveFocus()
if (delegateItem.isEnabled) {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
transportPacketMagicHeaderTextField.textField.text,
responsePacketMagicHeaderTextField.textField.text,
initPacketMagicHeaderTextField.textField.text)) {
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
return
textField.onEditingFinished: {
if (textFieldText !== port) {
port = textFieldText
}
}
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
parseInt(responsePacketJunkSizeTextField.textField.text))) {
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
return
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
headerText: qsTr("Jc - Junk packet count")
textFieldText: serverJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText === "") {
textFieldText = "0"
}
if (textFieldText !== serverJunkPacketCount) {
serverJunkPacketCount = textFieldText
}
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveRestartButton.forceActiveFocus()
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jmin - Junk packet minimum size")
textFieldText: serverJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMinSize) {
serverJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jmax - Junk packet maximum size")
textFieldText: serverJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMaxSize) {
serverJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: initPacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S1 - Init packet junk size")
textFieldText: serverInitPacketJunkSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketJunkSize) {
serverInitPacketJunkSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: responsePacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S2 - Response packet junk size")
textFieldText: serverResponsePacketJunkSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketJunkSize) {
serverResponsePacketJunkSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: initPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H1 - Init packet magic header")
textFieldText: serverInitPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketMagicHeader) {
serverInitPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: responsePacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H2 - Response packet magic header")
textFieldText: serverResponsePacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketMagicHeader) {
serverResponsePacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: transportPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H4 - Transport packet magic header")
textFieldText: serverTransportPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverTransportPacketMagicHeader) {
serverTransportPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: underloadPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
headerText: qsTr("H3 - Underload packet magic header")
textFieldText: serverUnderloadPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverUnderloadPacketMagicHeader) {
serverUnderloadPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: saveRestartButton
}
BasicButtonType {
id: saveRestartButton
parentFlickable: fl
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
transportPacketMagicHeaderTextField.errorText === "" &&
responsePacketMagicHeaderTextField.errorText === "" &&
initPacketMagicHeaderTextField.errorText === "" &&
responsePacketJunkSizeTextField.errorText === "" &&
initPacketJunkSizeTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" &&
portTextField.errorText === ""
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
if (delegateItem.isEnabled) {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
transportPacketMagicHeaderTextField.textField.text,
responsePacketMagicHeaderTextField.textField.text,
initPacketMagicHeaderTextField.textField.text)) {
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
return
}
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
parseInt(responsePacketJunkSizeTextField.textField.text))) {
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
return
}
}
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveRestartButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
@@ -16,6 +16,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -27,6 +34,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.trafficFromField.textField
}
}
@@ -48,13 +56,11 @@ PageType {
ListView {
id: listview
property int selectedIndex: 0
width: parent.width
height: listview.contentItem.height
clip: true
reuseItems: true
interactive: false
model: CloakConfigModel
@@ -104,6 +110,8 @@ PageType {
}
}
}
KeyNavigation.tab: portTextField.textField
}
TextFieldWithHeaderType {
@@ -122,6 +130,8 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: cipherDropDown
}
DropDownType {
@@ -133,6 +143,7 @@ PageType {
headerText: qsTr("Cipher")
drawerParent: root
KeyNavigation.tab: saveRestartButton
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -150,7 +161,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
cipherDropDown.close()
}
Component.onCompleted: {
@@ -158,7 +169,7 @@ PageType {
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
selectedIndex = i
currentIndex = i
}
}
}
@@ -173,6 +184,7 @@ PageType {
Layout.bottomMargin: 24
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
@@ -17,6 +17,18 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
onActiveFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
}
ColumnLayout {
id: backButtonLayout
@@ -28,6 +40,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.vpnAddressSubnetTextField.textField
}
}
@@ -91,6 +104,7 @@ PageType {
textFieldText: subnetAddress
parentFlickable: fl
KeyNavigation.tab: transportProtoSelector
textField.onEditingFinished: {
if (textFieldText !== subnetAddress) {
@@ -118,6 +132,8 @@ PageType {
return transportProto === "tcp" ? 1 : 0
}
KeyNavigation.tab: portTextField.enabled ? portTextField.textField : autoNegotiateEncryprionSwitcher
onCurrentIndexChanged: {
if (transportProto === "tcp" && currentIndex === 0) {
transportProto = "udp"
@@ -146,6 +162,8 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: autoNegotiateEncryprionSwitcher
}
SwitcherType {
@@ -163,6 +181,10 @@ PageType {
autoNegotiateEncryprion = checked
}
}
KeyNavigation.tab: hashDropDown.enabled ?
hashDropDown :
tlsAuthCheckBox
}
DropDownType {
@@ -176,6 +198,10 @@ PageType {
headerText: qsTr("Hash")
drawerParent: root
parentFlickable: fl
KeyNavigation.tab: cipherDropDown.enabled ?
cipherDropDown :
tlsAuthCheckBox
listView: ListViewWithRadioButtonType {
id: hashListView
@@ -198,7 +224,7 @@ PageType {
clickedFunction: function() {
hashDropDown.text = selectedText
hash = hashDropDown.text
hashDropDown.closeTriggered()
hashDropDown.close()
}
Component.onCompleted: {
@@ -224,6 +250,9 @@ PageType {
headerText: qsTr("Cipher")
drawerParent: root
parentFlickable: fl
KeyNavigation.tab: tlsAuthCheckBox
listView: ListViewWithRadioButtonType {
id: cipherListView
@@ -246,7 +275,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
cipherDropDown.close()
}
Component.onCompleted: {
@@ -291,6 +320,8 @@ PageType {
text: qsTr("TLS auth")
checked: tlsAuth
KeyNavigation.tab: blockDnsCheckBox
onCheckedChanged: {
if (checked !== tlsAuth) {
console.log("tlsAuth changed to: " + checked)
@@ -308,6 +339,8 @@ PageType {
text: qsTr("Block DNS requests outside of VPN")
checked: blockDns
KeyNavigation.tab: additionalClientCommandsSwitcher
onCheckedChanged: {
if (checked !== blockDns) {
blockDns = checked
@@ -322,6 +355,9 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 32
parentFlickable: fl
KeyNavigation.tab: additionalClientCommandsTextArea.visible ?
additionalClientCommandsTextArea.textArea :
additionalServerCommandsSwitcher
checked: additionalClientCommands !== ""
@@ -340,7 +376,7 @@ PageType {
Layout.topMargin: 16
visible: additionalClientCommandsSwitcher.checked
KeyNavigation.tab: additionalServerCommandsSwitcher
parentFlickable: fl
textAreaText: additionalClientCommands
@@ -358,6 +394,9 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
KeyNavigation.tab: additionalServerCommandsTextArea.visible ?
additionalServerCommandsTextArea.textArea :
saveRestartButton
checked: additionalServerCommands !== ""
@@ -380,6 +419,7 @@ PageType {
textAreaText: additionalServerCommands
placeholderText: qsTr("Commands:")
parentFlickable: fl
KeyNavigation.tab: saveRestartButton
textArea.onEditingFinished: {
if (additionalServerCommands !== textAreaText) {
additionalServerCommands = textAreaText
@@ -396,6 +436,7 @@ PageType {
text: qsTr("Save")
parentFlickable: fl
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
+42 -3
View File
@@ -19,6 +19,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@@ -30,6 +37,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listView
}
HeaderType {
@@ -67,6 +75,13 @@ PageType {
activeFocusOnTab: true
focus: true
onActiveFocusChanged: {
if (focus) {
listView.currentIndex = 0
listView.currentItem.focusItem.forceActiveFocus()
}
}
delegate: Item {
implicitWidth: parent.width
implicitHeight: delegateContent.implicitHeight
@@ -86,9 +101,11 @@ PageType {
text: qsTr("Show connection options")
clickedFunction: function() {
configContentDrawer.openTriggered()
configContentDrawer.open()
}
KeyNavigation.tab: removeButton
MouseArea {
anchors.fill: button
cursorShape: Qt.PointingHandCursor
@@ -103,12 +120,31 @@ PageType {
expandedHeight: root.height * 0.9
onClosed: {
if (!GC.isMobile()) {
defaultActiveFocusItem.forceActiveFocus()
}
}
parent: root
anchors.fill: parent
expandedStateContent: Item {
expandedContent: Item {
implicitHeight: configContentDrawer.expandedHeight
Connections {
target: configContentDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem1.forceActiveFocus()
}
}
Item {
id: focusItem1
KeyNavigation.tab: backButton1
}
BackButtonType {
id: backButton1
@@ -118,8 +154,10 @@ PageType {
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.closeTriggered()
configContentDrawer.close()
}
KeyNavigation.tab: focusItem1
}
FlickableType {
@@ -188,6 +226,7 @@ PageType {
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: AmneziaStyle.color.vibrantRed
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.")
@@ -16,6 +16,15 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.focusItemId.enabled ?
listview.currentItem.focusItemId.textField :
focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -27,6 +36,9 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.focusItemId.enabled ?
listview.currentItem.focusItemId.textField :
focusItem
}
}
@@ -102,6 +114,8 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: cipherDropDown
}
DropDownType {
@@ -115,9 +129,9 @@ PageType {
headerText: qsTr("Cipher")
drawerParent: root
KeyNavigation.tab: saveRestartButton
listView: ListViewWithRadioButtonType {
id: cipherListView
rootWidth: root.width
@@ -133,7 +147,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
cipherDropDown.close()
}
Component.onCompleted: {
@@ -158,6 +172,7 @@ PageType {
enabled: isPortEditable | isCipherEditable
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.mtuTextField.textField
Item {
id: focusItem
onFocusChanged: {
@@ -148,6 +150,8 @@ PageType {
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")
@@ -16,6 +16,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -27,6 +34,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@@ -56,10 +64,17 @@ PageType {
model: WireGuardConfigModel
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
}
}
delegate: Item {
id: delegateItem
property alias focusItemId: vpnAddressSubnetTextField
property alias focusItemId: portTextField.textField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
implicitWidth: listview.width
@@ -82,29 +97,10 @@ PageType {
headerText: qsTr("WG settings")
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 40
enabled: delegateItem.isEnabled
headerText: qsTr("VPN address subnet")
textFieldText: subnetAddress
textField.onEditingFinished: {
if (textFieldText !== subnetAddress) {
subnetAddress = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.topMargin: 40
enabled: delegateItem.isEnabled
@@ -113,6 +109,8 @@ PageType {
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
KeyNavigation.tab: saveButton
textField.onEditingFinished: {
if (textFieldText !== port) {
port = textFieldText
@@ -128,11 +126,12 @@ PageType {
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === ""
enabled: portTextField.errorText === ""
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
onClicked: function() {
forceActiveFocus()
@@ -17,6 +17,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -28,6 +35,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@@ -57,6 +65,13 @@ PageType {
model: XrayConfigModel
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
}
}
delegate: Item {
property alias focusItemId: textFieldWithHeaderType.textField
@@ -88,6 +103,8 @@ PageType {
headerText: qsTr("Disguised as traffic from")
textFieldText: site
KeyNavigation.tab: basicButton
textField.onEditingFinished: {
if (textFieldText !== site) {
var tmpText = textFieldText
@@ -111,6 +128,8 @@ PageType {
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
onClicked: {
forceActiveFocus()
@@ -16,6 +16,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -27,6 +34,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: removeButton
}
}
@@ -64,6 +72,8 @@ PageType {
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: root.lastItemTabClicked()
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var yesButtonText = qsTr("Continue")
@@ -16,6 +16,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: InstallController
@@ -24,6 +26,11 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -35,6 +42,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@@ -99,6 +107,7 @@ PageType {
Layout.topMargin: 32
parentFlickable: fl
KeyNavigation.tab: portLabel.rightButton
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
@@ -127,6 +136,7 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: usernameLabel.rightButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -150,6 +160,7 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: passwordLabel.eyeButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -173,6 +184,14 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
eyeButton.KeyNavigation.tab: passwordLabel.rightButton
rightButton.Keys.onTabPressed: {
if (mountButton.visible) {
mountButton.forceActiveFocus()
} else {
detailedInstructionsButton.forceActiveFocus()
}
}
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -206,6 +225,7 @@ PageType {
borderWidth: 1
parentFlickable: fl
KeyNavigation.tab: detailedInstructionsButton
text: qsTr("Mount folder on device")
@@ -270,6 +290,7 @@ PageType {
text: qsTr("Detailed instructions")
parentFlickable: fl
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
@@ -17,6 +17,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Connections {
target: InstallController
@@ -25,6 +27,11 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -36,6 +43,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@@ -91,6 +99,7 @@ PageType {
Layout.topMargin: 32
parentFlickable: fl
KeyNavigation.tab: portLabel.rightButton
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
@@ -119,6 +128,7 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: usernameLabel.rightButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -142,6 +152,7 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: passwordLabel.eyeButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -165,6 +176,8 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
eyeButton.KeyNavigation.tab: passwordLabel.rightButton
rightButton.KeyNavigation.tab: changeSettingsButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -187,7 +200,13 @@ PageType {
anchors.fill: parent
expandedHeight: root.height * 0.9
expandedStateContent: ColumnLayout {
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
property string tempPort: port
property string tempUsername: username
property string tempPassword: password
@@ -203,6 +222,9 @@ PageType {
Connections {
target: changeSettingsDrawer
function onOpened() {
if (!GC.isMobile()) {
drawerFocusItem.forceActiveFocus()
}
tempPort = port
tempUsername = username
tempPassword = password
@@ -217,6 +239,11 @@ PageType {
}
}
Item {
id: drawerFocusItem
KeyNavigation.tab: portTextField.textField
}
HeaderType {
Layout.fillWidth: true
@@ -241,6 +268,8 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: usernameTextField.textField
}
TextFieldWithHeaderType {
@@ -261,6 +290,8 @@ PageType {
username = textFieldText
}
}
KeyNavigation.tab: passwordTextField.textField
}
TextFieldWithHeaderType {
@@ -291,6 +322,8 @@ PageType {
password = textFieldText
}
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
@@ -301,6 +334,7 @@ PageType {
Layout.bottomMargin: 24
text: qsTr("Change connection settings")
Keys.onTabPressed: lastItemTabClicked(drawerFocusItem)
clickedFunc: function() {
forceActiveFocus()
@@ -322,7 +356,7 @@ PageType {
tempPort = portTextField.textFieldText
tempUsername = usernameTextField.textFieldText
tempPassword = passwordTextField.textFieldText
changeSettingsDrawer.closeTriggered()
changeSettingsDrawer.close()
}
}
}
@@ -338,10 +372,11 @@ PageType {
Layout.rightMargin: 16
text: qsTr("Change connection settings")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
changeSettingsDrawer.openTriggered()
changeSettingsDrawer.open()
}
}
}
@@ -17,6 +17,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: InstallController
@@ -25,6 +27,11 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@@ -36,6 +43,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: websiteName.rightButton
}
}
@@ -80,6 +88,8 @@ PageType {
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
+20 -5
View File
@@ -14,6 +14,8 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: header
FlickableType {
id: fl
anchors.top: parent.top
@@ -37,6 +39,8 @@ PageType {
Layout.leftMargin: 16
headerText: qsTr("Settings")
KeyNavigation.tab: account.rightButton
}
LabelWithButtonType {
@@ -51,6 +55,8 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsServersList)
}
KeyNavigation.tab: connection.rightButton
}
DividerType {}
@@ -66,6 +72,8 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsConnection)
}
KeyNavigation.tab: application.rightButton
}
DividerType {}
@@ -81,13 +89,14 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsApplication)
}
KeyNavigation.tab: backup.rightButton
}
DividerType {}
LabelWithButtonType {
id: backup
visible: !SettingsController.isOnTv()
Layout.fillWidth: true
text: qsTr("Backup")
@@ -97,11 +106,11 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
KeyNavigation.tab: about.rightButton
}
DividerType {
visible: !SettingsController.isOnTv()
}
DividerType {}
LabelWithButtonType {
id: about
@@ -114,6 +123,8 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAbout)
}
KeyNavigation.tab: close
}
DividerType {}
@@ -127,6 +138,8 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/bug.svg"
// Keys.onTabPressed: lastItemTabClicked(header)
clickedFunction: function() {
PageController.goToPage(PageEnum.PageDevMenu)
}
@@ -144,7 +157,9 @@ PageType {
text: qsTr("Close application")
leftImageSource: "qrc:/images/controls/x-circle.svg"
isLeftImageHoverEnabled: false
isLeftImageHoverEnabled: false
Keys.onTabPressed: lastItemTabClicked(header)
clickedFunction: function() {
PageController.closeApplication()
+105 -122
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
@@ -22,107 +35,21 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 20
onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) {
listView.positionViewAtBeginning()
}
}
KeyNavigation.tab: telegramButton
}
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() {
GC.copyToClipBoard(title)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
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
FlickableType {
id: fl
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
contentHeight: content.height
property bool isFocusable: true
ColumnLayout {
id: content
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 {
width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Image {
id: image
@@ -169,29 +96,81 @@ PageType {
text: qsTr("Contacts")
}
}
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType {
id: telegramButton
Layout.fillWidth: true
Layout.topMargin: 6
Layout.topMargin: 16
text: title
descriptionText: description
leftImageSource: imageSource
text: qsTr("Telegram group")
descriptionText: qsTr("To discuss features")
leftImageSource: "qrc:/images/controls/telegram.svg"
clickedFunction: handler
KeyNavigation.tab: mailButton
parentFlickable: fl
clickedFunction: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
}
}
DividerType {}
}
LabelWithButtonType {
id: mailButton
Layout.fillWidth: true
footer: ColumnLayout {
width: listView.width
text: qsTr("support@amnezia.org")
descriptionText: qsTr("For reviews and bug reports")
leftImageSource: "qrc:/images/controls/mail.svg"
KeyNavigation.tab: githubButton
parentFlickable: fl
clickedFunction: function() {
GC.copyToClipBoard(text)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
DividerType {}
LabelWithButtonType {
id: githubButton
Layout.fillWidth: true
text: qsTr("GitHub")
leftImageSource: "qrc:/images/controls/github.svg"
KeyNavigation.tab: websiteButton
parentFlickable: fl
clickedFunction: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
}
}
DividerType {}
LabelWithButtonType {
id: websiteButton
Layout.fillWidth: true
text: qsTr("Website")
leftImageSource: "qrc:/images/controls/amnezia.svg"
KeyNavigation.tab: checkUpdatesButton
parentFlickable: fl
clickedFunction: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
DividerType {}
CaptionTextType {
Layout.fillWidth: true
@@ -217,7 +196,6 @@ PageType {
BasicButtonType {
id: checkUpdatesButton
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 8
Layout.bottomMargin: 16
@@ -231,30 +209,35 @@ PageType {
text: qsTr("Check for updates")
KeyNavigation.tab: privacyPolicyButton
parentFlickable: fl
clickedFunc: function() {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
BasicButtonType {
id: privacyPolicyButton
id: privacyPolicyButton
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 16
Layout.topMargin: -15
implicitHeight: 25
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 16
Layout.topMargin: -15
implicitHeight: 25
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
text: qsTr("Privacy Policy")
text: qsTr("Privacy Policy")
Keys.onTabPressed: lastItemTabClicked()
parentFlickable: fl
clickedFunc: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
}
clickedFunc: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
}
}
}
}
@@ -18,88 +18,92 @@ PageType {
ListView {
id: menuContent
property bool isFocusable: true
property var selectedText
width: parent.width
height: parent.height
height: menuContent.contentItem.height
clip: true
interactive: true
interactive: false
model: ApiCountryModel
ButtonGroup {
id: containersRadioButtonGroup
}
delegate: ColumnLayout {
id: content
delegate: Item {
implicitWidth: parent.width
implicitHeight: content.implicitHeight
width: menuContent.width
height: content.implicitHeight
ColumnLayout {
id: content
RowLayout {
VerticalRadioButton {
id: containerRadioButton
anchors.fill: parent
Layout.fillWidth: true
Layout.leftMargin: 16
RowLayout {
VerticalRadioButton {
id: containerRadioButton
text: countryName
Layout.fillWidth: true
Layout.leftMargin: 16
ButtonGroup.group: containersRadioButtonGroup
text: countryName
imageSource: "qrc:/images/controls/download.svg"
ButtonGroup.group: containersRadioButtonGroup
checked: index === ApiCountryModel.currentIndex
checkable: !ConnectionController.isConnected
imageSource: "qrc:/images/controls/download.svg"
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection"))
return
}
checked: index === ApiCountryModel.currentIndex
checkable: !ConnectionController.isConnected
if (index !== ApiCountryModel.currentIndex) {
PageController.showBusyIndicator(true)
var prevIndex = ApiCountryModel.currentIndex
ApiCountryModel.currentIndex = index
if (!InstallController.updateServiceFromApi(ServersModel.defaultIndex, countryCode, countryName)) {
ApiCountryModel.currentIndex = prevIndex
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection"))
return
}
if (index !== ApiCountryModel.currentIndex) {
PageController.showBusyIndicator(true)
var prevIndex = ApiCountryModel.currentIndex
ApiCountryModel.currentIndex = index
if (!InstallController.updateServiceFromApi(ServersModel.defaultIndex, countryCode, countryName)) {
ApiCountryModel.currentIndex = prevIndex
}
}
}
MouseArea {
anchors.fill: containerRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
Keys.onEnterPressed: {
if (checkable) {
checked = true
}
containerRadioButton.clicked()
}
Keys.onReturnPressed: {
if (checkable) {
checked = true
}
containerRadioButton.clicked()
}
}
MouseArea {
anchors.fill: containerRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
Image {
Layout.rightMargin: 32
Layout.alignment: Qt.AlignRight
Keys.onEnterPressed: {
if (checkable) {
checked = true
}
containerRadioButton.clicked()
}
Keys.onReturnPressed: {
if (checkable) {
checked = true
}
containerRadioButton.clicked()
source: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
}
}
Image {
Layout.rightMargin: 32
Layout.alignment: Qt.AlignRight
source: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
DividerType {
Layout.fillWidth: true
}
}
DividerType {
Layout.fillWidth: true
}
}
}
}
@@ -15,6 +15,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
FlickableType {
id: fl
anchors.top: parent.top
@@ -30,6 +32,11 @@ PageType {
spacing: 0
Item {
id: focusItem
// KeyNavigation.tab: backButton
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
@@ -104,6 +111,9 @@ PageType {
descriptionOnTop: true
// parentFlickable: fl
// KeyNavigation.tab: passwordLabel.eyeButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@@ -131,6 +141,8 @@ PageType {
text: qsTr("Reload API config")
// Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
var headerText = qsTr("Reload API config?")
var yesButtonText = qsTr("Continue")
@@ -169,6 +181,8 @@ PageType {
text: qsTr("Remove from application")
// Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
var headerText = qsTr("Remove from application?")
var yesButtonText = qsTr("Continue")
@@ -21,6 +21,8 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
property bool pageEnabled
Component.onCompleted: {
@@ -46,15 +48,13 @@ PageType {
QtObject {
id: onlyForwardApps
readonly property string name: qsTr("Only the apps from the list should have access via VPN")
readonly property int type: routeMode.onlyForwardApps
property string name: qsTr("Only the apps from the list should have access via VPN")
property int type: routeMode.onlyForwardApps
}
QtObject {
id: allExceptApps
readonly property string name: qsTr("Apps from the list should not have access via VPN")
readonly property int type: routeMode.allExceptApps
property string name: qsTr("Apps from the list should not have access via VPN")
property int type: routeMode.allExceptApps
}
function getRouteModesModelIndex() {
@@ -66,6 +66,11 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@@ -77,6 +82,7 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: switcher
}
RowLayout {
@@ -97,6 +103,10 @@ PageType {
enabled: root.pageEnabled
KeyNavigation.tab: selector.enabled ?
selector :
searchField.textField
checked: AppSplitTunnelingModel.isTunnelingEnabled
onToggled: {
AppSplitTunnelingModel.toggleSplitTunneling(checked)
@@ -120,23 +130,25 @@ PageType {
enabled: Qt.platform.os === "android" && root.pageEnabled
KeyNavigation.tab: searchField.textField
listView: ListViewWithRadioButtonType {
rootWidth: root.width
model: root.routeModesModel
selectedIndex: getRouteModesModelIndex()
currentIndex: getRouteModesModelIndex()
clickedFunction: function() {
selector.text = selectedText
selector.closeTriggered()
if (AppSplitTunnelingModel.routeMode !== root.routeModesModel[selectedIndex].type) {
AppSplitTunnelingModel.routeMode = root.routeModesModel[selectedIndex].type
selector.close()
if (AppSplitTunnelingModel.routeMode !== root.routeModesModel[currentIndex].type) {
AppSplitTunnelingModel.routeMode = root.routeModesModel[currentIndex].type
}
}
Component.onCompleted: {
if (root.routeModesModel[selectedIndex].type === AppSplitTunnelingModel.routeMode) {
if (root.routeModesModel[currentIndex].type === AppSplitTunnelingModel.routeMode) {
selector.text = selectedText
} else {
selector.text = root.routeModesModel[0].name
@@ -146,7 +158,7 @@ PageType {
Connections {
target: AppSplitTunnelingModel
function onRouteModeChanged() {
selectedIndex = getRouteModesModelIndex()
currentIndex = getRouteModesModelIndex()
}
}
}
@@ -255,6 +267,7 @@ PageType {
textFieldPlaceholderText: qsTr("application name")
buttonImageSource: "qrc:/images/controls/plus.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
rightButtonClickedOnEnter: true
clickedFunc: function() {
@@ -268,7 +281,7 @@ PageType {
AppSplitTunnelingController.addApp(fileName)
}
} else if (Qt.platform.os === "android"){
installedAppDrawer.openTriggered()
installedAppDrawer.open()
}
PageController.showBusyIndicator(false)
@@ -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: GC.isMobile() ? switcher : switcherAutoStart
}
FlickableType {
@@ -62,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
}
@@ -80,6 +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
parentFlickable: fl
clickedFunction: function() {
@@ -101,6 +117,7 @@ PageType {
text: qsTr("Auto start")
descriptionText: qsTr("Launch the application every time the device is starts")
KeyNavigation.tab: switcherAutoConnect
parentFlickable: fl
checked: SettingsController.isAutoStartEnabled()
@@ -125,6 +142,7 @@ PageType {
text: qsTr("Auto connect")
descriptionText: qsTr("Connect to VPN on app start")
KeyNavigation.tab: switcherStartMinimized
parentFlickable: fl
checked: SettingsController.isAutoConnectEnabled()
@@ -149,6 +167,7 @@ PageType {
text: qsTr("Start minimized")
descriptionText: qsTr("Launch application minimized")
KeyNavigation.tab: labelWithButtonLanguage.rightButton
parentFlickable: fl
checked: SettingsController.isStartMinimizedEnabled()
@@ -171,10 +190,11 @@ PageType {
descriptionText: LanguageModel.currentLanguageName
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: labelWithButtonLogging.rightButton
parentFlickable: fl
clickedFunction: function() {
selectLanguageDrawer.openTriggered()
selectLanguageDrawer.open()
}
}
@@ -188,6 +208,7 @@ PageType {
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: labelWithButtonReset.rightButton
parentFlickable: fl
clickedFunction: function() {
@@ -205,6 +226,7 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: lastItemTabClicked()
parentFlickable: fl
clickedFunction: function() {
@@ -221,8 +243,15 @@ PageType {
SettingsController.clearSettings()
PageController.goToPageHome()
}
if (!GC.isMobile()) {
root.defaultActiveFocusItem.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
root.defaultActiveFocusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
@@ -238,5 +267,11 @@ PageType {
width: root.width
height: root.height
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
}
}
+13 -4
View File
@@ -17,6 +17,8 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: SettingsController
@@ -34,6 +36,11 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@@ -41,6 +48,8 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: makeBackupButton
}
FlickableType {
@@ -84,8 +93,6 @@ PageType {
text: qsTr("Make a backup")
parentFlickable: fl
clickedFunc: function() {
var fileName = ""
if (GC.isMobile()) {
@@ -104,6 +111,8 @@ PageType {
PageController.showNotificationMessage(qsTr("Backup file saved"))
}
}
KeyNavigation.tab: restoreBackupButton
}
BasicButtonType {
@@ -120,8 +129,6 @@ PageType {
text: qsTr("Restore from backup")
parentFlickable: fl
clickedFunc: function() {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
@@ -129,6 +136,8 @@ PageType {
restoreBackup(filePath)
}
}
Keys.onTabPressed: lastItemTabClicked()
}
}
}
@@ -12,8 +12,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,6 +28,8 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: amneziaDnsSwitch
}
FlickableType {
@@ -58,6 +67,8 @@ PageType {
SettingsController.toggleAmneziaDns(checked)
}
}
KeyNavigation.tab: dnsServersButton.rightButton
}
DividerType {}
@@ -70,11 +81,11 @@ PageType {
descriptionText: qsTr("When AmneziaDNS is not used or installed")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsDns)
}
KeyNavigation.tab: splitTunnelingButton.rightButton
}
DividerType {}
@@ -87,11 +98,19 @@ PageType {
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
}
Keys.onTabPressed: {
if (splitTunnelingButton2.visible) {
return splitTunnelingButton2.rightButton.forceActiveFocus()
} else if (killSwitchSwitcher.visible) {
return killSwitchSwitcher.forceActiveFocus()
} else {
lastItemTabClicked()
}
}
}
DividerType {
@@ -108,11 +127,17 @@ PageType {
descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
}
Keys.onTabPressed: {
if (killSwitchSwitcher.visible) {
return killSwitchSwitcher.forceActiveFocus()
} else {
lastItemTabClicked()
}
}
}
DividerType {
@@ -129,8 +154,6 @@ PageType {
text: qsTr("KillSwitch")
descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.")
parentFlickable: fl
checked: SettingsController.isKillSwitchEnabled()
checkable: !ConnectionController.isConnected
onCheckedChanged: {
@@ -143,6 +166,8 @@ PageType {
PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection"))
}
}
Keys.onTabPressed: lastItemTabClicked()
}
DividerType {

Some files were not shown because too many files have changed in this diff Show More