Compare commits

...

4 Commits

Author SHA1 Message Date
NickVs2015 3122c02f13 Fix black screen 2025-11-03 19:56:07 +03:00
NickVs2015 61e7cd073a Add support SafeMargins from Android 2025-11-03 19:21:06 +03:00
NickVs2015 2e7e65c1e0 add support android sdk 36 2025-10-27 20:22:46 +03:00
NickVs2015 3a6d160bce Fix qt 6.9 support 2025-10-10 19:28:53 +03:00
61 changed files with 1012 additions and 825 deletions
+2 -2
View File
@@ -469,8 +469,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
ANDROID_BUILD_PLATFORM: android-34 ANDROID_BUILD_PLATFORM: android-36
QT_VERSION: 6.7.3 QT_VERSION: 6.9.3
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools' QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
+1
View File
@@ -46,6 +46,7 @@
|fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc" |fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:windowSoftInputMode="stateUnchanged|adjustResize" android:windowSoftInputMode="stateUnchanged|adjustResize"
android:enableOnBackInvokedCallback="false"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
+3
View File
@@ -6,6 +6,9 @@
<item name="android:colorBackground">@color/black</item> <item name="android:colorBackground">@color/black</item>
<item name="android:windowActionBar">false</item> <item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:enforceNavigationBarContrast">false</item>
<item name="android:enforceStatusBarContrast">false</item>
</style> </style>
<style name="Translucent" parent="NoActionBar"> <style name="Translucent" parent="NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item>
@@ -35,6 +35,7 @@ import android.widget.Toast
import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.WindowInsetsControllerCompat
import java.io.IOException import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE import kotlin.LazyThreadSafetyMode.NONE
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@@ -170,10 +171,9 @@ class AmneziaActivity : QtActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Log.d(TAG, "Create Amnezia activity") Log.d(TAG, "Create Amnezia activity")
loadLibs() loadLibs()
window.apply {
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) // Configure window for edge-to-edge display
statusBarColor = getColor(R.color.black) configureWindowForEdgeToEdge()
}
mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
val proto = mainScope.async(Dispatchers.IO) { val proto = mainScope.async(Dispatchers.IO) {
VpnStateStore.getVpnState().vpnProto VpnStateStore.getVpnState().vpnProto
@@ -265,6 +265,49 @@ class AmneziaActivity : QtActivity() {
super.onStop() super.onStop()
} }
override fun onResume() {
super.onResume()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
window.decorView.apply {
invalidate()
postDelayed({
sendTouch(1f, 1f)
}, 100)
postDelayed({
sendTouch(2f, 2f)
}, 200)
postDelayed({
requestLayout()
invalidate()
}, 250)
}
}
}
private fun configureWindowForEdgeToEdge() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
window.apply {
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
addFlags(LayoutParams.FLAG_LAYOUT_NO_LIMITS)
statusBarColor = android.graphics.Color.TRANSPARENT
navigationBarColor = android.graphics.Color.TRANSPARENT
}
WindowInsetsControllerCompat(window, window.decorView).apply {
isAppearanceLightStatusBars = false
isAppearanceLightNavigationBars = false
}
} else {
window.apply {
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
statusBarColor = getColor(R.color.black)
}
}
}
override fun onDestroy() { override fun onDestroy() {
Log.d(TAG, "Destroy Amnezia activity") Log.d(TAG, "Destroy Amnezia activity")
unregisterBroadcastReceiver(notificationStateReceiver) unregisterBroadcastReceiver(notificationStateReceiver)
@@ -666,6 +709,43 @@ class AmneziaActivity : QtActivity() {
@Suppress("unused") @Suppress("unused")
fun isOnTv(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) fun isOnTv(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
@Suppress("unused")
fun isEdgeToEdgeEnabled(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
@Suppress("unused")
fun getStatusBarHeight(): Int {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) return 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
val heightPx = if (resourceId > 0) {
resources.getDimensionPixelSize(resourceId)
} else {
0
}
// Convert physical pixels to device-independent pixels for QML
val density = resources.displayMetrics.density
val heightDp = (heightPx / density).toInt()
return heightDp
}
@Suppress("unused")
fun getNavigationBarHeight(): Int {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) return 0
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
val heightPx = if (resourceId > 0) {
resources.getDimensionPixelSize(resourceId)
} else {
0
}
// Convert physical pixels to device-independent pixels for QML
val density = resources.displayMetrics.density
val heightDp = (heightPx / density).toInt()
return heightDp
}
@Suppress("unused") @Suppress("unused")
fun startQrCodeReader() { fun startQrCodeReader() {
Log.v(TAG, "Start camera") Log.v(TAG, "Start camera")
@@ -38,15 +38,15 @@ object AppListProvider {
} }
} }
private class App(pi: PackageInfo, pm: PackageManager, ai: ApplicationInfo = pi.applicationInfo) : Comparable<App> { private class App(pi: PackageInfo, pm: PackageManager, ai: ApplicationInfo? = pi.applicationInfo) : Comparable<App> {
val name: String? val name: String?
val packageName: String = pi.packageName val packageName: String = pi.packageName
val icon: Boolean = ai.icon != 0 val icon: Boolean = (ai?.icon ?: 0) != 0
val isLaunchable: Boolean = pm.getLaunchIntentForPackage(packageName) != null val isLaunchable: Boolean = pm.getLaunchIntentForPackage(packageName) != null
init { init {
val name = ai.loadLabel(pm).toString() val name = ai?.loadLabel(pm)?.toString()
this.name = if (name != packageName) name else null this.name = name?.takeIf { it != packageName }
} }
override fun compareTo(other: App): Int { override fun compareTo(other: App): Int {
+3 -3
View File
@@ -1,6 +1,6 @@
message("Client android ${CMAKE_ANDROID_ARCH_ABI} build") message("Client android ${CMAKE_ANDROID_ARCH_ABI} build")
set(APP_ANDROID_MIN_SDK 26) set(APP_ANDROID_MIN_SDK 28)
set(ANDROID_PLATFORM "android-${APP_ANDROID_MIN_SDK}" CACHE STRING set(ANDROID_PLATFORM "android-${APP_ANDROID_MIN_SDK}" CACHE STRING
"The minimum API level supported by the application or library" FORCE) "The minimum API level supported by the application or library" FORCE)
@@ -11,8 +11,8 @@ set_target_properties(${PROJECT} PROPERTIES
QT_ANDROID_VERSION_NAME ${CMAKE_PROJECT_VERSION} QT_ANDROID_VERSION_NAME ${CMAKE_PROJECT_VERSION}
QT_ANDROID_VERSION_CODE ${APP_ANDROID_VERSION_CODE} QT_ANDROID_VERSION_CODE ${APP_ANDROID_VERSION_CODE}
QT_ANDROID_MIN_SDK_VERSION ${APP_ANDROID_MIN_SDK} QT_ANDROID_MIN_SDK_VERSION ${APP_ANDROID_MIN_SDK}
QT_ANDROID_TARGET_SDK_VERSION 34 QT_ANDROID_TARGET_SDK_VERSION 36
QT_ANDROID_SDK_BUILD_TOOLS_REVISION 34.0.0 QT_ANDROID_SDK_BUILD_TOOLS_REVISION 36.0.0
QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
) )
@@ -202,6 +202,21 @@ bool AndroidController::isOnTv()
return callActivityMethod<jboolean>("isOnTv", "()Z"); return callActivityMethod<jboolean>("isOnTv", "()Z");
} }
bool AndroidController::isEdgeToEdgeEnabled()
{
return callActivityMethod<jboolean>("isEdgeToEdgeEnabled", "()Z");
}
int AndroidController::getStatusBarHeight()
{
return callActivityMethod<jint>("getStatusBarHeight", "()I");
}
int AndroidController::getNavigationBarHeight()
{
return callActivityMethod<jint>("getNavigationBarHeight", "()I");
}
void AndroidController::startQrReaderActivity() void AndroidController::startQrReaderActivity()
{ {
callActivityMethod("startQrCodeReader", "()V"); callActivityMethod("startQrCodeReader", "()V");
@@ -39,6 +39,9 @@ public:
QString getFileName(const QString &uri); QString getFileName(const QString &uri);
bool isCameraPresent(); bool isCameraPresent();
bool isOnTv(); bool isOnTv();
bool isEdgeToEdgeEnabled();
int getStatusBarHeight();
int getNavigationBarHeight();
void startQrReaderActivity(); void startQrReaderActivity();
void setSaveLogs(bool enabled); void setSaveLogs(bool enabled);
void exportLogsFile(const QString &fileName); void exportLogsFile(const QString &fileName);
-1
View File
@@ -131,7 +131,6 @@
<file>ui/qml/Components/SelectLanguageDrawer.qml</file> <file>ui/qml/Components/SelectLanguageDrawer.qml</file>
<file>ui/qml/Components/ServersListView.qml</file> <file>ui/qml/Components/ServersListView.qml</file>
<file>ui/qml/Components/SettingsContainersListView.qml</file> <file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Components/TransportProtoSelector.qml</file> <file>ui/qml/Components/TransportProtoSelector.qml</file>
<file>ui/qml/Components/AddSitePanel.qml</file> <file>ui/qml/Components/AddSitePanel.qml</file>
<file>ui/qml/Config/GlobalConfig.qml</file> <file>ui/qml/Config/GlobalConfig.qml</file>
@@ -431,6 +431,63 @@ bool SettingsController::isOnTv()
#endif #endif
} }
bool SettingsController::isEdgeToEdgeEnabled()
{
#ifdef Q_OS_ANDROID
return AndroidController::instance()->isEdgeToEdgeEnabled();
#else
return false;
#endif
}
int SettingsController::getStatusBarHeight()
{
#ifdef Q_OS_ANDROID
if (m_cachedStatusBarHeight < 0) {
m_cachedStatusBarHeight = AndroidController::instance()->getStatusBarHeight();
}
return m_cachedStatusBarHeight;
#else
return 0;
#endif
}
int SettingsController::getNavigationBarHeight()
{
#ifdef Q_OS_ANDROID
if (m_cachedNavigationBarHeight < 0) {
m_cachedNavigationBarHeight = AndroidController::instance()->getNavigationBarHeight();
}
return m_cachedNavigationBarHeight;
#else
return 0;
#endif
}
int SettingsController::getSafeAreaTopMargin()
{
#ifdef Q_OS_ANDROID
if (isEdgeToEdgeEnabled()) {
int height = getStatusBarHeight();
int result = height > 0 ? height : 40; // fallback to 40 if system returns 0
return result;
}
#endif
return 0;
}
int SettingsController::getSafeAreaBottomMargin()
{
#ifdef Q_OS_ANDROID
if (isEdgeToEdgeEnabled()) {
int height = getNavigationBarHeight();
int result = height > 0 ? height : 56; // fallback to 56 if system returns 0
return result;
}
#endif
return 0;
}
bool SettingsController::isHomeAdLabelVisible() bool SettingsController::isHomeAdLabelVisible()
{ {
return m_settings->isHomeAdLabelVisible(); return m_settings->isHomeAdLabelVisible();
@@ -33,6 +33,8 @@ public:
Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged) Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged)
Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged) Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged)
Q_PROPERTY(int safeAreaTopMargin READ getSafeAreaTopMargin CONSTANT)
Q_PROPERTY(int safeAreaBottomMargin READ getSafeAreaBottomMargin CONSTANT)
public slots: public slots:
void toggleAmneziaDns(bool enable); void toggleAmneziaDns(bool enable);
@@ -96,6 +98,11 @@ public slots:
void toggleDevGatewayEnv(bool enabled); void toggleDevGatewayEnv(bool enabled);
bool isOnTv(); bool isOnTv();
bool isEdgeToEdgeEnabled();
int getStatusBarHeight();
int getNavigationBarHeight();
int getSafeAreaTopMargin();
int getSafeAreaBottomMargin();
bool isHomeAdLabelVisible(); bool isHomeAdLabelVisible();
void disableHomeAdLabel(); void disableHomeAdLabel();
@@ -134,6 +141,9 @@ private:
QSharedPointer<LanguageModel> m_languageModel; QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<SitesModel> m_sitesModel; QSharedPointer<SitesModel> m_sitesModel;
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel; QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
mutable int m_cachedStatusBarHeight = -1;
mutable int m_cachedNavigationBarHeight = -1;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
QString m_appVersion; QString m_appVersion;
+1 -1
View File
@@ -32,7 +32,7 @@ DrawerType2 {
spacing: 8 spacing: 8
onImplicitHeightChanged: { onImplicitHeightChanged: {
root.expandedHeight = content.implicitHeight + 32 root.expandedHeight = content.implicitHeight + 32 + SettingsController.safeAreaBottomMargin
} }
Header2TextType { Header2TextType {
+1 -1
View File
@@ -15,7 +15,7 @@ Popup {
leftMargin: 25 leftMargin: 25
rightMargin: 25 rightMargin: 25
bottomMargin: 70 bottomMargin: 70 + SettingsController.safeAreaBottomMargin
width: parent.width - leftMargin - rightMargin width: parent.width - leftMargin - rightMargin
+1 -1
View File
@@ -68,7 +68,7 @@ PageType {
objectName: "homeColumnLayout" objectName: "homeColumnLayout"
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 12 anchors.topMargin: 12 + SettingsController.safeAreaTopMargin
anchors.bottomMargin: 16 anchors.bottomMargin: 16
AdLabel { AdLabel {
@@ -25,7 +25,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -23,7 +23,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
+1 -1
View File
@@ -25,7 +25,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -23,7 +23,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -30,7 +30,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -31,7 +31,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -31,7 +31,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
+1 -1
View File
@@ -25,7 +25,7 @@ PageType {
BaseHeaderType { BaseHeaderType {
id: header id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24 + SettingsController.safeAreaTopMargin
Layout.bottomMargin: 16 Layout.bottomMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
+1 -1
View File
@@ -20,7 +20,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -23,7 +23,7 @@ PageType {
id: listView id: listView
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
anchors.bottomMargin: 24 anchors.bottomMargin: 24
model: ApiDevicesModel model: ApiDevicesModel
@@ -79,7 +79,7 @@ PageType {
id: listView id: listView
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
anchors.bottomMargin: 24 anchors.bottomMargin: 24
model: instructionsModel model: instructionsModel
@@ -1,243 +1,243 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Dialogs import QtQuick.Dialogs
import QtCore import QtCore
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import PageEnum 1.0 import PageEnum 1.0
import Style 1.0 import Style 1.0
import "./" import "./"
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Config" import "../Config"
import "../Components" import "../Components"
PageType { PageType {
id: root id: root
property string configExtension: ".conf" property string configExtension: ".conf"
property string configCaption: qsTr("Save AmneziaVPN config") property string configCaption: qsTr("Save AmneziaVPN config")
BackButtonType { BackButtonType {
id: backButton id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
listView.positionViewAtBeginning() listView.positionViewAtBeginning()
} }
} }
} }
ListViewType { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
model: ApiCountryModel model: ApiCountryModel
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
BaseHeaderType { BaseHeaderType {
id: header id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
headerText: qsTr("Configuration Files") headerText: qsTr("Configuration Files")
descriptionText: qsTr("For router setup or the AmneziaWG app") descriptionText: qsTr("For router setup or the AmneziaWG app")
} }
} }
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 6 Layout.topMargin: 6
text: countryName text: countryName
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : "" descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
hideDescription: isWorkerExpired ? true : false hideDescription: isWorkerExpired ? true : false
descriptionColor: AmneziaStyle.color.vibrantRed descriptionColor: AmneziaStyle.color.vibrantRed
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg" leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg" rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg"
clickedFunction: function() { clickedFunction: function() {
if (isIssued) { if (isIssued) {
moreOptionsDrawer.countryName = countryName moreOptionsDrawer.countryName = countryName
moreOptionsDrawer.countryCode = countryCode moreOptionsDrawer.countryCode = countryCode
moreOptionsDrawer.openTriggered() moreOptionsDrawer.openTriggered()
} else { } else {
issueConfig(countryCode) issueConfig(countryCode)
} }
} }
} }
DividerType {} DividerType {}
} }
} }
DrawerType2 { DrawerType2 {
id: moreOptionsDrawer id: moreOptionsDrawer
property string countryName property string countryName
property string countryCode property string countryCode
anchors.fill: parent anchors.fill: parent
expandedHeight: parent.height * 0.4375 expandedHeight: parent.height * 0.4375
expandedStateContent: Item { expandedStateContent: Item {
implicitHeight: moreOptionsDrawer.expandedHeight implicitHeight: moreOptionsDrawer.expandedHeight
BackButtonType { BackButtonType {
id: moreOptionsDrawerBackButton id: moreOptionsDrawerBackButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 16 anchors.topMargin: 16
backButtonFunction: function() { backButtonFunction: function() {
moreOptionsDrawer.closeTriggered() moreOptionsDrawer.closeTriggered()
} }
} }
ListViewType { ListViewType {
id: drawerListView id: drawerListView
anchors.top: moreOptionsDrawerBackButton.bottom anchors.top: moreOptionsDrawerBackButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
header: ColumnLayout { header: ColumnLayout {
width: drawerListView.width width: drawerListView.width
Header2Type { Header2Type {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file") headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
} }
} }
model: 1 // fake model to force the ListView to be created without a model model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout { delegate: ColumnLayout {
width: drawerListView.width width: drawerListView.width
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
text: qsTr("Generate a new configuration file") text: qsTr("Generate a new configuration file")
descriptionText: qsTr("The previously created one will stop working") descriptionText: qsTr("The previously created one will stop working")
clickedFunction: function() { clickedFunction: function() {
showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
} }
} }
DividerType {} DividerType {}
} }
footer: ColumnLayout { footer: ColumnLayout {
width: drawerListView.width width: drawerListView.width
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
text: qsTr("Revoke the current configuration file") text: qsTr("Revoke the current configuration file")
clickedFunction: function() { clickedFunction: function() {
showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
} }
} }
DividerType {} DividerType {}
} }
} }
} }
} }
function issueConfig(countryCode) { function issueConfig(countryCode) {
var fileName = "" var fileName = ""
if (GC.isMobile()) { if (GC.isMobile()) {
fileName = countryCode + configExtension fileName = countryCode + configExtension
} else { } else {
fileName = SystemController.getFileName(configCaption, fileName = SystemController.getFileName(configCaption,
qsTr("Config files (*" + configExtension + ")"), qsTr("Config files (*" + configExtension + ")"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode, StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode,
true, true,
configExtension) configExtension)
} }
if (fileName !== "") { if (fileName !== "") {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
let result = ApiConfigsController.exportNativeConfig(countryCode, fileName) let result = ApiConfigsController.exportNativeConfig(countryCode, fileName)
if (result) { if (result) {
ApiSettingsController.getAccountInfo(true) ApiSettingsController.getAccountInfo(true)
} }
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
if (result) { if (result) {
PageController.showNotificationMessage(qsTr("Config file saved")) PageController.showNotificationMessage(qsTr("Config file saved"))
} }
} }
} }
function revokeConfig(countryCode) { function revokeConfig(countryCode) {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
let result = ApiConfigsController.revokeNativeConfig(countryCode) let result = ApiConfigsController.revokeNativeConfig(countryCode)
if (result) { if (result) {
ApiSettingsController.getAccountInfo(true) ApiSettingsController.getAccountInfo(true)
} }
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
if (result) { if (result) {
PageController.showNotificationMessage(qsTr("The config has been revoked")) PageController.showNotificationMessage(qsTr("The config has been revoked"))
} }
} }
function showQuestion(isConfigIssue, countryCode, countryName) { function showQuestion(isConfigIssue, countryCode, countryName) {
var headerText var headerText
if (isConfigIssue) { if (isConfigIssue) {
headerText = qsTr("Generate a new %1 configuration file?").arg(countryName) headerText = qsTr("Generate a new %1 configuration file?").arg(countryName)
} else { } else {
headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName) headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName)
} }
var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it") var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it")
var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue") var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue")
var noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() { var yesButtonFunction = function() {
if (isConfigIssue) { if (isConfigIssue) {
issueConfig(countryCode) issueConfig(countryCode)
} else { } else {
revokeConfig(countryCode) revokeConfig(countryCode)
} }
moreOptionsDrawer.closeTriggered() moreOptionsDrawer.closeTriggered()
} }
var noButtonFunction = function() {} var noButtonFunction = function() {}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
@@ -93,7 +93,7 @@ PageType {
id: backButton id: backButton
objectName: "backButton" objectName: "backButton"
Layout.topMargin: 20 Layout.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
HeaderTypeWithButton { HeaderTypeWithButton {
@@ -59,7 +59,7 @@ PageType {
id: listView id: listView
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
anchors.bottomMargin: 24 anchors.bottomMargin: 24
model: supportModel model: supportModel
@@ -74,7 +74,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
BackButtonType { BackButtonType {
id: backButton id: backButton
@@ -216,7 +216,7 @@ PageType {
Rectangle { Rectangle {
anchors.fill: addAppButton anchors.fill: addAppButton
anchors.bottomMargin: -24 anchors.bottomMargin: -24 - SettingsController.safeAreaBottomMargin
color: AmneziaStyle.color.midnightBlack color: AmneziaStyle.color.midnightBlack
opacity: 0.8 opacity: 0.8
} }
@@ -232,7 +232,7 @@ PageType {
anchors.topMargin: 24 anchors.topMargin: 24
anchors.rightMargin: 16 anchors.rightMargin: 16
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.bottomMargin: 24 anchors.bottomMargin: 24 + SettingsController.safeAreaBottomMargin
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: searchField id: searchField
@@ -20,7 +20,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
+1 -1
View File
@@ -40,7 +40,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -20,7 +20,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
+163 -163
View File
@@ -1,163 +1,163 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import PageEnum 1.0 import PageEnum 1.0
import Style 1.0 import Style 1.0
import "./" import "./"
import "../Controls2" import "../Controls2"
import "../Config" import "../Config"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Components" import "../Components"
PageType { PageType {
id: root id: root
BackButtonType { BackButtonType {
id: backButton id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
listView.positionViewAtBeginning() listView.positionViewAtBeginning()
} }
} }
} }
ListViewType { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
enabled: !isServerFromApi enabled: !isServerFromApi
Component.onCompleted: { Component.onCompleted: {
if (isServerFromApi) { if (isServerFromApi) {
PageController.showNotificationMessage(qsTr("Default server does not support custom DNS")) PageController.showNotificationMessage(qsTr("Default server does not support custom DNS"))
} }
} }
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
spacing: 16 spacing: 16
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
headerText: qsTr("DNS servers") headerText: qsTr("DNS servers")
} }
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
text: qsTr("If AmneziaDNS is not used or installed") text: qsTr("If AmneziaDNS is not used or installed")
} }
} }
model: 1 // fake model to force the ListView to be created without a model model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
spacing: 16 spacing: 16
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: primaryDns id: primaryDns
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
headerText: qsTr("Primary DNS") headerText: qsTr("Primary DNS")
textField.text: SettingsController.primaryDns textField.text: SettingsController.primaryDns
textField.validator: RegularExpressionValidator { textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp() regularExpression: InstallController.ipAddressRegExp()
} }
} }
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: secondaryDns id: secondaryDns
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
headerText: qsTr("Secondary DNS") headerText: qsTr("Secondary DNS")
textField.text: SettingsController.secondaryDns textField.text: SettingsController.secondaryDns
textField.validator: RegularExpressionValidator { textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp() regularExpression: InstallController.ipAddressRegExp()
} }
} }
BasicButtonType { BasicButtonType {
id: restoreDefaultButton id: restoreDefaultButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.paleGray textColor: AmneziaStyle.color.paleGray
borderWidth: 1 borderWidth: 1
text: qsTr("Restore default") text: qsTr("Restore default")
clickedFunc: function() { clickedFunc: function() {
var headerText = qsTr("Restore default DNS settings?") var headerText = qsTr("Restore default DNS settings?")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() { var yesButtonFunction = function() {
SettingsController.primaryDns = "1.1.1.1" SettingsController.primaryDns = "1.1.1.1"
primaryDns.textField.text = SettingsController.primaryDns primaryDns.textField.text = SettingsController.primaryDns
SettingsController.secondaryDns = "1.0.0.1" SettingsController.secondaryDns = "1.0.0.1"
secondaryDns.textField.text = SettingsController.secondaryDns secondaryDns.textField.text = SettingsController.secondaryDns
PageController.showNotificationMessage(qsTr("Settings have been reset")) PageController.showNotificationMessage(qsTr("Settings have been reset"))
} }
var noButtonFunction = function() { var noButtonFunction = function() {
} }
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
BasicButtonType { BasicButtonType {
id: saveButton id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
text: qsTr("Save") text: qsTr("Save")
clickedFunc: function() { clickedFunc: function() {
if (primaryDns.textField.text !== SettingsController.primaryDns) { if (primaryDns.textField.text !== SettingsController.primaryDns) {
SettingsController.primaryDns = primaryDns.textField.text SettingsController.primaryDns = primaryDns.textField.text
} }
if (secondaryDns.textField.text !== SettingsController.secondaryDns) { if (secondaryDns.textField.text !== SettingsController.secondaryDns) {
SettingsController.secondaryDns = secondaryDns.textField.text SettingsController.secondaryDns = secondaryDns.textField.text
} }
PageController.showNotificationMessage(qsTr("Settings saved")) PageController.showNotificationMessage(qsTr("Settings saved"))
} }
} }
} }
} }
} }
@@ -17,7 +17,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
FlickableType { FlickableType {
@@ -30,7 +30,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
BackButtonType { BackButtonType {
id: backButton id: backButton
+1 -1
View File
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -34,7 +34,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
FlickableType { FlickableType {
@@ -19,7 +19,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
BackButtonType { BackButtonType {
id: backButton id: backButton
@@ -62,7 +62,7 @@ PageType {
objectName: "mainLayout" objectName: "mainLayout"
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
spacing: 4 spacing: 4
@@ -27,7 +27,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -25,7 +25,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
BackButtonType { BackButtonType {
id: backButton id: backButton
@@ -81,18 +81,18 @@ PageType {
} }
} }
ColumnLayout { ColumnLayout {
id: header id: header
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
BackButtonType { BackButtonType {
id: backButton id: backButton
} }
HeaderTypeWithSwitcher { HeaderTypeWithSwitcher {
Layout.fillWidth: true Layout.fillWidth: true
@@ -1,179 +1,179 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Dialogs import QtQuick.Dialogs
import PageEnum 1.0 import PageEnum 1.0
import Style 1.0 import Style 1.0
import "./" import "./"
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Config" import "../Config"
import "../Components" import "../Components"
PageType { PageType {
id: root id: root
BackButtonType { BackButtonType {
id: backButton id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
listView.positionViewAtBeginning() listView.positionViewAtBeginning()
} }
} }
} }
ListViewType { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 8
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.bottomMargin: 32 Layout.bottomMargin: 32
headerText: ApiServicesModel.getSelectedServiceData("name") headerText: ApiServicesModel.getSelectedServiceData("name")
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
} }
} }
model: inputFields model: inputFields
spacing: 0 spacing: 0
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
LabelWithImageType { LabelWithImageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
imageSource: imagePath imageSource: imagePath
leftText: lText leftText: lText
rightText: rText rightText: rText
visible: isVisible visible: isVisible
} }
} }
footer: ColumnLayout { footer: ColumnLayout {
width: listView.width width: listView.width
spacing: 0 spacing: 0
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
onLinkActivated: function(link) { onLinkActivated: function(link) {
Qt.openUrlExternally(link) Qt.openUrlExternally(link)
} }
textFormat: Text.RichText textFormat: Text.RichText
text: { text: {
var text = ApiServicesModel.getSelectedServiceData("features") var text = ApiServicesModel.getSelectedServiceData("features")
return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")).replace("/free", "") // todo link should come from gateway return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")).replace("/free", "") // todo link should come from gateway
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
} }
} }
BasicButtonType { BasicButtonType {
id: continueButton id: continueButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.bottomMargin: 32 Layout.bottomMargin: 32
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
text: qsTr("Connect") text: qsTr("Connect")
clickedFunc: function() { clickedFunc: function() {
var endpoint = ApiServicesModel.getStoreEndpoint() var endpoint = ApiServicesModel.getStoreEndpoint()
if (endpoint !== undefined && endpoint !== "") { if (endpoint !== undefined && endpoint !== "") {
Qt.openUrlExternally(endpoint) Qt.openUrlExternally(endpoint)
PageController.closePage() PageController.closePage()
PageController.closePage() PageController.closePage()
} else { } else {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
ApiConfigsController.importServiceFromGateway() ApiConfigsController.importServiceFromGateway()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
} }
} }
} }
} }
property list<QtObject> inputFields: [ property list<QtObject> inputFields: [
region, region,
price, price,
timeLimit, timeLimit,
speed, speed,
features features
] ]
QtObject { QtObject {
id: region id: region
readonly property string imagePath: "qrc:/images/controls/map-pin.svg" readonly property string imagePath: "qrc:/images/controls/map-pin.svg"
readonly property string lText: qsTr("For the region") readonly property string lText: qsTr("For the region")
readonly property string rText: ApiServicesModel.getSelectedServiceData("region") readonly property string rText: ApiServicesModel.getSelectedServiceData("region")
property bool isVisible: true property bool isVisible: true
} }
QtObject { QtObject {
id: price id: price
readonly property string imagePath: "qrc:/images/controls/tag.svg" readonly property string imagePath: "qrc:/images/controls/tag.svg"
readonly property string lText: qsTr("Price") readonly property string lText: qsTr("Price")
readonly property string rText: ApiServicesModel.getSelectedServiceData("price") readonly property string rText: ApiServicesModel.getSelectedServiceData("price")
property bool isVisible: true property bool isVisible: true
} }
QtObject { QtObject {
id: timeLimit id: timeLimit
readonly property string imagePath: "qrc:/images/controls/history.svg" readonly property string imagePath: "qrc:/images/controls/history.svg"
readonly property string lText: qsTr("Work period") readonly property string lText: qsTr("Work period")
readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit") readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit")
property bool isVisible: rText !== "" property bool isVisible: rText !== ""
} }
QtObject { QtObject {
id: speed id: speed
readonly property string imagePath: "qrc:/images/controls/gauge.svg" readonly property string imagePath: "qrc:/images/controls/gauge.svg"
readonly property string lText: qsTr("Speed") readonly property string lText: qsTr("Speed")
readonly property string rText: ApiServicesModel.getSelectedServiceData("speed") readonly property string rText: ApiServicesModel.getSelectedServiceData("speed")
property bool isVisible: true property bool isVisible: true
} }
QtObject { QtObject {
id: features id: features
readonly property string imagePath: "qrc:/images/controls/info.svg" readonly property string imagePath: "qrc:/images/controls/info.svg"
readonly property string lText: qsTr("Features") readonly property string lText: qsTr("Features")
readonly property string rText: "" readonly property string rText: ""
property bool isVisible: true property bool isVisible: true
} }
} }
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
Layout.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -41,7 +41,7 @@ PageType {
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible() property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24 + SettingsController.safeAreaTopMargin
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
@@ -19,7 +19,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
+1 -1
View File
@@ -40,7 +40,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -35,7 +35,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -41,7 +41,7 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
@@ -19,7 +19,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
@@ -22,7 +22,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onActiveFocusChanged: { onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) { if(backButton.enabled && backButton.activeFocus) {
+1 -1
View File
@@ -173,7 +173,7 @@ PageType {
HeaderTypeWithButton { HeaderTypeWithButton {
id: header id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24 + SettingsController.safeAreaTopMargin
headerText: qsTr("Share VPN Access") headerText: qsTr("Share VPN Access")
+2 -2
View File
@@ -47,7 +47,7 @@ PageType {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
} }
Text { Text {
@@ -55,7 +55,7 @@ PageType {
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.rightMargin: 16 anchors.rightMargin: 16
+168 -168
View File
@@ -1,168 +1,168 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Dialogs import QtQuick.Dialogs
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import PageEnum 1.0 import PageEnum 1.0
import ContainerProps 1.0 import ContainerProps 1.0
import Style 1.0 import Style 1.0
import "./" import "./"
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Components" import "../Components"
import "../Config" import "../Config"
PageType { PageType {
id: root id: root
BackButtonType { BackButtonType {
id: backButton id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: { onFocusChanged: {
if (this.activeFocus) { if (this.activeFocus) {
listView.positionViewAtBeginning() listView.positionViewAtBeginning()
} }
} }
} }
ListViewType { ListViewType {
id: listView id: listView
property string headerText: "" property string headerText: ""
property string configContentHeaderText: "" property string configContentHeaderText: ""
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.topMargin: 24 Layout.topMargin: 24
headerText: qsTr("Full access to the server and VPN") headerText: qsTr("Full access to the server and VPN")
} }
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") + text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") +
qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ") qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ")
color: AmneziaStyle.color.mutedGray color: AmneziaStyle.color.mutedGray
} }
DropDownType { DropDownType {
id: serverSelector id: serverSelector
objectName: "serverSelector" objectName: "serverSelector"
signal severSelectorIndexChanged signal severSelectorIndexChanged
property int currentIndex: 0 property int currentIndex: 0
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.topMargin: 16 Layout.topMargin: 16
drawerHeight: 0.4375 drawerHeight: 0.4375
drawerParent: root drawerParent: root
descriptionText: qsTr("Server") descriptionText: qsTr("Server")
headerText: qsTr("Server") headerText: qsTr("Server")
listView: ListViewWithRadioButtonType { listView: ListViewWithRadioButtonType {
id: serverSelectorListView id: serverSelectorListView
rootWidth: root.width rootWidth: root.width
imageSource: "qrc:/images/controls/check.svg" imageSource: "qrc:/images/controls/check.svg"
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxyServersModel id: proxyServersModel
sourceModel: ServersModel sourceModel: ServersModel
filters: [ filters: [
ValueFilter { ValueFilter {
roleName: "hasWriteAccess" roleName: "hasWriteAccess"
value: true value: true
} }
] ]
} }
clickedFunction: function() { clickedFunction: function() {
handler() handler()
if (serverSelector.currentIndex !== serverSelectorListView.selectedIndex) { if (serverSelector.currentIndex !== serverSelectorListView.selectedIndex) {
serverSelector.currentIndex = serverSelectorListView.selectedIndex serverSelector.currentIndex = serverSelectorListView.selectedIndex
serverSelector.severSelectorIndexChanged() serverSelector.severSelectorIndexChanged()
} }
listView.headerText = qsTr("Accessing ") + serverSelector.text listView.headerText = qsTr("Accessing ") + serverSelector.text
listView.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text listView.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
serverSelector.closeTriggered() serverSelector.closeTriggered()
} }
Component.onCompleted: { Component.onCompleted: {
serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ? serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ?
proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0 proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0
serverSelectorListView.triggerCurrentItem() serverSelectorListView.triggerCurrentItem()
} }
function handler() { function handler() {
serverSelector.text = selectedText serverSelector.text = selectedText
ServersModel.processedIndex = proxyServersModel.mapToSource(selectedIndex) ServersModel.processedIndex = proxyServersModel.mapToSource(selectedIndex)
} }
} }
} }
} }
model: 1 // fake model to force the ListView to be created without a model model: 1 // fake model to force the ListView to be created without a model
spacing: 0 spacing: 0
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
BasicButtonType { BasicButtonType {
id: shareButton id: shareButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
text: qsTr("Share") text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg" leftImageSource: "qrc:/images/controls/share-2.svg"
clickedFunc: function() { clickedFunc: function() {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) { if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) {
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
ExportController.exportErrorOccurred(qsTr("Access error!")) ExportController.exportErrorOccurred(qsTr("Access error!"))
return return
} else { } else {
ExportController.generateFullAccessConfig() ExportController.generateFullAccessConfig()
} }
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
PageController.goToShareConnectionPage(listView.headerText, listView.configContentHeaderText, "", ".vpn", "amnezia_config") PageController.goToShareConnectionPage(listView.headerText, listView.configContentHeaderText, "", ".vpn", "amnezia_config")
} }
} }
} }
} }
} }
+1 -1
View File
@@ -306,7 +306,7 @@ PageType {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
topPadding: 8 topPadding: 8
bottomPadding: 8 bottomPadding: 8 + SettingsController.safeAreaBottomMargin
leftPadding: 96 leftPadding: 96
rightPadding: 96 rightPadding: 96
+21 -2
View File
@@ -16,6 +16,26 @@ Window {
id: root id: root
objectName: "mainWindow" objectName: "mainWindow"
Connections {
target: Qt.application
function onStateChanged() {
if (Qt.platform.os === "android" && Qt.application.state === Qt.ApplicationActive) {
refreshTimer.restart()
}
}
}
Timer {
id: refreshTimer
interval: 150
repeat: false
onTriggered: {
if (Qt.platform.os === "android" && SettingsController.isEdgeToEdgeEnabled()) {
console.log("QML: Application resumed with edge-to-edge")
}
}
}
visible: true visible: true
width: GC.screenWidth width: GC.screenWidth
height: GC.screenHeight height: GC.screenHeight
@@ -111,7 +131,6 @@ Window {
PageStart { PageStart {
objectName: "pageStart" objectName: "pageStart"
width: root.width width: root.width
height: root.height height: root.height
} }
@@ -164,7 +183,7 @@ Window {
id: privateKeyPassphraseDrawer id: privateKeyPassphraseDrawer
anchors.fill: parent anchors.fill: parent
expandedHeight: root.height * 0.35 expandedHeight: root.height * 0.35 + SettingsController.safeAreaBottomMargin
expandedStateContent: ColumnLayout { expandedStateContent: ColumnLayout {
anchors.top: parent.top anchors.top: parent.top