mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-02 08:33:38 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3122c02f13 | |||
| 61e7cd073a | |||
| 2e7e65c1e0 | |||
| 3a6d160bce |
@@ -469,8 +469,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
ANDROID_BUILD_PLATFORM: android-34
|
||||
QT_VERSION: 6.7.3
|
||||
ANDROID_BUILD_PLATFORM: android-36
|
||||
QT_VERSION: 6.9.3
|
||||
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc"
|
||||
android:launchMode="singleInstance"
|
||||
android:windowSoftInputMode="stateUnchanged|adjustResize"
|
||||
android:enableOnBackInvokedCallback="false"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<item name="android:colorBackground">@color/black</item>
|
||||
<item name="android:windowActionBar">false</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 name="Translucent" parent="NoActionBar">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.widget.Toast
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import java.io.IOException
|
||||
import kotlin.LazyThreadSafetyMode.NONE
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@@ -170,10 +171,9 @@ class AmneziaActivity : QtActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
Log.d(TAG, "Create Amnezia activity")
|
||||
loadLibs()
|
||||
window.apply {
|
||||
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
statusBarColor = getColor(R.color.black)
|
||||
}
|
||||
|
||||
// Configure window for edge-to-edge display
|
||||
configureWindowForEdgeToEdge()
|
||||
mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
val proto = mainScope.async(Dispatchers.IO) {
|
||||
VpnStateStore.getVpnState().vpnProto
|
||||
@@ -265,6 +265,49 @@ class AmneziaActivity : QtActivity() {
|
||||
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() {
|
||||
Log.d(TAG, "Destroy Amnezia activity")
|
||||
unregisterBroadcastReceiver(notificationStateReceiver)
|
||||
@@ -666,6 +709,43 @@ class AmneziaActivity : QtActivity() {
|
||||
@Suppress("unused")
|
||||
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")
|
||||
fun startQrCodeReader() {
|
||||
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 packageName: String = pi.packageName
|
||||
val icon: Boolean = ai.icon != 0
|
||||
val icon: Boolean = (ai?.icon ?: 0) != 0
|
||||
val isLaunchable: Boolean = pm.getLaunchIntentForPackage(packageName) != null
|
||||
|
||||
init {
|
||||
val name = ai.loadLabel(pm).toString()
|
||||
this.name = if (name != packageName) name else null
|
||||
val name = ai?.loadLabel(pm)?.toString()
|
||||
this.name = name?.takeIf { it != packageName }
|
||||
}
|
||||
|
||||
override fun compareTo(other: App): Int {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
"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_CODE ${APP_ANDROID_VERSION_CODE}
|
||||
QT_ANDROID_MIN_SDK_VERSION ${APP_ANDROID_MIN_SDK}
|
||||
QT_ANDROID_TARGET_SDK_VERSION 34
|
||||
QT_ANDROID_SDK_BUILD_TOOLS_REVISION 34.0.0
|
||||
QT_ANDROID_TARGET_SDK_VERSION 36
|
||||
QT_ANDROID_SDK_BUILD_TOOLS_REVISION 36.0.0
|
||||
QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
|
||||
)
|
||||
|
||||
|
||||
@@ -202,6 +202,21 @@ bool AndroidController::isOnTv()
|
||||
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()
|
||||
{
|
||||
callActivityMethod("startQrCodeReader", "()V");
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
QString getFileName(const QString &uri);
|
||||
bool isCameraPresent();
|
||||
bool isOnTv();
|
||||
bool isEdgeToEdgeEnabled();
|
||||
int getStatusBarHeight();
|
||||
int getNavigationBarHeight();
|
||||
void startQrReaderActivity();
|
||||
void setSaveLogs(bool enabled);
|
||||
void exportLogsFile(const QString &fileName);
|
||||
|
||||
@@ -131,7 +131,6 @@
|
||||
<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/TransportProtoSelector.qml</file>
|
||||
<file>ui/qml/Components/AddSitePanel.qml</file>
|
||||
<file>ui/qml/Config/GlobalConfig.qml</file>
|
||||
|
||||
@@ -431,6 +431,63 @@ bool SettingsController::isOnTv()
|
||||
#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()
|
||||
{
|
||||
return m_settings->isHomeAdLabelVisible();
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
|
||||
Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged)
|
||||
Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged)
|
||||
Q_PROPERTY(int safeAreaTopMargin READ getSafeAreaTopMargin CONSTANT)
|
||||
Q_PROPERTY(int safeAreaBottomMargin READ getSafeAreaBottomMargin CONSTANT)
|
||||
|
||||
public slots:
|
||||
void toggleAmneziaDns(bool enable);
|
||||
@@ -96,6 +98,11 @@ public slots:
|
||||
void toggleDevGatewayEnv(bool enabled);
|
||||
|
||||
bool isOnTv();
|
||||
bool isEdgeToEdgeEnabled();
|
||||
int getStatusBarHeight();
|
||||
int getNavigationBarHeight();
|
||||
int getSafeAreaTopMargin();
|
||||
int getSafeAreaBottomMargin();
|
||||
|
||||
bool isHomeAdLabelVisible();
|
||||
void disableHomeAdLabel();
|
||||
@@ -134,6 +141,9 @@ private:
|
||||
QSharedPointer<LanguageModel> m_languageModel;
|
||||
QSharedPointer<SitesModel> m_sitesModel;
|
||||
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
|
||||
|
||||
mutable int m_cachedStatusBarHeight = -1;
|
||||
mutable int m_cachedNavigationBarHeight = -1;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QString m_appVersion;
|
||||
|
||||
@@ -32,7 +32,7 @@ DrawerType2 {
|
||||
spacing: 8
|
||||
|
||||
onImplicitHeightChanged: {
|
||||
root.expandedHeight = content.implicitHeight + 32
|
||||
root.expandedHeight = content.implicitHeight + 32 + SettingsController.safeAreaBottomMargin
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
|
||||
@@ -15,7 +15,7 @@ Popup {
|
||||
|
||||
leftMargin: 25
|
||||
rightMargin: 25
|
||||
bottomMargin: 70
|
||||
bottomMargin: 70 + SettingsController.safeAreaBottomMargin
|
||||
|
||||
width: parent.width - leftMargin - rightMargin
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ PageType {
|
||||
objectName: "homeColumnLayout"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 12
|
||||
anchors.topMargin: 12 + SettingsController.safeAreaTopMargin
|
||||
anchors.bottomMargin: 16
|
||||
|
||||
AdLabel {
|
||||
|
||||
@@ -25,7 +25,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -23,7 +23,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -25,7 +25,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -23,7 +23,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -30,7 +30,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -31,7 +31,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -31,7 +31,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -25,7 +25,7 @@ PageType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.topMargin: 24 + SettingsController.safeAreaTopMargin
|
||||
Layout.bottomMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
@@ -20,7 +20,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -23,7 +23,7 @@ PageType {
|
||||
id: listView
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
model: ApiDevicesModel
|
||||
|
||||
@@ -79,7 +79,7 @@ PageType {
|
||||
id: listView
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
model: instructionsModel
|
||||
|
||||
@@ -1,243 +1,243 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import QtCore
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
property string configExtension: ".conf"
|
||||
property string configCaption: qsTr("Save AmneziaVPN config")
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
model: ApiCountryModel
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Configuration Files")
|
||||
descriptionText: qsTr("For router setup or the AmneziaWG app")
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 6
|
||||
|
||||
text: countryName
|
||||
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
|
||||
hideDescription: isWorkerExpired ? true : false
|
||||
descriptionColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
|
||||
rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
if (isIssued) {
|
||||
moreOptionsDrawer.countryName = countryName
|
||||
moreOptionsDrawer.countryCode = countryCode
|
||||
moreOptionsDrawer.openTriggered()
|
||||
} else {
|
||||
issueConfig(countryCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: moreOptionsDrawer
|
||||
|
||||
property string countryName
|
||||
property string countryCode
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: moreOptionsDrawer.expandedHeight
|
||||
|
||||
BackButtonType {
|
||||
id: moreOptionsDrawerBackButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() {
|
||||
moreOptionsDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: drawerListView
|
||||
|
||||
anchors.top: moreOptionsDrawerBackButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
header: ColumnLayout {
|
||||
width: drawerListView.width
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: drawerListView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Generate a new configuration file")
|
||||
descriptionText: qsTr("The previously created one will stop working")
|
||||
|
||||
clickedFunction: function() {
|
||||
showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
|
||||
footer: ColumnLayout {
|
||||
width: drawerListView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Revoke the current configuration file")
|
||||
|
||||
clickedFunction: function() {
|
||||
showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function issueConfig(countryCode) {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = countryCode + configExtension
|
||||
} else {
|
||||
fileName = SystemController.getFileName(configCaption,
|
||||
qsTr("Config files (*" + configExtension + ")"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode,
|
||||
true,
|
||||
configExtension)
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
let result = ApiConfigsController.exportNativeConfig(countryCode, fileName)
|
||||
if (result) {
|
||||
ApiSettingsController.getAccountInfo(true)
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
if (result) {
|
||||
PageController.showNotificationMessage(qsTr("Config file saved"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function revokeConfig(countryCode) {
|
||||
PageController.showBusyIndicator(true)
|
||||
let result = ApiConfigsController.revokeNativeConfig(countryCode)
|
||||
if (result) {
|
||||
ApiSettingsController.getAccountInfo(true)
|
||||
}
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
if (result) {
|
||||
PageController.showNotificationMessage(qsTr("The config has been revoked"))
|
||||
}
|
||||
}
|
||||
|
||||
function showQuestion(isConfigIssue, countryCode, countryName) {
|
||||
var headerText
|
||||
if (isConfigIssue) {
|
||||
headerText = qsTr("Generate a new %1 configuration file?").arg(countryName)
|
||||
} else {
|
||||
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 yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (isConfigIssue) {
|
||||
issueConfig(countryCode)
|
||||
} else {
|
||||
revokeConfig(countryCode)
|
||||
}
|
||||
moreOptionsDrawer.closeTriggered()
|
||||
}
|
||||
var noButtonFunction = function() {}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import QtCore
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
property string configExtension: ".conf"
|
||||
property string configCaption: qsTr("Save AmneziaVPN config")
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
model: ApiCountryModel
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Configuration Files")
|
||||
descriptionText: qsTr("For router setup or the AmneziaWG app")
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 6
|
||||
|
||||
text: countryName
|
||||
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
|
||||
hideDescription: isWorkerExpired ? true : false
|
||||
descriptionColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
|
||||
rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
if (isIssued) {
|
||||
moreOptionsDrawer.countryName = countryName
|
||||
moreOptionsDrawer.countryCode = countryCode
|
||||
moreOptionsDrawer.openTriggered()
|
||||
} else {
|
||||
issueConfig(countryCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: moreOptionsDrawer
|
||||
|
||||
property string countryName
|
||||
property string countryCode
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: moreOptionsDrawer.expandedHeight
|
||||
|
||||
BackButtonType {
|
||||
id: moreOptionsDrawerBackButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() {
|
||||
moreOptionsDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: drawerListView
|
||||
|
||||
anchors.top: moreOptionsDrawerBackButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
header: ColumnLayout {
|
||||
width: drawerListView.width
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: drawerListView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Generate a new configuration file")
|
||||
descriptionText: qsTr("The previously created one will stop working")
|
||||
|
||||
clickedFunction: function() {
|
||||
showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
|
||||
footer: ColumnLayout {
|
||||
width: drawerListView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Revoke the current configuration file")
|
||||
|
||||
clickedFunction: function() {
|
||||
showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function issueConfig(countryCode) {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = countryCode + configExtension
|
||||
} else {
|
||||
fileName = SystemController.getFileName(configCaption,
|
||||
qsTr("Config files (*" + configExtension + ")"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode,
|
||||
true,
|
||||
configExtension)
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
let result = ApiConfigsController.exportNativeConfig(countryCode, fileName)
|
||||
if (result) {
|
||||
ApiSettingsController.getAccountInfo(true)
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
if (result) {
|
||||
PageController.showNotificationMessage(qsTr("Config file saved"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function revokeConfig(countryCode) {
|
||||
PageController.showBusyIndicator(true)
|
||||
let result = ApiConfigsController.revokeNativeConfig(countryCode)
|
||||
if (result) {
|
||||
ApiSettingsController.getAccountInfo(true)
|
||||
}
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
if (result) {
|
||||
PageController.showNotificationMessage(qsTr("The config has been revoked"))
|
||||
}
|
||||
}
|
||||
|
||||
function showQuestion(isConfigIssue, countryCode, countryName) {
|
||||
var headerText
|
||||
if (isConfigIssue) {
|
||||
headerText = qsTr("Generate a new %1 configuration file?").arg(countryName)
|
||||
} else {
|
||||
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 yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (isConfigIssue) {
|
||||
issueConfig(countryCode)
|
||||
} else {
|
||||
revokeConfig(countryCode)
|
||||
}
|
||||
moreOptionsDrawer.closeTriggered()
|
||||
}
|
||||
var noButtonFunction = function() {}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ PageType {
|
||||
id: backButton
|
||||
objectName: "backButton"
|
||||
|
||||
Layout.topMargin: 20
|
||||
Layout.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
}
|
||||
|
||||
HeaderTypeWithButton {
|
||||
|
||||
@@ -59,7 +59,7 @@ PageType {
|
||||
id: listView
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
model: supportModel
|
||||
|
||||
@@ -74,7 +74,7 @@ PageType {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
@@ -216,7 +216,7 @@ PageType {
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: addAppButton
|
||||
anchors.bottomMargin: -24
|
||||
anchors.bottomMargin: -24 - SettingsController.safeAreaBottomMargin
|
||||
color: AmneziaStyle.color.midnightBlack
|
||||
opacity: 0.8
|
||||
}
|
||||
@@ -232,7 +232,7 @@ PageType {
|
||||
anchors.topMargin: 24
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
anchors.bottomMargin: 24
|
||||
anchors.bottomMargin: 24 + SettingsController.safeAreaBottomMargin
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: searchField
|
||||
|
||||
@@ -20,7 +20,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -40,7 +40,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -20,7 +20,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -1,163 +1,163 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Config"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
|
||||
|
||||
enabled: !isServerFromApi
|
||||
|
||||
Component.onCompleted: {
|
||||
if (isServerFromApi) {
|
||||
PageController.showNotificationMessage(qsTr("Default server does not support custom DNS"))
|
||||
}
|
||||
}
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
spacing: 16
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("DNS servers")
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("If AmneziaDNS is not used or installed")
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
spacing: 16
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: primaryDns
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Primary DNS")
|
||||
|
||||
textField.text: SettingsController.primaryDns
|
||||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: secondaryDns
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Secondary DNS")
|
||||
|
||||
textField.text: SettingsController.secondaryDns
|
||||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: restoreDefaultButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Restore default")
|
||||
|
||||
clickedFunc: function() {
|
||||
var headerText = qsTr("Restore default DNS settings?")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
SettingsController.primaryDns = "1.1.1.1"
|
||||
primaryDns.textField.text = SettingsController.primaryDns
|
||||
SettingsController.secondaryDns = "1.0.0.1"
|
||||
secondaryDns.textField.text = SettingsController.secondaryDns
|
||||
PageController.showNotificationMessage(qsTr("Settings have been reset"))
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
clickedFunc: function() {
|
||||
if (primaryDns.textField.text !== SettingsController.primaryDns) {
|
||||
SettingsController.primaryDns = primaryDns.textField.text
|
||||
}
|
||||
if (secondaryDns.textField.text !== SettingsController.secondaryDns) {
|
||||
SettingsController.secondaryDns = secondaryDns.textField.text
|
||||
}
|
||||
PageController.showNotificationMessage(qsTr("Settings saved"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Config"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
|
||||
|
||||
enabled: !isServerFromApi
|
||||
|
||||
Component.onCompleted: {
|
||||
if (isServerFromApi) {
|
||||
PageController.showNotificationMessage(qsTr("Default server does not support custom DNS"))
|
||||
}
|
||||
}
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
spacing: 16
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("DNS servers")
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("If AmneziaDNS is not used or installed")
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
spacing: 16
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: primaryDns
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Primary DNS")
|
||||
|
||||
textField.text: SettingsController.primaryDns
|
||||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: secondaryDns
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Secondary DNS")
|
||||
|
||||
textField.text: SettingsController.secondaryDns
|
||||
textField.validator: RegularExpressionValidator {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: restoreDefaultButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Restore default")
|
||||
|
||||
clickedFunc: function() {
|
||||
var headerText = qsTr("Restore default DNS settings?")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
SettingsController.primaryDns = "1.1.1.1"
|
||||
primaryDns.textField.text = SettingsController.primaryDns
|
||||
SettingsController.secondaryDns = "1.0.0.1"
|
||||
secondaryDns.textField.text = SettingsController.secondaryDns
|
||||
PageController.showNotificationMessage(qsTr("Settings have been reset"))
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
clickedFunc: function() {
|
||||
if (primaryDns.textField.text !== SettingsController.primaryDns) {
|
||||
SettingsController.primaryDns = primaryDns.textField.text
|
||||
}
|
||||
if (secondaryDns.textField.text !== SettingsController.secondaryDns) {
|
||||
SettingsController.secondaryDns = secondaryDns.textField.text
|
||||
}
|
||||
PageController.showNotificationMessage(qsTr("Settings saved"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
||||
@@ -30,7 +30,7 @@ PageType {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -34,7 +34,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
||||
@@ -19,7 +19,7 @@ PageType {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
@@ -62,7 +62,7 @@ PageType {
|
||||
objectName: "mainLayout"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
spacing: 4
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -25,7 +25,7 @@ PageType {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
@@ -81,18 +81,18 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
}
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
HeaderTypeWithSwitcher {
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -1,179 +1,179 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 32
|
||||
|
||||
headerText: ApiServicesModel.getSelectedServiceData("name")
|
||||
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
|
||||
}
|
||||
}
|
||||
|
||||
model: inputFields
|
||||
spacing: 0
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: imagePath
|
||||
leftText: lText
|
||||
rightText: rText
|
||||
|
||||
visible: isVisible
|
||||
}
|
||||
}
|
||||
|
||||
footer: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
spacing: 0
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
onLinkActivated: function(link) {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
textFormat: Text.RichText
|
||||
text: {
|
||||
var text = ApiServicesModel.getSelectedServiceData("features")
|
||||
return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")).replace("/free", "") // todo link should come from gateway
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: continueButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.bottomMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Connect")
|
||||
|
||||
clickedFunc: function() {
|
||||
var endpoint = ApiServicesModel.getStoreEndpoint()
|
||||
if (endpoint !== undefined && endpoint !== "") {
|
||||
Qt.openUrlExternally(endpoint)
|
||||
PageController.closePage()
|
||||
PageController.closePage()
|
||||
} else {
|
||||
PageController.showBusyIndicator(true)
|
||||
ApiConfigsController.importServiceFromGateway()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property list<QtObject> inputFields: [
|
||||
region,
|
||||
price,
|
||||
timeLimit,
|
||||
speed,
|
||||
features
|
||||
]
|
||||
|
||||
QtObject {
|
||||
id: region
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/map-pin.svg"
|
||||
readonly property string lText: qsTr("For the region")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("region")
|
||||
property bool isVisible: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: price
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/tag.svg"
|
||||
readonly property string lText: qsTr("Price")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("price")
|
||||
property bool isVisible: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: timeLimit
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/history.svg"
|
||||
readonly property string lText: qsTr("Work period")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit")
|
||||
property bool isVisible: rText !== ""
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: speed
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/gauge.svg"
|
||||
readonly property string lText: qsTr("Speed")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("speed")
|
||||
property bool isVisible: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: features
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/info.svg"
|
||||
readonly property string lText: qsTr("Features")
|
||||
readonly property string rText: ""
|
||||
property bool isVisible: true
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 32
|
||||
|
||||
headerText: ApiServicesModel.getSelectedServiceData("name")
|
||||
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
|
||||
}
|
||||
}
|
||||
|
||||
model: inputFields
|
||||
spacing: 0
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
LabelWithImageType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
imageSource: imagePath
|
||||
leftText: lText
|
||||
rightText: rText
|
||||
|
||||
visible: isVisible
|
||||
}
|
||||
}
|
||||
|
||||
footer: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
spacing: 0
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
onLinkActivated: function(link) {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
textFormat: Text.RichText
|
||||
text: {
|
||||
var text = ApiServicesModel.getSelectedServiceData("features")
|
||||
return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")).replace("/free", "") // todo link should come from gateway
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: continueButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.bottomMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Connect")
|
||||
|
||||
clickedFunc: function() {
|
||||
var endpoint = ApiServicesModel.getStoreEndpoint()
|
||||
if (endpoint !== undefined && endpoint !== "") {
|
||||
Qt.openUrlExternally(endpoint)
|
||||
PageController.closePage()
|
||||
PageController.closePage()
|
||||
} else {
|
||||
PageController.showBusyIndicator(true)
|
||||
ApiConfigsController.importServiceFromGateway()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property list<QtObject> inputFields: [
|
||||
region,
|
||||
price,
|
||||
timeLimit,
|
||||
speed,
|
||||
features
|
||||
]
|
||||
|
||||
QtObject {
|
||||
id: region
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/map-pin.svg"
|
||||
readonly property string lText: qsTr("For the region")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("region")
|
||||
property bool isVisible: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: price
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/tag.svg"
|
||||
readonly property string lText: qsTr("Price")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("price")
|
||||
property bool isVisible: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: timeLimit
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/history.svg"
|
||||
readonly property string lText: qsTr("Work period")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit")
|
||||
property bool isVisible: rText !== ""
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: speed
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/gauge.svg"
|
||||
readonly property string lText: qsTr("Speed")
|
||||
readonly property string rText: ApiServicesModel.getSelectedServiceData("speed")
|
||||
property bool isVisible: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: features
|
||||
|
||||
readonly property string imagePath: "qrc:/images/controls/info.svg"
|
||||
readonly property string lText: qsTr("Features")
|
||||
readonly property string rText: ""
|
||||
property bool isVisible: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -41,7 +41,7 @@ PageType {
|
||||
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.topMargin: 24 + SettingsController.safeAreaTopMargin
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -40,7 +40,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -35,7 +35,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -41,7 +41,7 @@ PageType {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -19,7 +19,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
|
||||
@@ -22,7 +22,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
|
||||
@@ -173,7 +173,7 @@ PageType {
|
||||
HeaderTypeWithButton {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.topMargin: 24 + SettingsController.safeAreaTopMargin
|
||||
|
||||
headerText: qsTr("Share VPN Access")
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ PageType {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -55,7 +55,7 @@ PageType {
|
||||
anchors.top: backButton.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
|
||||
@@ -1,168 +1,168 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Components"
|
||||
import "../Config"
|
||||
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
property string headerText: ""
|
||||
property string configContentHeaderText: ""
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 24
|
||||
|
||||
headerText: qsTr("Full access to the server and VPN")
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
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. ")
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
id: serverSelector
|
||||
objectName: "serverSelector"
|
||||
|
||||
signal severSelectorIndexChanged
|
||||
property int currentIndex: 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 16
|
||||
|
||||
drawerHeight: 0.4375
|
||||
drawerParent: root
|
||||
|
||||
descriptionText: qsTr("Server")
|
||||
headerText: qsTr("Server")
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: serverSelectorListView
|
||||
|
||||
rootWidth: root.width
|
||||
imageSource: "qrc:/images/controls/check.svg"
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyServersModel
|
||||
sourceModel: ServersModel
|
||||
filters: [
|
||||
ValueFilter {
|
||||
roleName: "hasWriteAccess"
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
handler()
|
||||
|
||||
if (serverSelector.currentIndex !== serverSelectorListView.selectedIndex) {
|
||||
serverSelector.currentIndex = serverSelectorListView.selectedIndex
|
||||
serverSelector.severSelectorIndexChanged()
|
||||
}
|
||||
|
||||
listView.headerText = qsTr("Accessing ") + serverSelector.text
|
||||
listView.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
|
||||
serverSelector.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ?
|
||||
proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0
|
||||
serverSelectorListView.triggerCurrentItem()
|
||||
}
|
||||
|
||||
function handler() {
|
||||
serverSelector.text = selectedText
|
||||
ServersModel.processedIndex = proxyServersModel.mapToSource(selectedIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
spacing: 0
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BasicButtonType {
|
||||
id: shareButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Share")
|
||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
clickedFunc: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
|
||||
if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) {
|
||||
PageController.showBusyIndicator(false)
|
||||
ExportController.exportErrorOccurred(qsTr("Access error!"))
|
||||
return
|
||||
} else {
|
||||
ExportController.generateFullAccessConfig()
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
PageController.goToShareConnectionPage(listView.headerText, listView.configContentHeaderText, "", ".vpn", "amnezia_config")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Components"
|
||||
import "../Config"
|
||||
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
|
||||
|
||||
onFocusChanged: {
|
||||
if (this.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
property string headerText: ""
|
||||
property string configContentHeaderText: ""
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 24
|
||||
|
||||
headerText: qsTr("Full access to the server and VPN")
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
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. ")
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
id: serverSelector
|
||||
objectName: "serverSelector"
|
||||
|
||||
signal severSelectorIndexChanged
|
||||
property int currentIndex: 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 16
|
||||
|
||||
drawerHeight: 0.4375
|
||||
drawerParent: root
|
||||
|
||||
descriptionText: qsTr("Server")
|
||||
headerText: qsTr("Server")
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: serverSelectorListView
|
||||
|
||||
rootWidth: root.width
|
||||
imageSource: "qrc:/images/controls/check.svg"
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyServersModel
|
||||
sourceModel: ServersModel
|
||||
filters: [
|
||||
ValueFilter {
|
||||
roleName: "hasWriteAccess"
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
handler()
|
||||
|
||||
if (serverSelector.currentIndex !== serverSelectorListView.selectedIndex) {
|
||||
serverSelector.currentIndex = serverSelectorListView.selectedIndex
|
||||
serverSelector.severSelectorIndexChanged()
|
||||
}
|
||||
|
||||
listView.headerText = qsTr("Accessing ") + serverSelector.text
|
||||
listView.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
|
||||
serverSelector.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ?
|
||||
proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0
|
||||
serverSelectorListView.triggerCurrentItem()
|
||||
}
|
||||
|
||||
function handler() {
|
||||
serverSelector.text = selectedText
|
||||
ServersModel.processedIndex = proxyServersModel.mapToSource(selectedIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
spacing: 0
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BasicButtonType {
|
||||
id: shareButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Share")
|
||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
clickedFunc: function() {
|
||||
PageController.showBusyIndicator(true)
|
||||
|
||||
if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) {
|
||||
PageController.showBusyIndicator(false)
|
||||
ExportController.exportErrorOccurred(qsTr("Access error!"))
|
||||
return
|
||||
} else {
|
||||
ExportController.generateFullAccessConfig()
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
PageController.goToShareConnectionPage(listView.headerText, listView.configContentHeaderText, "", ".vpn", "amnezia_config")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ PageType {
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
bottomPadding: 8 + SettingsController.safeAreaBottomMargin
|
||||
leftPadding: 96
|
||||
rightPadding: 96
|
||||
|
||||
|
||||
+21
-2
@@ -16,6 +16,26 @@ Window {
|
||||
id: root
|
||||
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
|
||||
width: GC.screenWidth
|
||||
height: GC.screenHeight
|
||||
@@ -111,7 +131,6 @@ Window {
|
||||
|
||||
PageStart {
|
||||
objectName: "pageStart"
|
||||
|
||||
width: root.width
|
||||
height: root.height
|
||||
}
|
||||
@@ -164,7 +183,7 @@ Window {
|
||||
id: privateKeyPassphraseDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: root.height * 0.35
|
||||
expandedHeight: root.height * 0.35 + SettingsController.safeAreaBottomMargin
|
||||
|
||||
expandedStateContent: ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
|
||||
Reference in New Issue
Block a user