Compare commits
21 commits
dev
...
chore/focu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a8877c2ed | ||
|
|
09e3f39122 | ||
|
|
3393b97392 | ||
|
|
0bc762ccbf | ||
|
|
727526b39a | ||
|
|
00f49dbc82 | ||
|
|
b1627887eb | ||
|
|
ad32b68d84 | ||
|
|
117c66cd7d | ||
|
|
b8d49abdd1 | ||
|
|
0298371a52 | ||
|
|
5d133aa1a6 | ||
|
|
4b20250051 | ||
|
|
06544660a4 | ||
|
|
671d762a20 | ||
|
|
d110c96b5c | ||
|
|
cf5ecf1f1a | ||
|
|
111a60d81c | ||
|
|
8b01638424 | ||
|
|
65e7237610 | ||
|
|
7d187bf881 |
120 changed files with 6992 additions and 8329 deletions
18
.github/workflows/deploy.yml
vendored
18
.github/workflows/deploy.yml
vendored
|
|
@ -255,6 +255,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
||||||
QT_VERSION: 6.4.3
|
QT_VERSION: 6.4.3
|
||||||
|
QIF_VERSION: 4.6
|
||||||
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 }}
|
||||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
|
@ -282,6 +283,11 @@ jobs:
|
||||||
set-env: 'true'
|
set-env: 'true'
|
||||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||||
|
|
||||||
|
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
|
||||||
|
run: |
|
||||||
|
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
|
||||||
|
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
|
||||||
|
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
|
||||||
|
|
||||||
- name: 'Get sources'
|
- name: 'Get sources'
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -295,13 +301,14 @@ jobs:
|
||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
run: |
|
run: |
|
||||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||||
|
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
|
||||||
bash deploy/build_macos.sh
|
bash deploy/build_macos.sh
|
||||||
|
|
||||||
- name: 'Upload installer artifact'
|
- name: 'Upload installer artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: AmneziaVPN_MacOS_old_installer
|
name: AmneziaVPN_MacOS_old_installer
|
||||||
path: deploy/build/pkg/AmneziaVPN.pkg
|
path: AmneziaVPN.dmg
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
- name: 'Upload unpacked artifact'
|
- name: 'Upload unpacked artifact'
|
||||||
|
|
@ -318,6 +325,7 @@ jobs:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 6.8.0
|
QT_VERSION: 6.8.0
|
||||||
|
QIF_VERSION: 4.8.1
|
||||||
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 }}
|
||||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
|
@ -345,6 +353,11 @@ jobs:
|
||||||
set-env: 'true'
|
set-env: 'true'
|
||||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||||
|
|
||||||
|
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
|
||||||
|
run: |
|
||||||
|
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
|
||||||
|
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
|
||||||
|
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
|
||||||
|
|
||||||
- name: 'Get sources'
|
- name: 'Get sources'
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -358,13 +371,14 @@ jobs:
|
||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
run: |
|
run: |
|
||||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||||
|
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
|
||||||
bash deploy/build_macos.sh
|
bash deploy/build_macos.sh
|
||||||
|
|
||||||
- name: 'Upload installer artifact'
|
- name: 'Upload installer artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: AmneziaVPN_MacOS_installer
|
name: AmneziaVPN_MacOS_installer
|
||||||
path: deploy/build/pkg/AmneziaVPN.pkg
|
path: AmneziaVPN.dmg
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
- name: 'Upload unpacked artifact'
|
- name: 'Upload unpacked artifact'
|
||||||
|
|
|
||||||
1
.gitmodules
vendored
1
.gitmodules
vendored
|
|
@ -7,7 +7,6 @@
|
||||||
[submodule "client/3rd-prebuilt"]
|
[submodule "client/3rd-prebuilt"]
|
||||||
path = client/3rd-prebuilt
|
path = client/3rd-prebuilt
|
||||||
url = https://github.com/amnezia-vpn/3rd-prebuilt
|
url = https://github.com/amnezia-vpn/3rd-prebuilt
|
||||||
branch = feature/special-handshake
|
|
||||||
[submodule "client/3rd/amneziawg-apple"]
|
[submodule "client/3rd/amneziawg-apple"]
|
||||||
path = client/3rd/amneziawg-apple
|
path = client/3rd/amneziawg-apple
|
||||||
url = https://github.com/amnezia-vpn/amneziawg-apple
|
url = https://github.com/amnezia-vpn/amneziawg-apple
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
|
|
||||||
project(${PROJECT} VERSION 4.8.8.1
|
project(${PROJECT} VERSION 4.8.7.2
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
|
|
@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 2087)
|
set(APP_ANDROID_VERSION_CODE 2086)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 840b7b070e6ac8b90dda2fac6e98859b23727c0c
|
Subproject commit 0f3748efd7cc04e0c914304b68931f925bed1259
|
||||||
2
client/3rd/amneziawg-apple
vendored
2
client/3rd/amneziawg-apple
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit 811af0a83b3faeade89a9093a588595666d32066
|
Subproject commit 76e7db556a6d7e2582f9481df91db188a46c009c
|
||||||
|
|
@ -120,21 +120,10 @@ open class Wireguard : Protocol() {
|
||||||
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
|
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
|
||||||
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
|
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
|
||||||
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
|
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
|
||||||
configData.optStringOrNull("S3")?.let { setS3(it.toInt()) }
|
|
||||||
configData.optStringOrNull("S4")?.let { setS4(it.toInt()) }
|
|
||||||
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
|
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
|
||||||
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
|
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
|
||||||
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
|
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
|
||||||
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
|
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
|
||||||
configData.optStringOrNull("I1")?.let { setI1(it) }
|
|
||||||
configData.optStringOrNull("I2")?.let { setI2(it) }
|
|
||||||
configData.optStringOrNull("I3")?.let { setI3(it) }
|
|
||||||
configData.optStringOrNull("I4")?.let { setI4(it) }
|
|
||||||
configData.optStringOrNull("I5")?.let { setI5(it) }
|
|
||||||
configData.optStringOrNull("J1")?.let { setJ1(it) }
|
|
||||||
configData.optStringOrNull("J2")?.let { setJ2(it) }
|
|
||||||
configData.optStringOrNull("J3")?.let { setJ3(it) }
|
|
||||||
configData.optStringOrNull("Itime")?.let { setItime(it.toInt()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
|
|
|
||||||
|
|
@ -20,21 +20,10 @@ open class WireguardConfig protected constructor(
|
||||||
val jmax: Int?,
|
val jmax: Int?,
|
||||||
val s1: Int?,
|
val s1: Int?,
|
||||||
val s2: Int?,
|
val s2: Int?,
|
||||||
val s3: Int?,
|
|
||||||
val s4: Int?,
|
|
||||||
val h1: Long?,
|
val h1: Long?,
|
||||||
val h2: Long?,
|
val h2: Long?,
|
||||||
val h3: Long?,
|
val h3: Long?,
|
||||||
val h4: Long?,
|
val h4: Long?
|
||||||
var i1: String?,
|
|
||||||
var i2: String?,
|
|
||||||
var i3: String?,
|
|
||||||
var i4: String?,
|
|
||||||
var i5: String?,
|
|
||||||
var j1: String?,
|
|
||||||
var j2: String?,
|
|
||||||
var j3: String?,
|
|
||||||
var itime: Int?
|
|
||||||
) : ProtocolConfig(protocolConfigBuilder) {
|
) : ProtocolConfig(protocolConfigBuilder) {
|
||||||
|
|
||||||
protected constructor(builder: Builder) : this(
|
protected constructor(builder: Builder) : this(
|
||||||
|
|
@ -50,21 +39,10 @@ open class WireguardConfig protected constructor(
|
||||||
builder.jmax,
|
builder.jmax,
|
||||||
builder.s1,
|
builder.s1,
|
||||||
builder.s2,
|
builder.s2,
|
||||||
builder.s3,
|
|
||||||
builder.s4,
|
|
||||||
builder.h1,
|
builder.h1,
|
||||||
builder.h2,
|
builder.h2,
|
||||||
builder.h3,
|
builder.h3,
|
||||||
builder.h4,
|
builder.h4
|
||||||
builder.i1,
|
|
||||||
builder.i2,
|
|
||||||
builder.i3,
|
|
||||||
builder.i4,
|
|
||||||
builder.i5,
|
|
||||||
builder.j1,
|
|
||||||
builder.j2,
|
|
||||||
builder.j3,
|
|
||||||
builder.itime
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun toWgUserspaceString(): String = with(StringBuilder()) {
|
fun toWgUserspaceString(): String = with(StringBuilder()) {
|
||||||
|
|
@ -83,21 +61,10 @@ open class WireguardConfig protected constructor(
|
||||||
appendLine("jmax=$jmax")
|
appendLine("jmax=$jmax")
|
||||||
appendLine("s1=$s1")
|
appendLine("s1=$s1")
|
||||||
appendLine("s2=$s2")
|
appendLine("s2=$s2")
|
||||||
s3?.let { appendLine("s3=$it") }
|
|
||||||
s4?.let { appendLine("s4=$it") }
|
|
||||||
appendLine("h1=$h1")
|
appendLine("h1=$h1")
|
||||||
appendLine("h2=$h2")
|
appendLine("h2=$h2")
|
||||||
appendLine("h3=$h3")
|
appendLine("h3=$h3")
|
||||||
appendLine("h4=$h4")
|
appendLine("h4=$h4")
|
||||||
i1?.let { appendLine("i1=$it") }
|
|
||||||
i2?.let { appendLine("i2=$it") }
|
|
||||||
i3?.let { appendLine("i3=$it") }
|
|
||||||
i4?.let { appendLine("i4=$it") }
|
|
||||||
i5?.let { appendLine("i5=$it") }
|
|
||||||
j1?.let { appendLine("j1=$it") }
|
|
||||||
j2?.let { appendLine("j2=$it") }
|
|
||||||
j3?.let { appendLine("j3=$it") }
|
|
||||||
itime?.let { appendLine("itime=$it") }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,21 +117,10 @@ open class WireguardConfig protected constructor(
|
||||||
internal var jmax: Int? = null
|
internal var jmax: Int? = null
|
||||||
internal var s1: Int? = null
|
internal var s1: Int? = null
|
||||||
internal var s2: Int? = null
|
internal var s2: Int? = null
|
||||||
internal var s3: Int? = null
|
|
||||||
internal var s4: Int? = null
|
|
||||||
internal var h1: Long? = null
|
internal var h1: Long? = null
|
||||||
internal var h2: Long? = null
|
internal var h2: Long? = null
|
||||||
internal var h3: Long? = null
|
internal var h3: Long? = null
|
||||||
internal var h4: Long? = null
|
internal var h4: Long? = null
|
||||||
internal var i1: String? = null
|
|
||||||
internal var i2: String? = null
|
|
||||||
internal var i3: String? = null
|
|
||||||
internal var i4: String? = null
|
|
||||||
internal var i5: String? = null
|
|
||||||
internal var j1: String? = null
|
|
||||||
internal var j2: String? = null
|
|
||||||
internal var j3: String? = null
|
|
||||||
internal var itime: Int? = null
|
|
||||||
|
|
||||||
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
|
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
|
||||||
|
|
||||||
|
|
@ -183,21 +139,10 @@ open class WireguardConfig protected constructor(
|
||||||
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
|
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
|
||||||
fun setS1(s1: Int) = apply { this.s1 = s1 }
|
fun setS1(s1: Int) = apply { this.s1 = s1 }
|
||||||
fun setS2(s2: Int) = apply { this.s2 = s2 }
|
fun setS2(s2: Int) = apply { this.s2 = s2 }
|
||||||
fun setS3(s3: Int) = apply { this.s3 = s3 }
|
|
||||||
fun setS4(s4: Int) = apply { this.s4 = s4 }
|
|
||||||
fun setH1(h1: Long) = apply { this.h1 = h1 }
|
fun setH1(h1: Long) = apply { this.h1 = h1 }
|
||||||
fun setH2(h2: Long) = apply { this.h2 = h2 }
|
fun setH2(h2: Long) = apply { this.h2 = h2 }
|
||||||
fun setH3(h3: Long) = apply { this.h3 = h3 }
|
fun setH3(h3: Long) = apply { this.h3 = h3 }
|
||||||
fun setH4(h4: Long) = apply { this.h4 = h4 }
|
fun setH4(h4: Long) = apply { this.h4 = h4 }
|
||||||
fun setI1(i1: String) = apply { this.i1 = i1 }
|
|
||||||
fun setI2(i2: String) = apply { this.i2 = i2 }
|
|
||||||
fun setI3(i3: String) = apply { this.i3 = i3 }
|
|
||||||
fun setI4(i4: String) = apply { this.i4 = i4 }
|
|
||||||
fun setI5(i5: String) = apply { this.i5 = i5 }
|
|
||||||
fun setJ1(j1: String) = apply { this.j1 = j1 }
|
|
||||||
fun setJ2(j2: String) = apply { this.j2 = j2 }
|
|
||||||
fun setJ3(j3: String) = apply { this.j3 = j3 }
|
|
||||||
fun setItime(itime: Int) = apply { this.itime = itime }
|
|
||||||
|
|
||||||
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
|
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#include "awg_configurator.h"
|
#include "awg_configurator.h"
|
||||||
#include "protocols/protocols_defs.h"
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
@ -40,20 +39,6 @@ QString AwgConfigurator::createConfig(const ServerCredentials &credentials, Dock
|
||||||
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
|
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
|
||||||
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
|
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
|
||||||
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
|
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
|
||||||
|
|
||||||
// jsonConfig[config_key::cookieReplyPacketJunkSize] = configMap.value(config_key::cookieReplyPacketJunkSize);
|
|
||||||
// jsonConfig[config_key::transportPacketJunkSize] = configMap.value(config_key::transportPacketJunkSize);
|
|
||||||
|
|
||||||
// jsonConfig[config_key::specialJunk1] = configMap.value(amnezia::config_key::specialJunk1);
|
|
||||||
// jsonConfig[config_key::specialJunk2] = configMap.value(amnezia::config_key::specialJunk2);
|
|
||||||
// jsonConfig[config_key::specialJunk3] = configMap.value(amnezia::config_key::specialJunk3);
|
|
||||||
// jsonConfig[config_key::specialJunk4] = configMap.value(amnezia::config_key::specialJunk4);
|
|
||||||
// jsonConfig[config_key::specialJunk5] = configMap.value(amnezia::config_key::specialJunk5);
|
|
||||||
// jsonConfig[config_key::controlledJunk1] = configMap.value(amnezia::config_key::controlledJunk1);
|
|
||||||
// jsonConfig[config_key::controlledJunk2] = configMap.value(amnezia::config_key::controlledJunk2);
|
|
||||||
// jsonConfig[config_key::controlledJunk3] = configMap.value(amnezia::config_key::controlledJunk3);
|
|
||||||
// jsonConfig[config_key::specialHandshakeTimeout] = configMap.value(amnezia::config_key::specialHandshakeTimeout);
|
|
||||||
|
|
||||||
jsonConfig[config_key::mtu] =
|
jsonConfig[config_key::mtu] =
|
||||||
containerConfig.value(ProtocolProps::protoToString(Proto::Awg)).toObject().value(config_key::mtu).toString(protocols::awg::defaultMtu);
|
containerConfig.value(ProtocolProps::protoToString(Proto::Awg)).toObject().value(config_key::mtu).toString(protocols::awg::defaultMtu);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,12 +118,6 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString,
|
||||||
QRegularExpression regex("redirect-gateway.*");
|
QRegularExpression regex("redirect-gateway.*");
|
||||||
config.replace(regex, "");
|
config.replace(regex, "");
|
||||||
|
|
||||||
// We don't use secondary DNS if primary DNS is AmneziaDNS
|
|
||||||
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
|
|
||||||
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
|
|
||||||
config.replace(dnsRegex, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_settings->isSitesSplitTunnelingEnabled()) {
|
if (!m_settings->isSitesSplitTunnelingEnabled()) {
|
||||||
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
|
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
|
||||||
config.append("block-ipv6\n");
|
config.append("block-ipv6\n");
|
||||||
|
|
@ -167,12 +161,6 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair<QString
|
||||||
QRegularExpression regex("redirect-gateway.*");
|
QRegularExpression regex("redirect-gateway.*");
|
||||||
config.replace(regex, "");
|
config.replace(regex, "");
|
||||||
|
|
||||||
// We don't use secondary DNS if primary DNS is AmneziaDNS
|
|
||||||
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
|
|
||||||
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
|
|
||||||
config.replace(dnsRegex, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
|
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
|
||||||
|
|
||||||
// Prevent ipv6 leak
|
// Prevent ipv6 leak
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ namespace apiDefs
|
||||||
constexpr QLatin1String stackType("stack_type");
|
constexpr QLatin1String stackType("stack_type");
|
||||||
constexpr QLatin1String serviceType("service_type");
|
constexpr QLatin1String serviceType("service_type");
|
||||||
constexpr QLatin1String cliVersion("cli_version");
|
constexpr QLatin1String cliVersion("cli_version");
|
||||||
constexpr QLatin1String supportedProtocols("supported_protocols");
|
|
||||||
|
|
||||||
constexpr QLatin1String vpnKey("vpn_key");
|
constexpr QLatin1String vpnKey("vpn_key");
|
||||||
constexpr QLatin1String config("config");
|
constexpr QLatin1String config("config");
|
||||||
|
|
|
||||||
|
|
@ -349,7 +349,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
||||||
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
|
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
|
||||||
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|
||||||
|| (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
|
|| (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
|
||||||
!= newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort))
|
!= newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort))
|
||||||
|| (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)
|
|| (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)
|
||||||
!= newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount))
|
!= newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount))
|
||||||
|| (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize)
|
|| (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize)
|
||||||
|
|
@ -366,13 +366,8 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
||||||
!= newProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader))
|
!= newProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader))
|
||||||
|| (oldProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader)
|
|| (oldProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader)
|
||||||
!= newProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader))
|
!= newProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader))
|
||||||
|| (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))
|
|| (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)
|
||||||
!= newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))
|
!= newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)))
|
||||||
// || (oldProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize)
|
|
||||||
// != newProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize))
|
|
||||||
// || (oldProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize)
|
|
||||||
// != newProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize))
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,7 +375,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
||||||
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
|
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
|
||||||
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|
||||||
|| (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
|
|| (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
|
||||||
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
|
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -460,13 +455,11 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
|
||||||
runScript(credentials,
|
runScript(credentials,
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
|
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
|
||||||
cbReadStdOut, cbReadStdErr);
|
cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
if (stdOut.contains("doesn't work on cgroups v2"))
|
if (stdOut.contains("doesn't work on cgroups v2"))
|
||||||
return ErrorCode::ServerDockerOnCgroupsV2;
|
return ErrorCode::ServerDockerOnCgroupsV2;
|
||||||
if (stdOut.contains("cgroup mountpoint does not exist"))
|
if (stdOut.contains("cgroup mountpoint does not exist"))
|
||||||
return ErrorCode::ServerCgroupMountpoint;
|
return ErrorCode::ServerCgroupMountpoint;
|
||||||
if (stdOut.contains("have reached") && stdOut.contains("pull rate limit"))
|
|
||||||
return ErrorCode::DockerPullRateLimit;
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
@ -646,9 +639,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
|
||||||
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
|
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
|
||||||
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
|
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
|
||||||
|
|
||||||
vars.append({ { "$COOKIE_REPLY_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::cookieReplyPacketJunkSize).toString() } });
|
|
||||||
vars.append({ { "$TRANSPORT_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::transportPacketJunkSize).toString() } });
|
|
||||||
|
|
||||||
// Socks5 proxy vars
|
// Socks5 proxy vars
|
||||||
vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
|
vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
|
||||||
auto username = socks5ProxyConfig.value(config_key::userName).toString();
|
auto username = socks5ProxyConfig.value(config_key::userName).toString();
|
||||||
|
|
@ -835,7 +825,7 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
|
||||||
|
|
||||||
if (stdOut.contains("Packet manager not found"))
|
if (stdOut.contains("Packet manager not found"))
|
||||||
return ErrorCode::ServerPacketManagerError;
|
return ErrorCode::ServerPacketManagerError;
|
||||||
if (stdOut.contains("fuser not installed") || stdOut.contains("cat not installed"))
|
if (stdOut.contains("fuser not installed"))
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
|
|
||||||
if (stdOut.isEmpty()) {
|
if (stdOut.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ namespace amnezia
|
||||||
ServerUserPasswordRequired = 210,
|
ServerUserPasswordRequired = 210,
|
||||||
ServerDockerOnCgroupsV2 = 211,
|
ServerDockerOnCgroupsV2 = 211,
|
||||||
ServerCgroupMountpoint = 212,
|
ServerCgroupMountpoint = 212,
|
||||||
DockerPullRateLimit = 213,
|
|
||||||
|
|
||||||
// Ssh connection errors
|
// Ssh connection errors
|
||||||
SshRequestDeniedError = 300,
|
SshRequestDeniedError = 300,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ QString errorString(ErrorCode code) {
|
||||||
case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break;
|
case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break;
|
||||||
case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break;
|
case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break;
|
||||||
case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); break;
|
case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); break;
|
||||||
case(ErrorCode::DockerPullRateLimit): errorMessage = QObject::tr("Docker error: The pull rate limit has been reached"); break;
|
|
||||||
|
|
||||||
// Libssh errors
|
// Libssh errors
|
||||||
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
||||||
|
|
|
||||||
|
|
@ -169,14 +169,11 @@ bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
|
||||||
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
|
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
|
||||||
(config.m_hopType == InterfaceConfig::SingleHop)) {
|
(config.m_hopType == InterfaceConfig::SingleHop)) {
|
||||||
QList<QHostAddress> resolvers;
|
QList<QHostAddress> resolvers;
|
||||||
resolvers.append(QHostAddress(config.m_primaryDnsServer));
|
resolvers.append(QHostAddress(config.m_dnsServer));
|
||||||
if (!config.m_secondaryDnsServer.isEmpty()) {
|
|
||||||
resolvers.append(QHostAddress(config.m_secondaryDnsServer));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the DNS is not the Gateway, it's a user defined DNS
|
// If the DNS is not the Gateway, it's a user defined DNS
|
||||||
// thus, not add any other :)
|
// thus, not add any other :)
|
||||||
if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) {
|
if (config.m_dnsServer == config.m_serverIpv4Gateway) {
|
||||||
resolvers.append(QHostAddress(config.m_serverIpv6Gateway));
|
resolvers.append(QHostAddress(config.m_serverIpv6Gateway));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -282,26 +279,15 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||||
config.m_serverIpv4Gateway = obj.value("serverIpv4Gateway").toString();
|
config.m_serverIpv4Gateway = obj.value("serverIpv4Gateway").toString();
|
||||||
config.m_serverIpv6Gateway = obj.value("serverIpv6Gateway").toString();
|
config.m_serverIpv6Gateway = obj.value("serverIpv6Gateway").toString();
|
||||||
|
|
||||||
if (!obj.contains("primaryDnsServer")) {
|
if (!obj.contains("dnsServer")) {
|
||||||
config.m_primaryDnsServer = QString();
|
config.m_dnsServer = QString();
|
||||||
} else {
|
} else {
|
||||||
QJsonValue value = obj.value("primaryDnsServer");
|
QJsonValue value = obj.value("dnsServer");
|
||||||
if (!value.isString()) {
|
if (!value.isString()) {
|
||||||
logger.error() << "dnsServer is not a string";
|
logger.error() << "dnsServer is not a string";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
config.m_primaryDnsServer = value.toString();
|
config.m_dnsServer = value.toString();
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj.contains("secondaryDnsServer")) {
|
|
||||||
config.m_secondaryDnsServer = QString();
|
|
||||||
} else {
|
|
||||||
QJsonValue value = obj.value("secondaryDnsServer");
|
|
||||||
if (!value.isString()) {
|
|
||||||
logger.error() << "dnsServer is not a string";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
config.m_secondaryDnsServer = value.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!obj.contains("hopType")) {
|
if (!obj.contains("hopType")) {
|
||||||
|
|
@ -405,13 +391,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||||
if (!obj.value("S2").isNull()) {
|
if (!obj.value("S2").isNull()) {
|
||||||
config.m_responsePacketJunkSize = obj.value("S2").toString();
|
config.m_responsePacketJunkSize = obj.value("S2").toString();
|
||||||
}
|
}
|
||||||
if (!obj.value("S3").isNull()) {
|
|
||||||
config.m_cookieReplyPacketJunkSize = obj.value("S3").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("S4").isNull()) {
|
|
||||||
config.m_transportPacketJunkSize = obj.value("S4").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj.value("H1").isNull()) {
|
if (!obj.value("H1").isNull()) {
|
||||||
config.m_initPacketMagicHeader = obj.value("H1").toString();
|
config.m_initPacketMagicHeader = obj.value("H1").toString();
|
||||||
}
|
}
|
||||||
|
|
@ -425,34 +404,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||||
config.m_transportPacketMagicHeader = obj.value("H4").toString();
|
config.m_transportPacketMagicHeader = obj.value("H4").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!obj.value("I1").isNull()) {
|
|
||||||
config.m_specialJunk["I1"] = obj.value("I1").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("I2").isNull()) {
|
|
||||||
config.m_specialJunk["I2"] = obj.value("I2").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("I3").isNull()) {
|
|
||||||
config.m_specialJunk["I3"] = obj.value("I3").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("I4").isNull()) {
|
|
||||||
config.m_specialJunk["I4"] = obj.value("I4").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("I5").isNull()) {
|
|
||||||
config.m_specialJunk["I5"] = obj.value("I5").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("J1").isNull()) {
|
|
||||||
config.m_controlledJunk["J1"] = obj.value("J1").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("J2").isNull()) {
|
|
||||||
config.m_controlledJunk["J2"] = obj.value("J2").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("J3").isNull()) {
|
|
||||||
config.m_controlledJunk["J3"] = obj.value("J3").toString();
|
|
||||||
}
|
|
||||||
if (!obj.value("Itime").isNull()) {
|
|
||||||
config.m_specialHandshakeTimeout = obj.value("Itime").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,7 +446,7 @@ bool Daemon::deactivate(bool emitSignals) {
|
||||||
|
|
||||||
m_connections.clear();
|
m_connections.clear();
|
||||||
// Delete the interface
|
// Delete the interface
|
||||||
return wgutils()->deleteInterface();
|
return wgutils()->deleteInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Daemon::logs() {
|
QString Daemon::logs() {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ QJsonObject InterfaceConfig::toJson() const {
|
||||||
(m_hopType == InterfaceConfig::SingleHop)) {
|
(m_hopType == InterfaceConfig::SingleHop)) {
|
||||||
json.insert("serverIpv4Gateway", QJsonValue(m_serverIpv4Gateway));
|
json.insert("serverIpv4Gateway", QJsonValue(m_serverIpv4Gateway));
|
||||||
json.insert("serverIpv6Gateway", QJsonValue(m_serverIpv6Gateway));
|
json.insert("serverIpv6Gateway", QJsonValue(m_serverIpv6Gateway));
|
||||||
json.insert("primaryDnsServer", QJsonValue(m_primaryDnsServer));
|
json.insert("dnsServer", QJsonValue(m_dnsServer));
|
||||||
json.insert("secondaryDnsServer", QJsonValue(m_secondaryDnsServer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray allowedIPAddesses;
|
QJsonArray allowedIPAddesses;
|
||||||
|
|
@ -101,15 +100,11 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
||||||
out << "MTU = " << m_deviceMTU << "\n";
|
out << "MTU = " << m_deviceMTU << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_primaryDnsServer.isNull()) {
|
if (!m_dnsServer.isNull()) {
|
||||||
QStringList dnsServers;
|
QStringList dnsServers(m_dnsServer);
|
||||||
dnsServers.append(m_primaryDnsServer);
|
|
||||||
if (!m_secondaryDnsServer.isNull()) {
|
|
||||||
dnsServers.append(m_secondaryDnsServer);
|
|
||||||
}
|
|
||||||
// If the DNS is not the Gateway, it's a user defined DNS
|
// If the DNS is not the Gateway, it's a user defined DNS
|
||||||
// thus, not add any other :)
|
// thus, not add any other :)
|
||||||
if (m_primaryDnsServer == m_serverIpv4Gateway) {
|
if (m_dnsServer == m_serverIpv4Gateway) {
|
||||||
dnsServers.append(m_serverIpv6Gateway);
|
dnsServers.append(m_serverIpv6Gateway);
|
||||||
}
|
}
|
||||||
out << "DNS = " << dnsServers.join(", ") << "\n";
|
out << "DNS = " << dnsServers.join(", ") << "\n";
|
||||||
|
|
@ -130,12 +125,6 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
||||||
if (!m_responsePacketJunkSize.isNull()) {
|
if (!m_responsePacketJunkSize.isNull()) {
|
||||||
out << "S2 = " << m_responsePacketJunkSize << "\n";
|
out << "S2 = " << m_responsePacketJunkSize << "\n";
|
||||||
}
|
}
|
||||||
if (!m_cookieReplyPacketJunkSize.isNull()) {
|
|
||||||
out << "S3 = " << m_cookieReplyPacketJunkSize << "\n";
|
|
||||||
}
|
|
||||||
if (!m_transportPacketJunkSize.isNull()) {
|
|
||||||
out << "S4 = " << m_transportPacketJunkSize << "\n";
|
|
||||||
}
|
|
||||||
if (!m_initPacketMagicHeader.isNull()) {
|
if (!m_initPacketMagicHeader.isNull()) {
|
||||||
out << "H1 = " << m_initPacketMagicHeader << "\n";
|
out << "H1 = " << m_initPacketMagicHeader << "\n";
|
||||||
}
|
}
|
||||||
|
|
@ -149,16 +138,6 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
||||||
out << "H4 = " << m_transportPacketMagicHeader << "\n";
|
out << "H4 = " << m_transportPacketMagicHeader << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString& key : m_specialJunk.keys()) {
|
|
||||||
out << key << " = " << m_specialJunk[key] << "\n";
|
|
||||||
}
|
|
||||||
for (const QString& key : m_controlledJunk.keys()) {
|
|
||||||
out << key << " = " << m_controlledJunk[key] << "\n";
|
|
||||||
}
|
|
||||||
if (!m_specialHandshakeTimeout.isNull()) {
|
|
||||||
out << "Itime = " << m_specialHandshakeTimeout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// If any extra config was provided, append it now.
|
// If any extra config was provided, append it now.
|
||||||
for (const QString& key : extra.keys()) {
|
for (const QString& key : extra.keys()) {
|
||||||
out << key << " = " << extra[key] << "\n";
|
out << key << " = " << extra[key] << "\n";
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ class InterfaceConfig {
|
||||||
QString m_serverIpv4AddrIn;
|
QString m_serverIpv4AddrIn;
|
||||||
QString m_serverPskKey;
|
QString m_serverPskKey;
|
||||||
QString m_serverIpv6AddrIn;
|
QString m_serverIpv6AddrIn;
|
||||||
QString m_primaryDnsServer;
|
QString m_dnsServer;
|
||||||
QString m_secondaryDnsServer;
|
|
||||||
int m_serverPort = 0;
|
int m_serverPort = 0;
|
||||||
int m_deviceMTU = 1420;
|
int m_deviceMTU = 1420;
|
||||||
QList<IPAddress> m_allowedIPAddressRanges;
|
QList<IPAddress> m_allowedIPAddressRanges;
|
||||||
|
|
@ -50,15 +49,10 @@ class InterfaceConfig {
|
||||||
QString m_junkPacketMaxSize;
|
QString m_junkPacketMaxSize;
|
||||||
QString m_initPacketJunkSize;
|
QString m_initPacketJunkSize;
|
||||||
QString m_responsePacketJunkSize;
|
QString m_responsePacketJunkSize;
|
||||||
QString m_cookieReplyPacketJunkSize;
|
|
||||||
QString m_transportPacketJunkSize;
|
|
||||||
QString m_initPacketMagicHeader;
|
QString m_initPacketMagicHeader;
|
||||||
QString m_responsePacketMagicHeader;
|
QString m_responsePacketMagicHeader;
|
||||||
QString m_underloadPacketMagicHeader;
|
QString m_underloadPacketMagicHeader;
|
||||||
QString m_transportPacketMagicHeader;
|
QString m_transportPacketMagicHeader;
|
||||||
QMap<QString, QString> m_specialJunk;
|
|
||||||
QMap<QString, QString> m_controlledJunk;
|
|
||||||
QString m_specialHandshakeTimeout;
|
|
||||||
|
|
||||||
QJsonObject toJson() const;
|
QJsonObject toJson() const;
|
||||||
QString toWgConf(
|
QString toWgConf(
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ LocalSocketController::LocalSocketController() {
|
||||||
m_socket = new QLocalSocket(this);
|
m_socket = new QLocalSocket(this);
|
||||||
connect(m_socket, &QLocalSocket::connected, this,
|
connect(m_socket, &QLocalSocket::connected, this,
|
||||||
&LocalSocketController::daemonConnected);
|
&LocalSocketController::daemonConnected);
|
||||||
connect(m_socket, &QLocalSocket::disconnected, this,
|
connect(m_socket, &QLocalSocket::disconnected, this,
|
||||||
[&] { errorOccurred(QLocalSocket::PeerClosedError); });
|
[&] { errorOccurred(QLocalSocket::PeerClosedError); });
|
||||||
connect(m_socket, &QLocalSocket::errorOccurred, this,
|
connect(m_socket, &QLocalSocket::errorOccurred, this,
|
||||||
&LocalSocketController::errorOccurred);
|
&LocalSocketController::errorOccurred);
|
||||||
|
|
@ -135,7 +135,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
|
|
||||||
// set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable.
|
// set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable.
|
||||||
// this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4.
|
// this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4.
|
||||||
// Otherwise some OSes (Linux) try IPv6 forever and hang.
|
// Otherwise some OSes (Linux) try IPv6 forever and hang.
|
||||||
// https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193)
|
// https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193)
|
||||||
// https://man7.org/linux/man-pages/man5/gai.conf.5.html
|
// https://man7.org/linux/man-pages/man5/gai.conf.5.html
|
||||||
json.insert("deviceIpv6Address", "fd58:baa6:dead::1"); // simply "dead::1" is globally-routable, don't use it
|
json.insert("deviceIpv6Address", "fd58:baa6:dead::1"); // simply "dead::1" is globally-routable, don't use it
|
||||||
|
|
@ -149,14 +149,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
json.insert("serverPort", wgConfig.value(amnezia::config_key::port).toInt());
|
json.insert("serverPort", wgConfig.value(amnezia::config_key::port).toInt());
|
||||||
json.insert("serverIpv4Gateway", wgConfig.value(amnezia::config_key::hostName));
|
json.insert("serverIpv4Gateway", wgConfig.value(amnezia::config_key::hostName));
|
||||||
// json.insert("serverIpv6Gateway", QJsonValue(hop.m_server.ipv6Gateway()));
|
// json.insert("serverIpv6Gateway", QJsonValue(hop.m_server.ipv6Gateway()));
|
||||||
|
json.insert("dnsServer", rawConfig.value(amnezia::config_key::dns1));
|
||||||
json.insert("primaryDnsServer", rawConfig.value(amnezia::config_key::dns1));
|
|
||||||
|
|
||||||
// We don't use secondary DNS if primary DNS is AmneziaDNS
|
|
||||||
if (!rawConfig.value(amnezia::config_key::dns1).toString().
|
|
||||||
contains(amnezia::protocols::dns::amneziaDnsIp)) {
|
|
||||||
json.insert("secondaryDnsServer", rawConfig.value(amnezia::config_key::dns2));
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray jsAllowedIPAddesses;
|
QJsonArray jsAllowedIPAddesses;
|
||||||
|
|
||||||
|
|
@ -244,61 +237,28 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
|
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
|
||||||
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
|
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
|
||||||
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
|
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
|
||||||
json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize));
|
|
||||||
json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize));
|
|
||||||
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
|
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1));
|
|
||||||
json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2));
|
|
||||||
json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3));
|
|
||||||
json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4));
|
|
||||||
json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5));
|
|
||||||
json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1));
|
|
||||||
json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2));
|
|
||||||
json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3));
|
|
||||||
json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout));
|
|
||||||
} else if (!wgConfig.value(amnezia::config_key::junkPacketCount).isUndefined()
|
} else if (!wgConfig.value(amnezia::config_key::junkPacketCount).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::junkPacketMinSize).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::junkPacketMinSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::initPacketJunkSize).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::initPacketJunkSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::responsePacketJunkSize).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::responsePacketJunkSize).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::transportPacketJunkSize).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::initPacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::initPacketMagicHeader).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::responsePacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::responsePacketMagicHeader).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined()
|
||||||
&& !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined()
|
&& !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined()) {
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk1).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk2).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk3).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk4).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::specialJunk5).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::controlledJunk1).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::controlledJunk2).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::controlledJunk3).isUndefined()
|
|
||||||
&& !wgConfig.value(amnezia::config_key::specialHandshakeTimeout).isUndefined()) {
|
|
||||||
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
|
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
|
||||||
json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize));
|
json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize));
|
||||||
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
|
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
|
||||||
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
|
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
|
||||||
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
|
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
|
||||||
json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize));
|
|
||||||
json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize));
|
|
||||||
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
|
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
|
||||||
json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1));
|
|
||||||
json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2));
|
|
||||||
json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3));
|
|
||||||
json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4));
|
|
||||||
json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5));
|
|
||||||
json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1));
|
|
||||||
json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2));
|
|
||||||
json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3));
|
|
||||||
json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write(json);
|
write(json);
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,7 @@ struct WGConfig: Decodable {
|
||||||
let initPacketMagicHeader, responsePacketMagicHeader: String?
|
let initPacketMagicHeader, responsePacketMagicHeader: String?
|
||||||
let underloadPacketMagicHeader, transportPacketMagicHeader: String?
|
let underloadPacketMagicHeader, transportPacketMagicHeader: String?
|
||||||
let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String?
|
let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String?
|
||||||
let initPacketJunkSize, responsePacketJunkSize, cookieReplyPacketJunkSize, transportPacketJunkSize: String?
|
let initPacketJunkSize, responsePacketJunkSize: String?
|
||||||
let specialJunk1, specialJunk2, specialJunk3, specialJunk4, specialJunk5: String?
|
|
||||||
let controlledJunk1, controlledJunk2, controlledJunk3: String?
|
|
||||||
let specialHandshakeTimeout: String?
|
|
||||||
let dns1: String
|
let dns1: String
|
||||||
let dns2: String
|
let dns2: String
|
||||||
let mtu: String
|
let mtu: String
|
||||||
|
|
@ -26,10 +23,7 @@ struct WGConfig: Decodable {
|
||||||
case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2"
|
case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2"
|
||||||
case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4"
|
case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4"
|
||||||
case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax"
|
case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax"
|
||||||
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2", cookieReplyPacketJunkSize = "S3", transportPacketJunkSize = "S4"
|
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2"
|
||||||
case specialJunk1 = "I1", specialJunk2 = "I2", specialJunk3 = "I3", specialJunk4 = "I4", specialJunk5 = "I5"
|
|
||||||
case controlledJunk1 = "J1", controlledJunk2 = "J2", controlledJunk3 = "J3"
|
|
||||||
case specialHandshakeTimeout = "Itime"
|
|
||||||
case dns1
|
case dns1
|
||||||
case dns2
|
case dns2
|
||||||
case mtu
|
case mtu
|
||||||
|
|
@ -46,59 +40,19 @@ struct WGConfig: Decodable {
|
||||||
}
|
}
|
||||||
|
|
||||||
var settings: String {
|
var settings: String {
|
||||||
guard junkPacketCount != nil else { return "" }
|
junkPacketCount == nil ? "" :
|
||||||
|
"""
|
||||||
var settingsLines: [String] = []
|
Jc = \(junkPacketCount!)
|
||||||
|
Jmin = \(junkPacketMinSize!)
|
||||||
// Required parameters when junkPacketCount is present
|
Jmax = \(junkPacketMaxSize!)
|
||||||
settingsLines.append("Jc = \(junkPacketCount!)")
|
S1 = \(initPacketJunkSize!)
|
||||||
settingsLines.append("Jmin = \(junkPacketMinSize!)")
|
S2 = \(responsePacketJunkSize!)
|
||||||
settingsLines.append("Jmax = \(junkPacketMaxSize!)")
|
H1 = \(initPacketMagicHeader!)
|
||||||
settingsLines.append("S1 = \(initPacketJunkSize!)")
|
H2 = \(responsePacketMagicHeader!)
|
||||||
settingsLines.append("S2 = \(responsePacketJunkSize!)")
|
H3 = \(underloadPacketMagicHeader!)
|
||||||
|
H4 = \(transportPacketMagicHeader!)
|
||||||
settingsLines.append("H1 = \(initPacketMagicHeader!)")
|
|
||||||
settingsLines.append("H2 = \(responsePacketMagicHeader!)")
|
|
||||||
settingsLines.append("H3 = \(underloadPacketMagicHeader!)")
|
|
||||||
settingsLines.append("H4 = \(transportPacketMagicHeader!)")
|
|
||||||
|
|
||||||
// Optional parameters - only add if not nil and not empty
|
"""
|
||||||
if let s3 = cookieReplyPacketJunkSize, !s3.isEmpty {
|
|
||||||
settingsLines.append("S3 = \(s3)")
|
|
||||||
}
|
|
||||||
if let s4 = transportPacketJunkSize, !s4.isEmpty {
|
|
||||||
settingsLines.append("S4 = \(s4)")
|
|
||||||
}
|
|
||||||
|
|
||||||
if let i1 = specialJunk1, !i1.isEmpty {
|
|
||||||
settingsLines.append("I1 = \(i1)")
|
|
||||||
}
|
|
||||||
if let i2 = specialJunk2, !i2.isEmpty {
|
|
||||||
settingsLines.append("I2 = \(i2)")
|
|
||||||
}
|
|
||||||
if let i3 = specialJunk3, !i3.isEmpty {
|
|
||||||
settingsLines.append("I3 = \(i3)")
|
|
||||||
}
|
|
||||||
if let i4 = specialJunk4, !i4.isEmpty {
|
|
||||||
settingsLines.append("I4 = \(i4)")
|
|
||||||
}
|
|
||||||
if let i5 = specialJunk5, !i5.isEmpty {
|
|
||||||
settingsLines.append("I5 = \(i5)")
|
|
||||||
}
|
|
||||||
if let j1 = controlledJunk1, !j1.isEmpty {
|
|
||||||
settingsLines.append("J1 = \(j1)")
|
|
||||||
}
|
|
||||||
if let j2 = controlledJunk2, !j2.isEmpty {
|
|
||||||
settingsLines.append("J2 = \(j2)")
|
|
||||||
}
|
|
||||||
if let j3 = controlledJunk3, !j3.isEmpty {
|
|
||||||
settingsLines.append("J3 = \(j3)")
|
|
||||||
}
|
|
||||||
if let itime = specialHandshakeTimeout, !itime.isEmpty {
|
|
||||||
settingsLines.append("Itime = \(itime)")
|
|
||||||
}
|
|
||||||
|
|
||||||
return settingsLines.joined(separator: "\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var str: String {
|
var str: String {
|
||||||
|
|
|
||||||
|
|
@ -507,8 +507,6 @@ bool IosController::setupWireGuard()
|
||||||
|
|
||||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||||
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||||
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
|
|
||||||
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
|
|
||||||
|
|
||||||
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||||
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||||
|
|
@ -607,23 +605,11 @@ bool IosController::setupAwg()
|
||||||
|
|
||||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||||
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||||
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
|
|
||||||
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
|
|
||||||
|
|
||||||
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||||
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||||
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
|
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
|
||||||
|
|
||||||
wgConfig.insert(config_key::specialJunk1, config[config_key::specialJunk1]);
|
|
||||||
wgConfig.insert(config_key::specialJunk2, config[config_key::specialJunk2]);
|
|
||||||
wgConfig.insert(config_key::specialJunk3, config[config_key::specialJunk3]);
|
|
||||||
wgConfig.insert(config_key::specialJunk4, config[config_key::specialJunk4]);
|
|
||||||
wgConfig.insert(config_key::specialJunk5, config[config_key::specialJunk5]);
|
|
||||||
wgConfig.insert(config_key::controlledJunk1, config[config_key::controlledJunk1]);
|
|
||||||
wgConfig.insert(config_key::controlledJunk2, config[config_key::controlledJunk2]);
|
|
||||||
wgConfig.insert(config_key::controlledJunk3, config[config_key::controlledJunk3]);
|
|
||||||
wgConfig.insert(config_key::specialHandshakeTimeout, config[config_key::specialHandshakeTimeout]);
|
|
||||||
|
|
||||||
QJsonDocument wgConfigDoc(wgConfig);
|
QJsonDocument wgConfigDoc(wgConfig);
|
||||||
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
||||||
|
|
||||||
|
|
@ -808,9 +794,9 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||||
if (!qtController) return;
|
if (!qtController) return;
|
||||||
|
|
||||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||||
|
|
||||||
__block bool isAccepted = false;
|
__block bool isAccepted = false;
|
||||||
|
|
||||||
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
||||||
isAccepted = completed;
|
isAccepted = completed;
|
||||||
emit finished();
|
emit finished();
|
||||||
|
|
@ -822,11 +808,11 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||||
popController.sourceView = qtController.view;
|
popController.sourceView = qtController.view;
|
||||||
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec();
|
||||||
|
|
||||||
return isAccepted;
|
return isAccepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -840,7 +826,7 @@ QString IosController::openFile() {
|
||||||
if (!qtController) return;
|
if (!qtController) return;
|
||||||
|
|
||||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||||
|
|
||||||
__block QString filePath;
|
__block QString filePath;
|
||||||
|
|
||||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||||
|
|
@ -855,7 +841,7 @@ QString IosController::openFile() {
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||||
wait.exec();
|
wait.exec();
|
||||||
|
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,12 +121,6 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
|
||||||
if (!config.m_responsePacketJunkSize.isEmpty()) {
|
if (!config.m_responsePacketJunkSize.isEmpty()) {
|
||||||
out << "s2=" << config.m_responsePacketJunkSize << "\n";
|
out << "s2=" << config.m_responsePacketJunkSize << "\n";
|
||||||
}
|
}
|
||||||
if (!config.m_cookieReplyPacketJunkSize.isEmpty()) {
|
|
||||||
out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n";
|
|
||||||
}
|
|
||||||
if (!config.m_transportPacketJunkSize.isEmpty()) {
|
|
||||||
out << "s4=" << config.m_transportPacketJunkSize << "\n";
|
|
||||||
}
|
|
||||||
if (!config.m_initPacketMagicHeader.isEmpty()) {
|
if (!config.m_initPacketMagicHeader.isEmpty()) {
|
||||||
out << "h1=" << config.m_initPacketMagicHeader << "\n";
|
out << "h1=" << config.m_initPacketMagicHeader << "\n";
|
||||||
}
|
}
|
||||||
|
|
@ -140,26 +134,13 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
|
||||||
out << "h4=" << config.m_transportPacketMagicHeader << "\n";
|
out << "h4=" << config.m_transportPacketMagicHeader << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString& key : config.m_specialJunk.keys()) {
|
|
||||||
out << key.toLower() << "=" << config.m_specialJunk.value(key) << "\n";
|
|
||||||
}
|
|
||||||
for (const QString& key : config.m_controlledJunk.keys()) {
|
|
||||||
out << key.toLower() << "=" << config.m_controlledJunk.value(key) << "\n";
|
|
||||||
}
|
|
||||||
if (!config.m_specialHandshakeTimeout.isEmpty()) {
|
|
||||||
out << "itime=" << config.m_specialHandshakeTimeout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
int err = uapiErrno(uapiCommand(message));
|
int err = uapiErrno(uapiCommand(message));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
logger.error() << "Interface configuration failed:" << strerror(err);
|
logger.error() << "Interface configuration failed:" << strerror(err);
|
||||||
} else {
|
} else {
|
||||||
if (config.m_killSwitchEnabled) {
|
if (config.m_killSwitchEnabled) {
|
||||||
FirewallParams params { };
|
FirewallParams params { };
|
||||||
params.dnsServers.append(config.m_primaryDnsServer);
|
params.dnsServers.append(config.m_dnsServer);
|
||||||
if (!config.m_secondaryDnsServer.isEmpty()) {
|
|
||||||
params.dnsServers.append(config.m_secondaryDnsServer);
|
|
||||||
}
|
|
||||||
if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) {
|
if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) {
|
||||||
params.blockAll = true;
|
params.blockAll = true;
|
||||||
if (config.m_excludedAddresses.size()) {
|
if (config.m_excludedAddresses.size()) {
|
||||||
|
|
|
||||||
|
|
@ -43,16 +43,8 @@ namespace {
|
||||||
|
|
||||||
#include "macosfirewall.h"
|
#include "macosfirewall.h"
|
||||||
|
|
||||||
#include <QDir>
|
#define ResourceDir qApp->applicationDirPath() + "/pf"
|
||||||
#include <QStandardPaths>
|
#define DaemonDataDir qApp->applicationDirPath() + "/pf"
|
||||||
|
|
||||||
// Read-only rules bundled with the application.
|
|
||||||
#define ResourceDir (qApp->applicationDirPath() + "/pf")
|
|
||||||
|
|
||||||
// Writable location that does NOT live inside the signed bundle. Using a
|
|
||||||
// constant path under /Library/Application Support keeps the signature intact
|
|
||||||
// and is accessible to the root helper.
|
|
||||||
#define DaemonDataDir QStringLiteral("/Library/Application Support/AmneziaVPN/pf")
|
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
|
|
@ -129,8 +121,6 @@ void MacOSFirewall::install()
|
||||||
logger.info() << "Installing PF root anchor";
|
logger.info() << "Installing PF root anchor";
|
||||||
|
|
||||||
installRootAnchors();
|
installRootAnchors();
|
||||||
// Ensure writable directory exists, then store the token there.
|
|
||||||
QDir().mkpath(DaemonDataDir);
|
|
||||||
execute(QStringLiteral("pfctl -E 2>&1 | grep -F 'Token : ' | cut -c9- > '%1/pf.token'").arg(DaemonDataDir));
|
execute(QStringLiteral("pfctl -E 2>&1 | grep -F 'Token : ' | cut -c9- > '%1/pf.token'").arg(DaemonDataDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,12 +119,6 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
|
||||||
if (!config.m_responsePacketJunkSize.isEmpty()) {
|
if (!config.m_responsePacketJunkSize.isEmpty()) {
|
||||||
out << "s2=" << config.m_responsePacketJunkSize << "\n";
|
out << "s2=" << config.m_responsePacketJunkSize << "\n";
|
||||||
}
|
}
|
||||||
if (!config.m_cookieReplyPacketJunkSize.isEmpty()) {
|
|
||||||
out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n";
|
|
||||||
}
|
|
||||||
if (!config.m_transportPacketJunkSize.isEmpty()) {
|
|
||||||
out << "s4=" << config.m_transportPacketJunkSize << "\n";
|
|
||||||
}
|
|
||||||
if (!config.m_initPacketMagicHeader.isEmpty()) {
|
if (!config.m_initPacketMagicHeader.isEmpty()) {
|
||||||
out << "h1=" << config.m_initPacketMagicHeader << "\n";
|
out << "h1=" << config.m_initPacketMagicHeader << "\n";
|
||||||
}
|
}
|
||||||
|
|
@ -138,43 +132,30 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
|
||||||
out << "h4=" << config.m_transportPacketMagicHeader << "\n";
|
out << "h4=" << config.m_transportPacketMagicHeader << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QString& key : config.m_specialJunk.keys()) {
|
|
||||||
out << key.toLower() << "=" << config.m_specialJunk.value(key) << "\n";
|
|
||||||
}
|
|
||||||
for (const QString& key : config.m_controlledJunk.keys()) {
|
|
||||||
out << key.toLower() << "=" << config.m_controlledJunk.value(key) << "\n";
|
|
||||||
}
|
|
||||||
if (!config.m_specialHandshakeTimeout.isEmpty()) {
|
|
||||||
out << "itime=" << config.m_specialHandshakeTimeout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
int err = uapiErrno(uapiCommand(message));
|
int err = uapiErrno(uapiCommand(message));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
logger.error() << "Interface configuration failed:" << strerror(err);
|
logger.error() << "Interface configuration failed:" << strerror(err);
|
||||||
} else {
|
} else {
|
||||||
if (config.m_killSwitchEnabled) {
|
if (config.m_killSwitchEnabled) {
|
||||||
FirewallParams params { };
|
FirewallParams params { };
|
||||||
params.dnsServers.append(config.m_primaryDnsServer);
|
params.dnsServers.append(config.m_dnsServer);
|
||||||
if (!config.m_secondaryDnsServer.isEmpty()) {
|
|
||||||
params.dnsServers.append(config.m_secondaryDnsServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) {
|
if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) {
|
||||||
params.blockAll = true;
|
params.blockAll = true;
|
||||||
if (config.m_excludedAddresses.size()) {
|
if (config.m_excludedAddresses.size()) {
|
||||||
params.allowNets = true;
|
params.allowNets = true;
|
||||||
foreach (auto net, config.m_excludedAddresses) {
|
foreach (auto net, config.m_excludedAddresses) {
|
||||||
params.allowAddrs.append(net.toUtf8());
|
params.allowAddrs.append(net.toUtf8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
params.blockNets = true;
|
params.blockNets = true;
|
||||||
foreach (auto net, config.m_allowedIPAddressRanges) {
|
foreach (auto net, config.m_allowedIPAddressRanges) {
|
||||||
params.blockAddrs.append(net.toString());
|
params.blockAddrs.append(net.toString());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
applyFirewallRules(params);
|
||||||
}
|
}
|
||||||
applyFirewallRules(params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (err == 0);
|
return (err == 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -291,32 +291,15 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
||||||
"Block Internet", config.m_serverPublicKey)) {
|
"Block Internet", config.m_serverPublicKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!config.m_primaryDnsServer.isEmpty()) {
|
if (!config.m_dnsServer.isEmpty()) {
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_primaryDnsServer), 53, HIGH_WEIGHT,
|
if (!allowTrafficTo(QHostAddress(config.m_dnsServer), 53, HIGH_WEIGHT,
|
||||||
"Allow DNS-Server", config.m_serverPublicKey)) {
|
"Allow DNS-Server", config.m_serverPublicKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// In some cases, we might configure a 2nd DNS server for IPv6, however
|
// In some cases, we might configure a 2nd DNS server for IPv6, however
|
||||||
// this should probably be cleaned up by converting m_dnsServer into
|
// this should probably be cleaned up by converting m_dnsServer into
|
||||||
// a QStringList instead.
|
// a QStringList instead.
|
||||||
if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) {
|
if (config.m_dnsServer == config.m_serverIpv4Gateway) {
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
|
|
||||||
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
|
||||||
config.m_serverPublicKey)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.m_secondaryDnsServer.isEmpty()) {
|
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_secondaryDnsServer), 53, HIGH_WEIGHT,
|
|
||||||
"Allow DNS-Server", config.m_serverPublicKey)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// In some cases, we might configure a 2nd DNS server for IPv6, however
|
|
||||||
// this should probably be cleaned up by converting m_dnsServer into
|
|
||||||
// a QStringList instead.
|
|
||||||
if (config.m_secondaryDnsServer == config.m_serverIpv4Gateway) {
|
|
||||||
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
|
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
|
||||||
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
||||||
config.m_serverPublicKey)) {
|
config.m_serverPublicKey)) {
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,6 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) {
|
||||||
// Enable the windows firewall
|
// Enable the windows firewall
|
||||||
NET_IFINDEX ifindex;
|
NET_IFINDEX ifindex;
|
||||||
ConvertInterfaceLuidToIndex(&luid, &ifindex);
|
ConvertInterfaceLuidToIndex(&luid, &ifindex);
|
||||||
m_firewall->allowAllTraffic();
|
|
||||||
m_firewall->enableInterface(ifindex);
|
m_firewall->enableInterface(ifindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
|
||||||
// killSwitch toggle
|
// killSwitch toggle
|
||||||
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
|
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
|
||||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index());
|
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
|
||||||
}
|
}
|
||||||
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
||||||
m_configData.insert("vpnGateway", m_vpnGateway);
|
m_configData.insert("vpnGateway", m_vpnGateway);
|
||||||
|
|
|
||||||
|
|
@ -72,21 +72,10 @@ namespace amnezia
|
||||||
constexpr char junkPacketMaxSize[] = "Jmax";
|
constexpr char junkPacketMaxSize[] = "Jmax";
|
||||||
constexpr char initPacketJunkSize[] = "S1";
|
constexpr char initPacketJunkSize[] = "S1";
|
||||||
constexpr char responsePacketJunkSize[] = "S2";
|
constexpr char responsePacketJunkSize[] = "S2";
|
||||||
constexpr char cookieReplyPacketJunkSize[] = "S3";
|
|
||||||
constexpr char transportPacketJunkSize[] = "S4";
|
|
||||||
constexpr char initPacketMagicHeader[] = "H1";
|
constexpr char initPacketMagicHeader[] = "H1";
|
||||||
constexpr char responsePacketMagicHeader[] = "H2";
|
constexpr char responsePacketMagicHeader[] = "H2";
|
||||||
constexpr char underloadPacketMagicHeader[] = "H3";
|
constexpr char underloadPacketMagicHeader[] = "H3";
|
||||||
constexpr char transportPacketMagicHeader[] = "H4";
|
constexpr char transportPacketMagicHeader[] = "H4";
|
||||||
constexpr char specialJunk1[] = "I1";
|
|
||||||
constexpr char specialJunk2[] = "I2";
|
|
||||||
constexpr char specialJunk3[] = "I3";
|
|
||||||
constexpr char specialJunk4[] = "I4";
|
|
||||||
constexpr char specialJunk5[] = "I5";
|
|
||||||
constexpr char controlledJunk1[] = "J1";
|
|
||||||
constexpr char controlledJunk2[] = "J2";
|
|
||||||
constexpr char controlledJunk3[] = "J3";
|
|
||||||
constexpr char specialHandshakeTimeout[] = "Itime";
|
|
||||||
|
|
||||||
constexpr char openvpn[] = "openvpn";
|
constexpr char openvpn[] = "openvpn";
|
||||||
constexpr char wireguard[] = "wireguard";
|
constexpr char wireguard[] = "wireguard";
|
||||||
|
|
@ -227,22 +216,10 @@ namespace amnezia
|
||||||
constexpr char defaultJunkPacketMaxSize[] = "30";
|
constexpr char defaultJunkPacketMaxSize[] = "30";
|
||||||
constexpr char defaultInitPacketJunkSize[] = "15";
|
constexpr char defaultInitPacketJunkSize[] = "15";
|
||||||
constexpr char defaultResponsePacketJunkSize[] = "18";
|
constexpr char defaultResponsePacketJunkSize[] = "18";
|
||||||
constexpr char defaultCookieReplyPacketJunkSize[] = "20";
|
|
||||||
constexpr char defaultTransportPacketJunkSize[] = "23";
|
|
||||||
|
|
||||||
constexpr char defaultInitPacketMagicHeader[] = "1020325451";
|
constexpr char defaultInitPacketMagicHeader[] = "1020325451";
|
||||||
constexpr char defaultResponsePacketMagicHeader[] = "3288052141";
|
constexpr char defaultResponsePacketMagicHeader[] = "3288052141";
|
||||||
constexpr char defaultTransportPacketMagicHeader[] = "2528465083";
|
constexpr char defaultTransportPacketMagicHeader[] = "2528465083";
|
||||||
constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858";
|
constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858";
|
||||||
constexpr char defaultSpecialJunk1[] = "";
|
|
||||||
constexpr char defaultSpecialJunk2[] = "";
|
|
||||||
constexpr char defaultSpecialJunk3[] = "";
|
|
||||||
constexpr char defaultSpecialJunk4[] = "";
|
|
||||||
constexpr char defaultSpecialJunk5[] = "";
|
|
||||||
constexpr char defaultControlledJunk1[] = "";
|
|
||||||
constexpr char defaultControlledJunk2[] = "";
|
|
||||||
constexpr char defaultControlledJunk3[] = "";
|
|
||||||
constexpr char defaultSpecialHandshakeTimeout[] = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace socks5Proxy
|
namespace socks5Proxy
|
||||||
|
|
|
||||||
|
|
@ -98,13 +98,8 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||||
if (vpnState == Vpn::ConnectionState::Connected) {
|
if (vpnState == Vpn::ConnectionState::Connected) {
|
||||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
QList<QHostAddress> dnsAddr;
|
QList<QHostAddress> dnsAddr;
|
||||||
|
|
||||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
||||||
// We don't use secondary DNS if primary DNS is AmneziaDNS
|
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
||||||
if (!m_configData.value(amnezia::config_key::dns1).toString().
|
|
||||||
contains(amnezia::protocols::dns::amneziaDnsIp)) {
|
|
||||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
|
||||||
}
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QThread::msleep(8000);
|
QThread::msleep(8000);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -139,7 +134,7 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||||
// killSwitch toggle
|
// killSwitch toggle
|
||||||
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
|
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
|
||||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index());
|
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
|
||||||
}
|
}
|
||||||
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
||||||
m_configData.insert("vpnGateway", m_vpnGateway);
|
m_configData.insert("vpnGateway", m_vpnGateway);
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,6 @@
|
||||||
<file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file>
|
<file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file>
|
||||||
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
|
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
|
||||||
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
|
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
|
||||||
<file>ui/qml/Components/AwgTextField.qml</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/countriesFlags">
|
<qresource prefix="/countriesFlags">
|
||||||
<file>images/flagKit/ZW.svg</file>
|
<file>images/flagKit/ZW.svg</file>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ RUN mkdir -p /opt/amnezia
|
||||||
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
|
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
|
||||||
RUN chmod a+x /opt/amnezia/start.sh
|
RUN chmod a+x /opt/amnezia/start.sh
|
||||||
|
|
||||||
# Tune network
|
# Tune network
|
||||||
RUN echo -e " \n\
|
RUN echo -e " \n\
|
||||||
fs.file-max = 51200 \n\
|
fs.file-max = 51200 \n\
|
||||||
\n\
|
\n\
|
||||||
|
|
@ -40,8 +40,7 @@ RUN echo -e " \n\
|
||||||
echo -e " \n\
|
echo -e " \n\
|
||||||
* soft nofile 51200 \n\
|
* soft nofile 51200 \n\
|
||||||
* hard nofile 51200 \n\
|
* hard nofile 51200 \n\
|
||||||
" | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf
|
" | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf
|
||||||
|
|
||||||
ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]
|
ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]
|
||||||
CMD [ "" ]
|
CMD [ "" ]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,4 @@ H1 = $INIT_PACKET_MAGIC_HEADER
|
||||||
H2 = $RESPONSE_PACKET_MAGIC_HEADER
|
H2 = $RESPONSE_PACKET_MAGIC_HEADER
|
||||||
H3 = $UNDERLOAD_PACKET_MAGIC_HEADER
|
H3 = $UNDERLOAD_PACKET_MAGIC_HEADER
|
||||||
H4 = $TRANSPORT_PACKET_MAGIC_HEADER
|
H4 = $TRANSPORT_PACKET_MAGIC_HEADER
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
if which apt-get > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/dpkg/lock-frontend";\
|
if which apt-get > /dev/null 2>&1; then LOCK_FILE="/var/lib/dpkg/lock-frontend";\
|
||||||
elif which dnf > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/cache/dnf/* /var/run/dnf/* /var/lib/dnf/* /var/lib/rpm/*";\
|
elif which dnf > /dev/null 2>&1; then LOCK_FILE="/var/run/dnf.pid";\
|
||||||
elif which yum > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/yum.pid";\
|
elif which yum > /dev/null 2>&1; then LOCK_FILE="/var/run/yum.pid";\
|
||||||
elif which zypper > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/zypp.pid";\
|
elif which pacman > /dev/null 2>&1; then LOCK_FILE="/var/lib/pacman/db.lck";\
|
||||||
elif which pacman > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/pacman/db.lck";\
|
|
||||||
else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\
|
else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\
|
||||||
if command -v $LOCK_CMD > /dev/null 2>&1; then sudo $LOCK_CMD $LOCK_FILE 2>/dev/null; else echo "$LOCK_CMD not installed"; fi
|
if command -v fuser > /dev/null 2>&1; then sudo fuser $LOCK_FILE 2>/dev/null; else echo "fuser not installed"; fi
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\
|
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\
|
||||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\
|
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\
|
||||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\
|
elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\
|
||||||
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); opt="--version";\
|
|
||||||
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\
|
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\
|
||||||
else pm="uname"; opt="-a";\
|
else pm="uname"; opt="-a";\
|
||||||
fi;\
|
fi;\
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
|
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
|
||||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
|
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
|
||||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
|
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
|
||||||
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); silent_inst="-nq install"; check_pkgs="-nq refresh"; docker_pkg="docker"; dist="opensuse";\
|
|
||||||
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux";\
|
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux";\
|
||||||
else echo "Packet manager not found"; exit 1; fi;\
|
else echo "Packet manager not found"; exit 1; fi;\
|
||||||
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\
|
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ namespace
|
||||||
{
|
{
|
||||||
constexpr char cloak[] = "cloak";
|
constexpr char cloak[] = "cloak";
|
||||||
constexpr char awg[] = "awg";
|
constexpr char awg[] = "awg";
|
||||||
constexpr char vless[] = "vless";
|
|
||||||
|
|
||||||
constexpr char apiEndpoint[] = "api_endpoint";
|
constexpr char apiEndpoint[] = "api_endpoint";
|
||||||
constexpr char accessToken[] = "api_key";
|
constexpr char accessToken[] = "api_key";
|
||||||
|
|
@ -36,6 +35,10 @@ namespace
|
||||||
constexpr char serviceInfo[] = "service_info";
|
constexpr char serviceInfo[] = "service_info";
|
||||||
constexpr char serviceProtocol[] = "service_protocol";
|
constexpr char serviceProtocol[] = "service_protocol";
|
||||||
|
|
||||||
|
constexpr char aesKey[] = "aes_key";
|
||||||
|
constexpr char aesIv[] = "aes_iv";
|
||||||
|
constexpr char aesSalt[] = "aes_salt";
|
||||||
|
|
||||||
constexpr char apiPayload[] = "api_payload";
|
constexpr char apiPayload[] = "api_payload";
|
||||||
constexpr char keyPayload[] = "key_payload";
|
constexpr char keyPayload[] = "key_payload";
|
||||||
|
|
||||||
|
|
@ -44,185 +47,6 @@ namespace
|
||||||
|
|
||||||
constexpr char config[] = "config";
|
constexpr char config[] = "config";
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProtocolData
|
|
||||||
{
|
|
||||||
OpenVpnConfigurator::ConnectionData certRequest;
|
|
||||||
|
|
||||||
QString wireGuardClientPrivKey;
|
|
||||||
QString wireGuardClientPubKey;
|
|
||||||
|
|
||||||
QString xrayUuid;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GatewayRequestData
|
|
||||||
{
|
|
||||||
QString osVersion;
|
|
||||||
QString appVersion;
|
|
||||||
|
|
||||||
QString installationUuid;
|
|
||||||
|
|
||||||
QString userCountryCode;
|
|
||||||
QString serverCountryCode;
|
|
||||||
QString serviceType;
|
|
||||||
QString serviceProtocol;
|
|
||||||
|
|
||||||
QJsonObject authData;
|
|
||||||
|
|
||||||
QJsonObject toJsonObject() const
|
|
||||||
{
|
|
||||||
QJsonObject obj;
|
|
||||||
if (!osVersion.isEmpty()) {
|
|
||||||
obj[configKey::osVersion] = osVersion;
|
|
||||||
}
|
|
||||||
if (!appVersion.isEmpty()) {
|
|
||||||
obj[configKey::appVersion] = appVersion;
|
|
||||||
}
|
|
||||||
if (!installationUuid.isEmpty()) {
|
|
||||||
obj[configKey::uuid] = installationUuid;
|
|
||||||
}
|
|
||||||
if (!userCountryCode.isEmpty()) {
|
|
||||||
obj[configKey::userCountryCode] = userCountryCode;
|
|
||||||
}
|
|
||||||
if (!serverCountryCode.isEmpty()) {
|
|
||||||
obj[configKey::serverCountryCode] = serverCountryCode;
|
|
||||||
}
|
|
||||||
if (!serviceType.isEmpty()) {
|
|
||||||
obj[configKey::serviceType] = serviceType;
|
|
||||||
}
|
|
||||||
if (!serviceProtocol.isEmpty()) {
|
|
||||||
obj[configKey::serviceProtocol] = serviceProtocol;
|
|
||||||
}
|
|
||||||
if (!authData.isEmpty()) {
|
|
||||||
obj[configKey::authData] = authData;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProtocolData generateProtocolData(const QString &protocol)
|
|
||||||
{
|
|
||||||
ProtocolData protocolData;
|
|
||||||
if (protocol == configKey::cloak) {
|
|
||||||
protocolData.certRequest = OpenVpnConfigurator::createCertRequest();
|
|
||||||
} else if (protocol == configKey::awg) {
|
|
||||||
auto connData = WireguardConfigurator::genClientKeys();
|
|
||||||
protocolData.wireGuardClientPubKey = connData.clientPubKey;
|
|
||||||
protocolData.wireGuardClientPrivKey = connData.clientPrivKey;
|
|
||||||
} else if (protocol == configKey::vless) {
|
|
||||||
protocolData.xrayUuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
|
||||||
}
|
|
||||||
|
|
||||||
return protocolData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void appendProtocolDataToApiPayload(const QString &protocol, const ProtocolData &protocolData, QJsonObject &apiPayload)
|
|
||||||
{
|
|
||||||
if (protocol == configKey::cloak) {
|
|
||||||
apiPayload[configKey::certificate] = protocolData.certRequest.request;
|
|
||||||
} else if (protocol == configKey::awg) {
|
|
||||||
apiPayload[configKey::publicKey] = protocolData.wireGuardClientPubKey;
|
|
||||||
} else if (protocol == configKey::vless) {
|
|
||||||
apiPayload[configKey::publicKey] = protocolData.xrayUuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorCode fillServerConfig(const QString &protocol, const ProtocolData &apiPayloadData, const QByteArray &apiResponseBody,
|
|
||||||
QJsonObject &serverConfig)
|
|
||||||
{
|
|
||||||
QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString();
|
|
||||||
|
|
||||||
data.replace("vpn://", "");
|
|
||||||
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
|
||||||
|
|
||||||
if (ba.isEmpty()) {
|
|
||||||
qDebug() << "empty vpn key";
|
|
||||||
return ErrorCode::ApiConfigEmptyError;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray ba_uncompressed = qUncompress(ba);
|
|
||||||
if (!ba_uncompressed.isEmpty()) {
|
|
||||||
ba = ba_uncompressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString configStr = ba;
|
|
||||||
if (protocol == configKey::cloak) {
|
|
||||||
configStr.replace("<key>", "<key>\n");
|
|
||||||
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
|
|
||||||
} else if (protocol == configKey::awg) {
|
|
||||||
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
|
|
||||||
auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
|
||||||
auto containers = newServerConfig.value(config_key::containers).toArray();
|
|
||||||
if (containers.isEmpty()) {
|
|
||||||
qDebug() << "missing containers field";
|
|
||||||
return ErrorCode::ApiConfigEmptyError;
|
|
||||||
}
|
|
||||||
auto container = containers.at(0).toObject();
|
|
||||||
QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg);
|
|
||||||
auto serverProtocolConfig = container.value(containerName).toObject();
|
|
||||||
auto clientProtocolConfig =
|
|
||||||
QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
|
|
||||||
|
|
||||||
//TODO looks like this block can be removed after v1 configs EOL
|
|
||||||
|
|
||||||
serverProtocolConfig[config_key::junkPacketCount] = clientProtocolConfig.value(config_key::junkPacketCount);
|
|
||||||
serverProtocolConfig[config_key::junkPacketMinSize] = clientProtocolConfig.value(config_key::junkPacketMinSize);
|
|
||||||
serverProtocolConfig[config_key::junkPacketMaxSize] = clientProtocolConfig.value(config_key::junkPacketMaxSize);
|
|
||||||
serverProtocolConfig[config_key::initPacketJunkSize] = clientProtocolConfig.value(config_key::initPacketJunkSize);
|
|
||||||
serverProtocolConfig[config_key::responsePacketJunkSize] = clientProtocolConfig.value(config_key::responsePacketJunkSize);
|
|
||||||
serverProtocolConfig[config_key::initPacketMagicHeader] = clientProtocolConfig.value(config_key::initPacketMagicHeader);
|
|
||||||
serverProtocolConfig[config_key::responsePacketMagicHeader] = clientProtocolConfig.value(config_key::responsePacketMagicHeader);
|
|
||||||
serverProtocolConfig[config_key::underloadPacketMagicHeader] = clientProtocolConfig.value(config_key::underloadPacketMagicHeader);
|
|
||||||
serverProtocolConfig[config_key::transportPacketMagicHeader] = clientProtocolConfig.value(config_key::transportPacketMagicHeader);
|
|
||||||
|
|
||||||
serverProtocolConfig[config_key::cookieReplyPacketJunkSize] = clientProtocolConfig.value(config_key::cookieReplyPacketJunkSize);
|
|
||||||
serverProtocolConfig[config_key::transportPacketJunkSize] = clientProtocolConfig.value(config_key::transportPacketJunkSize);
|
|
||||||
serverProtocolConfig[config_key::specialJunk1] = clientProtocolConfig.value(config_key::specialJunk1);
|
|
||||||
serverProtocolConfig[config_key::specialJunk2] = clientProtocolConfig.value(config_key::specialJunk2);
|
|
||||||
serverProtocolConfig[config_key::specialJunk3] = clientProtocolConfig.value(config_key::specialJunk3);
|
|
||||||
serverProtocolConfig[config_key::specialJunk4] = clientProtocolConfig.value(config_key::specialJunk4);
|
|
||||||
serverProtocolConfig[config_key::specialJunk5] = clientProtocolConfig.value(config_key::specialJunk5);
|
|
||||||
serverProtocolConfig[config_key::controlledJunk1] = clientProtocolConfig.value(config_key::controlledJunk1);
|
|
||||||
serverProtocolConfig[config_key::controlledJunk2] = clientProtocolConfig.value(config_key::controlledJunk2);
|
|
||||||
serverProtocolConfig[config_key::controlledJunk3] = clientProtocolConfig.value(config_key::controlledJunk3);
|
|
||||||
serverProtocolConfig[config_key::specialHandshakeTimeout] = clientProtocolConfig.value(config_key::specialHandshakeTimeout);
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
container[containerName] = serverProtocolConfig;
|
|
||||||
containers.replace(0, container);
|
|
||||||
newServerConfig[config_key::containers] = containers;
|
|
||||||
configStr = QString(QJsonDocument(newServerConfig).toJson());
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
|
||||||
serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
|
|
||||||
serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
|
|
||||||
serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
|
|
||||||
serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
|
|
||||||
|
|
||||||
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
|
|
||||||
serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
|
|
||||||
serverConfig[config_key::description] = newServerConfig.value(config_key::description);
|
|
||||||
serverConfig[config_key::name] = newServerConfig.value(config_key::name);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString();
|
|
||||||
serverConfig[config_key::defaultContainer] = defaultContainer;
|
|
||||||
|
|
||||||
QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap();
|
|
||||||
map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap());
|
|
||||||
auto apiConfig = QJsonObject::fromVariantMap(map);
|
|
||||||
|
|
||||||
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
|
|
||||||
apiConfig.insert(apiDefs::key::supportedProtocols,
|
|
||||||
QJsonDocument::fromJson(apiResponseBody).object().value(apiDefs::key::supportedProtocols).toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
serverConfig[configKey::apiConfig] = apiConfig;
|
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiConfigsController::ApiConfigsController(const QSharedPointer<ServersModel> &serversModel,
|
ApiConfigsController::ApiConfigsController(const QSharedPointer<ServersModel> &serversModel,
|
||||||
|
|
@ -239,26 +63,24 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
||||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||||
|
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
|
||||||
QString(APP_VERSION),
|
|
||||||
m_settings->getInstallationUuid(true),
|
|
||||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
|
||||||
serverCountryCode,
|
|
||||||
apiConfigObject.value(configKey::serviceType).toString(),
|
|
||||||
m_apiServicesModel->getSelectedServiceProtocol(),
|
|
||||||
serverConfigObject.value(configKey::authData).toObject() };
|
|
||||||
|
|
||||||
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||||
ProtocolData protocolData = generateProtocolData(protocol);
|
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
|
||||||
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload);
|
apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
|
||||||
|
apiPayload[configKey::serverCountryCode] = serverCountryCode;
|
||||||
|
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
|
||||||
|
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
|
||||||
|
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = executeRequest(QString("%1v1/native_config"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/native_config"), apiPayload, responseBody);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
emit errorOccurred(errorCode);
|
emit errorOccurred(errorCode);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -266,7 +88,7 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
||||||
|
|
||||||
QJsonObject jsonConfig = QJsonDocument::fromJson(responseBody).object();
|
QJsonObject jsonConfig = QJsonDocument::fromJson(responseBody).object();
|
||||||
QString nativeConfig = jsonConfig.value(configKey::config).toString();
|
QString nativeConfig = jsonConfig.value(configKey::config).toString();
|
||||||
nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", protocolData.wireGuardClientPrivKey);
|
nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
|
||||||
|
|
||||||
SystemController::saveFile(fileName, nativeConfig);
|
SystemController::saveFile(fileName, nativeConfig);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -274,22 +96,24 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
||||||
|
|
||||||
bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
|
bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
|
||||||
{
|
{
|
||||||
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
||||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||||
|
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||||
QString(APP_VERSION),
|
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||||
m_settings->getInstallationUuid(true),
|
|
||||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
|
||||||
serverCountryCode,
|
|
||||||
apiConfigObject.value(configKey::serviceType).toString(),
|
|
||||||
m_apiServicesModel->getSelectedServiceProtocol(),
|
|
||||||
serverConfigObject.value(configKey::authData).toObject() };
|
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
|
||||||
|
apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
|
||||||
|
apiPayload[configKey::serverCountryCode] = serverCountryCode;
|
||||||
|
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
|
||||||
|
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
|
||||||
|
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_native_config"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_native_config"), apiPayload, responseBody);
|
||||||
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
||||||
emit errorOccurred(errorCode);
|
emit errorOccurred(errorCode);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -320,11 +144,14 @@ void ApiConfigsController::copyVpnKeyToClipboard()
|
||||||
|
|
||||||
bool ApiConfigsController::fillAvailableServices()
|
bool ApiConfigsController::fillAvailableServices()
|
||||||
{
|
{
|
||||||
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
QJsonObject apiPayload;
|
QJsonObject apiPayload;
|
||||||
apiPayload[configKey::osVersion] = QSysInfo::productType();
|
apiPayload[configKey::osVersion] = QSysInfo::productType();
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = executeRequest(QString("%1v1/services"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/services"), apiPayload, responseBody);
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
if (!responseBody.contains("services")) {
|
if (!responseBody.contains("services")) {
|
||||||
errorCode = ErrorCode::ApiServicesMissingError;
|
errorCode = ErrorCode::ApiServicesMissingError;
|
||||||
|
|
@ -343,36 +170,34 @@ bool ApiConfigsController::fillAvailableServices()
|
||||||
|
|
||||||
bool ApiConfigsController::importServiceFromGateway()
|
bool ApiConfigsController::importServiceFromGateway()
|
||||||
{
|
{
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
if (m_serversModel->isServerFromApiAlreadyExists(m_apiServicesModel->getCountryCode(), m_apiServicesModel->getSelectedServiceType(),
|
||||||
QString(APP_VERSION),
|
m_apiServicesModel->getSelectedServiceProtocol())) {
|
||||||
m_settings->getInstallationUuid(true),
|
|
||||||
m_apiServicesModel->getCountryCode(),
|
|
||||||
"",
|
|
||||||
m_apiServicesModel->getSelectedServiceType(),
|
|
||||||
m_apiServicesModel->getSelectedServiceProtocol(),
|
|
||||||
QJsonObject() };
|
|
||||||
|
|
||||||
if (m_serversModel->isServerFromApiAlreadyExists(gatewayRequestData.userCountryCode, gatewayRequestData.serviceType,
|
|
||||||
gatewayRequestData.serviceProtocol)) {
|
|
||||||
emit errorOccurred(ErrorCode::ApiConfigAlreadyAdded);
|
emit errorOccurred(ErrorCode::ApiConfigAlreadyAdded);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol);
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||||
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload);
|
auto userCountryCode = m_apiServicesModel->getCountryCode();
|
||||||
|
auto serviceType = m_apiServicesModel->getSelectedServiceType();
|
||||||
|
auto serviceProtocol = m_apiServicesModel->getSelectedServiceProtocol();
|
||||||
|
|
||||||
|
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
|
||||||
|
|
||||||
|
QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
|
||||||
|
apiPayload[configKey::userCountryCode] = userCountryCode;
|
||||||
|
apiPayload[configKey::serviceType] = serviceType;
|
||||||
|
apiPayload[configKey::uuid] = installationUuid;
|
||||||
|
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody);
|
||||||
|
|
||||||
QJsonObject serverConfig;
|
QJsonObject serverConfig;
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, serverConfig);
|
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
|
||||||
emit errorOccurred(errorCode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||||
apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode());
|
apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode());
|
||||||
|
|
@ -393,33 +218,39 @@ bool ApiConfigsController::importServiceFromGateway()
|
||||||
bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
||||||
bool reloadServiceConfig)
|
bool reloadServiceConfig)
|
||||||
{
|
{
|
||||||
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||||
|
auto authData = serverConfig.value(configKey::authData).toObject();
|
||||||
|
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||||
QString(APP_VERSION),
|
auto userCountryCode = apiConfig.value(configKey::userCountryCode).toString();
|
||||||
m_settings->getInstallationUuid(true),
|
auto serviceType = apiConfig.value(configKey::serviceType).toString();
|
||||||
apiConfig.value(configKey::userCountryCode).toString(),
|
auto serviceProtocol = apiConfig.value(configKey::serviceProtocol).toString();
|
||||||
newCountryCode,
|
|
||||||
apiConfig.value(configKey::serviceType).toString(),
|
|
||||||
apiConfig.value(configKey::serviceProtocol).toString(),
|
|
||||||
serverConfig.value(configKey::authData).toObject() };
|
|
||||||
|
|
||||||
ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol);
|
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
|
||||||
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload);
|
apiPayload[configKey::userCountryCode] = userCountryCode;
|
||||||
|
apiPayload[configKey::serviceType] = serviceType;
|
||||||
|
apiPayload[configKey::uuid] = installationUuid;
|
||||||
|
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||||
|
|
||||||
|
if (!newCountryCode.isEmpty()) {
|
||||||
|
apiPayload[configKey::serverCountryCode] = newCountryCode;
|
||||||
|
}
|
||||||
|
if (!authData.isEmpty()) {
|
||||||
|
apiPayload[configKey::authData] = authData;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody);
|
||||||
|
|
||||||
QJsonObject newServerConfig;
|
QJsonObject newServerConfig;
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, newServerConfig);
|
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, newServerConfig);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
|
||||||
emit errorOccurred(errorCode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
|
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
|
||||||
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
|
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
|
||||||
|
|
@ -428,7 +259,7 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||||
newApiConfig.insert(apiDefs::key::vpnKey, apiConfig.value(apiDefs::key::vpnKey));
|
newApiConfig.insert(apiDefs::key::vpnKey, apiConfig.value(apiDefs::key::vpnKey));
|
||||||
|
|
||||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||||
newServerConfig.insert(configKey::authData, gatewayRequestData.authData);
|
newServerConfig.insert(configKey::authData, authData);
|
||||||
|
|
||||||
if (serverConfig.value(config_key::nameOverriddenByUser).toBool()) {
|
if (serverConfig.value(config_key::nameOverriddenByUser).toBool()) {
|
||||||
newServerConfig.insert(config_key::name, serverConfig.value(config_key::name));
|
newServerConfig.insert(config_key::name, serverConfig.value(config_key::name));
|
||||||
|
|
@ -463,13 +294,10 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||||
|
|
||||||
QString serviceProtocol = serverConfig.value(configKey::protocol).toString();
|
QString serviceProtocol = serverConfig.value(configKey::protocol).toString();
|
||||||
ProtocolData protocolData = generateProtocolData(serviceProtocol);
|
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
|
||||||
|
|
||||||
QJsonObject apiPayload;
|
QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
|
||||||
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
|
|
||||||
apiPayload[configKey::uuid] = installationUuid;
|
apiPayload[configKey::uuid] = installationUuid;
|
||||||
apiPayload[configKey::osVersion] = QSysInfo::productType();
|
|
||||||
apiPayload[configKey::appVersion] = QString(APP_VERSION);
|
|
||||||
apiPayload[configKey::accessToken] = serverConfig.value(configKey::accessToken).toString();
|
apiPayload[configKey::accessToken] = serverConfig.value(configKey::accessToken).toString();
|
||||||
apiPayload[configKey::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString();
|
apiPayload[configKey::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString();
|
||||||
|
|
||||||
|
|
@ -477,11 +305,7 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody);
|
||||||
|
|
||||||
if (errorCode == ErrorCode::NoError) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
errorCode = fillServerConfig(serviceProtocol, protocolData, responseBody, serverConfig);
|
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
|
||||||
emit errorOccurred(errorCode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_serversModel->editServer(serverConfig, serverIndex);
|
m_serversModel->editServer(serverConfig, serverIndex);
|
||||||
emit updateServerFromApiFinished();
|
emit updateServerFromApiFinished();
|
||||||
|
|
@ -494,6 +318,9 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||||
|
|
||||||
bool ApiConfigsController::deactivateDevice()
|
bool ApiConfigsController::deactivateDevice()
|
||||||
{
|
{
|
||||||
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
||||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||||
|
|
@ -502,19 +329,19 @@ bool ApiConfigsController::deactivateDevice()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||||
QString(APP_VERSION),
|
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||||
m_settings->getInstallationUuid(true),
|
|
||||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
|
||||||
apiConfigObject.value(configKey::serverCountryCode).toString(),
|
|
||||||
apiConfigObject.value(configKey::serviceType).toString(),
|
|
||||||
"",
|
|
||||||
serverConfigObject.value(configKey::authData).toObject() };
|
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
|
||||||
|
apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
|
||||||
|
apiPayload[configKey::serverCountryCode] = apiConfigObject.value(configKey::serverCountryCode);
|
||||||
|
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
|
||||||
|
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
|
||||||
|
apiPayload[configKey::uuid] = m_settings->getInstallationUuid(true);
|
||||||
|
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
||||||
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
||||||
emit errorOccurred(errorCode);
|
emit errorOccurred(errorCode);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -528,6 +355,9 @@ bool ApiConfigsController::deactivateDevice()
|
||||||
|
|
||||||
bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode)
|
bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode)
|
||||||
{
|
{
|
||||||
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||||
|
m_settings->isStrictKillSwitchEnabled());
|
||||||
|
|
||||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
||||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||||
|
|
@ -536,19 +366,19 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||||
QString(APP_VERSION),
|
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||||
uuid,
|
|
||||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
|
||||||
serverCountryCode,
|
|
||||||
apiConfigObject.value(configKey::serviceType).toString(),
|
|
||||||
"",
|
|
||||||
serverConfigObject.value(configKey::authData).toObject() };
|
|
||||||
|
|
||||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
|
||||||
|
apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
|
||||||
|
apiPayload[configKey::serverCountryCode] = serverCountryCode;
|
||||||
|
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
|
||||||
|
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
|
||||||
|
apiPayload[configKey::uuid] = uuid;
|
||||||
|
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
||||||
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
||||||
emit errorOccurred(errorCode);
|
emit errorOccurred(errorCode);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -587,29 +417,108 @@ bool ApiConfigsController::isConfigValid()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiConfigsController::setCurrentProtocol(const QString &protocolName)
|
ApiConfigsController::ApiPayloadData ApiConfigsController::generateApiPayloadData(const QString &protocol)
|
||||||
{
|
{
|
||||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
ApiConfigsController::ApiPayloadData apiPayload;
|
||||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
if (protocol == configKey::cloak) {
|
||||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
apiPayload.certRequest = OpenVpnConfigurator::createCertRequest();
|
||||||
|
} else if (protocol == configKey::awg) {
|
||||||
apiConfigObject[configKey::serviceProtocol] = protocolName;
|
auto connData = WireguardConfigurator::genClientKeys();
|
||||||
|
apiPayload.wireGuardClientPubKey = connData.clientPubKey;
|
||||||
serverConfigObject.insert(configKey::apiConfig, apiConfigObject);
|
apiPayload.wireGuardClientPrivKey = connData.clientPrivKey;
|
||||||
|
}
|
||||||
m_serversModel->editServer(serverConfigObject, serverIndex);
|
return apiPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApiConfigsController::isVlessProtocol()
|
QJsonObject ApiConfigsController::fillApiPayload(const QString &protocol, const ApiPayloadData &apiPayloadData)
|
||||||
{
|
{
|
||||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
QJsonObject obj;
|
||||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
if (protocol == configKey::cloak) {
|
||||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
obj[configKey::certificate] = apiPayloadData.certRequest.request;
|
||||||
|
} else if (protocol == configKey::awg) {
|
||||||
if (apiConfigObject[configKey::serviceProtocol].toString() == "vless") {
|
obj[configKey::publicKey] = apiPayloadData.wireGuardClientPubKey;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
obj[configKey::osVersion] = QSysInfo::productType();
|
||||||
|
obj[configKey::appVersion] = QString(APP_VERSION);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiConfigsController::fillServerConfig(const QString &protocol, const ApiPayloadData &apiPayloadData,
|
||||||
|
const QByteArray &apiResponseBody, QJsonObject &serverConfig)
|
||||||
|
{
|
||||||
|
QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString();
|
||||||
|
|
||||||
|
data.replace("vpn://", "");
|
||||||
|
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||||
|
|
||||||
|
if (ba.isEmpty()) {
|
||||||
|
emit errorOccurred(ErrorCode::ApiConfigEmptyError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray ba_uncompressed = qUncompress(ba);
|
||||||
|
if (!ba_uncompressed.isEmpty()) {
|
||||||
|
ba = ba_uncompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString configStr = ba;
|
||||||
|
if (protocol == configKey::cloak) {
|
||||||
|
configStr.replace("<key>", "<key>\n");
|
||||||
|
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
|
||||||
|
} else if (protocol == configKey::awg) {
|
||||||
|
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
|
||||||
|
auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
||||||
|
auto containers = newServerConfig.value(config_key::containers).toArray();
|
||||||
|
if (containers.isEmpty()) {
|
||||||
|
return; // todo process error
|
||||||
|
}
|
||||||
|
auto container = containers.at(0).toObject();
|
||||||
|
QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg);
|
||||||
|
auto containerConfig = container.value(containerName).toObject();
|
||||||
|
auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object();
|
||||||
|
containerConfig[config_key::junkPacketCount] = protocolConfig.value(config_key::junkPacketCount);
|
||||||
|
containerConfig[config_key::junkPacketMinSize] = protocolConfig.value(config_key::junkPacketMinSize);
|
||||||
|
containerConfig[config_key::junkPacketMaxSize] = protocolConfig.value(config_key::junkPacketMaxSize);
|
||||||
|
containerConfig[config_key::initPacketJunkSize] = protocolConfig.value(config_key::initPacketJunkSize);
|
||||||
|
containerConfig[config_key::responsePacketJunkSize] = protocolConfig.value(config_key::responsePacketJunkSize);
|
||||||
|
containerConfig[config_key::initPacketMagicHeader] = protocolConfig.value(config_key::initPacketMagicHeader);
|
||||||
|
containerConfig[config_key::responsePacketMagicHeader] = protocolConfig.value(config_key::responsePacketMagicHeader);
|
||||||
|
containerConfig[config_key::underloadPacketMagicHeader] = protocolConfig.value(config_key::underloadPacketMagicHeader);
|
||||||
|
containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader);
|
||||||
|
container[containerName] = containerConfig;
|
||||||
|
containers.replace(0, container);
|
||||||
|
newServerConfig[config_key::containers] = containers;
|
||||||
|
configStr = QString(QJsonDocument(newServerConfig).toJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
||||||
|
serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
|
||||||
|
serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
|
||||||
|
serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
|
||||||
|
serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
|
||||||
|
|
||||||
|
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
|
||||||
|
serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
|
||||||
|
serverConfig[config_key::description] = newServerConfig.value(config_key::description);
|
||||||
|
serverConfig[config_key::name] = newServerConfig.value(config_key::name);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString();
|
||||||
|
serverConfig[config_key::defaultContainer] = defaultContainer;
|
||||||
|
|
||||||
|
QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap();
|
||||||
|
map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap());
|
||||||
|
auto apiConfig = QJsonObject::fromVariantMap(map);
|
||||||
|
|
||||||
|
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
|
||||||
|
apiConfig.insert(configKey::serviceInfo, QJsonDocument::fromJson(apiResponseBody).object().value(configKey::serviceInfo).toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConfig[configKey::apiConfig] = apiConfig;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QString> ApiConfigsController::getQrCodes()
|
QList<QString> ApiConfigsController::getQrCodes()
|
||||||
|
|
@ -626,10 +535,3 @@ QString ApiConfigsController::getVpnKey()
|
||||||
{
|
{
|
||||||
return m_vpnKey;
|
return m_vpnKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ApiConfigsController::executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody)
|
|
||||||
{
|
|
||||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
|
||||||
m_settings->isStrictKillSwitchEnabled());
|
|
||||||
return gatewayController.post(endpoint, apiPayload, responseBody);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,6 @@ public slots:
|
||||||
|
|
||||||
bool isConfigValid();
|
bool isConfigValid();
|
||||||
|
|
||||||
void setCurrentProtocol(const QString &protocolName);
|
|
||||||
bool isVlessProtocol();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void errorOccurred(ErrorCode errorCode);
|
void errorOccurred(ErrorCode errorCode);
|
||||||
|
|
||||||
|
|
@ -49,12 +46,23 @@ signals:
|
||||||
void vpnKeyExportReady();
|
void vpnKeyExportReady();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ApiPayloadData
|
||||||
|
{
|
||||||
|
OpenVpnConfigurator::ConnectionData certRequest;
|
||||||
|
|
||||||
|
QString wireGuardClientPrivKey;
|
||||||
|
QString wireGuardClientPubKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
ApiPayloadData generateApiPayloadData(const QString &protocol);
|
||||||
|
QJsonObject fillApiPayload(const QString &protocol, const ApiPayloadData &apiPayloadData);
|
||||||
|
void fillServerConfig(const QString &protocol, const ApiPayloadData &apiPayloadData, const QByteArray &apiResponseBody,
|
||||||
|
QJsonObject &serverConfig);
|
||||||
|
|
||||||
QList<QString> getQrCodes();
|
QList<QString> getQrCodes();
|
||||||
int getQrCodesCount();
|
int getQrCodesCount();
|
||||||
QString getVpnKey();
|
QString getVpnKey();
|
||||||
|
|
||||||
ErrorCode executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody);
|
|
||||||
|
|
||||||
QList<QString> m_qrCodes;
|
QList<QString> m_qrCodes;
|
||||||
QString m_vpnKey;
|
QString m_vpnKey;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
#include "core/errorstrings.h"
|
#include "core/errorstrings.h"
|
||||||
#include "core/qrCodeUtils.h"
|
#include "core/qrCodeUtils.h"
|
||||||
#include "core/serialization/serialization.h"
|
#include "core/serialization/serialization.h"
|
||||||
#include "protocols/protocols_defs.h"
|
|
||||||
#include "systemController.h"
|
#include "systemController.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
|
|
@ -287,19 +286,6 @@ void ImportController::processNativeWireGuardConfig()
|
||||||
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
||||||
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
|
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
|
||||||
|
|
||||||
// clientProtocolConfig[config_key::cookieReplyPacketJunkSize] = "0";
|
|
||||||
// clientProtocolConfig[config_key::transportPacketJunkSize] = "0";
|
|
||||||
|
|
||||||
// clientProtocolConfig[config_key::specialJunk1] = "";
|
|
||||||
// clientProtocolConfig[config_key::specialJunk2] = "";
|
|
||||||
// clientProtocolConfig[config_key::specialJunk3] = "";
|
|
||||||
// clientProtocolConfig[config_key::specialJunk4] = "";
|
|
||||||
// clientProtocolConfig[config_key::specialJunk5] = "";
|
|
||||||
// clientProtocolConfig[config_key::controlledJunk1] = "";
|
|
||||||
// clientProtocolConfig[config_key::controlledJunk2] = "";
|
|
||||||
// clientProtocolConfig[config_key::controlledJunk3] = "";
|
|
||||||
// clientProtocolConfig[config_key::specialHandshakeTimeout] = "0";
|
|
||||||
|
|
||||||
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
|
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
|
||||||
|
|
||||||
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
|
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
|
||||||
|
|
@ -452,33 +438,21 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
|
||||||
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
||||||
|
|
||||||
QString protocolName = "wireguard";
|
QString protocolName = "wireguard";
|
||||||
|
if (!configMap.value(config_key::junkPacketCount).isEmpty() && !configMap.value(config_key::junkPacketMinSize).isEmpty()
|
||||||
const QStringList requiredJunkFields = { config_key::junkPacketCount, config_key::junkPacketMinSize,
|
&& !configMap.value(config_key::junkPacketMaxSize).isEmpty() && !configMap.value(config_key::initPacketJunkSize).isEmpty()
|
||||||
config_key::junkPacketMaxSize, config_key::initPacketJunkSize,
|
&& !configMap.value(config_key::responsePacketJunkSize).isEmpty() && !configMap.value(config_key::initPacketMagicHeader).isEmpty()
|
||||||
config_key::responsePacketJunkSize, config_key::initPacketMagicHeader,
|
&& !configMap.value(config_key::responsePacketMagicHeader).isEmpty()
|
||||||
config_key::responsePacketMagicHeader, config_key::underloadPacketMagicHeader,
|
&& !configMap.value(config_key::underloadPacketMagicHeader).isEmpty()
|
||||||
config_key::transportPacketMagicHeader };
|
&& !configMap.value(config_key::transportPacketMagicHeader).isEmpty()) {
|
||||||
|
lastConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount);
|
||||||
const QStringList optionalJunkFields = { // config_key::cookieReplyPacketJunkSize,
|
lastConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize);
|
||||||
// config_key::transportPacketJunkSize,
|
lastConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize);
|
||||||
config_key::specialJunk1, config_key::specialJunk2, config_key::specialJunk3,
|
lastConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize);
|
||||||
config_key::specialJunk4, config_key::specialJunk5, config_key::controlledJunk1,
|
lastConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize);
|
||||||
config_key::controlledJunk2, config_key::controlledJunk3, config_key::specialHandshakeTimeout
|
lastConfig[config_key::initPacketMagicHeader] = configMap.value(config_key::initPacketMagicHeader);
|
||||||
};
|
lastConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
|
||||||
|
lastConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
|
||||||
bool hasAllRequiredFields = std::all_of(requiredJunkFields.begin(), requiredJunkFields.end(),
|
lastConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
|
||||||
[&configMap](const QString &field) { return !configMap.value(field).isEmpty(); });
|
|
||||||
if (hasAllRequiredFields) {
|
|
||||||
for (const QString &field : requiredJunkFields) {
|
|
||||||
lastConfig[field] = configMap.value(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QString &field : optionalJunkFields) {
|
|
||||||
if (!configMap.value(field).isEmpty()) {
|
|
||||||
lastConfig[field] = configMap.value(field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protocolName = "awg";
|
protocolName = "awg";
|
||||||
m_configType = ConfigTypes::Awg;
|
m_configType = ConfigTypes::Awg;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
#include "core/api/apiUtils.h"
|
|
||||||
#include "core/controllers/serverController.h"
|
#include "core/controllers/serverController.h"
|
||||||
#include "core/controllers/vpnConfigurationController.h"
|
#include "core/controllers/vpnConfigurationController.h"
|
||||||
#include "core/networkUtilities.h"
|
#include "core/networkUtilities.h"
|
||||||
|
|
@ -16,6 +15,7 @@
|
||||||
#include "ui/models/protocols/awgConfigModel.h"
|
#include "ui/models/protocols/awgConfigModel.h"
|
||||||
#include "ui/models/protocols/wireguardConfigModel.h"
|
#include "ui/models/protocols/wireguardConfigModel.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
#include "core/api/apiUtils.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
@ -79,36 +79,12 @@ void InstallController::install(DockerContainer container, int port, TransportPr
|
||||||
|
|
||||||
int s1 = QRandomGenerator::global()->bounded(15, 150);
|
int s1 = QRandomGenerator::global()->bounded(15, 150);
|
||||||
int s2 = QRandomGenerator::global()->bounded(15, 150);
|
int s2 = QRandomGenerator::global()->bounded(15, 150);
|
||||||
// int s3 = QRandomGenerator::global()->bounded(15, 150);
|
while (s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) {
|
||||||
// int s4 = QRandomGenerator::global()->bounded(15, 150);
|
|
||||||
|
|
||||||
// Ensure all values are unique and don't create equal packet sizes
|
|
||||||
QSet<int> usedValues;
|
|
||||||
usedValues.insert(s1);
|
|
||||||
|
|
||||||
while (usedValues.contains(s2) || s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) {
|
|
||||||
s2 = QRandomGenerator::global()->bounded(15, 150);
|
s2 = QRandomGenerator::global()->bounded(15, 150);
|
||||||
}
|
}
|
||||||
usedValues.insert(s2);
|
|
||||||
|
|
||||||
// while (usedValues.contains(s3)
|
|
||||||
// || s1 + AwgConstant::messageInitiationSize == s3 + AwgConstant::messageCookieReplySize
|
|
||||||
// || s2 + AwgConstant::messageResponseSize == s3 + AwgConstant::messageCookieReplySize) {
|
|
||||||
// s3 = QRandomGenerator::global()->bounded(15, 150);
|
|
||||||
// }
|
|
||||||
// usedValues.insert(s3);
|
|
||||||
|
|
||||||
// while (usedValues.contains(s4)
|
|
||||||
// || s1 + AwgConstant::messageInitiationSize == s4 + AwgConstant::messageTransportSize
|
|
||||||
// || s2 + AwgConstant::messageResponseSize == s4 + AwgConstant::messageTransportSize
|
|
||||||
// || s3 + AwgConstant::messageCookieReplySize == s4 + AwgConstant::messageTransportSize) {
|
|
||||||
// s4 = QRandomGenerator::global()->bounded(15, 150);
|
|
||||||
// }
|
|
||||||
|
|
||||||
QString initPacketJunkSize = QString::number(s1);
|
QString initPacketJunkSize = QString::number(s1);
|
||||||
QString responsePacketJunkSize = QString::number(s2);
|
QString responsePacketJunkSize = QString::number(s2);
|
||||||
// QString cookieReplyPacketJunkSize = QString::number(s3);
|
|
||||||
// QString transportPacketJunkSize = QString::number(s4);
|
|
||||||
|
|
||||||
QSet<QString> headersValue;
|
QSet<QString> headersValue;
|
||||||
while (headersValue.size() != 4) {
|
while (headersValue.size() != 4) {
|
||||||
|
|
@ -132,21 +108,6 @@ void InstallController::install(DockerContainer container, int port, TransportPr
|
||||||
containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader;
|
containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader;
|
||||||
containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader;
|
containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader;
|
||||||
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
|
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// containerConfig[config_key::cookieReplyPacketJunkSize] = cookieReplyPacketJunkSize;
|
|
||||||
// containerConfig[config_key::transportPacketJunkSize] = transportPacketJunkSize;
|
|
||||||
|
|
||||||
// containerConfig[config_key::specialJunk1] = specialJunk1;
|
|
||||||
// containerConfig[config_key::specialJunk2] = specialJunk2;
|
|
||||||
// containerConfig[config_key::specialJunk3] = specialJunk3;
|
|
||||||
// containerConfig[config_key::specialJunk4] = specialJunk4;
|
|
||||||
// containerConfig[config_key::specialJunk5] = specialJunk5;
|
|
||||||
// containerConfig[config_key::controlledJunk1] = controlledJunk1;
|
|
||||||
// containerConfig[config_key::controlledJunk2] = controlledJunk2;
|
|
||||||
// containerConfig[config_key::controlledJunk3] = controlledJunk3;
|
|
||||||
// containerConfig[config_key::specialHandshakeTimeout] = specialHandshakeTimeout;
|
|
||||||
|
|
||||||
} else if (container == DockerContainer::Sftp) {
|
} else if (container == DockerContainer::Sftp) {
|
||||||
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
|
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
|
||||||
containerConfig.insert(config_key::password, Utils::getRandomString(16));
|
containerConfig.insert(config_key::password, Utils::getRandomString(16));
|
||||||
|
|
@ -440,19 +401,6 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||||
containerConfig[config_key::transportPacketMagicHeader] =
|
containerConfig[config_key::transportPacketMagicHeader] =
|
||||||
serverConfigMap.value(config_key::transportPacketMagicHeader);
|
serverConfigMap.value(config_key::transportPacketMagicHeader);
|
||||||
|
|
||||||
// containerConfig[config_key::cookieReplyPacketJunkSize] = serverConfigMap.value(config_key::cookieReplyPacketJunkSize);
|
|
||||||
// containerConfig[config_key::transportPacketJunkSize] = serverConfigMap.value(config_key::transportPacketJunkSize);
|
|
||||||
|
|
||||||
// containerConfig[config_key::specialJunk1] = serverConfigMap.value(config_key::specialJunk1);
|
|
||||||
// containerConfig[config_key::specialJunk2] = serverConfigMap.value(config_key::specialJunk2);
|
|
||||||
// containerConfig[config_key::specialJunk3] = serverConfigMap.value(config_key::specialJunk3);
|
|
||||||
// containerConfig[config_key::specialJunk4] = serverConfigMap.value(config_key::specialJunk4);
|
|
||||||
// containerConfig[config_key::specialJunk5] = serverConfigMap.value(config_key::specialJunk5);
|
|
||||||
// containerConfig[config_key::controlledJunk1] = serverConfigMap.value(config_key::controlledJunk1);
|
|
||||||
// containerConfig[config_key::controlledJunk2] = serverConfigMap.value(config_key::controlledJunk2);
|
|
||||||
// containerConfig[config_key::controlledJunk3] = serverConfigMap.value(config_key::controlledJunk3);
|
|
||||||
// containerConfig[config_key::specialHandshakeTimeout] = serverConfigMap.value(config_key::specialHandshakeTimeout);
|
|
||||||
|
|
||||||
} else if (protocol == Proto::WireGuard) {
|
} else if (protocol == Proto::WireGuard) {
|
||||||
QString serverConfig = serverController->getTextFileFromContainer(container, credentials,
|
QString serverConfig = serverController->getTextFileFromContainer(container, credentials,
|
||||||
protocols::wireguard::serverConfigPath, errorCode);
|
protocols::wireguard::serverConfigPath, errorCode);
|
||||||
|
|
|
||||||
|
|
@ -1,309 +1,311 @@
|
||||||
#include "listViewFocusController.h"
|
#include "listViewFocusController.h"
|
||||||
#include "utils/qmlUtils.h"
|
#include "utils/qmlUtils.h"
|
||||||
|
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
|
|
||||||
ListViewFocusController::ListViewFocusController(QQuickItem *listView, QObject *parent)
|
ListViewFocusController::ListViewFocusController(QQuickItem *listView, QObject *parent)
|
||||||
: QObject { parent },
|
: QObject { parent },
|
||||||
m_listView { listView },
|
m_listView { listView },
|
||||||
m_focusChain {},
|
m_focusChain {},
|
||||||
m_currentSection { Section::Default },
|
m_currentSection { Section::Default },
|
||||||
m_header { nullptr },
|
m_header { nullptr },
|
||||||
m_footer { nullptr },
|
m_footer { nullptr },
|
||||||
m_focusedItem { nullptr },
|
m_focusedItem { nullptr },
|
||||||
m_focusedItemIndex { -1 },
|
m_focusedItemIndex { -1 },
|
||||||
m_delegateIndex { 0 },
|
m_delegateIndex { 0 },
|
||||||
m_isReturnNeeded { false },
|
m_isReturnNeeded { false },
|
||||||
m_currentSectionString { "Default", "Header", "Delegate", "Footer" }
|
m_currentSectionString { "Default", "Header", "Delegate", "Footer" }
|
||||||
{
|
{
|
||||||
QVariant headerItemProperty = m_listView->property("headerItem");
|
QVariant headerItemProperty = m_listView->property("headerItem");
|
||||||
m_header = headerItemProperty.canConvert<QQuickItem *>() ? headerItemProperty.value<QQuickItem *>() : nullptr;
|
m_header = headerItemProperty.canConvert<QQuickItem *>() ? headerItemProperty.value<QQuickItem *>() : nullptr;
|
||||||
|
|
||||||
QVariant footerItemProperty = m_listView->property("footerItem");
|
QVariant footerItemProperty = m_listView->property("footerItem");
|
||||||
m_footer = footerItemProperty.canConvert<QQuickItem *>() ? footerItemProperty.value<QQuickItem *>() : nullptr;
|
m_footer = footerItemProperty.canConvert<QQuickItem *>() ? footerItemProperty.value<QQuickItem *>() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListViewFocusController::~ListViewFocusController()
|
ListViewFocusController::~ListViewFocusController()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListViewFocusController::viewAtCurrentIndex() const
|
void ListViewFocusController::viewAtCurrentIndex() const
|
||||||
{
|
{
|
||||||
switch (m_currentSection) {
|
switch (m_currentSection) {
|
||||||
case Section::Default: [[fallthrough]];
|
case Section::Default: [[fallthrough]];
|
||||||
case Section::Header: {
|
case Section::Header: {
|
||||||
QMetaObject::invokeMethod(m_listView, "positionViewAtBeginning");
|
QMetaObject::invokeMethod(m_listView, "positionViewAtBeginning");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Section::Delegate: {
|
case Section::Delegate: {
|
||||||
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index
|
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index
|
||||||
Q_ARG(int, 2)); // PositionMode (0 = Visible)
|
Q_ARG(int, 6)); // PositionMode (0 = Beginning; 1 = Center; 2 = End; 3 = Visible; 4 = Contain; 5 = SnapPosition)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Section::Footer: {
|
case Section::Footer: {
|
||||||
QMetaObject::invokeMethod(m_listView, "positionViewAtEnd");
|
QMetaObject::invokeMethod(m_listView, "positionViewAtEnd");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ListViewFocusController::size() const
|
int ListViewFocusController::size() const
|
||||||
{
|
{
|
||||||
return m_listView->property("count").toInt();
|
return m_listView->property("count").toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ListViewFocusController::currentIndex() const
|
int ListViewFocusController::currentIndex() const
|
||||||
{
|
{
|
||||||
return m_delegateIndex;
|
return m_delegateIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListViewFocusController::setDelegateIndex(int index)
|
void ListViewFocusController::setDelegateIndex(int index)
|
||||||
{
|
{
|
||||||
m_delegateIndex = index;
|
m_delegateIndex = index;
|
||||||
m_listView->setProperty("currentIndex", index);
|
m_listView->setProperty("currentIndex", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListViewFocusController::nextDelegate()
|
void ListViewFocusController::nextDelegate()
|
||||||
{
|
{
|
||||||
switch (m_currentSection) {
|
switch (m_currentSection) {
|
||||||
case Section::Default: {
|
case Section::Default: {
|
||||||
if (hasHeader()) {
|
if (hasHeader()) {
|
||||||
m_currentSection = Section::Header;
|
m_currentSection = Section::Header;
|
||||||
viewAtCurrentIndex();
|
viewAtCurrentIndex();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case Section::Header: {
|
case Section::Header: {
|
||||||
if (size() > 0) {
|
if (size() > 0) {
|
||||||
m_currentSection = Section::Delegate;
|
m_currentSection = Section::Delegate;
|
||||||
viewAtCurrentIndex();
|
viewAtCurrentIndex();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case Section::Delegate:
|
case Section::Delegate:
|
||||||
if (m_delegateIndex < (size() - 1)) {
|
if (m_delegateIndex < (size() - 1)) {
|
||||||
setDelegateIndex(m_delegateIndex + 1);
|
setDelegateIndex(m_delegateIndex + 1);
|
||||||
viewAtCurrentIndex();
|
viewAtCurrentIndex();
|
||||||
break;
|
break;
|
||||||
} else if (hasFooter()) {
|
} else if (hasFooter()) {
|
||||||
m_currentSection = Section::Footer;
|
m_currentSection = Section::Footer;
|
||||||
viewAtCurrentIndex();
|
viewAtCurrentIndex();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case Section::Footer: {
|
case Section::Footer: {
|
||||||
m_isReturnNeeded = true;
|
m_isReturnNeeded = true;
|
||||||
m_currentSection = Section::Default;
|
m_currentSection = Section::Default;
|
||||||
viewAtCurrentIndex();
|
viewAtCurrentIndex();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
qCritical() << "Current section is invalid!";
|
qCritical() << "Current section is invalid!";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListViewFocusController::previousDelegate()
|
void ListViewFocusController::previousDelegate()
|
||||||
{
|
{
|
||||||
switch (m_currentSection) {
|
switch (m_currentSection) {
|
||||||
case Section::Default: {
|
case Section::Default: {
|
||||||
if (hasFooter()) {
|
if (hasFooter()) {
|
||||||
m_currentSection = Section::Footer;
|
m_currentSection = Section::Footer;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case Section::Footer: {
|
case Section::Footer: {
|
||||||
if (size() > 0) {
|
if (size() > 0) {
|
||||||
m_currentSection = Section::Delegate;
|
m_currentSection = Section::Delegate;
|
||||||
setDelegateIndex(size() - 1);
|
setDelegateIndex(size() - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case Section::Delegate: {
|
case Section::Delegate: {
|
||||||
if (m_delegateIndex > 0) {
|
if (m_delegateIndex > 0) {
|
||||||
setDelegateIndex(m_delegateIndex - 1);
|
setDelegateIndex(m_delegateIndex - 1);
|
||||||
break;
|
break;
|
||||||
} else if (hasHeader()) {
|
} else if (hasHeader()) {
|
||||||
m_currentSection = Section::Header;
|
m_currentSection = Section::Header;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case Section::Header: {
|
case Section::Header: {
|
||||||
m_isReturnNeeded = true;
|
m_isReturnNeeded = true;
|
||||||
m_currentSection = Section::Default;
|
m_currentSection = Section::Default;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
qCritical() << "Current section is invalid!";
|
qCritical() << "Current section is invalid!";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListViewFocusController::decrementIndex()
|
void ListViewFocusController::decrementIndex()
|
||||||
{
|
{
|
||||||
m_delegateIndex--;
|
m_delegateIndex--;
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickItem *ListViewFocusController::itemAtIndex(const int index) const
|
QQuickItem *ListViewFocusController::itemAtIndex(const int index) const
|
||||||
{
|
{
|
||||||
QQuickItem *item { nullptr };
|
QQuickItem *item { nullptr };
|
||||||
|
|
||||||
QMetaObject::invokeMethod(m_listView, "itemAtIndex", Q_RETURN_ARG(QQuickItem *, item), Q_ARG(int, index));
|
QMetaObject::invokeMethod(m_listView, "itemAtIndex", Q_RETURN_ARG(QQuickItem *, item), Q_ARG(int, index));
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickItem *ListViewFocusController::currentDelegate() const
|
QQuickItem *ListViewFocusController::currentDelegate() const
|
||||||
{
|
{
|
||||||
QQuickItem *result { nullptr };
|
QQuickItem *result { nullptr };
|
||||||
|
|
||||||
switch (m_currentSection) {
|
switch (m_currentSection) {
|
||||||
case Section::Default: {
|
case Section::Default: {
|
||||||
qWarning() << "No elements...";
|
qWarning() << "No elements...";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Section::Header: {
|
case Section::Header: {
|
||||||
result = m_header;
|
result = m_header;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Section::Delegate: {
|
case Section::Delegate: {
|
||||||
result = itemAtIndex(m_delegateIndex);
|
result = itemAtIndex(m_delegateIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Section::Footer: {
|
case Section::Footer: {
|
||||||
result = m_footer;
|
result = m_footer;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickItem *ListViewFocusController::focusedItem() const
|
QQuickItem *ListViewFocusController::focusedItem() const
|
||||||
{
|
{
|
||||||
return m_focusedItem;
|
return m_focusedItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListViewFocusController::focusNextItem()
|
void ListViewFocusController::focusNextItem()
|
||||||
{
|
{
|
||||||
if (m_isReturnNeeded) {
|
if (m_isReturnNeeded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadFocusChain();
|
reloadFocusChain();
|
||||||
|
|
||||||
if (m_focusChain.empty()) {
|
if (m_focusChain.empty()) {
|
||||||
qWarning() << "No elements found in the delegate. Going to next delegate...";
|
qWarning() << "No elements found in the delegate. Going to next delegate...";
|
||||||
nextDelegate();
|
nextDelegate();
|
||||||
focusNextItem();
|
focusNextItem();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_focusedItemIndex++;
|
m_focusedItemIndex++;
|
||||||
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
|
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
|
||||||
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
|
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
|
||||||
}
|
qDebug() << "Next focus is set to item: " << m_focusedItem;
|
||||||
|
}
|
||||||
void ListViewFocusController::focusPreviousItem()
|
|
||||||
{
|
void ListViewFocusController::focusPreviousItem()
|
||||||
if (m_isReturnNeeded) {
|
{
|
||||||
return;
|
if (m_isReturnNeeded) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
if (m_focusChain.empty()) {
|
|
||||||
qInfo() << "Empty focusChain with current delegate: " << currentDelegate() << "Scanning for elements...";
|
if (m_focusChain.empty()) {
|
||||||
reloadFocusChain();
|
qInfo() << "Empty focusChain with current delegate: " << currentDelegate() << "Scanning for elements...";
|
||||||
}
|
reloadFocusChain();
|
||||||
if (m_focusChain.empty()) {
|
}
|
||||||
qWarning() << "No elements found in the delegate. Going to next delegate...";
|
if (m_focusChain.empty()) {
|
||||||
previousDelegate();
|
qWarning() << "No elements found in the delegate. Going to next delegate...";
|
||||||
focusPreviousItem();
|
previousDelegate();
|
||||||
return;
|
focusPreviousItem();
|
||||||
}
|
return;
|
||||||
if (m_focusedItemIndex == -1) {
|
}
|
||||||
m_focusedItemIndex = m_focusChain.size();
|
if (m_focusedItemIndex == -1) {
|
||||||
}
|
m_focusedItemIndex = m_focusChain.size();
|
||||||
m_focusedItemIndex--;
|
}
|
||||||
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
|
m_focusedItemIndex--;
|
||||||
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
|
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
|
||||||
}
|
m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
|
||||||
|
}
|
||||||
void ListViewFocusController::resetFocusChain()
|
|
||||||
{
|
void ListViewFocusController::resetFocusChain()
|
||||||
m_focusChain.clear();
|
{
|
||||||
m_focusedItem = nullptr;
|
m_focusChain.clear();
|
||||||
m_focusedItemIndex = -1;
|
m_focusedItem = nullptr;
|
||||||
}
|
m_focusedItemIndex = -1;
|
||||||
|
qDebug() << "Focus chain was reset";
|
||||||
void ListViewFocusController::reloadFocusChain()
|
}
|
||||||
{
|
|
||||||
m_focusChain = FocusControl::getItemsChain(currentDelegate());
|
void ListViewFocusController::reloadFocusChain()
|
||||||
}
|
{
|
||||||
|
m_focusChain = FocusControl::getItemsChain(currentDelegate());
|
||||||
bool ListViewFocusController::isFirstFocusItemInDelegate() const
|
}
|
||||||
{
|
|
||||||
return m_focusedItem && (m_focusedItem == m_focusChain.first());
|
bool ListViewFocusController::isFirstFocusItemInDelegate() const
|
||||||
}
|
{
|
||||||
|
return m_focusedItem && (m_focusedItem == m_focusChain.first());
|
||||||
bool ListViewFocusController::isLastFocusItemInDelegate() const
|
}
|
||||||
{
|
|
||||||
return m_focusedItem && (m_focusedItem == m_focusChain.last());
|
bool ListViewFocusController::isLastFocusItemInDelegate() const
|
||||||
}
|
{
|
||||||
|
return m_focusedItem && (m_focusedItem == m_focusChain.last());
|
||||||
bool ListViewFocusController::hasHeader() const
|
}
|
||||||
{
|
|
||||||
return m_header && !FocusControl::getItemsChain(m_header).isEmpty();
|
bool ListViewFocusController::hasHeader() const
|
||||||
}
|
{
|
||||||
|
return m_header && !FocusControl::getItemsChain(m_header).isEmpty();
|
||||||
bool ListViewFocusController::hasFooter() const
|
}
|
||||||
{
|
|
||||||
return m_footer && !FocusControl::getItemsChain(m_footer).isEmpty();
|
bool ListViewFocusController::hasFooter() const
|
||||||
}
|
{
|
||||||
|
return m_footer && !FocusControl::getItemsChain(m_footer).isEmpty();
|
||||||
bool ListViewFocusController::isFirstFocusItemInListView() const
|
}
|
||||||
{
|
|
||||||
switch (m_currentSection) {
|
bool ListViewFocusController::isFirstFocusItemInListView() const
|
||||||
case Section::Footer: {
|
{
|
||||||
return isFirstFocusItemInDelegate() && !hasHeader() && (size() == 0);
|
switch (m_currentSection) {
|
||||||
}
|
case Section::Footer: {
|
||||||
case Section::Delegate: {
|
return isFirstFocusItemInDelegate() && !hasHeader() && (size() == 0);
|
||||||
return isFirstFocusItemInDelegate() && (m_delegateIndex == 0) && !hasHeader();
|
}
|
||||||
}
|
case Section::Delegate: {
|
||||||
case Section::Header: {
|
return isFirstFocusItemInDelegate() && (m_delegateIndex == 0) && !hasHeader();
|
||||||
isFirstFocusItemInDelegate();
|
}
|
||||||
}
|
case Section::Header: {
|
||||||
case Section::Default: {
|
isFirstFocusItemInDelegate();
|
||||||
return true;
|
}
|
||||||
}
|
case Section::Default: {
|
||||||
default: qWarning() << "Wrong section"; return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
default: qWarning() << "Wrong section"; return true;
|
||||||
|
}
|
||||||
bool ListViewFocusController::isLastFocusItemInListView() const
|
}
|
||||||
{
|
|
||||||
switch (m_currentSection) {
|
bool ListViewFocusController::isLastFocusItemInListView() const
|
||||||
case Section::Default: {
|
{
|
||||||
return !hasHeader() && (size() == 0) && !hasFooter();
|
switch (m_currentSection) {
|
||||||
}
|
case Section::Default: {
|
||||||
case Section::Header: {
|
return !hasHeader() && (size() == 0) && !hasFooter();
|
||||||
return isLastFocusItemInDelegate() && (size() == 0) && !hasFooter();
|
}
|
||||||
}
|
case Section::Header: {
|
||||||
case Section::Delegate: {
|
return isLastFocusItemInDelegate() && (size() == 0) && !hasFooter();
|
||||||
return isLastFocusItemInDelegate() && (m_delegateIndex == size() - 1) && !hasFooter();
|
}
|
||||||
}
|
case Section::Delegate: {
|
||||||
case Section::Footer: {
|
return isLastFocusItemInDelegate() && (m_delegateIndex == size() - 1) && !hasFooter();
|
||||||
return isLastFocusItemInDelegate();
|
}
|
||||||
}
|
case Section::Footer: {
|
||||||
default: qWarning() << "Wrong section"; return true;
|
return isLastFocusItemInDelegate();
|
||||||
}
|
}
|
||||||
}
|
default: qWarning() << "Wrong section"; return true;
|
||||||
|
}
|
||||||
bool ListViewFocusController::isReturnNeeded() const
|
}
|
||||||
{
|
|
||||||
return m_isReturnNeeded;
|
bool ListViewFocusController::isReturnNeeded() const
|
||||||
}
|
{
|
||||||
|
return m_isReturnNeeded;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,6 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case IsProtocolSelectionSupportedRole: {
|
|
||||||
if (m_accountInfoData.supportedProtocols.size() > 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
@ -101,10 +95,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons
|
||||||
|
|
||||||
accountInfoData.configType = apiUtils::getConfigType(serverConfig);
|
accountInfoData.configType = apiUtils::getConfigType(serverConfig);
|
||||||
|
|
||||||
for (const auto &protocol : accountInfoObject.value(apiDefs::key::supportedProtocols).toArray()) {
|
|
||||||
accountInfoData.supportedProtocols.push_back(protocol.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_accountInfoData = accountInfoData;
|
m_accountInfoData = accountInfoData;
|
||||||
|
|
||||||
m_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject();
|
m_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject();
|
||||||
|
|
@ -169,7 +159,6 @@ QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
|
||||||
roles[ServiceDescriptionRole] = "serviceDescription";
|
roles[ServiceDescriptionRole] = "serviceDescription";
|
||||||
roles[IsComponentVisibleRole] = "isComponentVisible";
|
roles[IsComponentVisibleRole] = "isComponentVisible";
|
||||||
roles[HasExpiredWorkerRole] = "hasExpiredWorker";
|
roles[HasExpiredWorkerRole] = "hasExpiredWorker";
|
||||||
roles[IsProtocolSelectionSupportedRole] = "isProtocolSelectionSupported";
|
|
||||||
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,7 @@ public:
|
||||||
ServiceDescriptionRole,
|
ServiceDescriptionRole,
|
||||||
EndDateRole,
|
EndDateRole,
|
||||||
IsComponentVisibleRole,
|
IsComponentVisibleRole,
|
||||||
HasExpiredWorkerRole,
|
HasExpiredWorkerRole
|
||||||
IsProtocolSelectionSupportedRole
|
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ApiAccountInfoModel(QObject *parent = nullptr);
|
explicit ApiAccountInfoModel(QObject *parent = nullptr);
|
||||||
|
|
@ -52,8 +51,6 @@ private:
|
||||||
int maxDeviceCount;
|
int maxDeviceCount;
|
||||||
|
|
||||||
apiDefs::ConfigType configType;
|
apiDefs::ConfigType configType;
|
||||||
|
|
||||||
QStringList supportedProtocols;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AccountInfoData m_accountInfoData;
|
AccountInfoData m_accountInfoData;
|
||||||
|
|
|
||||||
|
|
@ -28,17 +28,7 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
|
||||||
case Roles::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
|
case Roles::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
|
||||||
case Roles::ClientJunkPacketMinSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
|
case Roles::ClientJunkPacketMinSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
|
||||||
case Roles::ClientJunkPacketMaxSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
case Roles::ClientJunkPacketMaxSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
||||||
case Roles::ClientSpecialJunk1Role: m_clientProtocolConfig.insert(config_key::specialJunk1, value.toString()); break;
|
|
||||||
case Roles::ClientSpecialJunk2Role: m_clientProtocolConfig.insert(config_key::specialJunk2, value.toString()); break;
|
|
||||||
case Roles::ClientSpecialJunk3Role: m_clientProtocolConfig.insert(config_key::specialJunk3, value.toString()); break;
|
|
||||||
case Roles::ClientSpecialJunk4Role: m_clientProtocolConfig.insert(config_key::specialJunk4, value.toString()); break;
|
|
||||||
case Roles::ClientSpecialJunk5Role: m_clientProtocolConfig.insert(config_key::specialJunk5, value.toString()); break;
|
|
||||||
case Roles::ClientControlledJunk1Role: m_clientProtocolConfig.insert(config_key::controlledJunk1, value.toString()); break;
|
|
||||||
case Roles::ClientControlledJunk2Role: m_clientProtocolConfig.insert(config_key::controlledJunk2, value.toString()); break;
|
|
||||||
case Roles::ClientControlledJunk3Role: m_clientProtocolConfig.insert(config_key::controlledJunk3, value.toString()); break;
|
|
||||||
case Roles::ClientSpecialHandshakeTimeoutRole:
|
|
||||||
m_clientProtocolConfig.insert(config_key::specialHandshakeTimeout, value.toString());
|
|
||||||
break;
|
|
||||||
case Roles::ServerJunkPacketCountRole: m_serverProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
|
case Roles::ServerJunkPacketCountRole: m_serverProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
|
||||||
case Roles::ServerJunkPacketMinSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
|
case Roles::ServerJunkPacketMinSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
|
||||||
case Roles::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
case Roles::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
||||||
|
|
@ -46,12 +36,6 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
|
||||||
case Roles::ServerResponsePacketJunkSizeRole:
|
case Roles::ServerResponsePacketJunkSizeRole:
|
||||||
m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString());
|
m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString());
|
||||||
break;
|
break;
|
||||||
// case Roles::ServerCookieReplyPacketJunkSizeRole:
|
|
||||||
// m_serverProtocolConfig.insert(config_key::cookieReplyPacketJunkSize, value.toString());
|
|
||||||
// break;
|
|
||||||
// case Roles::ServerTransportPacketJunkSizeRole:
|
|
||||||
// m_serverProtocolConfig.insert(config_key::transportPacketJunkSize, value.toString());
|
|
||||||
// break;
|
|
||||||
case Roles::ServerInitPacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break;
|
case Roles::ServerInitPacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break;
|
||||||
case Roles::ServerResponsePacketMagicHeaderRole:
|
case Roles::ServerResponsePacketMagicHeaderRole:
|
||||||
m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString());
|
m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString());
|
||||||
|
|
@ -82,23 +66,12 @@ QVariant AwgConfigModel::data(const QModelIndex &index, int role) const
|
||||||
case Roles::ClientJunkPacketCountRole: return m_clientProtocolConfig.value(config_key::junkPacketCount);
|
case Roles::ClientJunkPacketCountRole: return m_clientProtocolConfig.value(config_key::junkPacketCount);
|
||||||
case Roles::ClientJunkPacketMinSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMinSize);
|
case Roles::ClientJunkPacketMinSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMinSize);
|
||||||
case Roles::ClientJunkPacketMaxSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMaxSize);
|
case Roles::ClientJunkPacketMaxSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMaxSize);
|
||||||
case Roles::ClientSpecialJunk1Role: return m_clientProtocolConfig.value(config_key::specialJunk1);
|
|
||||||
case Roles::ClientSpecialJunk2Role: return m_clientProtocolConfig.value(config_key::specialJunk2);
|
|
||||||
case Roles::ClientSpecialJunk3Role: return m_clientProtocolConfig.value(config_key::specialJunk3);
|
|
||||||
case Roles::ClientSpecialJunk4Role: return m_clientProtocolConfig.value(config_key::specialJunk4);
|
|
||||||
case Roles::ClientSpecialJunk5Role: return m_clientProtocolConfig.value(config_key::specialJunk5);
|
|
||||||
case Roles::ClientControlledJunk1Role: return m_clientProtocolConfig.value(config_key::controlledJunk1);
|
|
||||||
case Roles::ClientControlledJunk2Role: return m_clientProtocolConfig.value(config_key::controlledJunk2);
|
|
||||||
case Roles::ClientControlledJunk3Role: return m_clientProtocolConfig.value(config_key::controlledJunk3);
|
|
||||||
case Roles::ClientSpecialHandshakeTimeoutRole: return m_clientProtocolConfig.value(config_key::specialHandshakeTimeout);
|
|
||||||
|
|
||||||
case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount);
|
case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount);
|
||||||
case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize);
|
case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize);
|
||||||
case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize);
|
case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize);
|
||||||
case Roles::ServerInitPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::initPacketJunkSize);
|
case Roles::ServerInitPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::initPacketJunkSize);
|
||||||
case Roles::ServerResponsePacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::responsePacketJunkSize);
|
case Roles::ServerResponsePacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::responsePacketJunkSize);
|
||||||
// case Roles::ServerCookieReplyPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize);
|
|
||||||
// case Roles::ServerTransportPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::transportPacketJunkSize);
|
|
||||||
case Roles::ServerInitPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::initPacketMagicHeader);
|
case Roles::ServerInitPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::initPacketMagicHeader);
|
||||||
case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader);
|
case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader);
|
||||||
case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader);
|
case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader);
|
||||||
|
|
@ -121,8 +94,7 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||||
m_serverProtocolConfig.insert(config_key::transport_proto,
|
m_serverProtocolConfig.insert(config_key::transport_proto,
|
||||||
serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
|
serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
|
||||||
m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config);
|
m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config);
|
||||||
m_serverProtocolConfig[config_key::subnet_address] =
|
m_serverProtocolConfig[config_key::subnet_address] = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
|
||||||
serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
|
|
||||||
m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
||||||
m_serverProtocolConfig[config_key::junkPacketCount] =
|
m_serverProtocolConfig[config_key::junkPacketCount] =
|
||||||
serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||||
|
|
@ -134,10 +106,6 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||||
serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||||
m_serverProtocolConfig[config_key::responsePacketJunkSize] =
|
m_serverProtocolConfig[config_key::responsePacketJunkSize] =
|
||||||
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
||||||
// m_serverProtocolConfig[config_key::cookieReplyPacketJunkSize] =
|
|
||||||
// serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize);
|
|
||||||
// m_serverProtocolConfig[config_key::transportPacketJunkSize] =
|
|
||||||
// serverProtocolConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize);
|
|
||||||
m_serverProtocolConfig[config_key::initPacketMagicHeader] =
|
m_serverProtocolConfig[config_key::initPacketMagicHeader] =
|
||||||
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||||
m_serverProtocolConfig[config_key::responsePacketMagicHeader] =
|
m_serverProtocolConfig[config_key::responsePacketMagicHeader] =
|
||||||
|
|
@ -156,24 +124,6 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||||
clientProtocolConfig.value(config_key::junkPacketMinSize).toString(m_serverProtocolConfig[config_key::junkPacketMinSize].toString());
|
clientProtocolConfig.value(config_key::junkPacketMinSize).toString(m_serverProtocolConfig[config_key::junkPacketMinSize].toString());
|
||||||
m_clientProtocolConfig[config_key::junkPacketMaxSize] =
|
m_clientProtocolConfig[config_key::junkPacketMaxSize] =
|
||||||
clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(m_serverProtocolConfig[config_key::junkPacketMaxSize].toString());
|
clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(m_serverProtocolConfig[config_key::junkPacketMaxSize].toString());
|
||||||
m_clientProtocolConfig[config_key::specialJunk1] =
|
|
||||||
clientProtocolConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1);
|
|
||||||
m_clientProtocolConfig[config_key::specialJunk2] =
|
|
||||||
clientProtocolConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2);
|
|
||||||
m_clientProtocolConfig[config_key::specialJunk3] =
|
|
||||||
clientProtocolConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3);
|
|
||||||
m_clientProtocolConfig[config_key::specialJunk4] =
|
|
||||||
clientProtocolConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4);
|
|
||||||
m_clientProtocolConfig[config_key::specialJunk5] =
|
|
||||||
clientProtocolConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5);
|
|
||||||
m_clientProtocolConfig[config_key::controlledJunk1] =
|
|
||||||
clientProtocolConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1);
|
|
||||||
m_clientProtocolConfig[config_key::controlledJunk2] =
|
|
||||||
clientProtocolConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2);
|
|
||||||
m_clientProtocolConfig[config_key::controlledJunk3] =
|
|
||||||
clientProtocolConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3);
|
|
||||||
m_clientProtocolConfig[config_key::specialHandshakeTimeout] =
|
|
||||||
clientProtocolConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout);
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,15 +141,6 @@ QJsonObject AwgConfigModel::getConfig()
|
||||||
jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount];
|
jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount];
|
||||||
jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize];
|
jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize];
|
||||||
jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize];
|
jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize];
|
||||||
jsonConfig[config_key::specialJunk1] = m_clientProtocolConfig[config_key::specialJunk1];
|
|
||||||
jsonConfig[config_key::specialJunk2] = m_clientProtocolConfig[config_key::specialJunk2];
|
|
||||||
jsonConfig[config_key::specialJunk3] = m_clientProtocolConfig[config_key::specialJunk3];
|
|
||||||
jsonConfig[config_key::specialJunk4] = m_clientProtocolConfig[config_key::specialJunk4];
|
|
||||||
jsonConfig[config_key::specialJunk5] = m_clientProtocolConfig[config_key::specialJunk5];
|
|
||||||
jsonConfig[config_key::controlledJunk1] = m_clientProtocolConfig[config_key::controlledJunk1];
|
|
||||||
jsonConfig[config_key::controlledJunk2] = m_clientProtocolConfig[config_key::controlledJunk2];
|
|
||||||
jsonConfig[config_key::controlledJunk3] = m_clientProtocolConfig[config_key::controlledJunk3];
|
|
||||||
jsonConfig[config_key::specialHandshakeTimeout] = m_clientProtocolConfig[config_key::specialHandshakeTimeout];
|
|
||||||
|
|
||||||
m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
|
m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
|
||||||
}
|
}
|
||||||
|
|
@ -218,17 +159,6 @@ bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2)
|
||||||
return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2);
|
return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2, const int s3, const int s4)
|
|
||||||
// {
|
|
||||||
// int initSize = AwgConstant::messageInitiationSize + s1;
|
|
||||||
// int responseSize = AwgConstant::messageResponseSize + s2;
|
|
||||||
// int cookieSize = AwgConstant::messageCookieReplySize + s3;
|
|
||||||
// int transportSize = AwgConstant::messageTransportSize + s4;
|
|
||||||
|
|
||||||
// return (initSize == responseSize || initSize == cookieSize || initSize == transportSize || responseSize == cookieSize
|
|
||||||
// || responseSize == transportSize || cookieSize == transportSize);
|
|
||||||
// }
|
|
||||||
|
|
||||||
bool AwgConfigModel::isServerSettingsEqual()
|
bool AwgConfigModel::isServerSettingsEqual()
|
||||||
{
|
{
|
||||||
const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject());
|
const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject());
|
||||||
|
|
@ -248,24 +178,12 @@ QHash<int, QByteArray> AwgConfigModel::roleNames() const
|
||||||
roles[ClientJunkPacketCountRole] = "clientJunkPacketCount";
|
roles[ClientJunkPacketCountRole] = "clientJunkPacketCount";
|
||||||
roles[ClientJunkPacketMinSizeRole] = "clientJunkPacketMinSize";
|
roles[ClientJunkPacketMinSizeRole] = "clientJunkPacketMinSize";
|
||||||
roles[ClientJunkPacketMaxSizeRole] = "clientJunkPacketMaxSize";
|
roles[ClientJunkPacketMaxSizeRole] = "clientJunkPacketMaxSize";
|
||||||
roles[ClientSpecialJunk1Role] = "clientSpecialJunk1";
|
|
||||||
roles[ClientSpecialJunk2Role] = "clientSpecialJunk2";
|
|
||||||
roles[ClientSpecialJunk3Role] = "clientSpecialJunk3";
|
|
||||||
roles[ClientSpecialJunk4Role] = "clientSpecialJunk4";
|
|
||||||
roles[ClientSpecialJunk5Role] = "clientSpecialJunk5";
|
|
||||||
roles[ClientControlledJunk1Role] = "clientControlledJunk1";
|
|
||||||
roles[ClientControlledJunk2Role] = "clientControlledJunk2";
|
|
||||||
roles[ClientControlledJunk3Role] = "clientControlledJunk3";
|
|
||||||
roles[ClientSpecialHandshakeTimeoutRole] = "clientSpecialHandshakeTimeout";
|
|
||||||
|
|
||||||
roles[ServerJunkPacketCountRole] = "serverJunkPacketCount";
|
roles[ServerJunkPacketCountRole] = "serverJunkPacketCount";
|
||||||
roles[ServerJunkPacketMinSizeRole] = "serverJunkPacketMinSize";
|
roles[ServerJunkPacketMinSizeRole] = "serverJunkPacketMinSize";
|
||||||
roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize";
|
roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize";
|
||||||
roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize";
|
roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize";
|
||||||
roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize";
|
roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize";
|
||||||
roles[ServerCookieReplyPacketJunkSizeRole] = "serverCookieReplyPacketJunkSize";
|
|
||||||
roles[ServerTransportPacketJunkSizeRole] = "serverTransportPacketJunkSize";
|
|
||||||
|
|
||||||
roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader";
|
roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader";
|
||||||
roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader";
|
roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader";
|
||||||
roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader";
|
roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader";
|
||||||
|
|
@ -282,16 +200,6 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
|
||||||
clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||||
clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||||
clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
||||||
clientSpecialJunk1 = clientProtocolConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1);
|
|
||||||
clientSpecialJunk2 = clientProtocolConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2);
|
|
||||||
clientSpecialJunk3 = clientProtocolConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3);
|
|
||||||
clientSpecialJunk4 = clientProtocolConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4);
|
|
||||||
clientSpecialJunk5 = clientProtocolConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5);
|
|
||||||
clientControlledJunk1 = clientProtocolConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1);
|
|
||||||
clientControlledJunk2 = clientProtocolConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2);
|
|
||||||
clientControlledJunk3 = clientProtocolConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3);
|
|
||||||
clientSpecialHandshakeTimeout =
|
|
||||||
clientProtocolConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout);
|
|
||||||
|
|
||||||
subnetAddress = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
|
subnetAddress = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
|
||||||
port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
||||||
|
|
@ -301,10 +209,6 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
|
||||||
serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||||
serverResponsePacketJunkSize =
|
serverResponsePacketJunkSize =
|
||||||
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
||||||
// serverCookieReplyPacketJunkSize =
|
|
||||||
// serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize);
|
|
||||||
// serverTransportPacketJunkSize =
|
|
||||||
// serverProtocolConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize);
|
|
||||||
serverInitPacketMagicHeader =
|
serverInitPacketMagicHeader =
|
||||||
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||||
serverResponsePacketMagicHeader =
|
serverResponsePacketMagicHeader =
|
||||||
|
|
@ -320,8 +224,6 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
|
||||||
if (subnetAddress != other.subnetAddress || port != other.port || serverJunkPacketCount != other.serverJunkPacketCount
|
if (subnetAddress != other.subnetAddress || port != other.port || serverJunkPacketCount != other.serverJunkPacketCount
|
||||||
|| serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize
|
|| serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize
|
||||||
|| serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize
|
|| serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize
|
||||||
// || serverCookieReplyPacketJunkSize != other.serverCookieReplyPacketJunkSize
|
|
||||||
// || serverTransportPacketJunkSize != other.serverTransportPacketJunkSize
|
|
||||||
|| serverInitPacketMagicHeader != other.serverInitPacketMagicHeader
|
|| serverInitPacketMagicHeader != other.serverInitPacketMagicHeader
|
||||||
|| serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader
|
|| serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader
|
||||||
|| serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader
|
|| serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader
|
||||||
|
|
@ -334,12 +236,7 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
|
||||||
bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const
|
bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const
|
||||||
{
|
{
|
||||||
if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount
|
if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount
|
||||||
|| clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize
|
|| clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize) {
|
||||||
|| clientSpecialJunk1 != other.clientSpecialJunk1 || clientSpecialJunk2 != other.clientSpecialJunk2
|
|
||||||
|| clientSpecialJunk3 != other.clientSpecialJunk3 || clientSpecialJunk4 != other.clientSpecialJunk4
|
|
||||||
|| clientSpecialJunk5 != other.clientSpecialJunk5 || clientControlledJunk1 != other.clientControlledJunk1
|
|
||||||
|| clientControlledJunk2 != other.clientControlledJunk2 || clientControlledJunk3 != other.clientControlledJunk3
|
|
||||||
|| clientSpecialHandshakeTimeout != other.clientSpecialHandshakeTimeout) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,9 @@
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
|
|
||||||
namespace AwgConstant
|
namespace AwgConstant {
|
||||||
{
|
|
||||||
const int messageInitiationSize = 148;
|
const int messageInitiationSize = 148;
|
||||||
const int messageResponseSize = 92;
|
const int messageResponseSize = 92;
|
||||||
const int messageCookieReplySize = 64;
|
|
||||||
const int messageTransportSize = 32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AwgConfig
|
struct AwgConfig
|
||||||
|
|
@ -25,23 +22,12 @@ struct AwgConfig
|
||||||
QString clientJunkPacketCount;
|
QString clientJunkPacketCount;
|
||||||
QString clientJunkPacketMinSize;
|
QString clientJunkPacketMinSize;
|
||||||
QString clientJunkPacketMaxSize;
|
QString clientJunkPacketMaxSize;
|
||||||
QString clientSpecialJunk1;
|
|
||||||
QString clientSpecialJunk2;
|
|
||||||
QString clientSpecialJunk3;
|
|
||||||
QString clientSpecialJunk4;
|
|
||||||
QString clientSpecialJunk5;
|
|
||||||
QString clientControlledJunk1;
|
|
||||||
QString clientControlledJunk2;
|
|
||||||
QString clientControlledJunk3;
|
|
||||||
QString clientSpecialHandshakeTimeout;
|
|
||||||
|
|
||||||
QString serverJunkPacketCount;
|
QString serverJunkPacketCount;
|
||||||
QString serverJunkPacketMinSize;
|
QString serverJunkPacketMinSize;
|
||||||
QString serverJunkPacketMaxSize;
|
QString serverJunkPacketMaxSize;
|
||||||
QString serverInitPacketJunkSize;
|
QString serverInitPacketJunkSize;
|
||||||
QString serverResponsePacketJunkSize;
|
QString serverResponsePacketJunkSize;
|
||||||
QString serverCookieReplyPacketJunkSize;
|
|
||||||
QString serverTransportPacketJunkSize;
|
|
||||||
QString serverInitPacketMagicHeader;
|
QString serverInitPacketMagicHeader;
|
||||||
QString serverResponsePacketMagicHeader;
|
QString serverResponsePacketMagicHeader;
|
||||||
QString serverUnderloadPacketMagicHeader;
|
QString serverUnderloadPacketMagicHeader;
|
||||||
|
|
@ -49,6 +35,7 @@ struct AwgConfig
|
||||||
|
|
||||||
bool hasEqualServerSettings(const AwgConfig &other) const;
|
bool hasEqualServerSettings(const AwgConfig &other) const;
|
||||||
bool hasEqualClientSettings(const AwgConfig &other) const;
|
bool hasEqualClientSettings(const AwgConfig &other) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AwgConfigModel : public QAbstractListModel
|
class AwgConfigModel : public QAbstractListModel
|
||||||
|
|
@ -64,28 +51,16 @@ public:
|
||||||
ClientJunkPacketCountRole,
|
ClientJunkPacketCountRole,
|
||||||
ClientJunkPacketMinSizeRole,
|
ClientJunkPacketMinSizeRole,
|
||||||
ClientJunkPacketMaxSizeRole,
|
ClientJunkPacketMaxSizeRole,
|
||||||
ClientSpecialJunk1Role,
|
|
||||||
ClientSpecialJunk2Role,
|
|
||||||
ClientSpecialJunk3Role,
|
|
||||||
ClientSpecialJunk4Role,
|
|
||||||
ClientSpecialJunk5Role,
|
|
||||||
ClientControlledJunk1Role,
|
|
||||||
ClientControlledJunk2Role,
|
|
||||||
ClientControlledJunk3Role,
|
|
||||||
ClientSpecialHandshakeTimeoutRole,
|
|
||||||
|
|
||||||
ServerJunkPacketCountRole,
|
ServerJunkPacketCountRole,
|
||||||
ServerJunkPacketMinSizeRole,
|
ServerJunkPacketMinSizeRole,
|
||||||
ServerJunkPacketMaxSizeRole,
|
ServerJunkPacketMaxSizeRole,
|
||||||
ServerInitPacketJunkSizeRole,
|
ServerInitPacketJunkSizeRole,
|
||||||
ServerResponsePacketJunkSizeRole,
|
ServerResponsePacketJunkSizeRole,
|
||||||
ServerCookieReplyPacketJunkSizeRole,
|
|
||||||
ServerTransportPacketJunkSizeRole,
|
|
||||||
|
|
||||||
ServerInitPacketMagicHeaderRole,
|
ServerInitPacketMagicHeaderRole,
|
||||||
ServerResponsePacketMagicHeaderRole,
|
ServerResponsePacketMagicHeaderRole,
|
||||||
ServerUnderloadPacketMagicHeaderRole,
|
ServerUnderloadPacketMagicHeaderRole,
|
||||||
ServerTransportPacketMagicHeaderRole,
|
ServerTransportPacketMagicHeaderRole
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit AwgConfigModel(QObject *parent = nullptr);
|
explicit AwgConfigModel(QObject *parent = nullptr);
|
||||||
|
|
@ -100,7 +75,7 @@ public slots:
|
||||||
QJsonObject getConfig();
|
QJsonObject getConfig();
|
||||||
|
|
||||||
bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4);
|
bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4);
|
||||||
bool isPacketSizeEqual(const int s1, const int s2/*, const int s3, const int s4*/);
|
bool isPacketSizeEqual(const int s1, const int s2);
|
||||||
|
|
||||||
bool isServerSettingsEqual();
|
bool isServerSettingsEqual();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,72 +2,128 @@
|
||||||
|
|
||||||
#include "protocols/protocols_defs.h"
|
#include "protocols/protocols_defs.h"
|
||||||
|
|
||||||
OpenVpnConfigModel::OpenVpnConfigModel(QObject *parent) : QAbstractListModel(parent)
|
OpenVpnConfigModel::OpenVpnConfigModel(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int OpenVpnConfigModel::rowCount(const QModelIndex &parent) const
|
QString OpenVpnConfigModel::subnetAddress() const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenVpnConfigModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
void OpenVpnConfigModel::setSubnetAddress(const QString &subnetAddress)
|
||||||
{
|
{
|
||||||
if (!index.isValid() || index.row() < 0 || index.row() >= ContainerProps::allContainers().size()) {
|
m_protocolConfig.insert(amnezia::config_key::subnet_address, subnetAddress);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case Roles::SubnetAddressRole: m_protocolConfig.insert(amnezia::config_key::subnet_address, value.toString()); break;
|
|
||||||
case Roles::TransportProtoRole: m_protocolConfig.insert(config_key::transport_proto, value.toString()); break;
|
|
||||||
case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break;
|
|
||||||
case Roles::AutoNegotiateEncryprionRole: m_protocolConfig.insert(config_key::ncp_disable, !value.toBool()); break;
|
|
||||||
case Roles::HashRole: m_protocolConfig.insert(config_key::hash, value.toString()); break;
|
|
||||||
case Roles::CipherRole: m_protocolConfig.insert(config_key::cipher, value.toString()); break;
|
|
||||||
case Roles::TlsAuthRole: m_protocolConfig.insert(config_key::tls_auth, value.toBool()); break;
|
|
||||||
case Roles::BlockDnsRole: m_protocolConfig.insert(config_key::block_outside_dns, value.toBool()); break;
|
|
||||||
case Roles::AdditionalClientCommandsRole: m_protocolConfig.insert(config_key::additional_client_config, value.toString()); break;
|
|
||||||
case Roles::AdditionalServerCommandsRole: m_protocolConfig.insert(config_key::additional_server_config, value.toString()); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit dataChanged(index, index, QList { role });
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant OpenVpnConfigModel::data(const QModelIndex &index, int role) const
|
QString OpenVpnConfigModel::transportProto() const
|
||||||
{
|
{
|
||||||
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) {
|
return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto);
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch (role) {
|
void OpenVpnConfigModel::setTransportProto(const QString &transportProto)
|
||||||
case Roles::SubnetAddressRole:
|
{
|
||||||
return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress);
|
m_protocolConfig.insert(config_key::transport_proto, transportProto);
|
||||||
case Roles::TransportProtoRole:
|
}
|
||||||
return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto);
|
|
||||||
case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort);
|
QString OpenVpnConfigModel::port() const
|
||||||
case Roles::AutoNegotiateEncryprionRole:
|
{
|
||||||
return !m_protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
|
return m_protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort);
|
||||||
case Roles::HashRole: return m_protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash);
|
}
|
||||||
case Roles::CipherRole: return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher);
|
|
||||||
case Roles::TlsAuthRole: return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
|
void OpenVpnConfigModel::setPort(const QString &port)
|
||||||
case Roles::BlockDnsRole:
|
{
|
||||||
return m_protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns);
|
m_protocolConfig.insert(config_key::port, port);
|
||||||
case Roles::AdditionalClientCommandsRole:
|
}
|
||||||
return m_protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig);
|
|
||||||
case Roles::AdditionalServerCommandsRole:
|
bool OpenVpnConfigModel::autoNegotiateEncryption() const
|
||||||
return m_protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig);
|
{
|
||||||
case Roles::IsPortEditable: return m_container == DockerContainer::OpenVpn ? true : false;
|
return !m_protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
|
||||||
case Roles::IsTransportProtoEditable: return m_container == DockerContainer::OpenVpn ? true : false;
|
}
|
||||||
case Roles::HasRemoveButton: return m_container == DockerContainer::OpenVpn ? true : false;
|
|
||||||
}
|
void OpenVpnConfigModel::setAutoNegotiateEncryption(bool enabled)
|
||||||
return QVariant();
|
{
|
||||||
|
m_protocolConfig.insert(config_key::ncp_disable, !enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenVpnConfigModel::hash() const
|
||||||
|
{
|
||||||
|
return m_protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVpnConfigModel::setHash(const QString &hash)
|
||||||
|
{
|
||||||
|
m_protocolConfig.insert(config_key::hash, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenVpnConfigModel::cipher() const
|
||||||
|
{
|
||||||
|
return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVpnConfigModel::setCipher(const QString &cipher)
|
||||||
|
{
|
||||||
|
m_protocolConfig.insert(config_key::cipher, cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenVpnConfigModel::tlsAuth() const
|
||||||
|
{
|
||||||
|
return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVpnConfigModel::setTlsAuth(bool enabled)
|
||||||
|
{
|
||||||
|
m_protocolConfig.insert(config_key::tls_auth, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenVpnConfigModel::blockDns() const
|
||||||
|
{
|
||||||
|
return m_protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVpnConfigModel::setBlockDns(bool enabled)
|
||||||
|
{
|
||||||
|
m_protocolConfig.insert(config_key::block_outside_dns, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenVpnConfigModel::additionalClientCommands() const
|
||||||
|
{
|
||||||
|
return m_protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVpnConfigModel::setAdditionalClientCommands(const QString &commands)
|
||||||
|
{
|
||||||
|
m_protocolConfig.insert(config_key::additional_client_config, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OpenVpnConfigModel::additionalServerCommands() const
|
||||||
|
{
|
||||||
|
return m_protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVpnConfigModel::setAdditionalServerCommands(const QString &commands)
|
||||||
|
{
|
||||||
|
m_protocolConfig.insert(config_key::additional_server_config, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenVpnConfigModel::isPortEditable() const
|
||||||
|
{
|
||||||
|
return m_container == DockerContainer::OpenVpn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenVpnConfigModel::isTransportProtoEditable() const
|
||||||
|
{
|
||||||
|
return m_container == DockerContainer::OpenVpn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenVpnConfigModel::hasRemoveButton() const
|
||||||
|
{
|
||||||
|
return m_container == DockerContainer::OpenVpn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenVpnConfigModel::updateModel(const QJsonObject &config)
|
void OpenVpnConfigModel::updateModel(const QJsonObject &config)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
|
||||||
m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
|
m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
|
||||||
|
|
||||||
m_fullConfig = config;
|
m_fullConfig = config;
|
||||||
|
|
@ -100,8 +156,6 @@ void OpenVpnConfigModel::updateModel(const QJsonObject &config)
|
||||||
m_protocolConfig.insert(
|
m_protocolConfig.insert(
|
||||||
config_key::additional_server_config,
|
config_key::additional_server_config,
|
||||||
protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig));
|
protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig));
|
||||||
|
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject OpenVpnConfigModel::getConfig()
|
QJsonObject OpenVpnConfigModel::getConfig()
|
||||||
|
|
@ -109,26 +163,3 @@ QJsonObject OpenVpnConfigModel::getConfig()
|
||||||
m_fullConfig.insert(config_key::openvpn, m_protocolConfig);
|
m_fullConfig.insert(config_key::openvpn, m_protocolConfig);
|
||||||
return m_fullConfig;
|
return m_fullConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> OpenVpnConfigModel::roleNames() const
|
|
||||||
{
|
|
||||||
QHash<int, QByteArray> roles;
|
|
||||||
|
|
||||||
roles[SubnetAddressRole] = "subnetAddress";
|
|
||||||
roles[TransportProtoRole] = "transportProto";
|
|
||||||
roles[PortRole] = "port";
|
|
||||||
roles[AutoNegotiateEncryprionRole] = "autoNegotiateEncryprion";
|
|
||||||
roles[HashRole] = "hash";
|
|
||||||
roles[CipherRole] = "cipher";
|
|
||||||
roles[TlsAuthRole] = "tlsAuth";
|
|
||||||
roles[BlockDnsRole] = "blockDns";
|
|
||||||
roles[AdditionalClientCommandsRole] = "additionalClientCommands";
|
|
||||||
roles[AdditionalServerCommandsRole] = "additionalServerCommands";
|
|
||||||
|
|
||||||
roles[IsPortEditable] = "isPortEditable";
|
|
||||||
roles[IsTransportProtoEditable] = "isTransportProtoEditable";
|
|
||||||
|
|
||||||
roles[HasRemoveButton] = "hasRemoveButton";
|
|
||||||
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,90 @@
|
||||||
#ifndef OPENVPNCONFIGMODEL_H
|
#ifndef OPENVPNCONFIGMODEL_H
|
||||||
#define OPENVPNCONFIGMODEL_H
|
#define OPENVPNCONFIGMODEL_H
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QObject>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
|
|
||||||
class OpenVpnConfigModel : public QAbstractListModel
|
class OpenVpnConfigModel : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString subnetAddress READ subnetAddress WRITE setSubnetAddress NOTIFY subnetAddressChanged)
|
||||||
|
Q_PROPERTY(QString transportProto READ transportProto WRITE setTransportProto NOTIFY transportProtoChanged)
|
||||||
|
Q_PROPERTY(QString port READ port WRITE setPort NOTIFY portChanged)
|
||||||
|
Q_PROPERTY(bool autoNegotiateEncryption READ autoNegotiateEncryption WRITE setAutoNegotiateEncryption NOTIFY autoNegotiateEncryptionChanged)
|
||||||
|
Q_PROPERTY(QString hash READ hash WRITE setHash NOTIFY hashChanged)
|
||||||
|
Q_PROPERTY(QString cipher READ cipher WRITE setCipher NOTIFY cipherChanged)
|
||||||
|
Q_PROPERTY(bool tlsAuth READ tlsAuth WRITE setTlsAuth NOTIFY tlsAuthChanged)
|
||||||
|
Q_PROPERTY(bool blockDns READ blockDns WRITE setBlockDns NOTIFY blockDnsChanged)
|
||||||
|
Q_PROPERTY(QString additionalClientCommands READ additionalClientCommands WRITE setAdditionalClientCommands NOTIFY additionalClientCommandsChanged)
|
||||||
|
Q_PROPERTY(QString additionalServerCommands READ additionalServerCommands WRITE setAdditionalServerCommands NOTIFY additionalServerCommandsChanged)
|
||||||
|
Q_PROPERTY(bool isPortEditable READ isPortEditable NOTIFY isPortEditableChanged)
|
||||||
|
Q_PROPERTY(bool isTransportProtoEditable READ isTransportProtoEditable NOTIFY isTransportProtoEditableChanged)
|
||||||
|
Q_PROPERTY(bool hasRemoveButton READ hasRemoveButton NOTIFY hasRemoveButtonChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Roles {
|
|
||||||
SubnetAddressRole = Qt::UserRole + 1,
|
|
||||||
TransportProtoRole,
|
|
||||||
PortRole,
|
|
||||||
AutoNegotiateEncryprionRole,
|
|
||||||
HashRole,
|
|
||||||
CipherRole,
|
|
||||||
TlsAuthRole,
|
|
||||||
BlockDnsRole,
|
|
||||||
AdditionalClientCommandsRole,
|
|
||||||
AdditionalServerCommandsRole,
|
|
||||||
|
|
||||||
IsPortEditable,
|
|
||||||
IsTransportProtoEditable,
|
|
||||||
|
|
||||||
HasRemoveButton
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit OpenVpnConfigModel(QObject *parent = nullptr);
|
explicit OpenVpnConfigModel(QObject *parent = nullptr);
|
||||||
|
~OpenVpnConfigModel() override = default;
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
OpenVpnConfigModel(const OpenVpnConfigModel &) = delete;
|
||||||
|
OpenVpnConfigModel &operator=(const OpenVpnConfigModel &) = delete;
|
||||||
|
OpenVpnConfigModel(OpenVpnConfigModel &&) = delete;
|
||||||
|
OpenVpnConfigModel &operator=(OpenVpnConfigModel &&) = delete;
|
||||||
|
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
QString subnetAddress() const;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
void setSubnetAddress(const QString &subnetAddress);
|
||||||
|
|
||||||
|
QString transportProto() const;
|
||||||
|
void setTransportProto(const QString &transportProto);
|
||||||
|
|
||||||
|
QString port() const;
|
||||||
|
void setPort(const QString &port);
|
||||||
|
|
||||||
|
bool autoNegotiateEncryption() const;
|
||||||
|
void setAutoNegotiateEncryption(bool enabled);
|
||||||
|
|
||||||
|
QString hash() const;
|
||||||
|
void setHash(const QString &hash);
|
||||||
|
|
||||||
|
QString cipher() const;
|
||||||
|
void setCipher(const QString &cipher);
|
||||||
|
|
||||||
|
bool tlsAuth() const;
|
||||||
|
void setTlsAuth(bool enabled);
|
||||||
|
|
||||||
|
bool blockDns() const;
|
||||||
|
void setBlockDns(bool enabled);
|
||||||
|
|
||||||
|
QString additionalClientCommands() const;
|
||||||
|
void setAdditionalClientCommands(const QString &commands);
|
||||||
|
|
||||||
|
QString additionalServerCommands() const;
|
||||||
|
void setAdditionalServerCommands(const QString &commands);
|
||||||
|
|
||||||
|
bool isPortEditable() const;
|
||||||
|
bool isTransportProtoEditable() const;
|
||||||
|
bool hasRemoveButton() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QJsonObject getConfig();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void subnetAddressChanged(const QString &);
|
||||||
|
void transportProtoChanged(const QString &);
|
||||||
|
void portChanged(const QString &);
|
||||||
|
void autoNegotiateEncryptionChanged(bool);
|
||||||
|
void hashChanged(const QString &);
|
||||||
|
void cipherChanged(const QString &);
|
||||||
|
void tlsAuthChanged(bool);
|
||||||
|
void blockDnsChanged(bool);
|
||||||
|
void additionalClientCommandsChanged(const QString &);
|
||||||
|
void additionalServerCommandsChanged(const QString &);
|
||||||
|
void isPortEditableChanged(bool);
|
||||||
|
void isTransportProtoEditableChanged(bool);
|
||||||
|
void hasRemoveButtonChanged(bool);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateModel(const QJsonObject &config);
|
void updateModel(const QJsonObject &config);
|
||||||
QJsonObject getConfig();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DockerContainer m_container;
|
DockerContainer m_container;
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@
|
||||||
#include <AmneziaVPN-Swift.h>
|
#include <AmneziaVPN-Swift.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "core/api/apiUtils.h"
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
namespace configKey
|
namespace configKey
|
||||||
|
|
@ -429,7 +427,7 @@ void ServersModel::updateDefaultServerContainersModel()
|
||||||
emit defaultServerContainersUpdated(containers);
|
emit defaultServerContainersUpdated(containers);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject ServersModel::getServerConfig(const int serverIndex) const
|
QJsonObject ServersModel::getServerConfig(const int serverIndex)
|
||||||
{
|
{
|
||||||
return m_servers.at(serverIndex).toObject();
|
return m_servers.at(serverIndex).toObject();
|
||||||
}
|
}
|
||||||
|
|
@ -816,8 +814,3 @@ const QString ServersModel::getDefaultServerImagePathCollapsed()
|
||||||
}
|
}
|
||||||
return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper());
|
return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServersModel::processedServerIsPremium() const
|
|
||||||
{
|
|
||||||
return apiUtils::isPremiumServer(getServerConfig(m_processedServerIndex));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -63,9 +63,6 @@ public:
|
||||||
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
|
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
|
||||||
|
|
||||||
Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
|
Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
|
||||||
Q_PROPERTY(bool processedServerIsPremium READ processedServerIsPremium NOTIFY processedServerChanged)
|
|
||||||
|
|
||||||
bool processedServerIsPremium() const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setDefaultServerIndex(const int index);
|
void setDefaultServerIndex(const int index);
|
||||||
|
|
@ -95,7 +92,7 @@ public slots:
|
||||||
void removeServer();
|
void removeServer();
|
||||||
void removeServer(const int serverIndex);
|
void removeServer(const int serverIndex);
|
||||||
|
|
||||||
QJsonObject getServerConfig(const int serverIndex) const;
|
QJsonObject getServerConfig(const int serverIndex);
|
||||||
|
|
||||||
void reloadDefaultServerContainerConfig();
|
void reloadDefaultServerContainerConfig();
|
||||||
void updateContainerConfig(const int containerIndex, const QJsonObject config);
|
void updateContainerConfig(const int containerIndex, const QJsonObject config);
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
|
|
||||||
import "../Controls2"
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
textField.validator: IntValidator { bottom: 0 }
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
@ -10,8 +10,7 @@ import ProtocolEnum 1.0
|
||||||
import "../Controls2"
|
import "../Controls2"
|
||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
|
|
||||||
|
ListViewType {
|
||||||
ListView {
|
|
||||||
id: menuContent
|
id: menuContent
|
||||||
|
|
||||||
property var rootWidth
|
property var rootWidth
|
||||||
|
|
@ -21,13 +20,6 @@ ListView {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
clip: true
|
|
||||||
snapMode: ListView.SnapToItem
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: containersRadioButtonGroup
|
id: containersRadioButtonGroup
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,97 +1,97 @@
|
||||||
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 "../Controls2"
|
import "../Controls2"
|
||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
import "../Config"
|
import "../Config"
|
||||||
|
|
||||||
DrawerType2 {
|
DrawerType2 {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
|
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
expandedHeight: parent.height * 0.9
|
expandedHeight: parent.height * 0.9
|
||||||
|
|
||||||
expandedStateContent: ColumnLayout {
|
expandedStateContent: ColumnLayout {
|
||||||
id: content
|
id: content
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Header2Type {
|
Header2Type {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
Layout.bottomMargin: 16
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Split tunneling")
|
headerText: qsTr("Split tunneling")
|
||||||
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
|
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: splitTunnelingSwitch
|
id: splitTunnelingSwitch
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
|
|
||||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||||
|
|
||||||
text: qsTr("Split tunneling on the server")
|
text: qsTr("Split tunneling on the server")
|
||||||
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||||
root.closeTriggered()
|
root.closeTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: siteBasedSplitTunnelingSwitch
|
id: siteBasedSplitTunnelingSwitch
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
|
|
||||||
text: qsTr("Site-based split tunneling")
|
text: qsTr("Site-based split tunneling")
|
||||||
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||||
root.closeTriggered()
|
root.closeTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: appSplitTunnelingSwitch
|
id: appSplitTunnelingSwitch
|
||||||
visible: isAppSplitTinnelingEnabled
|
visible: isAppSplitTinnelingEnabled
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("App-based split tunneling")
|
text: qsTr("App-based split tunneling")
|
||||||
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||||
root.closeTriggered()
|
root.closeTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: isAppSplitTinnelingEnabled
|
visible: isAppSplitTinnelingEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ DrawerType2 {
|
||||||
headerText: qsTr("Choose application")
|
headerText: qsTr("Choose application")
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -66,11 +66,6 @@ DrawerType2 {
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
clip: true
|
|
||||||
interactive: true
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
model: SortFilterProxyModel {
|
model: SortFilterProxyModel {
|
||||||
id: proxyInstalledAppsModel
|
id: proxyInstalledAppsModel
|
||||||
sourceModel: installedAppsModel
|
sourceModel: installedAppsModel
|
||||||
|
|
@ -81,44 +76,37 @@ DrawerType2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: buttonGroup
|
id: buttonGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Item {
|
delegate: ColumnLayout {
|
||||||
implicitWidth: root.width
|
id: delegateContent
|
||||||
implicitHeight: delegateContent.implicitHeight
|
|
||||||
|
|
||||||
ColumnLayout {
|
width: listView.width
|
||||||
id: delegateContent
|
|
||||||
|
|
||||||
anchors.fill: parent
|
RowLayout {
|
||||||
|
CheckBoxType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
RowLayout {
|
text: appName
|
||||||
CheckBoxType {
|
checked: isAppSelected
|
||||||
Layout.fillWidth: true
|
onCheckedChanged: {
|
||||||
|
installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked)
|
||||||
text: appName
|
|
||||||
checked: isAppSelected
|
|
||||||
onCheckedChanged: {
|
|
||||||
installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
source: "image://installedAppImage/" + appIcon
|
|
||||||
|
|
||||||
sourceSize.width: 24
|
|
||||||
sourceSize.height: 24
|
|
||||||
|
|
||||||
Layout.rightMargin: 48
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
Image {
|
||||||
|
source: "image://installedAppImage/" + appIcon
|
||||||
|
|
||||||
|
sourceSize.width: 24
|
||||||
|
sourceSize.height: 24
|
||||||
|
|
||||||
|
Layout.rightMargin: 48
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ DrawerType2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButtonLayout.bottom
|
anchors.top: backButtonLayout.bottom
|
||||||
|
|
@ -57,14 +57,8 @@ DrawerType2 {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
property int selectedIndex: LanguageModel.currentLanguageIndex
|
property int selectedIndex: LanguageModel.currentLanguageIndex
|
||||||
|
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
model: LanguageModel
|
model: LanguageModel
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import "../Controls2"
|
||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
import "../Config"
|
import "../Config"
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property int selectedIndex: ServersModel.defaultIndex
|
property int selectedIndex: ServersModel.defaultIndex
|
||||||
|
|
@ -28,10 +28,6 @@ ListView {
|
||||||
|
|
||||||
model: ServersModel
|
model: ServersModel
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ServersModel
|
target: ServersModel
|
||||||
function onDefaultServerIndexChanged(serverIndex) {
|
function onDefaultServerIndexChanged(serverIndex) {
|
||||||
|
|
@ -39,9 +35,6 @@ ListView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
id: menuContentDelegate
|
id: menuContentDelegate
|
||||||
objectName: "menuContentDelegate"
|
objectName: "menuContentDelegate"
|
||||||
|
|
|
||||||
|
|
@ -13,78 +13,64 @@ import "../Controls2"
|
||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
|
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
width: parent.width
|
anchors.fill: parent
|
||||||
height: root.contentItem.height
|
|
||||||
|
|
||||||
clip: true
|
delegate: ColumnLayout {
|
||||||
reuseItems: true
|
width: root.width
|
||||||
|
|
||||||
property bool isFocusable: false
|
LabelWithButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
delegate: Item {
|
text: name
|
||||||
implicitWidth: root.width
|
descriptionText: description
|
||||||
implicitHeight: delegateContent.implicitHeight
|
rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg"
|
||||||
|
|
||||||
ColumnLayout {
|
clickedFunction: function() {
|
||||||
id: delegateContent
|
if (isInstalled) {
|
||||||
|
var containerIndex = root.model.mapToSource(index)
|
||||||
|
ContainersModel.setProcessedContainerIndex(containerIndex)
|
||||||
|
|
||||||
anchors.fill: parent
|
if (serviceType !== ProtocolEnum.Other) {
|
||||||
|
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
|
||||||
LabelWithButtonType {
|
|
||||||
id: containerRadioButton
|
|
||||||
implicitWidth: parent.width
|
|
||||||
|
|
||||||
text: name
|
|
||||||
descriptionText: description
|
|
||||||
rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg"
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
if (isInstalled) {
|
|
||||||
var containerIndex = root.model.mapToSource(index)
|
|
||||||
ContainersModel.setProcessedContainerIndex(containerIndex)
|
|
||||||
|
|
||||||
if (serviceType !== ProtocolEnum.Other) {
|
|
||||||
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
|
|
||||||
ProtocolsModel.updateModel(config)
|
|
||||||
PageController.goToPage(PageEnum.PageProtocolRaw)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (containerIndex) {
|
|
||||||
case ContainerEnum.Ipsec: {
|
|
||||||
ProtocolsModel.updateModel(config)
|
ProtocolsModel.updateModel(config)
|
||||||
PageController.goToPage(PageEnum.PageProtocolRaw)
|
PageController.goToPage(PageEnum.PageProtocolRaw)
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
case ContainerEnum.Dns: {
|
|
||||||
PageController.goToPage(PageEnum.PageServiceDnsSettings)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
ProtocolsModel.updateModel(config)
|
|
||||||
PageController.goToPage(PageEnum.PageSettingsServerProtocol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
|
|
||||||
InstallController.setShouldCreateServer(false)
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
switch (containerIndex) {
|
||||||
anchors.fill: parent
|
case ContainerEnum.Ipsec: {
|
||||||
cursorShape: Qt.PointingHandCursor
|
ProtocolsModel.updateModel(config)
|
||||||
enabled: false
|
PageController.goToPage(PageEnum.PageProtocolRaw)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case ContainerEnum.Dns: {
|
||||||
|
PageController.goToPage(PageEnum.PageServiceDnsSettings)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
ProtocolsModel.updateModel(config)
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsServerProtocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
|
||||||
|
InstallController.setShouldCreateServer(false)
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ DrawerType2 {
|
||||||
headerText: root.headerText
|
headerText: root.headerText
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
|
|
@ -61,14 +61,7 @@ DrawerType2 {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
property bool isFocusable: true
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
model: 1
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
@ -185,9 +178,21 @@ DrawerType2 {
|
||||||
Connections {
|
Connections {
|
||||||
target: copyNativeConfigStringButton
|
target: copyNativeConfigStringButton
|
||||||
function onClicked() {
|
function onClicked() {
|
||||||
nativeConfigString.selectAll()
|
const headerItem = configListView.headerItem;
|
||||||
nativeConfigString.copy()
|
if (!headerItem) {
|
||||||
nativeConfigString.select(0, 0)
|
console.error("Failed to copy: header item not found in ListView")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const nativeConfigStringItem = configListView.findChildWithObjectName(headerItem.children, "nativeConfigString");
|
||||||
|
if (!nativeConfigStringItem) {
|
||||||
|
console.error("Failed to copy: nativeConfigString item not found in ListView")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeConfigStringItem.selectAll()
|
||||||
|
nativeConfigStringItem.copy()
|
||||||
|
nativeConfigStringItem.select(0, 0)
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,11 +200,22 @@ DrawerType2 {
|
||||||
Connections {
|
Connections {
|
||||||
target: copyConfigTextButton
|
target: copyConfigTextButton
|
||||||
function onClicked() {
|
function onClicked() {
|
||||||
configText.selectAll()
|
const headerItem = configListView.headerItem;
|
||||||
configText.copy()
|
if (!headerItem) {
|
||||||
configText.select(0, 0)
|
console.error("Failed to copy: header item not found in ListView")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const configTextItem = configListView.findChildWithObjectName(headerItem.children, "configText");
|
||||||
|
if (!configTextItem) {
|
||||||
|
console.error("Failed to copy: configText item not found in ListView")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
configTextItem.selectAll()
|
||||||
|
configTextItem.copy()
|
||||||
|
configTextItem.select(0, 0)
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
header.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,30 +230,37 @@ DrawerType2 {
|
||||||
backButtonFunction: function() { configContentDrawer.closeTriggered() }
|
backButtonFunction: function() { configContentDrawer.closeTriggered() }
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
|
id: configListView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
|
|
||||||
|
|
||||||
ColumnLayout {
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
id: configContent
|
|
||||||
|
|
||||||
anchors.fill: parent
|
header: ColumnLayout {
|
||||||
anchors.rightMargin: 16
|
width: configListView.width
|
||||||
anchors.leftMargin: 16
|
|
||||||
|
|
||||||
Header2Type {
|
Header2Type {
|
||||||
id: configContentHeader
|
id: configContentHeader
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: root.configContentHeaderText
|
headerText: root.configContentHeaderText
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: nativeConfigString
|
id: nativeConfigString
|
||||||
|
objectName: "nativeConfigString"
|
||||||
|
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
visible: false
|
visible: false
|
||||||
text: ExportController.nativeConfigString
|
text: ExportController.nativeConfigString
|
||||||
|
|
||||||
|
|
@ -248,10 +271,13 @@ DrawerType2 {
|
||||||
|
|
||||||
TextArea {
|
TextArea {
|
||||||
id: configText
|
id: configText
|
||||||
|
objectName: "configText"
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
Layout.bottomMargin: 16
|
Layout.bottomMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
padding: 0
|
padding: 0
|
||||||
leftPadding: 0
|
leftPadding: 0
|
||||||
|
|
|
||||||
|
|
@ -1,220 +1,210 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string hoveredColor: AmneziaStyle.color.lightGray
|
property string hoveredColor: AmneziaStyle.color.lightGray
|
||||||
property string defaultColor: AmneziaStyle.color.paleGray
|
property string defaultColor: AmneziaStyle.color.paleGray
|
||||||
property string disabledColor: AmneziaStyle.color.charcoalGray
|
property string disabledColor: AmneziaStyle.color.charcoalGray
|
||||||
property string pressedColor: AmneziaStyle.color.mutedGray
|
property string pressedColor: AmneziaStyle.color.mutedGray
|
||||||
|
|
||||||
property string textColor: AmneziaStyle.color.midnightBlack
|
property string textColor: AmneziaStyle.color.midnightBlack
|
||||||
|
|
||||||
property string borderColor: AmneziaStyle.color.paleGray
|
property string borderColor: AmneziaStyle.color.paleGray
|
||||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||||
property int borderWidth: 0
|
property int borderWidth: 0
|
||||||
property int borderFocusedWidth: 1
|
property int borderFocusedWidth: 1
|
||||||
|
|
||||||
property string leftImageSource
|
property string leftImageSource
|
||||||
property string rightImageSource
|
property string rightImageSource
|
||||||
property string leftImageColor: textColor
|
property string leftImageColor: textColor
|
||||||
property bool changeLeftImageSize: true
|
property bool changeLeftImageSize: true
|
||||||
|
|
||||||
property bool squareLeftSide: false
|
property bool squareLeftSide: false
|
||||||
|
|
||||||
property FlickableType parentFlickable
|
property var clickedFunc
|
||||||
|
|
||||||
property var clickedFunc
|
property alias buttonTextLabel: buttonText
|
||||||
|
|
||||||
property alias buttonTextLabel: buttonText
|
property bool isFocusable: true
|
||||||
|
|
||||||
property bool isFocusable: true
|
Keys.onTabPressed: {
|
||||||
|
FocusController.nextKeyTabItem()
|
||||||
Keys.onTabPressed: {
|
}
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
Keys.onBacktabPressed: {
|
||||||
|
FocusController.previousKeyTabItem()
|
||||||
Keys.onBacktabPressed: {
|
}
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
Keys.onUpPressed: {
|
||||||
|
FocusController.nextKeyUpItem()
|
||||||
Keys.onUpPressed: {
|
}
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
Keys.onDownPressed: {
|
||||||
|
FocusController.nextKeyDownItem()
|
||||||
Keys.onDownPressed: {
|
}
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
Keys.onLeftPressed: {
|
||||||
|
FocusController.nextKeyLeftItem()
|
||||||
Keys.onLeftPressed: {
|
}
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
Keys.onRightPressed: {
|
||||||
|
FocusController.nextKeyRightItem()
|
||||||
Keys.onRightPressed: {
|
}
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
implicitHeight: 56
|
||||||
|
|
||||||
implicitHeight: 56
|
hoverEnabled: true
|
||||||
|
|
||||||
hoverEnabled: true
|
background: Rectangle {
|
||||||
|
id: focusBorder
|
||||||
onFocusChanged: {
|
|
||||||
if (root.activeFocus) {
|
color: AmneziaStyle.color.transparent
|
||||||
if (root.parentFlickable) {
|
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
||||||
root.parentFlickable.ensureVisible(this)
|
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
||||||
}
|
|
||||||
}
|
anchors.fill: parent
|
||||||
}
|
|
||||||
|
radius: 16
|
||||||
background: Rectangle {
|
|
||||||
id: focusBorder
|
Rectangle {
|
||||||
|
id: background
|
||||||
color: AmneziaStyle.color.transparent
|
|
||||||
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
anchors.fill: focusBorder
|
||||||
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
anchors.margins: root.activeFocus ? 2 : 0
|
||||||
|
|
||||||
anchors.fill: parent
|
radius: root.activeFocus ? 14 : 16
|
||||||
|
color: {
|
||||||
radius: 16
|
if (root.enabled) {
|
||||||
|
if (root.pressed) {
|
||||||
Rectangle {
|
return pressedColor
|
||||||
id: background
|
}
|
||||||
|
return root.hovered ? hoveredColor : defaultColor
|
||||||
anchors.fill: focusBorder
|
} else {
|
||||||
anchors.margins: root.activeFocus ? 2 : 0
|
return disabledColor
|
||||||
|
}
|
||||||
radius: root.activeFocus ? 14 : 16
|
}
|
||||||
color: {
|
border.color: borderColor
|
||||||
if (root.enabled) {
|
border.width: borderWidth
|
||||||
if (root.pressed) {
|
|
||||||
return pressedColor
|
Behavior on color {
|
||||||
}
|
PropertyAnimation { duration: 200 }
|
||||||
return root.hovered ? hoveredColor : defaultColor
|
}
|
||||||
} else {
|
|
||||||
return disabledColor
|
Rectangle {
|
||||||
}
|
visible: root.squareLeftSide
|
||||||
}
|
|
||||||
border.color: borderColor
|
z: 1
|
||||||
border.width: borderWidth
|
|
||||||
|
width: parent.radius
|
||||||
Behavior on color {
|
height: parent.radius
|
||||||
PropertyAnimation { duration: 200 }
|
anchors.top: parent.top
|
||||||
}
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
Rectangle {
|
color: {
|
||||||
visible: root.squareLeftSide
|
if (root.enabled) {
|
||||||
|
if (root.pressed) {
|
||||||
z: 1
|
return pressedColor
|
||||||
|
}
|
||||||
width: parent.radius
|
return root.hovered ? hoveredColor : defaultColor
|
||||||
height: parent.radius
|
} else {
|
||||||
anchors.top: parent.top
|
return disabledColor
|
||||||
anchors.bottom: parent.bottom
|
}
|
||||||
anchors.left: parent.left
|
}
|
||||||
color: {
|
|
||||||
if (root.enabled) {
|
Behavior on color {
|
||||||
if (root.pressed) {
|
PropertyAnimation { duration: 200 }
|
||||||
return pressedColor
|
}
|
||||||
}
|
}
|
||||||
return root.hovered ? hoveredColor : defaultColor
|
}
|
||||||
} else {
|
}
|
||||||
return disabledColor
|
|
||||||
}
|
MouseArea {
|
||||||
}
|
anchors.fill: focusBorder
|
||||||
|
enabled: false
|
||||||
Behavior on color {
|
cursorShape: Qt.PointingHandCursor
|
||||||
PropertyAnimation { duration: 200 }
|
}
|
||||||
}
|
|
||||||
}
|
contentItem: Item {
|
||||||
}
|
anchors.fill: focusBorder
|
||||||
}
|
|
||||||
|
implicitWidth: content.implicitWidth
|
||||||
MouseArea {
|
implicitHeight: content.implicitHeight
|
||||||
anchors.fill: focusBorder
|
|
||||||
enabled: false
|
RowLayout {
|
||||||
cursorShape: Qt.PointingHandCursor
|
id: content
|
||||||
}
|
anchors.centerIn: parent
|
||||||
|
|
||||||
contentItem: Item {
|
Image {
|
||||||
anchors.fill: focusBorder
|
id: leftImage
|
||||||
|
source: root.leftImageSource
|
||||||
implicitWidth: content.implicitWidth
|
visible: root.leftImageSource === "" ? false : true
|
||||||
implicitHeight: content.implicitHeight
|
|
||||||
|
layer {
|
||||||
RowLayout {
|
enabled: leftImageColor !== "" ? true : false
|
||||||
id: content
|
effect: ColorOverlay {
|
||||||
anchors.centerIn: parent
|
color: leftImageColor
|
||||||
|
}
|
||||||
Image {
|
}
|
||||||
id: leftImage
|
|
||||||
source: root.leftImageSource
|
Component.onCompleted: {
|
||||||
visible: root.leftImageSource === "" ? false : true
|
if (root.changeLeftImageSize) {
|
||||||
|
leftImage.Layout.preferredHeight = 20
|
||||||
layer {
|
leftImage.Layout.preferredWidth = 20
|
||||||
enabled: leftImageColor !== "" ? true : false
|
}
|
||||||
effect: ColorOverlay {
|
}
|
||||||
color: leftImageColor
|
}
|
||||||
}
|
|
||||||
}
|
ButtonTextType {
|
||||||
|
id: buttonText
|
||||||
Component.onCompleted: {
|
|
||||||
if (root.changeLeftImageSize) {
|
color: root.textColor
|
||||||
leftImage.Layout.preferredHeight = 20
|
text: root.text
|
||||||
leftImage.Layout.preferredWidth = 20
|
visible: root.text === "" ? false : true
|
||||||
}
|
|
||||||
}
|
horizontalAlignment: Text.AlignLeft
|
||||||
}
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
ButtonTextType {
|
|
||||||
id: buttonText
|
Image {
|
||||||
|
Layout.preferredHeight: 20
|
||||||
color: root.textColor
|
Layout.preferredWidth: 20
|
||||||
text: root.text
|
|
||||||
visible: root.text === "" ? false : true
|
source: root.rightImageSource
|
||||||
|
visible: root.rightImageSource === "" ? false : true
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
layer {
|
||||||
}
|
enabled: true
|
||||||
|
effect: ColorOverlay {
|
||||||
Image {
|
color: textColor
|
||||||
Layout.preferredHeight: 20
|
}
|
||||||
Layout.preferredWidth: 20
|
}
|
||||||
|
}
|
||||||
source: root.rightImageSource
|
}
|
||||||
visible: root.rightImageSource === "" ? false : true
|
}
|
||||||
|
|
||||||
layer {
|
Keys.onEnterPressed: {
|
||||||
enabled: true
|
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||||
effect: ColorOverlay {
|
root.clickedFunc()
|
||||||
color: textColor
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
Keys.onReturnPressed: {
|
||||||
}
|
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||||
}
|
root.clickedFunc()
|
||||||
|
}
|
||||||
Keys.onEnterPressed: {
|
}
|
||||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
|
||||||
root.clickedFunc()
|
onClicked: {
|
||||||
}
|
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||||
}
|
root.clickedFunc()
|
||||||
|
}
|
||||||
Keys.onReturnPressed: {
|
}
|
||||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
}
|
||||||
root.clickedFunc()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
|
||||||
root.clickedFunc()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,203 +1,185 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string headerText
|
property string headerText
|
||||||
property string bodyText
|
property string bodyText
|
||||||
property string footerText
|
property string footerText
|
||||||
|
|
||||||
property string hoveredColor: AmneziaStyle.color.slateGray
|
property string hoveredColor: AmneziaStyle.color.slateGray
|
||||||
property string defaultColor: AmneziaStyle.color.onyxBlack
|
property string defaultColor: AmneziaStyle.color.onyxBlack
|
||||||
|
|
||||||
property string textColor: AmneziaStyle.color.midnightBlack
|
property string textColor: AmneziaStyle.color.midnightBlack
|
||||||
|
|
||||||
property string rightImageSource
|
property string rightImageSource
|
||||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
property string leftImageSource
|
property string leftImageSource
|
||||||
|
|
||||||
property real textOpacity: 1.0
|
property real textOpacity: 1.0
|
||||||
|
|
||||||
property alias focusItem: rightImage
|
property alias focusItem: rightImage
|
||||||
|
|
||||||
property FlickableType parentFlickable
|
hoverEnabled: true
|
||||||
|
|
||||||
hoverEnabled: true
|
background: Rectangle {
|
||||||
|
id: backgroundRect
|
||||||
background: Rectangle {
|
|
||||||
id: backgroundRect
|
anchors.fill: parent
|
||||||
|
radius: 16
|
||||||
anchors.fill: parent
|
|
||||||
radius: 16
|
color: defaultColor
|
||||||
|
|
||||||
color: defaultColor
|
Behavior on color {
|
||||||
|
PropertyAnimation { duration: 200 }
|
||||||
Behavior on color {
|
}
|
||||||
PropertyAnimation { duration: 200 }
|
}
|
||||||
}
|
|
||||||
}
|
contentItem: Item {
|
||||||
|
anchors.left: parent.left
|
||||||
function ensureVisible(item) {
|
anchors.right: parent.right
|
||||||
if (item.activeFocus) {
|
|
||||||
if (root.parentFlickable) {
|
implicitHeight: content.implicitHeight
|
||||||
root.parentFlickable.ensureVisible(root)
|
|
||||||
}
|
RowLayout {
|
||||||
}
|
id: content
|
||||||
}
|
|
||||||
|
anchors.fill: parent
|
||||||
onFocusChanged: {
|
|
||||||
ensureVisible(root)
|
Image {
|
||||||
}
|
id: leftImage
|
||||||
|
source: leftImageSource
|
||||||
focusItem.onFocusChanged: {
|
|
||||||
root.ensureVisible(focusItem)
|
visible: leftImageSource !== ""
|
||||||
}
|
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||||
contentItem: Item {
|
Layout.topMargin: 24
|
||||||
anchors.left: parent.left
|
Layout.bottomMargin: 24
|
||||||
anchors.right: parent.right
|
Layout.leftMargin: 24
|
||||||
|
}
|
||||||
implicitHeight: content.implicitHeight
|
|
||||||
|
ColumnLayout {
|
||||||
RowLayout {
|
|
||||||
id: content
|
ListItemTitleType {
|
||||||
|
text: root.headerText
|
||||||
anchors.fill: parent
|
visible: text !== ""
|
||||||
|
|
||||||
Image {
|
Layout.fillWidth: true
|
||||||
id: leftImage
|
Layout.rightMargin: 16
|
||||||
source: leftImageSource
|
Layout.leftMargin: 16
|
||||||
|
Layout.topMargin: 16
|
||||||
visible: leftImageSource !== ""
|
Layout.bottomMargin: root.bodyText !== "" ? 0 : 16
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
opacity: root.textOpacity
|
||||||
Layout.topMargin: 24
|
}
|
||||||
Layout.bottomMargin: 24
|
|
||||||
Layout.leftMargin: 24
|
CaptionTextType {
|
||||||
}
|
text: root.bodyText
|
||||||
|
visible: text !== ""
|
||||||
ColumnLayout {
|
|
||||||
|
color: AmneziaStyle.color.mutedGray
|
||||||
ListItemTitleType {
|
textFormat: Text.RichText
|
||||||
text: root.headerText
|
|
||||||
visible: text !== ""
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: 16
|
||||||
Layout.fillWidth: true
|
Layout.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.bottomMargin: root.footerText !== "" ? 0 : 16
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.topMargin: 16
|
opacity: root.textOpacity
|
||||||
Layout.bottomMargin: root.bodyText !== "" ? 0 : 16
|
}
|
||||||
|
|
||||||
opacity: root.textOpacity
|
ButtonTextType {
|
||||||
}
|
text: root.footerText
|
||||||
|
visible: text !== ""
|
||||||
CaptionTextType {
|
|
||||||
text: root.bodyText
|
color: AmneziaStyle.color.mutedGray
|
||||||
visible: text !== ""
|
|
||||||
|
Layout.fillWidth: true
|
||||||
color: AmneziaStyle.color.mutedGray
|
Layout.rightMargin: 16
|
||||||
textFormat: Text.RichText
|
Layout.leftMargin: 16
|
||||||
|
Layout.topMargin: 16
|
||||||
Layout.fillWidth: true
|
Layout.bottomMargin: 16
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
opacity: root.textOpacity
|
||||||
Layout.bottomMargin: root.footerText !== "" ? 0 : 16
|
}
|
||||||
|
}
|
||||||
opacity: root.textOpacity
|
|
||||||
}
|
ImageButtonType {
|
||||||
|
id: rightImage
|
||||||
ButtonTextType {
|
|
||||||
text: root.footerText
|
implicitWidth: 40
|
||||||
visible: text !== ""
|
implicitHeight: 40
|
||||||
|
|
||||||
color: AmneziaStyle.color.mutedGray
|
hoverEnabled: false
|
||||||
|
image: rightImageSource
|
||||||
Layout.fillWidth: true
|
imageColor: rightImageColor
|
||||||
Layout.rightMargin: 16
|
visible: rightImageSource ? true : false
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.topMargin: 16
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
Layout.bottomMargin: 16
|
Layout.topMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
opacity: root.textOpacity
|
Layout.rightMargin: 16
|
||||||
}
|
|
||||||
}
|
Rectangle {
|
||||||
|
id: rightImageBackground
|
||||||
ImageButtonType {
|
|
||||||
id: rightImage
|
anchors.fill: parent
|
||||||
|
radius: 12
|
||||||
implicitWidth: 40
|
color: "transparent"
|
||||||
implicitHeight: 40
|
|
||||||
|
Behavior on color {
|
||||||
hoverEnabled: false
|
PropertyAnimation { duration: 200 }
|
||||||
image: rightImageSource
|
}
|
||||||
imageColor: rightImageColor
|
}
|
||||||
visible: rightImageSource ? true : false
|
|
||||||
|
onClicked: {
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
root.clicked()
|
||||||
Layout.topMargin: 16
|
}
|
||||||
Layout.bottomMargin: 16
|
}
|
||||||
Layout.rightMargin: 16
|
}
|
||||||
|
}
|
||||||
Rectangle {
|
|
||||||
id: rightImageBackground
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
anchors.fill: parent
|
|
||||||
radius: 12
|
cursorShape: Qt.PointingHandCursor
|
||||||
color: "transparent"
|
hoverEnabled: true
|
||||||
|
enabled: root.enabled
|
||||||
Behavior on color {
|
|
||||||
PropertyAnimation { duration: 200 }
|
onEntered: {
|
||||||
}
|
backgroundRect.color = root.hoveredColor
|
||||||
}
|
|
||||||
|
if (rightImageSource) {
|
||||||
onClicked: {
|
rightImageBackground.color = rightImage.hoveredColor
|
||||||
root.clicked()
|
}
|
||||||
}
|
root.textOpacity = 0.8
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
onExited: {
|
||||||
|
backgroundRect.color = root.defaultColor
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
if (rightImageSource) {
|
||||||
|
rightImageBackground.color = rightImage.defaultColor
|
||||||
cursorShape: Qt.PointingHandCursor
|
}
|
||||||
hoverEnabled: true
|
root.textOpacity = 1
|
||||||
enabled: root.enabled
|
}
|
||||||
|
|
||||||
onEntered: {
|
onPressedChanged: {
|
||||||
backgroundRect.color = root.hoveredColor
|
if (rightImageSource) {
|
||||||
|
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||||
if (rightImageSource) {
|
}
|
||||||
rightImageBackground.color = rightImage.hoveredColor
|
root.textOpacity = 0.7
|
||||||
}
|
}
|
||||||
root.textOpacity = 0.8
|
|
||||||
}
|
onClicked: {
|
||||||
|
root.clicked()
|
||||||
onExited: {
|
}
|
||||||
backgroundRect.color = root.defaultColor
|
}
|
||||||
|
}
|
||||||
if (rightImageSource) {
|
|
||||||
rightImageBackground.color = rightImage.defaultColor
|
|
||||||
}
|
|
||||||
root.textOpacity = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
onPressedChanged: {
|
|
||||||
if (rightImageSource) {
|
|
||||||
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
|
||||||
}
|
|
||||||
root.textOpacity = 0.7
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.clicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,170 +1,187 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string descriptionText
|
property string descriptionText
|
||||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||||
|
|
||||||
property string textColor: AmneziaStyle.color.paleGray
|
property string textColor: AmneziaStyle.color.paleGray
|
||||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
|
||||||
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||||
property string defaultColor: AmneziaStyle.color.transparent
|
property string defaultColor: AmneziaStyle.color.transparent
|
||||||
property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite
|
property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||||
|
|
||||||
property string defaultBorderColor: AmneziaStyle.color.paleGray
|
property string defaultBorderColor: AmneziaStyle.color.paleGray
|
||||||
property string checkedBorderColor: AmneziaStyle.color.goldenApricot
|
property string checkedBorderColor: AmneziaStyle.color.goldenApricot
|
||||||
property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown
|
property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown
|
||||||
|
|
||||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
property string checkedImageColor: AmneziaStyle.color.goldenApricot
|
property string checkedImageColor: AmneziaStyle.color.goldenApricot
|
||||||
property string pressedImageColor: AmneziaStyle.color.burntOrange
|
property string pressedImageColor: AmneziaStyle.color.burntOrange
|
||||||
property string defaultImageColor: AmneziaStyle.color.transparent
|
property string defaultImageColor: AmneziaStyle.color.transparent
|
||||||
property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown
|
property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown
|
||||||
|
|
||||||
property string imageSource: "qrc:/images/controls/check.svg"
|
property string imageSource: "qrc:/images/controls/check.svg"
|
||||||
|
|
||||||
property var parentFlickable
|
property bool isFocusable: true
|
||||||
onFocusChanged: {
|
|
||||||
if (root.activeFocus) {
|
Keys.onTabPressed: {
|
||||||
if (root.parentFlickable) {
|
FocusController.nextKeyTabItem()
|
||||||
root.parentFlickable.ensureVisible(root)
|
}
|
||||||
}
|
|
||||||
}
|
Keys.onBacktabPressed: {
|
||||||
}
|
FocusController.previousKeyTabItem()
|
||||||
|
}
|
||||||
hoverEnabled: enabled ? true : false
|
|
||||||
focusPolicy: Qt.NoFocus
|
Keys.onUpPressed: {
|
||||||
|
FocusController.nextKeyUpItem()
|
||||||
background: Rectangle {
|
}
|
||||||
color: AmneziaStyle.color.transparent
|
|
||||||
border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent
|
Keys.onDownPressed: {
|
||||||
border.width: 1
|
FocusController.nextKeyDownItem()
|
||||||
radius: 16
|
}
|
||||||
}
|
|
||||||
|
Keys.onLeftPressed: {
|
||||||
indicator: Rectangle {
|
FocusController.nextKeyLeftItem()
|
||||||
id: background
|
}
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Keys.onRightPressed: {
|
||||||
|
FocusController.nextKeyRightItem()
|
||||||
implicitWidth: 56
|
}
|
||||||
implicitHeight: 56
|
|
||||||
radius: 16
|
hoverEnabled: enabled ? true : false
|
||||||
|
focusPolicy: Qt.NoFocus
|
||||||
color: {
|
|
||||||
if (root.hovered) {
|
background: Rectangle {
|
||||||
return hoveredColor
|
color: AmneziaStyle.color.transparent
|
||||||
}
|
border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent
|
||||||
return defaultColor
|
border.width: 1
|
||||||
}
|
radius: 16
|
||||||
|
}
|
||||||
Behavior on color {
|
|
||||||
PropertyAnimation { duration: 200 }
|
indicator: Rectangle {
|
||||||
}
|
id: background
|
||||||
|
|
||||||
Rectangle {
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
id: imageBorder
|
|
||||||
|
implicitWidth: 56
|
||||||
anchors.centerIn: parent
|
implicitHeight: 56
|
||||||
width: 24
|
radius: 16
|
||||||
height: 24
|
|
||||||
color: AmneziaStyle.color.transparent
|
color: {
|
||||||
border.color: root.checked ?
|
if (root.hovered) {
|
||||||
(root.enabled ?
|
return hoveredColor
|
||||||
checkedBorderColor :
|
}
|
||||||
checkedBorderDisabledColor) :
|
return defaultColor
|
||||||
defaultBorderColor
|
}
|
||||||
border.width: 1
|
|
||||||
radius: 4
|
Behavior on color {
|
||||||
|
PropertyAnimation { duration: 200 }
|
||||||
Image {
|
}
|
||||||
anchors.centerIn: parent
|
|
||||||
|
Rectangle {
|
||||||
source: root.pressed ? imageSource : root.checked ? imageSource : ""
|
id: imageBorder
|
||||||
layer {
|
|
||||||
enabled: true
|
anchors.centerIn: parent
|
||||||
effect: ColorOverlay {
|
width: 24
|
||||||
color: {
|
height: 24
|
||||||
if (root.pressed) {
|
color: AmneziaStyle.color.transparent
|
||||||
return root.pressedImageColor
|
border.color: root.checked ?
|
||||||
} else if (root.checked) {
|
(root.enabled ?
|
||||||
if (root.enabled) {
|
checkedBorderColor :
|
||||||
return root.checkedImageColor
|
checkedBorderDisabledColor) :
|
||||||
} else {
|
defaultBorderColor
|
||||||
return root.checkedDisabledImageColor
|
border.width: 1
|
||||||
}
|
radius: 4
|
||||||
} else {
|
|
||||||
return root.defaultImageColor
|
Image {
|
||||||
}
|
anchors.centerIn: parent
|
||||||
}
|
|
||||||
}
|
source: root.pressed ? imageSource : root.checked ? imageSource : ""
|
||||||
}
|
layer {
|
||||||
}
|
enabled: true
|
||||||
}
|
effect: ColorOverlay {
|
||||||
}
|
color: {
|
||||||
|
if (root.pressed) {
|
||||||
contentItem: Item {
|
return root.pressedImageColor
|
||||||
anchors.left: parent.left
|
} else if (root.checked) {
|
||||||
anchors.right: parent.right
|
if (root.enabled) {
|
||||||
anchors.leftMargin: 8 + background.width
|
return root.checkedImageColor
|
||||||
|
} else {
|
||||||
implicitHeight: content.implicitHeight
|
return root.checkedDisabledImageColor
|
||||||
|
}
|
||||||
ColumnLayout {
|
} else {
|
||||||
id: content
|
return root.defaultImageColor
|
||||||
|
}
|
||||||
anchors.left: parent.left
|
}
|
||||||
anchors.right: parent.right
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
}
|
||||||
|
}
|
||||||
spacing: 4
|
}
|
||||||
|
}
|
||||||
ListItemTitleType {
|
|
||||||
Layout.fillWidth: true
|
contentItem: Item {
|
||||||
|
anchors.left: parent.left
|
||||||
text: root.text
|
anchors.right: parent.right
|
||||||
color: root.enabled ? root.textColor : root.textDisabledColor
|
anchors.leftMargin: 8 + background.width
|
||||||
}
|
|
||||||
|
implicitHeight: content.implicitHeight
|
||||||
CaptionTextType {
|
|
||||||
id: description
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
Layout.fillWidth: true
|
|
||||||
|
anchors.left: parent.left
|
||||||
text: root.descriptionText
|
anchors.right: parent.right
|
||||||
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
visible: root.descriptionText !== ""
|
spacing: 4
|
||||||
}
|
|
||||||
}
|
ListItemTitleType {
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
|
||||||
MouseArea {
|
text: root.text
|
||||||
anchors.fill: parent
|
color: root.enabled ? root.textColor : root.textDisabledColor
|
||||||
cursorShape: Qt.PointingHandCursor
|
}
|
||||||
enabled: false
|
|
||||||
}
|
CaptionTextType {
|
||||||
|
id: description
|
||||||
|
|
||||||
Keys.onEnterPressed: {
|
Layout.fillWidth: true
|
||||||
root.checked = !root.checked
|
|
||||||
}
|
text: root.descriptionText
|
||||||
|
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
||||||
Keys.onReturnPressed: {
|
|
||||||
root.checked = !root.checked
|
visible: root.descriptionText !== ""
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Keys.onEnterPressed: {
|
||||||
|
root.checked = !root.checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
root.checked = !root.checked
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,328 +1,309 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string text
|
// property alias focusObjectName: eyeImage.objectName
|
||||||
property int textMaximumLineCount: 2
|
property string text
|
||||||
property int textElide: Qt.ElideRight
|
property int textMaximumLineCount: 2
|
||||||
|
property int textElide: Qt.ElideRight
|
||||||
property string descriptionText
|
|
||||||
|
property string descriptionText
|
||||||
property var clickedFunction
|
|
||||||
|
property var clickedFunction
|
||||||
property string buttonImageSource
|
|
||||||
property string rightImageSource
|
property string buttonImageSource
|
||||||
property string leftImageSource
|
property string rightImageSource
|
||||||
property bool isLeftImageHoverEnabled: true
|
property string leftImageSource
|
||||||
property bool isSmallLeftImage: false
|
property bool isLeftImageHoverEnabled: true
|
||||||
|
property bool isSmallLeftImage: false
|
||||||
property alias rightButton: rightImage
|
|
||||||
property alias eyeButton: eyeImage
|
property alias rightButton: rightImage
|
||||||
property FlickableType parentFlickable
|
property alias eyeButton: eyeImage
|
||||||
|
|
||||||
property string textColor: AmneziaStyle.color.paleGray
|
property string textColor: AmneziaStyle.color.paleGray
|
||||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||||
property string descriptionColor: AmneziaStyle.color.mutedGray
|
property string descriptionColor: AmneziaStyle.color.mutedGray
|
||||||
property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray
|
property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray
|
||||||
property real textOpacity: 1.0
|
property real textOpacity: 1.0
|
||||||
|
|
||||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||||
property int borderFocusedWidth: 1
|
property int borderFocusedWidth: 1
|
||||||
|
|
||||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
property bool descriptionOnTop: false
|
property bool descriptionOnTop: false
|
||||||
property bool hideDescription: true
|
property bool hideDescription: true
|
||||||
|
|
||||||
property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items
|
property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
Keys.onTabPressed: {
|
||||||
FocusController.nextKeyTabItem()
|
FocusController.nextKeyTabItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
Keys.onBacktabPressed: {
|
||||||
FocusController.previousKeyTabItem()
|
FocusController.previousKeyTabItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
Keys.onUpPressed: {
|
||||||
FocusController.nextKeyUpItem()
|
FocusController.nextKeyUpItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
Keys.onDownPressed: {
|
||||||
FocusController.nextKeyDownItem()
|
FocusController.nextKeyDownItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
Keys.onLeftPressed: {
|
||||||
FocusController.nextKeyLeftItem()
|
FocusController.nextKeyLeftItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
Keys.onRightPressed: {
|
||||||
FocusController.nextKeyRightItem()
|
FocusController.nextKeyRightItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
||||||
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
|
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
|
||||||
|
|
||||||
onFocusChanged: {
|
MouseArea {
|
||||||
if (root.activeFocus) {
|
anchors.fill: parent
|
||||||
if (root.parentFlickable) {
|
cursorShape: Qt.PointingHandCursor
|
||||||
root.parentFlickable.ensureVisible(root)
|
hoverEnabled: root.enabled
|
||||||
}
|
|
||||||
}
|
onEntered: {
|
||||||
}
|
if (rightImageSource) {
|
||||||
|
rightImageBackground.color = rightImage.hoveredColor
|
||||||
Connections {
|
} else if (leftImageSource) {
|
||||||
target: rightImage
|
leftImageBackground.color = rightImage.hoveredColor
|
||||||
function onFocusChanged() {
|
}
|
||||||
if (rightImage.activeFocus) {
|
root.textOpacity = 0.8
|
||||||
if (root.parentFlickable) {
|
}
|
||||||
root.parentFlickable.ensureVisible(root)
|
|
||||||
}
|
onExited: {
|
||||||
}
|
if (rightImageSource) {
|
||||||
}
|
rightImageBackground.color = rightImage.defaultColor
|
||||||
}
|
} else if (leftImageSource) {
|
||||||
|
leftImageBackground.color = rightImage.defaultColor
|
||||||
MouseArea {
|
}
|
||||||
anchors.fill: parent
|
root.textOpacity = 1
|
||||||
cursorShape: Qt.PointingHandCursor
|
}
|
||||||
hoverEnabled: root.enabled
|
|
||||||
|
onPressedChanged: {
|
||||||
onEntered: {
|
if (rightImageSource) {
|
||||||
if (rightImageSource) {
|
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||||
rightImageBackground.color = rightImage.hoveredColor
|
} else if (leftImageSource) {
|
||||||
} else if (leftImageSource) {
|
leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||||
leftImageBackground.color = rightImage.hoveredColor
|
}
|
||||||
}
|
root.textOpacity = 0.7
|
||||||
root.textOpacity = 0.8
|
}
|
||||||
}
|
|
||||||
|
onClicked: {
|
||||||
onExited: {
|
if (clickedFunction && typeof clickedFunction === "function") {
|
||||||
if (rightImageSource) {
|
clickedFunction()
|
||||||
rightImageBackground.color = rightImage.defaultColor
|
}
|
||||||
} else if (leftImageSource) {
|
}
|
||||||
leftImageBackground.color = rightImage.defaultColor
|
}
|
||||||
}
|
|
||||||
root.textOpacity = 1
|
RowLayout {
|
||||||
}
|
id: content
|
||||||
|
anchors.fill: parent
|
||||||
onPressedChanged: {
|
anchors.leftMargin: 16
|
||||||
if (rightImageSource) {
|
anchors.rightMargin: 16
|
||||||
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
anchors.topMargin: 16
|
||||||
} else if (leftImageSource) {
|
anchors.bottomMargin: 16
|
||||||
leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
|
||||||
}
|
Rectangle {
|
||||||
root.textOpacity = 0.7
|
id: leftImageBackground
|
||||||
}
|
|
||||||
|
visible: leftImageSource ? true : false
|
||||||
onClicked: {
|
|
||||||
if (clickedFunction && typeof clickedFunction === "function") {
|
Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56
|
||||||
clickedFunction()
|
Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56
|
||||||
}
|
Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0
|
||||||
}
|
|
||||||
}
|
radius: 12
|
||||||
|
color: AmneziaStyle.color.transparent
|
||||||
RowLayout {
|
|
||||||
id: content
|
Behavior on color {
|
||||||
anchors.fill: parent
|
PropertyAnimation { duration: 200 }
|
||||||
anchors.leftMargin: 16
|
}
|
||||||
anchors.rightMargin: 16
|
|
||||||
anchors.topMargin: 16
|
Image {
|
||||||
anchors.bottomMargin: 16
|
id: leftImage
|
||||||
|
|
||||||
Rectangle {
|
anchors.centerIn: parent
|
||||||
id: leftImageBackground
|
source: leftImageSource
|
||||||
|
}
|
||||||
visible: leftImageSource ? true : false
|
}
|
||||||
|
|
||||||
Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56
|
ColumnLayout {
|
||||||
Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56
|
property real textLineHeight: 21.6
|
||||||
Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0
|
property real descriptionTextLineHeight: 16
|
||||||
|
|
||||||
radius: 12
|
property int textPixelSize: 18
|
||||||
color: AmneziaStyle.color.transparent
|
property int descriptionTextSize: 13
|
||||||
|
|
||||||
Behavior on color {
|
ListItemTitleType {
|
||||||
PropertyAnimation { duration: 200 }
|
text: root.text
|
||||||
}
|
color: {
|
||||||
|
if (root.enabled) {
|
||||||
Image {
|
return root.descriptionOnTop ? root.descriptionColor : root.textColor
|
||||||
id: leftImage
|
} else {
|
||||||
|
return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor
|
||||||
anchors.centerIn: parent
|
}
|
||||||
source: leftImageSource
|
}
|
||||||
}
|
|
||||||
}
|
maximumLineCount: root.textMaximumLineCount
|
||||||
|
elide: root.textElide
|
||||||
ColumnLayout {
|
|
||||||
property real textLineHeight: 21.6
|
opacity: root.textOpacity
|
||||||
property real descriptionTextLineHeight: 16
|
|
||||||
|
Layout.fillWidth: true
|
||||||
property int textPixelSize: 18
|
|
||||||
property int descriptionTextSize: 13
|
lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight
|
||||||
|
font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize
|
||||||
ListItemTitleType {
|
font.letterSpacing: root.descriptionOnTop ? 0.02 : 0
|
||||||
text: root.text
|
|
||||||
color: {
|
horizontalAlignment: Text.AlignLeft
|
||||||
if (root.enabled) {
|
verticalAlignment: Text.AlignVCenter
|
||||||
return root.descriptionOnTop ? root.descriptionColor : root.textColor
|
|
||||||
} else {
|
Behavior on opacity {
|
||||||
return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor
|
PropertyAnimation { duration: 200 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maximumLineCount: root.textMaximumLineCount
|
|
||||||
elide: root.textElide
|
CaptionTextType {
|
||||||
|
id: description
|
||||||
opacity: root.textOpacity
|
|
||||||
|
text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText
|
||||||
Layout.fillWidth: true
|
color: {
|
||||||
|
if (root.enabled) {
|
||||||
lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight
|
return root.descriptionOnTop ? root.textColor : root.descriptionColor
|
||||||
font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize
|
} else {
|
||||||
font.letterSpacing: root.descriptionOnTop ? 0.02 : 0
|
return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor
|
||||||
|
}
|
||||||
horizontalAlignment: Text.AlignLeft
|
}
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
|
opacity: root.textOpacity
|
||||||
Behavior on opacity {
|
|
||||||
PropertyAnimation { duration: 200 }
|
visible: root.descriptionText !== ""
|
||||||
}
|
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight
|
||||||
CaptionTextType {
|
font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize
|
||||||
id: description
|
font.letterSpacing: root.descriptionOnTop ? 0 : 0.02
|
||||||
|
|
||||||
text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText
|
horizontalAlignment: Text.AlignLeft
|
||||||
color: {
|
verticalAlignment: Text.AlignVCenter
|
||||||
if (root.enabled) {
|
|
||||||
return root.descriptionOnTop ? root.textColor : root.descriptionColor
|
Behavior on opacity {
|
||||||
} else {
|
PropertyAnimation { duration: 200 }
|
||||||
return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor
|
}
|
||||||
}
|
|
||||||
}
|
function replaceWithAsterisks(input) {
|
||||||
|
return '*'.repeat(input.length)
|
||||||
opacity: root.textOpacity
|
}
|
||||||
|
}
|
||||||
visible: root.descriptionText !== ""
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
ImageButtonType {
|
||||||
|
id: eyeImage
|
||||||
lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight
|
visible: buttonImageSource !== ""
|
||||||
font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize
|
|
||||||
font.letterSpacing: root.descriptionOnTop ? 0 : 0.02
|
implicitWidth: 40
|
||||||
|
implicitHeight: 40
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
hoverEnabled: true
|
||||||
|
image: buttonImageSource
|
||||||
Behavior on opacity {
|
imageColor: rightImageColor
|
||||||
PropertyAnimation { duration: 200 }
|
|
||||||
}
|
Layout.alignment: Qt.AlignRight
|
||||||
|
|
||||||
function replaceWithAsterisks(input) {
|
Rectangle {
|
||||||
return '*'.repeat(input.length)
|
id: eyeImageBackground
|
||||||
}
|
anchors.fill: parent
|
||||||
}
|
radius: 12
|
||||||
}
|
color: AmneziaStyle.color.transparent
|
||||||
|
|
||||||
ImageButtonType {
|
Behavior on color {
|
||||||
id: eyeImage
|
PropertyAnimation { duration: 200 }
|
||||||
visible: buttonImageSource !== ""
|
}
|
||||||
|
}
|
||||||
implicitWidth: 40
|
|
||||||
implicitHeight: 40
|
onClicked: {
|
||||||
|
hideDescription = !hideDescription
|
||||||
hoverEnabled: true
|
}
|
||||||
image: buttonImageSource
|
|
||||||
imageColor: rightImageColor
|
Keys.onEnterPressed: {
|
||||||
|
clicked()
|
||||||
Layout.alignment: Qt.AlignRight
|
}
|
||||||
|
|
||||||
Rectangle {
|
Keys.onReturnPressed: {
|
||||||
id: eyeImageBackground
|
clicked()
|
||||||
anchors.fill: parent
|
}
|
||||||
radius: 12
|
}
|
||||||
color: AmneziaStyle.color.transparent
|
|
||||||
|
ImageButtonType {
|
||||||
Behavior on color {
|
id: rightImage
|
||||||
PropertyAnimation { duration: 200 }
|
|
||||||
}
|
implicitWidth: 40
|
||||||
}
|
implicitHeight: 40
|
||||||
|
|
||||||
onClicked: {
|
hoverEnabled: false
|
||||||
hideDescription = !hideDescription
|
image: rightImageSource
|
||||||
}
|
imageColor: rightImageColor
|
||||||
|
visible: rightImageSource ? true : false
|
||||||
Keys.onEnterPressed: {
|
|
||||||
clicked()
|
Layout.alignment: Qt.AlignRight
|
||||||
}
|
|
||||||
|
Rectangle {
|
||||||
Keys.onReturnPressed: {
|
id: rightImageBackground
|
||||||
clicked()
|
anchors.fill: parent
|
||||||
}
|
radius: 12
|
||||||
}
|
color: AmneziaStyle.color.transparent
|
||||||
|
|
||||||
ImageButtonType {
|
Behavior on color {
|
||||||
id: rightImage
|
PropertyAnimation { duration: 200 }
|
||||||
|
}
|
||||||
implicitWidth: 40
|
}
|
||||||
implicitHeight: 40
|
onClicked: {
|
||||||
|
if (clickedFunction && typeof clickedFunction === "function") {
|
||||||
hoverEnabled: false
|
clickedFunction()
|
||||||
image: rightImageSource
|
}
|
||||||
imageColor: rightImageColor
|
}
|
||||||
visible: rightImageSource ? true : false
|
}
|
||||||
|
}
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
|
Rectangle {
|
||||||
Rectangle {
|
id: background
|
||||||
id: rightImageBackground
|
anchors.fill: root
|
||||||
anchors.fill: parent
|
color: AmneziaStyle.color.transparent
|
||||||
radius: 12
|
|
||||||
color: AmneziaStyle.color.transparent
|
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
||||||
|
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
||||||
Behavior on color {
|
|
||||||
PropertyAnimation { duration: 200 }
|
|
||||||
}
|
Behavior on color {
|
||||||
}
|
PropertyAnimation { duration: 200 }
|
||||||
onClicked: {
|
}
|
||||||
if (clickedFunction && typeof clickedFunction === "function") {
|
}
|
||||||
clickedFunction()
|
|
||||||
}
|
Keys.onEnterPressed: {
|
||||||
}
|
if (clickedFunction && typeof clickedFunction === "function") {
|
||||||
}
|
clickedFunction()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Rectangle {
|
|
||||||
id: background
|
Keys.onReturnPressed: {
|
||||||
anchors.fill: root
|
if (clickedFunction && typeof clickedFunction === "function") {
|
||||||
color: AmneziaStyle.color.transparent
|
clickedFunction()
|
||||||
|
}
|
||||||
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
}
|
||||||
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
}
|
||||||
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
PropertyAnimation { duration: 200 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: {
|
|
||||||
if (clickedFunction && typeof clickedFunction === "function") {
|
|
||||||
clickedFunction()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onReturnPressed: {
|
|
||||||
if (clickedFunction && typeof clickedFunction === "function") {
|
|
||||||
clickedFunction()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,33 +6,16 @@ ListView {
|
||||||
|
|
||||||
property bool isFocusable: true
|
property bool isFocusable: true
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
ScrollBar.vertical: ScrollBarType {}
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
reuseItems: true
|
reuseItems: true
|
||||||
snapMode: ListView.SnapToItem
|
|
||||||
|
function findChildWithObjectName(items, name) {
|
||||||
|
for (var i = 0; i < items.length; ++i) {
|
||||||
|
if (items[i].objectName === name)
|
||||||
|
return items[i];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var rootWidth
|
property var rootWidth
|
||||||
|
|
@ -25,13 +25,6 @@ ListView {
|
||||||
width: rootWidth
|
width: rootWidth
|
||||||
height: root.contentItem.height
|
height: root.contentItem.height
|
||||||
|
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: buttonGroup
|
id: buttonGroup
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,172 +1,162 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
Switch {
|
Switch {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property alias descriptionText: description.text
|
property alias descriptionText: description.text
|
||||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||||
|
|
||||||
property string textColor: AmneziaStyle.color.paleGray
|
property string textColor: AmneziaStyle.color.paleGray
|
||||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
|
||||||
property string checkedIndicatorColor: AmneziaStyle.color.richBrown
|
property string checkedIndicatorColor: AmneziaStyle.color.richBrown
|
||||||
property string defaultIndicatorColor: AmneziaStyle.color.transparent
|
property string defaultIndicatorColor: AmneziaStyle.color.transparent
|
||||||
property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown
|
property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown
|
||||||
|
|
||||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||||
property int borderFocusedWidth: 1
|
property int borderFocusedWidth: 1
|
||||||
|
|
||||||
property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown
|
property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown
|
||||||
property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray
|
property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray
|
||||||
property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown
|
property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown
|
||||||
|
|
||||||
property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot
|
property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot
|
||||||
property string defaultInnerCircleColor: AmneziaStyle.color.paleGray
|
property string defaultInnerCircleColor: AmneziaStyle.color.paleGray
|
||||||
property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown
|
property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown
|
||||||
property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray
|
property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray
|
||||||
|
|
||||||
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite
|
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite
|
||||||
property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent
|
property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent
|
||||||
|
|
||||||
property bool isFocusable: true
|
property bool isFocusable: true
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
Keys.onTabPressed: {
|
||||||
FocusController.nextKeyTabItem()
|
FocusController.nextKeyTabItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
Keys.onBacktabPressed: {
|
||||||
FocusController.previousKeyTabItem()
|
FocusController.previousKeyTabItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
Keys.onUpPressed: {
|
||||||
FocusController.nextKeyUpItem()
|
FocusController.nextKeyUpItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
Keys.onDownPressed: {
|
||||||
FocusController.nextKeyDownItem()
|
FocusController.nextKeyDownItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
Keys.onLeftPressed: {
|
||||||
FocusController.nextKeyLeftItem()
|
FocusController.nextKeyLeftItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
Keys.onRightPressed: {
|
||||||
FocusController.nextKeyRightItem()
|
FocusController.nextKeyRightItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
hoverEnabled: enabled ? true : false
|
hoverEnabled: enabled ? true : false
|
||||||
focusPolicy: Qt.TabFocus
|
focusPolicy: Qt.TabFocus
|
||||||
|
|
||||||
property FlickableType parentFlickable: null
|
indicator: Rectangle {
|
||||||
|
id: switcher
|
||||||
onFocusChanged: {
|
|
||||||
if (root.activeFocus) {
|
anchors.right: parent.right
|
||||||
if (root.parentFlickable) {
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
root.parentFlickable.ensureVisible(root)
|
|
||||||
}
|
implicitWidth: 52
|
||||||
}
|
implicitHeight: 32
|
||||||
}
|
|
||||||
|
radius: 16
|
||||||
indicator: Rectangle {
|
color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor)
|
||||||
id: switcher
|
: root.defaultIndicatorColor
|
||||||
|
|
||||||
anchors.right: parent.right
|
border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor)
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
: root.defaultIndicatorBorderColor)
|
||||||
|
|
||||||
implicitWidth: 52
|
Behavior on color {
|
||||||
implicitHeight: 32
|
PropertyAnimation { duration: 200 }
|
||||||
|
}
|
||||||
radius: 16
|
Behavior on border.color {
|
||||||
color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor)
|
PropertyAnimation { duration: 200 }
|
||||||
: root.defaultIndicatorColor
|
}
|
||||||
|
|
||||||
border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor)
|
Rectangle {
|
||||||
: root.defaultIndicatorBorderColor)
|
id: innerCircle
|
||||||
|
|
||||||
Behavior on color {
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
PropertyAnimation { duration: 200 }
|
x: root.checked ? parent.width - width - 4 : 8
|
||||||
}
|
width: root.checked ? 24 : 16
|
||||||
Behavior on border.color {
|
height: root.checked ? 24 : 16
|
||||||
PropertyAnimation { duration: 200 }
|
radius: 23
|
||||||
}
|
color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor)
|
||||||
|
: (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor)
|
||||||
Rectangle {
|
|
||||||
id: innerCircle
|
Behavior on x {
|
||||||
|
PropertyAnimation { duration: 200 }
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
}
|
||||||
x: root.checked ? parent.width - width - 4 : 8
|
}
|
||||||
width: root.checked ? 24 : 16
|
|
||||||
height: root.checked ? 24 : 16
|
Rectangle {
|
||||||
radius: 23
|
anchors.centerIn: innerCircle
|
||||||
color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor)
|
width: 40
|
||||||
: (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor)
|
height: 40
|
||||||
|
radius: 23
|
||||||
Behavior on x {
|
color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor
|
||||||
PropertyAnimation { duration: 200 }
|
|
||||||
}
|
Behavior on color {
|
||||||
}
|
PropertyAnimation { duration: 200 }
|
||||||
|
}
|
||||||
Rectangle {
|
}
|
||||||
anchors.centerIn: innerCircle
|
}
|
||||||
width: 40
|
|
||||||
height: 40
|
contentItem: ColumnLayout {
|
||||||
radius: 23
|
id: content
|
||||||
color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
Behavior on color {
|
anchors.left: parent.left
|
||||||
PropertyAnimation { duration: 200 }
|
|
||||||
}
|
ListItemTitleType {
|
||||||
}
|
Layout.fillWidth: true
|
||||||
}
|
rightPadding: indicator.width
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
text: root.text
|
||||||
id: content
|
color: root.enabled ? root.textColor : root.textDisabledColor
|
||||||
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
CaptionTextType {
|
||||||
|
id: description
|
||||||
ListItemTitleType {
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
rightPadding: indicator.width
|
rightPadding: indicator.width
|
||||||
|
|
||||||
text: root.text
|
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
||||||
color: root.enabled ? root.textColor : root.textDisabledColor
|
|
||||||
}
|
visible: text !== ""
|
||||||
|
}
|
||||||
CaptionTextType {
|
}
|
||||||
id: description
|
|
||||||
|
MouseArea {
|
||||||
Layout.fillWidth: true
|
anchors.fill: parent
|
||||||
rightPadding: indicator.width
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
}
|
||||||
|
|
||||||
visible: text !== ""
|
Keys.onEnterPressed: event => handleSwitch(event)
|
||||||
}
|
Keys.onReturnPressed: event => handleSwitch(event)
|
||||||
}
|
Keys.onSpacePressed: event => handleSwitch(event)
|
||||||
|
|
||||||
MouseArea {
|
function handleSwitch(event) {
|
||||||
anchors.fill: parent
|
if (!event.isAutoRepeat) {
|
||||||
cursorShape: Qt.PointingHandCursor
|
root.checked = !root.checked
|
||||||
enabled: false
|
root.checkedChanged()
|
||||||
}
|
}
|
||||||
|
event.accepted = true
|
||||||
Keys.onEnterPressed: event => handleSwitch(event)
|
}
|
||||||
Keys.onReturnPressed: event => handleSwitch(event)
|
}
|
||||||
Keys.onSpacePressed: event => handleSwitch(event)
|
|
||||||
|
|
||||||
function handleSwitch(event) {
|
|
||||||
if (!event.isAutoRepeat) {
|
|
||||||
root.checked = !root.checked
|
|
||||||
root.checkedChanged()
|
|
||||||
}
|
|
||||||
event.accepted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,118 +1,135 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string placeholderText
|
property string placeholderText
|
||||||
property string text
|
property string text
|
||||||
property alias textArea: textArea
|
property alias textArea: textArea
|
||||||
property alias textAreaText: textArea.text
|
property alias textAreaText: textArea.text
|
||||||
|
|
||||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
height: 148
|
height: 148
|
||||||
color: AmneziaStyle.color.onyxBlack
|
color: AmneziaStyle.color.onyxBlack
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: getBorderColor(borderNormalColor)
|
border.color: getBorderColor(borderNormalColor)
|
||||||
radius: 16
|
radius: 16
|
||||||
|
|
||||||
property FlickableType parentFlickable: null
|
MouseArea {
|
||||||
onFocusChanged: {
|
id: parentMouse
|
||||||
if (root.activeFocus) {
|
anchors.fill: parent
|
||||||
if (root.parentFlickable) {
|
cursorShape: Qt.IBeamCursor
|
||||||
root.parentFlickable.ensureVisible(root)
|
onClicked: textArea.forceActiveFocus()
|
||||||
}
|
hoverEnabled: true
|
||||||
}
|
|
||||||
}
|
FlickableType {
|
||||||
|
id: fl
|
||||||
MouseArea {
|
interactive: false
|
||||||
id: parentMouse
|
|
||||||
anchors.fill: parent
|
anchors.top: parent.top
|
||||||
cursorShape: Qt.IBeamCursor
|
anchors.bottom: parent.bottom
|
||||||
onClicked: textArea.forceActiveFocus()
|
contentHeight: textArea.implicitHeight
|
||||||
hoverEnabled: true
|
TextArea {
|
||||||
|
id: textArea
|
||||||
FlickableType {
|
|
||||||
id: fl
|
width: parent.width
|
||||||
interactive: false
|
|
||||||
|
topPadding: 16
|
||||||
anchors.top: parent.top
|
leftPadding: 16
|
||||||
anchors.bottom: parent.bottom
|
anchors.topMargin: 16
|
||||||
contentHeight: textArea.implicitHeight
|
anchors.bottomMargin: 16
|
||||||
TextArea {
|
|
||||||
id: textArea
|
property bool isFocusable: true
|
||||||
|
|
||||||
width: parent.width
|
Keys.onTabPressed: {
|
||||||
|
FocusController.nextKeyTabItem()
|
||||||
topPadding: 16
|
}
|
||||||
leftPadding: 16
|
|
||||||
anchors.topMargin: 16
|
Keys.onBacktabPressed: {
|
||||||
anchors.bottomMargin: 16
|
FocusController.previousKeyTabItem()
|
||||||
|
}
|
||||||
color: AmneziaStyle.color.paleGray
|
|
||||||
selectionColor: AmneziaStyle.color.richBrown
|
Keys.onUpPressed: {
|
||||||
selectedTextColor: AmneziaStyle.color.paleGray
|
FocusController.nextKeyUpItem()
|
||||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
}
|
||||||
|
|
||||||
font.pixelSize: 16
|
Keys.onDownPressed: {
|
||||||
font.weight: Font.Medium
|
FocusController.nextKeyDownItem()
|
||||||
font.family: "PT Root UI VF"
|
}
|
||||||
|
|
||||||
placeholderText: root.placeholderText
|
Keys.onLeftPressed: {
|
||||||
text: root.text
|
FocusController.nextKeyLeftItem()
|
||||||
|
}
|
||||||
onCursorVisibleChanged: {
|
|
||||||
if (textArea.cursorVisible) {
|
Keys.onRightPressed: {
|
||||||
fl.interactive = true
|
FocusController.nextKeyRightItem()
|
||||||
} else {
|
}
|
||||||
fl.interactive = false
|
|
||||||
}
|
color: AmneziaStyle.color.paleGray
|
||||||
}
|
selectionColor: AmneziaStyle.color.richBrown
|
||||||
|
selectedTextColor: AmneziaStyle.color.paleGray
|
||||||
wrapMode: Text.Wrap
|
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||||
|
|
||||||
MouseArea {
|
font.pixelSize: 16
|
||||||
id: textAreaMouse
|
font.weight: Font.Medium
|
||||||
anchors.fill: parent
|
font.family: "PT Root UI VF"
|
||||||
acceptedButtons: Qt.RightButton
|
|
||||||
hoverEnabled: true
|
placeholderText: root.placeholderText
|
||||||
onClicked: {
|
text: root.text
|
||||||
fl.interactive = true
|
|
||||||
contextMenu.open()
|
onCursorVisibleChanged: {
|
||||||
}
|
if (textArea.cursorVisible) {
|
||||||
}
|
fl.interactive = true
|
||||||
|
} else {
|
||||||
onFocusChanged: {
|
fl.interactive = false
|
||||||
root.border.color = getBorderColor(borderNormalColor)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextMenuType {
|
wrapMode: Text.Wrap
|
||||||
id: contextMenu
|
|
||||||
textObj: textArea
|
MouseArea {
|
||||||
}
|
id: textAreaMouse
|
||||||
}
|
anchors.fill: parent
|
||||||
}
|
acceptedButtons: Qt.RightButton
|
||||||
|
hoverEnabled: true
|
||||||
onPressed: {
|
onClicked: {
|
||||||
root.border.color = getBorderColor(borderFocusedColor)
|
fl.interactive = true
|
||||||
}
|
contextMenu.open()
|
||||||
|
}
|
||||||
onExited: {
|
}
|
||||||
root.border.color = getBorderColor(borderNormalColor)
|
|
||||||
}
|
onFocusChanged: {
|
||||||
|
root.border.color = getBorderColor(borderNormalColor)
|
||||||
onEntered: {
|
}
|
||||||
root.border.color = getBorderColor(borderHoveredColor)
|
|
||||||
}
|
ContextMenuType {
|
||||||
}
|
id: contextMenu
|
||||||
|
textObj: textArea
|
||||||
|
}
|
||||||
function getBorderColor(noneFocusedColor) {
|
}
|
||||||
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
}
|
||||||
}
|
|
||||||
}
|
onPressed: {
|
||||||
|
root.border.color = getBorderColor(borderFocusedColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: {
|
||||||
|
root.border.color = getBorderColor(borderNormalColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
onEntered: {
|
||||||
|
root.border.color = getBorderColor(borderHoveredColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getBorderColor(noneFocusedColor) {
|
||||||
|
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,180 +1,171 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string placeholderText
|
property string placeholderText
|
||||||
property string text
|
property string text
|
||||||
property string headerText
|
property string headerText
|
||||||
property alias textArea: textArea
|
property alias textArea: textArea
|
||||||
property alias textAreaText: textArea.text
|
property alias textAreaText: textArea.text
|
||||||
|
|
||||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
property string firstButtonImage
|
property string firstButtonImage
|
||||||
property string secondButtonImage
|
property string secondButtonImage
|
||||||
|
|
||||||
property var firstButtonClickedFunc
|
property var firstButtonClickedFunc
|
||||||
property var secondButtonClickedFunc
|
property var secondButtonClickedFunc
|
||||||
|
|
||||||
height: 148
|
height: 148
|
||||||
color: AmneziaStyle.color.onyxBlack
|
color: AmneziaStyle.color.onyxBlack
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: getBorderColor(borderNormalColor)
|
border.color: getBorderColor(borderNormalColor)
|
||||||
radius: 16
|
radius: 16
|
||||||
|
|
||||||
property FlickableType parentFlickable: null
|
MouseArea {
|
||||||
onFocusChanged: {
|
id: parentMouse
|
||||||
if (root.activeFocus) {
|
anchors.fill: parent
|
||||||
if (root.parentFlickable) {
|
cursorShape: Qt.IBeamCursor
|
||||||
root.parentFlickable.ensureVisible(root)
|
onClicked: textArea.forceActiveFocus()
|
||||||
}
|
hoverEnabled: true
|
||||||
}
|
|
||||||
}
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
MouseArea {
|
anchors.margins: 16
|
||||||
id: parentMouse
|
spacing: 0
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.IBeamCursor
|
LabelTextType {
|
||||||
onClicked: textArea.forceActiveFocus()
|
Layout.fillWidth: true
|
||||||
hoverEnabled: true
|
text: root.headerText
|
||||||
|
}
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
TextArea {
|
||||||
anchors.margins: 16
|
id: textArea
|
||||||
spacing: 0
|
|
||||||
|
Layout.fillWidth: true
|
||||||
LabelTextType {
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
|
||||||
text: root.headerText
|
leftPadding: 0
|
||||||
}
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
TextArea {
|
color: AmneziaStyle.color.paleGray
|
||||||
id: textArea
|
selectionColor: AmneziaStyle.color.richBrown
|
||||||
|
selectedTextColor: AmneziaStyle.color.paleGray
|
||||||
Layout.fillWidth: true
|
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||||
Layout.fillHeight: true
|
|
||||||
|
font.pixelSize: 16
|
||||||
leftPadding: 0
|
font.weight: Font.Medium
|
||||||
Layout.bottomMargin: 16
|
font.family: "PT Root UI VF"
|
||||||
|
|
||||||
color: AmneziaStyle.color.paleGray
|
placeholderText: root.placeholderText
|
||||||
selectionColor: AmneziaStyle.color.richBrown
|
text: root.text
|
||||||
selectedTextColor: AmneziaStyle.color.paleGray
|
|
||||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
onCursorVisibleChanged: {
|
||||||
|
if (textArea.cursorVisible) {
|
||||||
font.pixelSize: 16
|
fl.interactive = true
|
||||||
font.weight: Font.Medium
|
} else {
|
||||||
font.family: "PT Root UI VF"
|
fl.interactive = false
|
||||||
|
}
|
||||||
placeholderText: root.placeholderText
|
}
|
||||||
text: root.text
|
|
||||||
|
wrapMode: Text.Wrap
|
||||||
onCursorVisibleChanged: {
|
|
||||||
if (textArea.cursorVisible) {
|
MouseArea {
|
||||||
fl.interactive = true
|
id: textAreaMouse
|
||||||
} else {
|
anchors.fill: parent
|
||||||
fl.interactive = false
|
acceptedButtons: Qt.RightButton
|
||||||
}
|
hoverEnabled: true
|
||||||
}
|
onClicked: {
|
||||||
|
fl.interactive = true
|
||||||
wrapMode: Text.Wrap
|
contextMenu.open()
|
||||||
|
}
|
||||||
MouseArea {
|
}
|
||||||
id: textAreaMouse
|
|
||||||
anchors.fill: parent
|
onFocusChanged: {
|
||||||
acceptedButtons: Qt.RightButton
|
root.border.color = getBorderColor(borderNormalColor)
|
||||||
hoverEnabled: true
|
}
|
||||||
onClicked: {
|
|
||||||
fl.interactive = true
|
ContextMenuType {
|
||||||
contextMenu.open()
|
id: contextMenu
|
||||||
}
|
textObj: textArea
|
||||||
}
|
}
|
||||||
|
}
|
||||||
onFocusChanged: {
|
|
||||||
root.border.color = getBorderColor(borderNormalColor)
|
RowLayout {
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: -8
|
||||||
ContextMenuType {
|
spacing: 0
|
||||||
id: contextMenu
|
ImageButtonType {
|
||||||
textObj: textArea
|
id: firstButton
|
||||||
}
|
visible: root.firstButtonImage !== ""
|
||||||
}
|
|
||||||
|
imageColor: AmneziaStyle.color.paleGray
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
image: root.firstButtonImage
|
||||||
Layout.leftMargin: -8
|
onClicked: function() {
|
||||||
spacing: 0
|
if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") {
|
||||||
ImageButtonType {
|
root.firstButtonClickedFunc()
|
||||||
id: firstButton
|
}
|
||||||
visible: root.firstButtonImage !== ""
|
}
|
||||||
|
}
|
||||||
imageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
ImageButtonType {
|
||||||
image: root.firstButtonImage
|
id: secondButton
|
||||||
onClicked: function() {
|
visible: root.secondButtonImage !== ""
|
||||||
if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") {
|
|
||||||
root.firstButtonClickedFunc()
|
imageColor: AmneziaStyle.color.paleGray
|
||||||
}
|
|
||||||
}
|
image: root.secondButtonImage
|
||||||
}
|
onClicked: function() {
|
||||||
|
if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") {
|
||||||
ImageButtonType {
|
root.secondButtonClickedFunc()
|
||||||
id: secondButton
|
}
|
||||||
visible: root.secondButtonImage !== ""
|
}
|
||||||
|
}
|
||||||
imageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
Item {
|
||||||
image: root.secondButtonImage
|
Layout.fillWidth: true
|
||||||
onClicked: function() {
|
}
|
||||||
if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") {
|
|
||||||
root.secondButtonClickedFunc()
|
ImageButtonType {
|
||||||
}
|
id: resetButton
|
||||||
}
|
imageColor: AmneziaStyle.color.paleGray
|
||||||
}
|
|
||||||
|
visible: root.textAreaText !== ""
|
||||||
Item {
|
image: "qrc:/images/controls/close.svg"
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
onClicked: function() {
|
||||||
|
root.textAreaText = ""
|
||||||
ImageButtonType {
|
textArea.focus = true
|
||||||
id: resetButton
|
}
|
||||||
imageColor: AmneziaStyle.color.paleGray
|
}
|
||||||
|
}
|
||||||
visible: root.textAreaText !== ""
|
}
|
||||||
image: "qrc:/images/controls/close.svg"
|
|
||||||
|
onPressed: {
|
||||||
onClicked: function() {
|
root.border.color = getBorderColor(borderFocusedColor)
|
||||||
root.textAreaText = ""
|
}
|
||||||
textArea.focus = true
|
|
||||||
}
|
onExited: {
|
||||||
}
|
root.border.color = getBorderColor(borderNormalColor)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
onEntered: {
|
||||||
onPressed: {
|
root.border.color = getBorderColor(borderHoveredColor)
|
||||||
root.border.color = getBorderColor(borderFocusedColor)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
|
||||||
root.border.color = getBorderColor(borderNormalColor)
|
function getBorderColor(noneFocusedColor) {
|
||||||
}
|
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
||||||
|
}
|
||||||
onEntered: {
|
}
|
||||||
root.border.color = getBorderColor(borderHoveredColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function getBorderColor(noneFocusedColor) {
|
|
||||||
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,233 +1,220 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "TextTypes"
|
import "TextTypes"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string headerText
|
property string headerText
|
||||||
property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray
|
property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||||
property string headerTextColor: AmneziaStyle.color.mutedGray
|
property string headerTextColor: AmneziaStyle.color.mutedGray
|
||||||
|
|
||||||
property alias errorText: errorField.text
|
property alias errorText: errorField.text
|
||||||
property bool checkEmptyText: false
|
property bool checkEmptyText: false
|
||||||
property bool rightButtonClickedOnEnter: false
|
property bool rightButtonClickedOnEnter: false
|
||||||
|
|
||||||
property string buttonText
|
property string buttonText
|
||||||
property string buttonImageSource
|
property string buttonImageSource
|
||||||
property var clickedFunc
|
property var clickedFunc
|
||||||
|
|
||||||
property alias textField: textField
|
property alias textField: textField
|
||||||
property string textFieldTextColor: AmneziaStyle.color.paleGray
|
property string textFieldTextColor: AmneziaStyle.color.paleGray
|
||||||
property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray
|
property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
|
||||||
property bool textFieldEditable: true
|
property bool textFieldEditable: true
|
||||||
|
|
||||||
property string borderColor: AmneziaStyle.color.slateGray
|
property string borderColor: AmneziaStyle.color.slateGray
|
||||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
property string backgroundColor: AmneziaStyle.color.onyxBlack
|
property string backgroundColor: AmneziaStyle.color.onyxBlack
|
||||||
property string backgroundDisabledColor: AmneziaStyle.color.transparent
|
property string backgroundDisabledColor: AmneziaStyle.color.transparent
|
||||||
property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray
|
property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||||
|
|
||||||
implicitWidth: content.implicitWidth
|
implicitWidth: content.implicitWidth
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
|
|
||||||
property FlickableType parentFlickable
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
Connections {
|
anchors.fill: parent
|
||||||
target: textField
|
|
||||||
function onFocusChanged() {
|
Rectangle {
|
||||||
if (textField.activeFocus) {
|
id: backgroud
|
||||||
if (root.parentFlickable) {
|
Layout.fillWidth: true
|
||||||
root.parentFlickable.ensureVisible(root)
|
Layout.preferredHeight: input.implicitHeight
|
||||||
}
|
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
||||||
}
|
radius: 16
|
||||||
}
|
border.color: getBackgroundBorderColor(root.borderColor)
|
||||||
}
|
border.width: 1
|
||||||
|
|
||||||
ColumnLayout {
|
Behavior on border.color {
|
||||||
id: content
|
PropertyAnimation { duration: 200 }
|
||||||
anchors.fill: parent
|
}
|
||||||
|
|
||||||
Rectangle {
|
RowLayout {
|
||||||
id: backgroud
|
id: input
|
||||||
Layout.fillWidth: true
|
anchors.fill: backgroud
|
||||||
Layout.preferredHeight: input.implicitHeight
|
ColumnLayout {
|
||||||
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
Layout.margins: 16
|
||||||
radius: 16
|
LabelTextType {
|
||||||
border.color: getBackgroundBorderColor(root.borderColor)
|
text: root.headerText
|
||||||
border.width: 1
|
color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor
|
||||||
|
|
||||||
Behavior on border.color {
|
visible: text !== ""
|
||||||
PropertyAnimation { duration: 200 }
|
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
RowLayout {
|
|
||||||
id: input
|
TextField {
|
||||||
anchors.fill: backgroud
|
id: textField
|
||||||
ColumnLayout {
|
|
||||||
Layout.margins: 16
|
property bool isFocusable: true
|
||||||
LabelTextType {
|
|
||||||
text: root.headerText
|
Keys.onTabPressed: {
|
||||||
color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor
|
FocusController.nextKeyTabItem()
|
||||||
|
}
|
||||||
visible: text !== ""
|
|
||||||
|
Keys.onBacktabPressed: {
|
||||||
Layout.fillWidth: true
|
FocusController.previousKeyTabItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
enabled: root.textFieldEditable
|
||||||
id: textField
|
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
|
||||||
|
|
||||||
property bool isFocusable: true
|
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
placeholderTextColor: AmneziaStyle.color.charcoalGray
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
selectionColor: AmneziaStyle.color.richBrown
|
||||||
|
selectedTextColor: AmneziaStyle.color.paleGray
|
||||||
Keys.onBacktabPressed: {
|
|
||||||
FocusController.previousKeyTabItem()
|
font.pixelSize: 16
|
||||||
}
|
font.weight: 400
|
||||||
|
font.family: "PT Root UI VF"
|
||||||
enabled: root.textFieldEditable
|
|
||||||
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
|
height: 24
|
||||||
|
Layout.fillWidth: true
|
||||||
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
|
|
||||||
|
topPadding: 0
|
||||||
placeholderTextColor: AmneziaStyle.color.charcoalGray
|
rightPadding: 0
|
||||||
|
leftPadding: 0
|
||||||
selectionColor: AmneziaStyle.color.richBrown
|
bottomPadding: 0
|
||||||
selectedTextColor: AmneziaStyle.color.paleGray
|
|
||||||
|
background: Rectangle {
|
||||||
font.pixelSize: 16
|
anchors.fill: parent
|
||||||
font.weight: 400
|
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
||||||
font.family: "PT Root UI VF"
|
}
|
||||||
|
|
||||||
height: 24
|
onTextChanged: {
|
||||||
Layout.fillWidth: true
|
root.errorText = ""
|
||||||
|
}
|
||||||
topPadding: 0
|
|
||||||
rightPadding: 0
|
onActiveFocusChanged: {
|
||||||
leftPadding: 0
|
if (root.checkEmptyText && text === "") {
|
||||||
bottomPadding: 0
|
root.errorText = qsTr("The field can't be empty")
|
||||||
|
}
|
||||||
background: Rectangle {
|
}
|
||||||
anchors.fill: parent
|
|
||||||
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
MouseArea {
|
||||||
}
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
onTextChanged: {
|
onClicked: contextMenu.open()
|
||||||
root.errorText = ""
|
enabled: true
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
ContextMenuType {
|
||||||
if (root.checkEmptyText && text === "") {
|
id: contextMenu
|
||||||
root.errorText = qsTr("The field can't be empty")
|
textObj: textField
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
onFocusChanged: {
|
||||||
MouseArea {
|
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||||
anchors.fill: parent
|
}
|
||||||
acceptedButtons: Qt.RightButton
|
}
|
||||||
onClicked: contextMenu.open()
|
}
|
||||||
enabled: true
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextMenuType {
|
SmallTextType {
|
||||||
id: contextMenu
|
id: errorField
|
||||||
textObj: textField
|
|
||||||
}
|
text: root.errorText
|
||||||
|
visible: root.errorText !== ""
|
||||||
onFocusChanged: {
|
color: AmneziaStyle.color.vibrantRed
|
||||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
|
||||||
}
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
MouseArea {
|
||||||
|
anchors.fill: root
|
||||||
SmallTextType {
|
cursorShape: Qt.IBeamCursor
|
||||||
id: errorField
|
|
||||||
|
hoverEnabled: true
|
||||||
text: root.errorText
|
|
||||||
visible: root.errorText !== ""
|
onPressed: function(mouse) {
|
||||||
color: AmneziaStyle.color.vibrantRed
|
textField.forceActiveFocus()
|
||||||
|
mouse.accepted = false
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
onEntered: {
|
||||||
anchors.fill: root
|
backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor)
|
||||||
cursorShape: Qt.IBeamCursor
|
}
|
||||||
|
|
||||||
hoverEnabled: true
|
|
||||||
|
onExited: {
|
||||||
onPressed: function(mouse) {
|
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||||
textField.forceActiveFocus()
|
}
|
||||||
mouse.accepted = false
|
}
|
||||||
|
|
||||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
BasicButtonType {
|
||||||
}
|
visible: (root.buttonText !== "") || (root.buttonImageSource !== "")
|
||||||
|
|
||||||
onEntered: {
|
focusPolicy: Qt.NoFocus
|
||||||
backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor)
|
text: root.buttonText
|
||||||
}
|
leftImageSource: root.buttonImageSource
|
||||||
|
|
||||||
|
anchors.top: content.top
|
||||||
onExited: {
|
anchors.bottom: content.bottom
|
||||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
anchors.right: content.right
|
||||||
}
|
|
||||||
}
|
height: content.implicitHeight
|
||||||
|
width: content.implicitHeight
|
||||||
BasicButtonType {
|
squareLeftSide: true
|
||||||
visible: (root.buttonText !== "") || (root.buttonImageSource !== "")
|
|
||||||
|
clickedFunc: function() {
|
||||||
focusPolicy: Qt.NoFocus
|
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||||
text: root.buttonText
|
root.clickedFunc()
|
||||||
leftImageSource: root.buttonImageSource
|
}
|
||||||
|
}
|
||||||
anchors.top: content.top
|
}
|
||||||
anchors.bottom: content.bottom
|
|
||||||
anchors.right: content.right
|
function getBackgroundBorderColor(noneFocusedColor) {
|
||||||
|
return textField.focus ? root.borderFocusedColor : noneFocusedColor
|
||||||
height: content.implicitHeight
|
}
|
||||||
width: content.implicitHeight
|
|
||||||
squareLeftSide: true
|
Keys.onEnterPressed: {
|
||||||
|
if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||||
clickedFunc: function() {
|
clickedFunc()
|
||||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
}
|
||||||
root.clickedFunc()
|
|
||||||
}
|
// if (KeyNavigation.tab) {
|
||||||
}
|
// KeyNavigation.tab.forceActiveFocus();
|
||||||
}
|
// }
|
||||||
|
}
|
||||||
function getBackgroundBorderColor(noneFocusedColor) {
|
|
||||||
return textField.focus ? root.borderFocusedColor : noneFocusedColor
|
Keys.onReturnPressed: {
|
||||||
}
|
if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||||
|
clickedFunc()
|
||||||
Keys.onEnterPressed: {
|
}
|
||||||
if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") {
|
|
||||||
clickedFunc()
|
// if (KeyNavigation.tab) {
|
||||||
}
|
// KeyNavigation.tab.forceActiveFocus();
|
||||||
|
// }
|
||||||
// if (KeyNavigation.tab) {
|
}
|
||||||
// KeyNavigation.tab.forceActiveFocus();
|
}
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onReturnPressed: {
|
|
||||||
if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") {
|
|
||||||
clickedFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (KeyNavigation.tab) {
|
|
||||||
// KeyNavigation.tab.forceActiveFocus();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ PageType {
|
||||||
|
|
||||||
SortFilterProxyModel {
|
SortFilterProxyModel {
|
||||||
id: proxyServersModel
|
id: proxyServersModel
|
||||||
|
|
||||||
sourceModel: ServersModel
|
sourceModel: ServersModel
|
||||||
|
|
||||||
filters: [
|
filters: [
|
||||||
ValueFilter {
|
ValueFilter {
|
||||||
roleName: "isCurrentlyProcessed"
|
roleName: "isCurrentlyProcessed"
|
||||||
|
|
@ -29,67 +31,55 @@ PageType {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
contentHeight: content.height
|
|
||||||
|
|
||||||
Column {
|
spacing: 16
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
model: proxyServersModel
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
spacing: 16
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
Repeater {
|
BaseHeaderType {
|
||||||
model: proxyServersModel
|
Layout.fillWidth: true
|
||||||
delegate: Item {
|
Layout.topMargin: 20
|
||||||
implicitWidth: parent.width
|
Layout.leftMargin: 16
|
||||||
implicitHeight: delegateContent.implicitHeight
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
ColumnLayout {
|
headerText: qsTr("Removing services from %1").arg(name)
|
||||||
id: delegateContent
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
ProgressBarType {
|
||||||
anchors.rightMargin: 16
|
id: progressBar
|
||||||
anchors.leftMargin: 16
|
|
||||||
|
|
||||||
BaseHeaderType {
|
Layout.fillWidth: true
|
||||||
Layout.fillWidth: true
|
Layout.topMargin: 32
|
||||||
Layout.topMargin: 20
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Removing services from %1").arg(name)
|
Timer {
|
||||||
}
|
id: timer
|
||||||
|
|
||||||
ProgressBarType {
|
interval: 300
|
||||||
id: progressBar
|
repeat: true
|
||||||
|
running: true
|
||||||
Layout.fillWidth: true
|
onTriggered: {
|
||||||
Layout.topMargin: 32
|
progressBar.value += 0.003
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: timer
|
|
||||||
|
|
||||||
interval: 300
|
|
||||||
repeat: true
|
|
||||||
running: true
|
|
||||||
onTriggered: {
|
|
||||||
progressBar.value += 0.003
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParagraphTextType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 8
|
|
||||||
|
|
||||||
text: qsTr("Usually it takes no more than 5 minutes")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Usually it takes no more than 5 minutes")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,23 +25,17 @@ PageType {
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
id: header
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
|
@ -50,16 +44,14 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model: 1
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
clip: true
|
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
TextFieldWithHeaderType {
|
||||||
id: passwordTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
@ -87,8 +79,6 @@ PageType {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcher
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
|
||||||
|
|
@ -30,335 +30,223 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listview
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButtonLayout.bottom
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.bottom: saveButton.top
|
anchors.bottom: saveButton.top
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
model: AwgConfigModel
|
model: AwgConfigModel
|
||||||
|
|
||||||
delegate: Item {
|
delegate: ColumnLayout {
|
||||||
id: delegateItem
|
width: listView.width
|
||||||
implicitWidth: listview.width
|
|
||||||
implicitHeight: col.implicitHeight
|
|
||||||
|
|
||||||
property alias mtuTextField: mtuTextField
|
|
||||||
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
|
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
|
||||||
junkPacketMaxSizeTextField.errorText === "" &&
|
junkPacketMaxSizeTextField.errorText === "" &&
|
||||||
junkPacketMinSizeTextField.errorText === "" &&
|
junkPacketMinSizeTextField.errorText === "" &&
|
||||||
junkPacketCountTextField.errorText === ""
|
junkPacketCountTextField.errorText === ""
|
||||||
|
|
||||||
ColumnLayout {
|
spacing: 0
|
||||||
id: col
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
BaseHeaderType {
|
||||||
anchors.left: parent.left
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
headerText: qsTr("AmneziaWG settings")
|
||||||
anchors.rightMargin: 16
|
}
|
||||||
|
|
||||||
spacing: 0
|
TextFieldWithHeaderType {
|
||||||
|
id: mtuTextField
|
||||||
|
|
||||||
BaseHeaderType {
|
Layout.fillWidth: true
|
||||||
Layout.fillWidth: true
|
Layout.topMargin: 40
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("AmneziaWG settings")
|
headerText: qsTr("MTU")
|
||||||
}
|
textField.text: clientMtu
|
||||||
|
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
textField.onEditingFinished: {
|
||||||
id: mtuTextField
|
if (textField.text !== clientMtu) {
|
||||||
Layout.fillWidth: true
|
clientMtu = textField.text
|
||||||
Layout.topMargin: 40
|
|
||||||
|
|
||||||
headerText: qsTr("MTU")
|
|
||||||
textField.text: clientMtu
|
|
||||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientMtu) {
|
|
||||||
clientMtu = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checkEmptyText: true
|
|
||||||
KeyNavigation.tab: junkPacketCountTextField.textField
|
|
||||||
}
|
}
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
id: junkPacketCountTextField
|
id: junkPacketCountTextField
|
||||||
headerText: "Jc - Junk packet count"
|
|
||||||
textField.text: clientJunkPacketCount
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
Layout.fillWidth: true
|
||||||
if (textField.text !== clientJunkPacketCount) {
|
Layout.topMargin: 16
|
||||||
clientJunkPacketCount = textField.text
|
Layout.leftMargin: 16
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
}
|
|
||||||
|
|
||||||
KeyNavigation.tab: junkPacketMinSizeTextField.textField
|
headerText: "Jc - Junk packet count"
|
||||||
}
|
textField.text: clientJunkPacketCount
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
AwgTextField {
|
textField.onEditingFinished: {
|
||||||
id: junkPacketMinSizeTextField
|
if (textField.text !== clientJunkPacketCount) {
|
||||||
headerText: "Jmin - Junk packet minimum size"
|
clientJunkPacketCount = textField.text
|
||||||
textField.text: clientJunkPacketMinSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientJunkPacketMinSize) {
|
|
||||||
clientJunkPacketMinSize = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: junkPacketMaxSizeTextField
|
|
||||||
headerText: "Jmax - Junk packet maximum size"
|
|
||||||
textField.text: clientJunkPacketMaxSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientJunkPacketMaxSize) {
|
|
||||||
clientJunkPacketMaxSize = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: specialJunk1TextField
|
}
|
||||||
headerText: qsTr("I1 - First special junk packet")
|
|
||||||
textField.text: clientSpecialJunk1
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
if (textField.text !== clientSpecialJunk1) {
|
id: junkPacketMinSizeTextField
|
||||||
clientSpecialJunk1 = textField.text
|
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: "Jmin - Junk packet minimum size"
|
||||||
|
textField.text: clientJunkPacketMinSize
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== clientJunkPacketMinSize) {
|
||||||
|
clientJunkPacketMinSize = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: specialJunk2TextField
|
}
|
||||||
headerText: qsTr("I2 - Second special junk packet")
|
|
||||||
textField.text: clientSpecialJunk2
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
if (textField.text !== clientSpecialJunk2) {
|
id: junkPacketMaxSizeTextField
|
||||||
clientSpecialJunk2 = textField.text
|
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: "Jmax - Junk packet maximum size"
|
||||||
|
textField.text: clientJunkPacketMaxSize
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== clientJunkPacketMaxSize) {
|
||||||
|
clientJunkPacketMaxSize = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: specialJunk3TextField
|
|
||||||
headerText: qsTr("I3 - Third special junk packet")
|
|
||||||
textField.text: clientSpecialJunk3
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
}
|
||||||
if (textField.text !== clientSpecialJunk3) {
|
|
||||||
clientSpecialJunk3 = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
Header2TextType {
|
||||||
id: specialJunk4TextField
|
Layout.fillWidth: true
|
||||||
headerText: qsTr("I4 - Fourth special junk packet")
|
Layout.topMargin: 16
|
||||||
textField.text: clientSpecialJunk4
|
Layout.leftMargin: 16
|
||||||
textField.validator: null
|
Layout.rightMargin: 16
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
text: qsTr("Server settings")
|
||||||
if (textField.text !== clientSpecialJunk4) {
|
}
|
||||||
clientSpecialJunk4 = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
id: specialJunk5TextField
|
id: portTextField
|
||||||
headerText: qsTr("I5 - Fifth special junk packet")
|
|
||||||
textField.text: clientSpecialJunk5
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
Layout.fillWidth: true
|
||||||
if (textField.text !== clientSpecialJunk5 ) {
|
Layout.topMargin: 8
|
||||||
clientSpecialJunk5 = textField.text
|
Layout.leftMargin: 16
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
enabled: false
|
||||||
id: controlledJunk1TextField
|
|
||||||
headerText: qsTr("J1 - First controlled junk packet")
|
|
||||||
textField.text: clientControlledJunk1
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
headerText: qsTr("Port")
|
||||||
if (textField.text !== clientControlledJunk1) {
|
textField.text: port
|
||||||
clientControlledJunk1 = textField.text
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
id: controlledJunk2TextField
|
id: initPacketJunkSizeTextField
|
||||||
headerText: qsTr("J2 - Second controlled junk packet")
|
|
||||||
textField.text: clientControlledJunk2
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
Layout.fillWidth: true
|
||||||
if (textField.text !== clientControlledJunk2) {
|
Layout.topMargin: 16
|
||||||
clientControlledJunk2 = textField.text
|
Layout.leftMargin: 16
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
enabled: false
|
||||||
id: controlledJunk3TextField
|
|
||||||
headerText: qsTr("J3 - Third controlled junk packet")
|
|
||||||
textField.text: clientControlledJunk3
|
|
||||||
textField.validator: null
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
headerText: "S1 - Init packet junk size"
|
||||||
if (textField.text !== clientControlledJunk3) {
|
textField.text: serverInitPacketJunkSize
|
||||||
clientControlledJunk3 = textField.text
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
id: iTimeTextField
|
id: responsePacketJunkSizeTextField
|
||||||
headerText: qsTr("Itime - Special handshake timeout")
|
|
||||||
textField.text: clientSpecialHandshakeTimeout
|
|
||||||
checkEmptyText: false
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
Layout.fillWidth: true
|
||||||
if (textField.text !== clientSpecialHandshakeTimeout) {
|
Layout.topMargin: 16
|
||||||
clientSpecialHandshakeTimeout = textField.text
|
Layout.leftMargin: 16
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Header2TextType {
|
enabled: false
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Server settings")
|
headerText: "S2 - Response packet junk size"
|
||||||
}
|
textField.text: serverResponsePacketJunkSize
|
||||||
|
}
|
||||||
|
|
||||||
AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
id: portTextField
|
id: initPacketMagicHeaderTextField
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
Layout.fillWidth: true
|
||||||
textField.text: port
|
Layout.topMargin: 16
|
||||||
}
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
AwgTextField {
|
enabled: false
|
||||||
id: initPacketJunkSizeTextField
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "S1 - Init packet junk size"
|
headerText: "H1 - Init packet magic header"
|
||||||
textField.text: serverInitPacketJunkSize
|
textField.text: serverInitPacketMagicHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
id: responsePacketJunkSizeTextField
|
id: responsePacketMagicHeaderTextField
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "S2 - Response packet junk size"
|
Layout.fillWidth: true
|
||||||
textField.text: serverResponsePacketJunkSize
|
Layout.topMargin: 16
|
||||||
}
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
// AwgTextField {
|
enabled: false
|
||||||
// id: cookieReplyPacketJunkSizeTextField
|
|
||||||
// enabled: false
|
|
||||||
|
|
||||||
// headerText: "S3 - Cookie Reply packet junk size"
|
headerText: "H2 - Response packet magic header"
|
||||||
// textField.text: serverCookieReplyPacketJunkSize
|
textField.text: serverResponsePacketMagicHeader
|
||||||
// }
|
}
|
||||||
|
|
||||||
// AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
// id: transportPacketJunkSizeTextField
|
id: underloadPacketMagicHeaderTextField
|
||||||
// enabled: false
|
|
||||||
|
|
||||||
// headerText: "S4 - Transport packet junk size"
|
Layout.fillWidth: true
|
||||||
// textField.text: serverTransportPacketJunkSize
|
Layout.topMargin: 16
|
||||||
// }
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
AwgTextField {
|
enabled: false
|
||||||
id: initPacketMagicHeaderTextField
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H1 - Init packet magic header"
|
headerText: "H3 - Underload packet magic header"
|
||||||
textField.text: serverInitPacketMagicHeader
|
textField.text: serverUnderloadPacketMagicHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
TextFieldWithHeaderType {
|
||||||
id: responsePacketMagicHeaderTextField
|
id: transportPacketMagicHeaderTextField
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H2 - Response packet magic header"
|
Layout.fillWidth: true
|
||||||
textField.text: serverResponsePacketMagicHeader
|
Layout.topMargin: 16
|
||||||
}
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
AwgTextField {
|
enabled: false
|
||||||
id: underloadPacketMagicHeaderTextField
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H3 - Underload packet magic header"
|
|
||||||
textField.text: serverUnderloadPacketMagicHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: transportPacketMagicHeaderTextField
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: "H4 - Transport packet magic header"
|
|
||||||
textField.text: serverTransportPacketMagicHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
|
headerText: "H4 - Transport packet magic header"
|
||||||
|
textField.text: serverTransportPacketMagicHeader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -375,18 +263,17 @@ PageType {
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: 16
|
||||||
anchors.leftMargin: 16
|
anchors.leftMargin: 16
|
||||||
|
|
||||||
enabled: listview.currentItem.isSaveButtonEnabled
|
enabled: listView.currentItem.isSaveButtonEnabled
|
||||||
|
|
||||||
text: qsTr("Save")
|
text: qsTr("Save")
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
onActiveFocusChanged: {
|
||||||
if(activeFocus) {
|
if(activeFocus) {
|
||||||
listview.positionViewAtEnd()
|
listView.positionViewAtEnd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
forceActiveFocus()
|
|
||||||
var headerText = qsTr("Save settings?")
|
var headerText = qsTr("Save settings?")
|
||||||
var descriptionText = qsTr("Only the settings for this device will be changed")
|
var descriptionText = qsTr("Only the settings for this device will be changed")
|
||||||
var yesButtonText = qsTr("Continue")
|
var yesButtonText = qsTr("Continue")
|
||||||
|
|
@ -401,11 +288,9 @@ PageType {
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
InstallController.updateContainer(AwgConfigModel.getConfig())
|
InstallController.updateContainer(AwgConfigModel.getConfig())
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
var noButtonFunction = function() {}
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,320 +33,339 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listview
|
id: listView
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
anchors.top: backButtonLayout.bottom
|
anchors.top: backButtonLayout.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
model: AwgConfigModel
|
model: AwgConfigModel
|
||||||
|
|
||||||
delegate: Item {
|
delegate: ColumnLayout {
|
||||||
id: delegateItem
|
id: delegateItem
|
||||||
implicitWidth: listview.width
|
|
||||||
implicitHeight: col.implicitHeight
|
width: listView.width
|
||||||
|
|
||||||
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
ColumnLayout {
|
spacing: 0
|
||||||
id: col
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
BaseHeaderType {
|
||||||
anchors.left: parent.left
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
headerText: qsTr("AmneziaWG settings")
|
||||||
anchors.rightMargin: 16
|
}
|
||||||
|
|
||||||
spacing: 0
|
TextFieldWithHeaderType {
|
||||||
|
id: vpnAddressSubnetTextField
|
||||||
|
|
||||||
BaseHeaderType {
|
Layout.fillWidth: true
|
||||||
Layout.fillWidth: true
|
Layout.topMargin: 40
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("AmneziaWG settings")
|
enabled: delegateItem.isEnabled
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
headerText: qsTr("VPN address subnet")
|
||||||
id: vpnAddressSubnetTextField
|
textField.text: subnetAddress
|
||||||
|
|
||||||
Layout.fillWidth: true
|
textField.onEditingFinished: {
|
||||||
Layout.topMargin: 40
|
if (textField.text !== subnetAddress) {
|
||||||
|
subnetAddress = textField.text
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("VPN address subnet")
|
|
||||||
textField.text: subnetAddress
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== subnetAddress) {
|
|
||||||
subnetAddress = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: junkPacketCountTextField
|
|
||||||
headerText: qsTr("Jc - Junk packet count")
|
|
||||||
textField.text: serverJunkPacketCount
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverJunkPacketCount) {
|
|
||||||
serverJunkPacketCount = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: junkPacketMinSizeTextField
|
}
|
||||||
headerText: qsTr("Jmin - Junk packet minimum size")
|
|
||||||
textField.text: serverJunkPacketMinSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
if (textField.text !== serverJunkPacketMinSize) {
|
id: portTextField
|
||||||
serverJunkPacketMinSize = textField.text
|
Layout.fillWidth: true
|
||||||
}
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: junkPacketMaxSizeTextField
|
}
|
||||||
headerText: qsTr("Jmax - Junk packet maximum size")
|
|
||||||
textField.text: serverJunkPacketMaxSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
if (textField.text !== serverJunkPacketMaxSize) {
|
id: junkPacketCountTextField
|
||||||
serverJunkPacketMaxSize = textField.text
|
Layout.fillWidth: true
|
||||||
}
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("Jc - Junk packet count")
|
||||||
|
textField.text: serverJunkPacketCount
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text === "") {
|
||||||
|
textField.text = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textField.text !== serverJunkPacketCount) {
|
||||||
|
serverJunkPacketCount = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: initPacketJunkSizeTextField
|
}
|
||||||
headerText: qsTr("S1 - Init packet junk size")
|
|
||||||
textField.text: serverInitPacketJunkSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
if (textField.text !== serverInitPacketJunkSize) {
|
id: junkPacketMinSizeTextField
|
||||||
serverInitPacketJunkSize = textField.text
|
Layout.fillWidth: true
|
||||||
}
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("Jmin - Junk packet minimum size")
|
||||||
|
textField.text: serverJunkPacketMinSize
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverJunkPacketMinSize) {
|
||||||
|
serverJunkPacketMinSize = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: responsePacketJunkSizeTextField
|
}
|
||||||
headerText: qsTr("S2 - Response packet junk size")
|
|
||||||
textField.text: serverResponsePacketJunkSize
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
if (textField.text !== serverResponsePacketJunkSize) {
|
id: junkPacketMaxSizeTextField
|
||||||
serverResponsePacketJunkSize = textField.text
|
Layout.fillWidth: true
|
||||||
}
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("Jmax - Junk packet maximum size")
|
||||||
|
textField.text: serverJunkPacketMaxSize
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverJunkPacketMaxSize) {
|
||||||
|
serverJunkPacketMaxSize = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AwgTextField {
|
checkEmptyText: true
|
||||||
// id: cookieReplyPacketJunkSizeTextField
|
}
|
||||||
// headerText: qsTr("S3 - Cookie reply packet junk size")
|
|
||||||
// textField.text: serverCookieReplyPacketJunkSize
|
|
||||||
|
|
||||||
// textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
// if (textField.text !== serverCookieReplyPacketJunkSize) {
|
id: initPacketJunkSizeTextField
|
||||||
// serverCookieReplyPacketJunkSize = textField.text
|
Layout.fillWidth: true
|
||||||
// }
|
Layout.topMargin: 16
|
||||||
// }
|
Layout.leftMargin: 16
|
||||||
// }
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
// AwgTextField {
|
headerText: qsTr("S1 - Init packet junk size")
|
||||||
// id: transportPacketJunkSizeTextField
|
textField.text: serverInitPacketJunkSize
|
||||||
// headerText: qsTr("S4 - Transport packet junk size")
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
// textField.text: serverTransportPacketJunkSize
|
|
||||||
|
|
||||||
// textField.onEditingFinished: {
|
textField.onEditingFinished: {
|
||||||
// if (textField.text !== serverTransportPacketJunkSize) {
|
if (textField.text !== serverInitPacketJunkSize) {
|
||||||
// serverTransportPacketJunkSize = textField.text
|
serverInitPacketJunkSize = textField.text
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
AwgTextField {
|
|
||||||
id: initPacketMagicHeaderTextField
|
|
||||||
headerText: qsTr("H1 - Init packet magic header")
|
|
||||||
textField.text: serverInitPacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== serverInitPacketMagicHeader) {
|
|
||||||
serverInitPacketMagicHeader = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: responsePacketMagicHeaderTextField
|
|
||||||
headerText: qsTr("H2 - Response packet magic header")
|
|
||||||
textField.text: serverResponsePacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
onActiveFocusChanged: {
|
||||||
if (textField.text !== serverResponsePacketMagicHeader) {
|
if(activeFocus) {
|
||||||
serverResponsePacketMagicHeader = textField.text
|
listview.positionViewAtEnd()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: responsePacketJunkSizeTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("S2 - Response packet junk size")
|
||||||
|
textField.text: serverResponsePacketJunkSize
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverResponsePacketJunkSize) {
|
||||||
|
serverResponsePacketJunkSize = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: underloadPacketMagicHeaderTextField
|
|
||||||
headerText: qsTr("H3 - Underload packet magic header")
|
|
||||||
textField.text: serverUnderloadPacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
onActiveFocusChanged: {
|
||||||
if (textField.text !== serverUnderloadPacketMagicHeader) {
|
if(activeFocus) {
|
||||||
serverUnderloadPacketMagicHeader = textField.text
|
listview.positionViewAtEnd()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: initPacketMagicHeaderTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("H1 - Init packet magic header")
|
||||||
|
textField.text: serverInitPacketMagicHeader
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverInitPacketMagicHeader) {
|
||||||
|
serverInitPacketMagicHeader = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgTextField {
|
checkEmptyText: true
|
||||||
id: transportPacketMagicHeaderTextField
|
}
|
||||||
headerText: qsTr("H4 - Transport packet magic header")
|
|
||||||
textField.text: serverTransportPacketMagicHeader
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
TextFieldWithHeaderType {
|
||||||
if (textField.text !== serverTransportPacketMagicHeader) {
|
id: responsePacketMagicHeaderTextField
|
||||||
serverTransportPacketMagicHeader = textField.text
|
Layout.fillWidth: true
|
||||||
}
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("H2 - Response packet magic header")
|
||||||
|
textField.text: serverResponsePacketMagicHeader
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverResponsePacketMagicHeader) {
|
||||||
|
serverResponsePacketMagicHeader = textField.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
TextFieldWithHeaderType {
|
||||||
id: saveRestartButton
|
id: transportPacketMagicHeaderTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
Layout.fillWidth: true
|
headerText: qsTr("H4 - Transport packet magic header")
|
||||||
Layout.topMargin: 24
|
textField.text: serverTransportPacketMagicHeader
|
||||||
Layout.bottomMargin: 24
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
|
textField.onEditingFinished: {
|
||||||
transportPacketMagicHeaderTextField.errorText === "" &&
|
if (textField.text !== serverTransportPacketMagicHeader) {
|
||||||
responsePacketMagicHeaderTextField.errorText === "" &&
|
serverTransportPacketMagicHeader = textField.text
|
||||||
initPacketMagicHeaderTextField.errorText === "" &&
|
}
|
||||||
responsePacketJunkSizeTextField.errorText === "" &&
|
}
|
||||||
// cookieReplyHeaderJunkTextField.errorText === "" &&
|
|
||||||
// transportHeaderJunkTextField.errorText === "" &&
|
|
||||||
initPacketJunkSizeTextField.errorText === "" &&
|
|
||||||
junkPacketMaxSizeTextField.errorText === "" &&
|
|
||||||
junkPacketMinSizeTextField.errorText === "" &&
|
|
||||||
junkPacketCountTextField.errorText === "" &&
|
|
||||||
portTextField.errorText === "" &&
|
|
||||||
vpnAddressSubnetTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
TextFieldWithHeaderType {
|
||||||
if(activeFocus) {
|
id: underloadPacketMagicHeaderTextField
|
||||||
listview.positionViewAtEnd()
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("H3 - Underload packet magic header")
|
||||||
|
textField.text: serverUnderloadPacketMagicHeader
|
||||||
|
textField.validator: IntValidator { bottom: 0 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== serverUnderloadPacketMagicHeader) {
|
||||||
|
serverUnderloadPacketMagicHeader = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveRestartButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
transportPacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
responsePacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
initPacketMagicHeaderTextField.errorText === "" &&
|
||||||
|
responsePacketJunkSizeTextField.errorText === "" &&
|
||||||
|
initPacketJunkSizeTextField.errorText === "" &&
|
||||||
|
junkPacketMaxSizeTextField.errorText === "" &&
|
||||||
|
junkPacketMinSizeTextField.errorText === "" &&
|
||||||
|
junkPacketCountTextField.errorText === "" &&
|
||||||
|
portTextField.errorText === "" &&
|
||||||
|
vpnAddressSubnetTextField.errorText === ""
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
onActiveFocusChanged: {
|
||||||
|
if(activeFocus) {
|
||||||
|
listView.positionViewAtEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
if (delegateItem.isEnabled) {
|
||||||
|
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
|
||||||
|
transportPacketMagicHeaderTextField.textField.text,
|
||||||
|
responsePacketMagicHeaderTextField.textField.text,
|
||||||
|
initPacketMagicHeaderTextField.textField.text)) {
|
||||||
|
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
||||||
|
parseInt(responsePacketJunkSizeTextField.textField.text))) {
|
||||||
|
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clickedFunc: function() {
|
var headerText = qsTr("Save settings?")
|
||||||
forceActiveFocus()
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
if (delegateItem.isEnabled) {
|
var yesButtonFunction = function() {
|
||||||
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
transportPacketMagicHeaderTextField.textField.text,
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
responsePacketMagicHeaderTextField.textField.text,
|
return
|
||||||
initPacketMagicHeaderTextField.textField.text)) {
|
|
||||||
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
|
||||||
parseInt(responsePacketJunkSizeTextField.textField.text))) {
|
|
||||||
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
|
|
||||||
// parseInt(responsePacketJunkSizeTextField.textField.text),
|
|
||||||
// parseInt(cookieReplyPacketJunkSizeTextField.textField.text),
|
|
||||||
// parseInt(transportPacketJunkSizeTextField.textField.text))) {
|
|
||||||
// PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) + S3 + cookie reply size (64) + S4 + transport packet size (32)"))
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
InstallController.updateContainer(AwgConfigModel.getConfig())
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(AwgConfigModel.getConfig())
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveRestartButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var noButtonFunction = function() {}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,212 +16,161 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
|
||||||
id: backButton
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
Column {
|
property int selectedIndex: 0
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
header: ColumnLayout {
|
||||||
|
|
||||||
ListView {
|
width: listView.width
|
||||||
id: listview
|
|
||||||
|
|
||||||
property int selectedIndex: 0
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
width: parent.width
|
headerText: qsTr("Cloak settings")
|
||||||
height: listview.contentItem.height
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clip: true
|
model: CloakConfigModel
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
model: CloakConfigModel
|
delegate: ColumnLayout {
|
||||||
|
|
||||||
delegate: Item {
|
width: listView.width
|
||||||
id: delegateItem
|
|
||||||
|
|
||||||
property alias trafficFromField: trafficFromField
|
property alias trafficFromField: trafficFromField
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
|
||||||
|
|
||||||
implicitWidth: listview.width
|
spacing: 0
|
||||||
implicitHeight: col.implicitHeight
|
|
||||||
|
|
||||||
ColumnLayout {
|
TextFieldWithHeaderType {
|
||||||
id: col
|
id: trafficFromField
|
||||||
|
|
||||||
anchors.top: parent.top
|
Layout.fillWidth: true
|
||||||
anchors.left: parent.left
|
Layout.topMargin: 32
|
||||||
anchors.right: parent.right
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
headerText: qsTr("Disguised as traffic from")
|
||||||
anchors.rightMargin: 16
|
textField.text: site
|
||||||
|
|
||||||
spacing: 0
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== site) {
|
||||||
|
var tmpText = textField.text
|
||||||
|
tmpText = tmpText.toLocaleLowerCase()
|
||||||
|
|
||||||
BaseHeaderType {
|
var indexHttps = tmpText.indexOf("https://")
|
||||||
Layout.fillWidth: true
|
if (indexHttps === 0) {
|
||||||
headerText: qsTr("Cloak settings")
|
tmpText = textField.text.substring(8)
|
||||||
}
|
} else {
|
||||||
|
site = textField.text
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: trafficFromField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Disguised as traffic from")
|
|
||||||
textField.text: site
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== site) {
|
|
||||||
var tmpText = textField.text
|
|
||||||
tmpText = tmpText.toLocaleLowerCase()
|
|
||||||
|
|
||||||
var indexHttps = tmpText.indexOf("https://")
|
|
||||||
if (indexHttps === 0) {
|
|
||||||
tmpText = textField.text.substring(8)
|
|
||||||
} else {
|
|
||||||
site = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
DropDownType {
|
|
||||||
id: cipherDropDown
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
descriptionText: qsTr("Cipher")
|
|
||||||
headerText: qsTr("Cipher")
|
|
||||||
|
|
||||||
drawerParent: root
|
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
|
||||||
id: cipherListView
|
|
||||||
|
|
||||||
rootWidth: root.width
|
|
||||||
|
|
||||||
model: ListModel {
|
|
||||||
ListElement { name : "chacha20-ietf-poly1305" }
|
|
||||||
ListElement { name : "xchacha20-ietf-poly1305" }
|
|
||||||
ListElement { name : "aes-256-gcm" }
|
|
||||||
ListElement { name : "aes-192-gcm" }
|
|
||||||
ListElement { name : "aes-128-gcm" }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
cipherDropDown.text = selectedText
|
|
||||||
cipher = cipherDropDown.text
|
|
||||||
cipherDropDown.closeTriggered()
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
cipherDropDown.text = cipher
|
|
||||||
|
|
||||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
|
||||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
|
||||||
selectedIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
enabled: trafficFromField.errorText === "" &&
|
|
||||||
portTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
|
||||||
InstallController.updateContainer(CloakConfigModel.getConfig())
|
|
||||||
}
|
|
||||||
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDownType {
|
||||||
|
id: cipherDropDown
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
descriptionText: qsTr("Cipher")
|
||||||
|
headerText: qsTr("Cipher")
|
||||||
|
|
||||||
|
drawerParent: root
|
||||||
|
|
||||||
|
listView: ListViewWithRadioButtonType {
|
||||||
|
id: cipherListView
|
||||||
|
|
||||||
|
rootWidth: root.width
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { name : "chacha20-ietf-poly1305" }
|
||||||
|
ListElement { name : "xchacha20-ietf-poly1305" }
|
||||||
|
ListElement { name : "aes-256-gcm" }
|
||||||
|
ListElement { name : "aes-192-gcm" }
|
||||||
|
ListElement { name : "aes-128-gcm" }
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
cipherDropDown.text = selectedText
|
||||||
|
cipher = cipherDropDown.text
|
||||||
|
cipherDropDown.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
cipherDropDown.text = cipher
|
||||||
|
|
||||||
|
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||||
|
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||||
|
selectedIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveRestartButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(CloakConfigModel.getConfig())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,428 +17,465 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
onFocusChanged: {
|
||||||
id: backButton
|
if (this.activeFocus) {
|
||||||
|
listView.positionViewAtBeginning()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
Column {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
header: ColumnLayout {
|
||||||
anchors.left: parent.left
|
width: listView.width
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
ListView {
|
headerText: qsTr("OpenVPN settings")
|
||||||
id: listview
|
}
|
||||||
|
}
|
||||||
|
|
||||||
width: parent.width
|
model: ListModel {
|
||||||
height: listview.contentItem.height
|
ListElement { type: "subnetHeader" }
|
||||||
|
ListElement { type: "networkProtocolText" }
|
||||||
|
ListElement { type: "protoSelector" }
|
||||||
|
ListElement { type: "portTextField" }
|
||||||
|
ListElement { type: "encryptionSection" }
|
||||||
|
ListElement { type: "checkboxSection" }
|
||||||
|
ListElement { type: "clientCommands" }
|
||||||
|
ListElement { type: "serverCommands" }
|
||||||
|
}
|
||||||
|
|
||||||
clip: true
|
delegate: DelegateChooser {
|
||||||
interactive: false
|
|
||||||
|
|
||||||
model: OpenVpnConfigModel
|
role: "type"
|
||||||
|
|
||||||
delegate: Item {
|
DelegateChoice {
|
||||||
id: delegateItem
|
// property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
||||||
|
roleValue: "subnetHeader"
|
||||||
|
ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
TextFieldWithHeaderType {
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
id: vpnAddressSubnetTextField
|
||||||
|
|
||||||
implicitWidth: listview.width
|
Layout.fillWidth: true
|
||||||
implicitHeight: col.implicitHeight
|
Layout.topMargin: 32
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
ColumnLayout {
|
headerText: qsTr("VPN address subnet")
|
||||||
id: col
|
textField.text: OpenVpnConfigModel.subnetAddress
|
||||||
|
|
||||||
anchors.top: parent.top
|
textField.onEditingFinished: {
|
||||||
anchors.left: parent.left
|
if (textField.text !== OpenVpnConfigModel.subnetAddress) {
|
||||||
anchors.right: parent.right
|
OpenVpnConfigModel.subnetAddress = textField.text
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
headerText: qsTr("OpenVPN settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: vpnAddressSubnetTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("VPN address subnet")
|
|
||||||
textField.text: subnetAddress
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== subnetAddress) {
|
|
||||||
subnetAddress = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checkEmptyText: true
|
DelegateChoice {
|
||||||
|
roleValue: "networkProtocolText"
|
||||||
|
ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 32
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Network protocol")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: "protoSelector"
|
||||||
|
ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
TransportProtoSelector {
|
||||||
|
id: transportProtoSelector
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
rootWidth: root.width
|
||||||
|
|
||||||
|
enabled: OpenVpnConfigModel.isTransportProtoEditable
|
||||||
|
|
||||||
|
currentIndex: {
|
||||||
|
return OpenVpnConfigModel.transportProto === "tcp" ? 1 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ParagraphTextType {
|
onCurrentIndexChanged: {
|
||||||
Layout.fillWidth: true
|
if (OpenVpnConfigModel.transportProto === "tcp" && currentIndex === 0) {
|
||||||
Layout.topMargin: 32
|
OpenVpnConfigModel.transportProto = "udp"
|
||||||
|
} else if (OpenVpnConfigModel.transportProto === "udp" && currentIndex === 1) {
|
||||||
text: qsTr("Network protocol")
|
OpenVpnConfigModel.transportProto = "tcp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: "portTextField"
|
||||||
|
ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 40
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: OpenVpnConfigModel.isPortEditable
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: OpenVpnConfigModel.port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== OpenVpnConfigModel.port) {
|
||||||
|
OpenVpnConfigModel.port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: "encryptionSection"
|
||||||
|
ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
SwitcherType {
|
||||||
|
id: autoNegotiateEncryprionSwitcher
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Auto-negotiate encryption")
|
||||||
|
checked: OpenVpnConfigModel.autoNegotiateEncryption
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (checked !== OpenVpnConfigModel.autoNegotiateEncryprion) {
|
||||||
|
OpenVpnConfigModel.autoNegotiateEncryprion = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDownType {
|
||||||
|
id: hashDropDown
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 20
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||||
|
|
||||||
|
descriptionText: qsTr("Hash")
|
||||||
|
headerText: qsTr("Hash")
|
||||||
|
|
||||||
|
drawerParent: root
|
||||||
|
|
||||||
|
listView: ListViewWithRadioButtonType {
|
||||||
|
id: hashListView
|
||||||
|
|
||||||
TransportProtoSelector {
|
|
||||||
id: transportProtoSelector
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
rootWidth: root.width
|
rootWidth: root.width
|
||||||
|
|
||||||
enabled: isTransportProtoEditable
|
model: ListModel {
|
||||||
|
ListElement { name : qsTr("SHA512") }
|
||||||
currentIndex: {
|
ListElement { name : qsTr("SHA384") }
|
||||||
return transportProto === "tcp" ? 1 : 0
|
ListElement { name : qsTr("SHA256") }
|
||||||
|
ListElement { name : qsTr("SHA3-512") }
|
||||||
|
ListElement { name : qsTr("SHA3-384") }
|
||||||
|
ListElement { name : qsTr("SHA3-256") }
|
||||||
|
ListElement { name : qsTr("whirlpool") }
|
||||||
|
ListElement { name : qsTr("BLAKE2b512") }
|
||||||
|
ListElement { name : qsTr("BLAKE2s256") }
|
||||||
|
ListElement { name : qsTr("SHA1") }
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
clickedFunction: function() {
|
||||||
if (transportProto === "tcp" && currentIndex === 0) {
|
hashDropDown.text = selectedText
|
||||||
transportProto = "udp"
|
OpenVpnConfigModel.hash = hashDropDown.text
|
||||||
} else if (transportProto === "udp" && currentIndex === 1) {
|
hashDropDown.closeTriggered()
|
||||||
transportProto = "tcp"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 40
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEmptyText: true
|
Component.onCompleted: {
|
||||||
}
|
hashDropDown.text = OpenVpnConfigModel.hash
|
||||||
|
|
||||||
SwitcherType {
|
for (var i = 0; i < hashListView.model.count; i++) {
|
||||||
id: autoNegotiateEncryprionSwitcher
|
if (hashListView.model.get(i).name === hashDropDown.text) {
|
||||||
|
currentIndex = i
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
text: qsTr("Auto-negotiate encryption")
|
|
||||||
checked: autoNegotiateEncryprion
|
|
||||||
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked !== autoNegotiateEncryprion) {
|
|
||||||
autoNegotiateEncryprion = checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DropDownType {
|
|
||||||
id: hashDropDown
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 20
|
|
||||||
|
|
||||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
|
||||||
|
|
||||||
descriptionText: qsTr("Hash")
|
|
||||||
headerText: qsTr("Hash")
|
|
||||||
|
|
||||||
drawerParent: root
|
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
|
||||||
id: hashListView
|
|
||||||
|
|
||||||
rootWidth: root.width
|
|
||||||
|
|
||||||
model: ListModel {
|
|
||||||
ListElement { name : qsTr("SHA512") }
|
|
||||||
ListElement { name : qsTr("SHA384") }
|
|
||||||
ListElement { name : qsTr("SHA256") }
|
|
||||||
ListElement { name : qsTr("SHA3-512") }
|
|
||||||
ListElement { name : qsTr("SHA3-384") }
|
|
||||||
ListElement { name : qsTr("SHA3-256") }
|
|
||||||
ListElement { name : qsTr("whirlpool") }
|
|
||||||
ListElement { name : qsTr("BLAKE2b512") }
|
|
||||||
ListElement { name : qsTr("BLAKE2s256") }
|
|
||||||
ListElement { name : qsTr("SHA1") }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
hashDropDown.text = selectedText
|
|
||||||
hash = hashDropDown.text
|
|
||||||
hashDropDown.closeTriggered()
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
hashDropDown.text = hash
|
|
||||||
|
|
||||||
for (var i = 0; i < hashListView.model.count; i++) {
|
|
||||||
if (hashListView.model.get(i).name === hashDropDown.text) {
|
|
||||||
currentIndex = i
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DropDownType {
|
DropDownType {
|
||||||
id: cipherDropDown
|
id: cipherDropDown
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
descriptionText: qsTr("Cipher")
|
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||||
headerText: qsTr("Cipher")
|
|
||||||
|
|
||||||
drawerParent: root
|
descriptionText: qsTr("Cipher")
|
||||||
|
headerText: qsTr("Cipher")
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
drawerParent: root
|
||||||
id: cipherListView
|
|
||||||
|
|
||||||
rootWidth: root.width
|
listView: ListViewWithRadioButtonType {
|
||||||
|
id: cipherListView
|
||||||
|
|
||||||
model: ListModel {
|
rootWidth: root.width
|
||||||
ListElement { name : qsTr("AES-256-GCM") }
|
|
||||||
ListElement { name : qsTr("AES-192-GCM") }
|
|
||||||
ListElement { name : qsTr("AES-128-GCM") }
|
|
||||||
ListElement { name : qsTr("AES-256-CBC") }
|
|
||||||
ListElement { name : qsTr("AES-192-CBC") }
|
|
||||||
ListElement { name : qsTr("AES-128-CBC") }
|
|
||||||
ListElement { name : qsTr("ChaCha20-Poly1305") }
|
|
||||||
ListElement { name : qsTr("ARIA-256-CBC") }
|
|
||||||
ListElement { name : qsTr("CAMELLIA-256-CBC") }
|
|
||||||
ListElement { name : qsTr("none") }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
model: ListModel {
|
||||||
cipherDropDown.text = selectedText
|
ListElement { name : qsTr("AES-256-GCM") }
|
||||||
cipher = cipherDropDown.text
|
ListElement { name : qsTr("AES-192-GCM") }
|
||||||
cipherDropDown.closeTriggered()
|
ListElement { name : qsTr("AES-128-GCM") }
|
||||||
}
|
ListElement { name : qsTr("AES-256-CBC") }
|
||||||
|
ListElement { name : qsTr("AES-192-CBC") }
|
||||||
|
ListElement { name : qsTr("AES-128-CBC") }
|
||||||
|
ListElement { name : qsTr("ChaCha20-Poly1305") }
|
||||||
|
ListElement { name : qsTr("ARIA-256-CBC") }
|
||||||
|
ListElement { name : qsTr("CAMELLIA-256-CBC") }
|
||||||
|
ListElement { name : qsTr("none") }
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
clickedFunction: function() {
|
||||||
cipherDropDown.text = cipher
|
cipherDropDown.text = selectedText
|
||||||
|
OpenVpnConfigModel.cipher = cipherDropDown.text
|
||||||
|
cipherDropDown.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
Component.onCompleted: {
|
||||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
cipherDropDown.text = OpenVpnConfigModel.cipher
|
||||||
currentIndex = i
|
|
||||||
}
|
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||||
|
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||||
|
currentIndex = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
DelegateChoice {
|
||||||
id: contentRect
|
roleValue: "checkboxSection"
|
||||||
Layout.fillWidth: true
|
ColumnLayout {
|
||||||
Layout.topMargin: 32
|
width: listView.width
|
||||||
Layout.preferredHeight: checkboxLayout.implicitHeight
|
|
||||||
color: AmneziaStyle.color.onyxBlack
|
|
||||||
radius: 16
|
|
||||||
|
|
||||||
Connections {
|
Rectangle {
|
||||||
target: tlsAuthCheckBox
|
id: contentRect
|
||||||
enabled: !GC.isMobile()
|
|
||||||
|
|
||||||
function onFocusChanged() {
|
Layout.fillWidth: true
|
||||||
if (tlsAuthCheckBox.activeFocus) {
|
Layout.topMargin: 32
|
||||||
fl.ensureVisible(contentRect)
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.preferredHeight: checkboxLayout.implicitHeight
|
||||||
|
color: AmneziaStyle.color.onyxBlack
|
||||||
|
radius: 16
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: checkboxLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
CheckBoxType {
|
||||||
|
id: tlsAuthCheckBox
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("TLS auth")
|
||||||
|
checked: OpenVpnConfigModel.tlsAuth
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (checked !== OpenVpnConfigModel.tlsAuth) {
|
||||||
|
console.log("tlsAuth changed to: " + checked)
|
||||||
|
OpenVpnConfigModel.tlsAuth = checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
DividerType {}
|
||||||
id: checkboxLayout
|
|
||||||
|
|
||||||
anchors.fill: parent
|
CheckBoxType {
|
||||||
CheckBoxType {
|
id: blockDnsCheckBox
|
||||||
id: tlsAuthCheckBox
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("TLS auth")
|
Layout.fillWidth: true
|
||||||
checked: tlsAuth
|
|
||||||
|
|
||||||
onCheckedChanged: {
|
text: qsTr("Block DNS requests outside of VPN")
|
||||||
if (checked !== tlsAuth) {
|
checked: OpenVpnConfigModel.blockDns
|
||||||
console.log("tlsAuth changed to: " + checked)
|
|
||||||
tlsAuth = checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {}
|
onCheckedChanged: {
|
||||||
|
if (checked !== OpenVpnConfigModel.blockDns) {
|
||||||
CheckBoxType {
|
OpenVpnConfigModel.blockDns = checked
|
||||||
id: blockDnsCheckBox
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Block DNS requests outside of VPN")
|
|
||||||
checked: blockDns
|
|
||||||
|
|
||||||
onCheckedChanged: {
|
|
||||||
if (checked !== blockDns) {
|
|
||||||
blockDns = checked
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SwitcherType {
|
DelegateChoice {
|
||||||
id: additionalClientCommandsSwitcher
|
roleValue: "clientCommands"
|
||||||
Layout.fillWidth: true
|
ColumnLayout {
|
||||||
Layout.topMargin: 32
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
checked: additionalClientCommands !== ""
|
width: listView.width
|
||||||
|
|
||||||
text: qsTr("Additional client configuration commands")
|
SwitcherType {
|
||||||
|
id: additionalClientCommandsSwitcher
|
||||||
|
|
||||||
onCheckedChanged: {
|
Layout.fillWidth: true
|
||||||
if (!checked) {
|
Layout.topMargin: 32
|
||||||
additionalClientCommands = ""
|
Layout.leftMargin: 16
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
checked: OpenVpnConfigModel.additionalClientCommands !== ""
|
||||||
|
|
||||||
|
text: qsTr("Additional client configuration commands")
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (!checked) {
|
||||||
|
OpenVpnConfigModel.additionalClientCommands = ""
|
||||||
|
}
|
||||||
|
// listView.positionViewAtIndex(index, ListView.Beginning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAreaType {
|
||||||
|
id: additionalClientCommandsTextArea
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
visible: additionalClientCommandsSwitcher.checked
|
||||||
|
|
||||||
|
textAreaText: OpenVpnConfigModel.additionalClientCommands
|
||||||
|
placeholderText: qsTr("Commands:")
|
||||||
|
|
||||||
|
textArea.onEditingFinished: {
|
||||||
|
if (OpenVpnConfigModel.additionalClientCommands !== textAreaText) {
|
||||||
|
OpenVpnConfigModel.additionalClientCommands = textAreaText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TextAreaType {
|
DelegateChoice {
|
||||||
id: additionalClientCommandsTextArea
|
roleValue: "serverCommands"
|
||||||
Layout.fillWidth: true
|
ColumnLayout {
|
||||||
Layout.topMargin: 16
|
width: listView.width
|
||||||
|
|
||||||
visible: additionalClientCommandsSwitcher.checked
|
SwitcherType {
|
||||||
|
id: additionalServerCommandsSwitcher
|
||||||
|
|
||||||
parentFlickable: fl
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
textAreaText: additionalClientCommands
|
checked: OpenVpnConfigModel.additionalServerCommands !== ""
|
||||||
placeholderText: qsTr("Commands:")
|
|
||||||
|
|
||||||
textArea.onEditingFinished: {
|
text: qsTr("Additional server configuration commands")
|
||||||
if (additionalClientCommands !== textAreaText) {
|
|
||||||
additionalClientCommands = textAreaText
|
onCheckedChanged: {
|
||||||
}
|
if (!checked) {
|
||||||
|
OpenVpnConfigModel.additionalServerCommands = ""
|
||||||
}
|
}
|
||||||
|
// listView.positionViewAtIndex(index, ListView.Beginning)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SwitcherType {
|
TextAreaType {
|
||||||
id: additionalServerCommandsSwitcher
|
id: additionalServerCommandsTextArea
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
checked: additionalServerCommands !== ""
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Additional server configuration commands")
|
visible: additionalServerCommandsSwitcher.checked
|
||||||
|
|
||||||
onCheckedChanged: {
|
textAreaText: OpenVpnConfigModel.additionalServerCommands
|
||||||
if (!checked) {
|
placeholderText: qsTr("Commands:")
|
||||||
additionalServerCommands = ""
|
|
||||||
}
|
textArea.onEditingFinished: {
|
||||||
|
if (OpenVpnConfigModel.additionalServerCommands !== textAreaText) {
|
||||||
|
OpenVpnConfigModel.additionalServerCommands = textAreaText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextAreaType {
|
|
||||||
id: additionalServerCommandsTextArea
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
visible: additionalServerCommandsSwitcher.checked
|
|
||||||
|
|
||||||
textAreaText: additionalServerCommands
|
|
||||||
placeholderText: qsTr("Commands:")
|
|
||||||
parentFlickable: fl
|
|
||||||
textArea.onEditingFinished: {
|
|
||||||
if (additionalServerCommands !== textAreaText) {
|
|
||||||
additionalServerCommands = textAreaText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
enabled: vpnAddressSubnetTextField.errorText === "" &&
|
|
||||||
portTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
onClicked: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveRestartButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,164 +19,154 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: header
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
onFocusChanged: {
|
||||||
id: backButton
|
if (this.activeFocus) {
|
||||||
}
|
listView.positionViewAtBeginning()
|
||||||
|
}
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: header.bottom
|
|
||||||
anchors.left: parent.left
|
anchors.top: backButton.bottom
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
contentHeight: content.height
|
anchors.left: parent.left
|
||||||
|
|
||||||
Column {
|
header: ColumnLayout {
|
||||||
id: content
|
width: listView.width
|
||||||
|
|
||||||
anchors.top: parent.top
|
BaseHeaderType {
|
||||||
anchors.left: parent.left
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
Layout.leftMargin: 16
|
||||||
anchors.topMargin: 32
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
ListView {
|
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
||||||
id: listView
|
}
|
||||||
width: parent.width
|
}
|
||||||
height: contentItem.height
|
|
||||||
clip: true
|
|
||||||
interactive: false
|
|
||||||
model: ProtocolsModel
|
|
||||||
|
|
||||||
activeFocusOnTab: true
|
model: ProtocolsModel
|
||||||
focus: true
|
|
||||||
|
|
||||||
delegate: Item {
|
delegate: ColumnLayout {
|
||||||
implicitWidth: parent.width
|
width: listView.width
|
||||||
implicitHeight: delegateContent.implicitHeight
|
|
||||||
|
|
||||||
property alias focusItem: button
|
LabelWithButtonType {
|
||||||
|
id: button
|
||||||
|
|
||||||
ColumnLayout {
|
Layout.fillWidth: true
|
||||||
id: delegateContent
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
anchors.fill: parent
|
text: qsTr("Show connection options")
|
||||||
|
|
||||||
LabelWithButtonType {
|
clickedFunction: function() {
|
||||||
id: button
|
configContentDrawer.openTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
MouseArea {
|
||||||
|
anchors.fill: button
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
text: qsTr("Show connection options")
|
DividerType {}
|
||||||
|
|
||||||
clickedFunction: function() {
|
DrawerType2 {
|
||||||
configContentDrawer.openTriggered()
|
id: configContentDrawer
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
expandedHeight: root.height * 0.9
|
||||||
anchors.fill: button
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
parent: root
|
||||||
enabled: false
|
anchors.fill: parent
|
||||||
|
|
||||||
|
expandedStateContent: Item {
|
||||||
|
implicitHeight: configContentDrawer.expandedHeight
|
||||||
|
|
||||||
|
BackButtonType {
|
||||||
|
id: drawerBackButton
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 16
|
||||||
|
|
||||||
|
backButtonFunction: function() {
|
||||||
|
configContentDrawer.closeTriggered()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListViewType {
|
||||||
|
id: drawerListView
|
||||||
|
|
||||||
|
anchors.top: drawerBackButton.bottom
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
header: ColumnLayout {
|
||||||
|
width: drawerListView.width
|
||||||
|
|
||||||
|
Header2Type {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
headerText: qsTr("Connection options %1").arg(protocolName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {}
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
|
|
||||||
DrawerType2 {
|
delegate: ColumnLayout {
|
||||||
id: configContentDrawer
|
width: drawerListView.width
|
||||||
|
|
||||||
expandedHeight: root.height * 0.9
|
TextArea {
|
||||||
|
id: configText
|
||||||
|
|
||||||
parent: root
|
Layout.fillWidth: true
|
||||||
anchors.fill: parent
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
expandedStateContent: Item {
|
padding: 0
|
||||||
implicitHeight: configContentDrawer.expandedHeight
|
height: 24
|
||||||
|
|
||||||
BackButtonType {
|
color: AmneziaStyle.color.paleGray
|
||||||
id: backButton1
|
selectionColor: AmneziaStyle.color.richBrown
|
||||||
|
selectedTextColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
anchors.top: parent.top
|
font.pixelSize: 16
|
||||||
anchors.left: parent.left
|
font.weight: Font.Medium
|
||||||
anchors.right: parent.right
|
font.family: "PT Root UI VF"
|
||||||
anchors.topMargin: 16
|
|
||||||
|
|
||||||
backButtonFunction: function() {
|
text: rawConfig
|
||||||
configContentDrawer.closeTriggered()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FlickableType {
|
wrapMode: Text.Wrap
|
||||||
anchors.top: backButton1.bottom
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
|
|
||||||
|
|
||||||
ColumnLayout {
|
background: Rectangle {
|
||||||
id: configContent
|
color: AmneziaStyle.color.transparent
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
|
|
||||||
Header2Type {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("Connection options %1").arg(protocolName)
|
|
||||||
}
|
|
||||||
|
|
||||||
TextArea {
|
|
||||||
id: configText
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
|
|
||||||
padding: 0
|
|
||||||
leftPadding: 0
|
|
||||||
height: 24
|
|
||||||
|
|
||||||
color: AmneziaStyle.color.paleGray
|
|
||||||
selectionColor: AmneziaStyle.color.richBrown
|
|
||||||
selectedTextColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
font.pixelSize: 16
|
|
||||||
font.weight: Font.Medium
|
|
||||||
font.family: "PT Root UI VF"
|
|
||||||
|
|
||||||
text: rawConfig
|
|
||||||
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
color: AmneziaStyle.color.transparent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: removeButton
|
id: removeButton
|
||||||
|
|
@ -198,11 +188,7 @@ PageType {
|
||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
InstallController.removeProcessedContainer()
|
InstallController.removeProcessedContainer()
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
var noButtonFunction = function() {}
|
||||||
if (!GC.isMobile()) {
|
|
||||||
focusItem.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,179 +16,138 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
onFocusChanged: {
|
||||||
id: backButton
|
if (this.activeFocus) {
|
||||||
|
listView.positionViewAtBeginning()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
Column {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
model: ShadowSocksConfigModel
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
ListView {
|
spacing: 0
|
||||||
id: listview
|
|
||||||
|
|
||||||
width: parent.width
|
BaseHeaderType {
|
||||||
height: listview.contentItem.height
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
clip: true
|
headerText: qsTr("Shadowsocks settings")
|
||||||
interactive: false
|
}
|
||||||
|
|
||||||
model: ShadowSocksConfigModel
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
|
||||||
delegate: Item {
|
Layout.fillWidth: true
|
||||||
id: delegateItem
|
Layout.topMargin: 40
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
enabled: isPortEditable
|
||||||
|
|
||||||
implicitWidth: listview.width
|
headerText: qsTr("Port")
|
||||||
implicitHeight: col.implicitHeight
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
ColumnLayout {
|
textField.onEditingFinished: {
|
||||||
id: col
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
anchors.top: parent.top
|
DropDownType {
|
||||||
anchors.left: parent.left
|
id: cipherDropDown
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
Layout.fillWidth: true
|
||||||
anchors.rightMargin: 16
|
Layout.topMargin: 20
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
spacing: 0
|
enabled: isCipherEditable
|
||||||
|
|
||||||
BaseHeaderType {
|
descriptionText: qsTr("Cipher")
|
||||||
Layout.fillWidth: true
|
headerText: qsTr("Cipher")
|
||||||
headerText: qsTr("Shadowsocks settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
drawerParent: root
|
||||||
id: portTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
listView: ListViewWithRadioButtonType {
|
||||||
Layout.topMargin: 40
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
id: cipherListView
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
rootWidth: root.width
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
model: ListModel {
|
||||||
if (textField.text !== port) {
|
ListElement { name : "chacha20-ietf-poly1305" }
|
||||||
port = textField.text
|
ListElement { name : "xchacha20-ietf-poly1305" }
|
||||||
}
|
ListElement { name : "aes-256-gcm" }
|
||||||
|
ListElement { name : "aes-192-gcm" }
|
||||||
|
ListElement { name : "aes-128-gcm" }
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
cipherDropDown.text = selectedText
|
||||||
|
cipher = cipherDropDown.text
|
||||||
|
cipherDropDown.closeTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
cipherDropDown.text = cipher
|
||||||
|
|
||||||
|
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||||
|
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||||
|
currentIndex = i
|
||||||
}
|
}
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
DropDownType {
|
|
||||||
id: cipherDropDown
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 20
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
descriptionText: qsTr("Cipher")
|
|
||||||
headerText: qsTr("Cipher")
|
|
||||||
|
|
||||||
drawerParent: root
|
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
|
||||||
|
|
||||||
id: cipherListView
|
|
||||||
|
|
||||||
rootWidth: root.width
|
|
||||||
|
|
||||||
model: ListModel {
|
|
||||||
ListElement { name : "chacha20-ietf-poly1305" }
|
|
||||||
ListElement { name : "xchacha20-ietf-poly1305" }
|
|
||||||
ListElement { name : "aes-256-gcm" }
|
|
||||||
ListElement { name : "aes-192-gcm" }
|
|
||||||
ListElement { name : "aes-128-gcm" }
|
|
||||||
}
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
cipherDropDown.text = selectedText
|
|
||||||
cipher = cipherDropDown.text
|
|
||||||
cipherDropDown.closeTriggered()
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
cipherDropDown.text = cipher
|
|
||||||
|
|
||||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
|
||||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
|
||||||
currentIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
enabled: portTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveRestartButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: isPortEditable | isCipherEditable
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,160 +16,124 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
Item {
|
BackButtonType {
|
||||||
id: focusItem
|
id: backButton
|
||||||
onFocusChanged: {
|
|
||||||
if (activeFocus) {
|
|
||||||
fl.ensureVisible(focusItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KeyNavigation.tab: backButton
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: backButtonLayout
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
onFocusChanged: {
|
||||||
id: backButton
|
if (this.activeFocus) {
|
||||||
KeyNavigation.tab: listview.currentItem.mtuTextField.textField
|
listView.positionViewAtBeginning()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
Column {
|
model: WireGuardConfigModel
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
delegate: ColumnLayout {
|
||||||
anchors.left: parent.left
|
width: listView.width
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
ListView {
|
property alias mtuTextField: mtuTextField
|
||||||
id: listview
|
property bool isSaveButtonEnabled: mtuTextField.errorText === ""
|
||||||
|
|
||||||
width: parent.width
|
spacing: 0
|
||||||
height: listview.contentItem.height
|
|
||||||
|
|
||||||
clip: true
|
BaseHeaderType {
|
||||||
interactive: false
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
model: WireGuardConfigModel
|
headerText: qsTr("WG settings")
|
||||||
|
}
|
||||||
|
|
||||||
delegate: Item {
|
TextFieldWithHeaderType {
|
||||||
id: delegateItem
|
id: mtuTextField
|
||||||
implicitWidth: listview.width
|
Layout.fillWidth: true
|
||||||
implicitHeight: col.implicitHeight
|
Layout.topMargin: 40
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
property alias mtuTextField: mtuTextField
|
headerText: qsTr("MTU")
|
||||||
property bool isSaveButtonEnabled: mtuTextField.errorText === ""
|
textField.text: clientMtu
|
||||||
|
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||||
|
|
||||||
ColumnLayout {
|
textField.onEditingFinished: {
|
||||||
id: col
|
if (textField.text !== clientMtu) {
|
||||||
|
clientMtu = textField.text
|
||||||
anchors.top: parent.top
|
}
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
headerText: qsTr("WG settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: mtuTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 40
|
|
||||||
|
|
||||||
headerText: qsTr("MTU")
|
|
||||||
textField.text: clientMtu
|
|
||||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== clientMtu) {
|
|
||||||
clientMtu = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkEmptyText: true
|
|
||||||
KeyNavigation.tab: saveButton
|
|
||||||
}
|
|
||||||
|
|
||||||
Header2TextType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
text: qsTr("Server settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 8
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Header2TextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Server settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
footer: ColumnLayout {
|
||||||
id: saveButton
|
width: listView.width
|
||||||
|
|
||||||
anchors.right: root.right
|
BasicButtonType {
|
||||||
anchors.left: root.left
|
id: saveButton
|
||||||
anchors.bottom: root.bottom
|
|
||||||
|
|
||||||
anchors.topMargin: 24
|
Layout.fillWidth: true
|
||||||
anchors.bottomMargin: 24
|
Layout.topMargin: 24
|
||||||
anchors.rightMargin: 16
|
Layout.bottomMargin: 24
|
||||||
anchors.leftMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
enabled: listview.currentItem.isSaveButtonEnabled
|
enabled: listView.currentItem.isSaveButtonEnabled
|
||||||
|
|
||||||
text: qsTr("Save")
|
text: qsTr("Save")
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
forceActiveFocus()
|
var headerText = qsTr("Save settings?")
|
||||||
var headerText = qsTr("Save settings?")
|
var descriptionText = qsTr("Only the settings for this device will be changed")
|
||||||
var descriptionText = qsTr("Only the settings for this device will be changed")
|
var yesButtonText = qsTr("Continue")
|
||||||
var yesButtonText = qsTr("Continue")
|
var noButtonText = qsTr("Cancel")
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
var noButtonFunction = function() {}
|
||||||
if (!GC.isMobile()) {
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,153 +16,134 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
onFocusChanged: {
|
||||||
id: backButton
|
if (this.activeFocus) {
|
||||||
|
listView.positionViewAtBeginning()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
Column {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
model: WireGuardConfigModel
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
ListView {
|
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: listview
|
|
||||||
|
|
||||||
width: parent.width
|
spacing: 0
|
||||||
height: listview.contentItem.height
|
|
||||||
|
|
||||||
clip: true
|
BaseHeaderType {
|
||||||
interactive: false
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
model: WireGuardConfigModel
|
headerText: qsTr("WG settings")
|
||||||
|
}
|
||||||
|
|
||||||
delegate: Item {
|
TextFieldWithHeaderType {
|
||||||
id: delegateItem
|
id: vpnAddressSubnetTextField
|
||||||
|
|
||||||
property alias focusItemId: vpnAddressSubnetTextField
|
Layout.fillWidth: true
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
Layout.topMargin: 40
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
implicitWidth: listview.width
|
enabled: delegateItem.isEnabled
|
||||||
implicitHeight: col.implicitHeight
|
|
||||||
|
|
||||||
ColumnLayout {
|
headerText: qsTr("VPN address subnet")
|
||||||
id: col
|
textField.text: subnetAddress
|
||||||
|
|
||||||
anchors.top: parent.top
|
textField.onEditingFinished: {
|
||||||
anchors.left: parent.left
|
if (textField.text !== subnetAddress) {
|
||||||
anchors.right: parent.right
|
subnetAddress = textField.text
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
headerText: qsTr("WG settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: vpnAddressSubnetTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 40
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("VPN address subnet")
|
|
||||||
textField.text: subnetAddress
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== subnetAddress) {
|
|
||||||
subnetAddress = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
enabled: portTextField.errorText === "" &&
|
|
||||||
vpnAddressSubnetTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
onClicked: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: portTextField.errorText === "" &&
|
||||||
|
vpnAddressSubnetTextField.errorText === ""
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
onClicked: function() {
|
||||||
|
forceActiveFocus()
|
||||||
|
|
||||||
|
var headerText = qsTr("Save settings?")
|
||||||
|
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(WireGuardConfigModel.getConfig())
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
|
saveRestartButton.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: saveButton.clicked()
|
||||||
|
Keys.onReturnPressed: saveButton.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,163 +17,114 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
|
||||||
id: backButton
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
Column {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: content
|
model: XrayConfigModel
|
||||||
|
|
||||||
anchors.top: parent.top
|
delegate: ColumnLayout {
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
width: listView.width
|
||||||
|
|
||||||
ListView {
|
property alias focusItemId: textFieldWithHeaderType.textField
|
||||||
id: listview
|
|
||||||
|
|
||||||
width: parent.width
|
spacing: 0
|
||||||
height: listview.contentItem.height
|
|
||||||
|
|
||||||
clip: true
|
BaseHeaderType {
|
||||||
interactive: false
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
headerText: qsTr("XRay settings")
|
||||||
|
}
|
||||||
|
|
||||||
model: XrayConfigModel
|
TextFieldWithHeaderType {
|
||||||
|
id: textFieldWithHeaderType
|
||||||
|
|
||||||
delegate: Item {
|
Layout.fillWidth: true
|
||||||
id: delegateItem
|
Layout.topMargin: 32
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
property alias focusItemId: textFieldWithHeaderType.textField
|
headerText: qsTr("Disguised as traffic from")
|
||||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
textField.text: site
|
||||||
|
|
||||||
implicitWidth: listview.width
|
textField.onEditingFinished: {
|
||||||
implicitHeight: col.implicitHeight
|
if (textField.text !== site) {
|
||||||
|
var tmpText = textField.text
|
||||||
|
tmpText = tmpText.toLocaleLowerCase()
|
||||||
|
|
||||||
ColumnLayout {
|
if (tmpText.startsWith("https://")) {
|
||||||
id: col
|
tmpText = textField.text.substring(8)
|
||||||
|
site = tmpText
|
||||||
anchors.top: parent.top
|
} else {
|
||||||
anchors.left: parent.left
|
site = textField.text
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
headerText: qsTr("XRay settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: textFieldWithHeaderType
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Disguised as traffic from")
|
|
||||||
textField.text: site
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== site) {
|
|
||||||
var tmpText = textField.text
|
|
||||||
tmpText = tmpText.toLocaleLowerCase()
|
|
||||||
|
|
||||||
if (tmpText.startsWith("https://")) {
|
|
||||||
tmpText = textField.text.substring(8)
|
|
||||||
site = tmpText
|
|
||||||
} else {
|
|
||||||
site = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
|
|
||||||
enabled: delegateItem.isEnabled
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkEmptyText: true
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
enabled: portTextField.errorText === ""
|
|
||||||
|
|
||||||
text: qsTr("Save")
|
|
||||||
|
|
||||||
onClicked: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
var headerText = qsTr("Save settings?")
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
|
||||||
InstallController.updateContainer(XrayConfigModel.getConfig())
|
|
||||||
//focusItem.forceActiveFocus()
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
saveButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
|
id: portTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
enabled: delegateItem.isEnabled
|
||||||
|
|
||||||
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
|
textField.onEditingFinished: {
|
||||||
|
if (textField.text !== port) {
|
||||||
|
port = textField.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmptyText: true
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: saveButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Save")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||||
|
InstallController.updateContainer(XrayConfigModel.getConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: saveButton.clicked()
|
||||||
|
Keys.onReturnPressed: saveButton.clicked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,50 +16,47 @@ import "../Components"
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
|
||||||
id: backButton
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
ColumnLayout {
|
header: ColumnLayout {
|
||||||
id: content
|
width: listView.width
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
id: header
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
headerText: "AmneziaDNS"
|
headerText: "AmneziaDNS"
|
||||||
descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") +
|
descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") +
|
||||||
qsTr("The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab.")
|
qsTr("The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab.")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: removeButton
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
Layout.topMargin: 24
|
Layout.rightMargin: 16
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
@ -71,19 +68,14 @@ PageType {
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
||||||
&& SettingsController.isAmneziaDnsEnabled()) {
|
&& SettingsController.isAmneziaDnsEnabled()) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server"))
|
PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server"))
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
InstallController.removeProcessedContainer()
|
InstallController.removeProcessedContainer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
var noButtonFunction = function() {}
|
||||||
if (!GC.isMobile()) {
|
|
||||||
removeButton.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,258 +24,215 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
onFocusChanged: {
|
||||||
id: backButton
|
if (this.activeFocus) {
|
||||||
|
listView.positionViewAtBeginning()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
Column {
|
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
model: SftpConfigModel
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
ListView {
|
spacing: 0
|
||||||
id: listview
|
|
||||||
|
|
||||||
width: parent.width
|
BaseHeaderType {
|
||||||
height: listview.contentItem.height
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
clip: true
|
headerText: qsTr("SFTP settings")
|
||||||
interactive: false
|
}
|
||||||
|
|
||||||
model: SftpConfigModel
|
LabelWithButtonType {
|
||||||
|
id: hostLabel
|
||||||
|
|
||||||
onFocusChanged: {
|
Layout.fillWidth: true
|
||||||
if (focus) {
|
Layout.topMargin: 32
|
||||||
listview.currentItem.listViewFocusItem.forceActiveFocus()
|
Layout.leftMargin: 16
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Host")
|
||||||
|
descriptionText: ServersModel.getProcessedServerData("hostName")
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: portLabel
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Port")
|
||||||
|
descriptionText: port
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: usernameLabel
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("User name")
|
||||||
|
descriptionText: username
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: passwordLabel
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Password")
|
||||||
|
descriptionText: password
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: mountButton
|
||||||
|
|
||||||
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
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("Mount folder on device")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.mountSftpDrive(port, password, username)
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
readonly property string windowsFirstLink: "<a href=\"https://github.com/billziss-gh/winfsp/releases/latest\" style=\"color: #FBB26A;\">WinFsp</a>"
|
||||||
|
readonly property string windowsSecondLink: "<a href=\"https://github.com/billziss-gh/sshfs-win/releases\" style=\"color: #FBB26A;\">SSHFS-Win</a>"
|
||||||
|
|
||||||
|
readonly property string macosFirstLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">macFUSE</a>"
|
||||||
|
readonly property string macosSecondLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">SSHFS</a>"
|
||||||
|
|
||||||
|
onLinkActivated: function(link) {
|
||||||
|
Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
textFormat: Text.RichText
|
||||||
|
text: {
|
||||||
|
var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps: <br>")
|
||||||
|
if (Qt.platform.os === "windows") {
|
||||||
|
str += qsTr("<br>1. Install the latest version of ") + windowsFirstLink + "\n"
|
||||||
|
str += qsTr("<br>2. Install the latest version of ") + windowsSecondLink + "\n"
|
||||||
|
} else if (Qt.platform.os === "osx") {
|
||||||
|
str += qsTr("<br>1. Install the latest version of ") + macosFirstLink + "\n"
|
||||||
|
str += qsTr("<br>2. Install the latest version of ") + macosSecondLink + "\n"
|
||||||
|
} else if (Qt.platform.os === "linux") {
|
||||||
|
return ""
|
||||||
|
} else return ""
|
||||||
|
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Item {
|
MouseArea {
|
||||||
implicitWidth: listview.width
|
anchors.fill: parent
|
||||||
implicitHeight: col.implicitHeight
|
acceptedButtons: Qt.NoButton
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property alias listViewFocusItem: hostLabel.rightButton
|
BasicButtonType {
|
||||||
|
id: detailedInstructionsButton
|
||||||
|
|
||||||
ColumnLayout {
|
Layout.topMargin: 16
|
||||||
id: col
|
Layout.bottomMargin: 16
|
||||||
|
Layout.leftMargin: 8
|
||||||
|
implicitHeight: 32
|
||||||
|
|
||||||
anchors.top: parent.top
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
anchors.left: parent.left
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
anchors.right: parent.right
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
|
disabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
textColor: AmneziaStyle.color.goldenApricot
|
||||||
|
|
||||||
spacing: 0
|
text: qsTr("Detailed instructions")
|
||||||
|
|
||||||
BaseHeaderType {
|
clickedFunc: function() {
|
||||||
Layout.fillWidth: true
|
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
headerText: qsTr("SFTP settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: hostLabel
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
text: qsTr("Host")
|
|
||||||
descriptionText: ServersModel.getProcessedServerData("hostName")
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: portLabel
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Port")
|
|
||||||
descriptionText: port
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: usernameLabel
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("User name")
|
|
||||||
descriptionText: username
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: passwordLabel
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Password")
|
|
||||||
descriptionText: password
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: mountButton
|
|
||||||
visible: !GC.isMobile()
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
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
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
text: qsTr("Mount folder on device")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
InstallController.mountSftpDrive(port, password, username)
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParagraphTextType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
readonly property string windowsFirstLink: "<a href=\"https://github.com/billziss-gh/winfsp/releases/latest\" style=\"color: #FBB26A;\">WinFsp</a>"
|
|
||||||
readonly property string windowsSecondLink: "<a href=\"https://github.com/billziss-gh/sshfs-win/releases\" style=\"color: #FBB26A;\">SSHFS-Win</a>"
|
|
||||||
|
|
||||||
readonly property string macosFirstLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">macFUSE</a>"
|
|
||||||
readonly property string macosSecondLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">SSHFS</a>"
|
|
||||||
|
|
||||||
onLinkActivated: function(link) {
|
|
||||||
Qt.openUrlExternally(link)
|
|
||||||
}
|
|
||||||
textFormat: Text.RichText
|
|
||||||
text: {
|
|
||||||
var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps: <br>")
|
|
||||||
if (Qt.platform.os === "windows") {
|
|
||||||
str += qsTr("<br>1. Install the latest version of ") + windowsFirstLink + "\n"
|
|
||||||
str += qsTr("<br>2. Install the latest version of ") + windowsSecondLink + "\n"
|
|
||||||
} else if (Qt.platform.os === "osx") {
|
|
||||||
str += qsTr("<br>1. Install the latest version of ") + macosFirstLink + "\n"
|
|
||||||
str += qsTr("<br>2. Install the latest version of ") + macosSecondLink + "\n"
|
|
||||||
} else if (Qt.platform.os === "linux") {
|
|
||||||
return ""
|
|
||||||
} else return ""
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: detailedInstructionsButton
|
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.bottomMargin: 16
|
|
||||||
Layout.leftMargin: 8
|
|
||||||
implicitHeight: 32
|
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
|
||||||
pressedColor: AmneziaStyle.color.sheerWhite
|
|
||||||
disabledColor: AmneziaStyle.color.mutedGray
|
|
||||||
textColor: AmneziaStyle.color.goldenApricot
|
|
||||||
|
|
||||||
text: qsTr("Detailed instructions")
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,327 +25,290 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
onFocusChanged: {
|
||||||
id: backButton
|
if (this.activeFocus) {
|
||||||
|
listView.positionViewAtBeginning()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: listview.implicitHeight
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
ListView {
|
model: Socks5ProxyConfigModel
|
||||||
id: listview
|
|
||||||
|
|
||||||
width: parent.width
|
delegate: ColumnLayout {
|
||||||
height: listview.contentItem.height
|
width: listView.width
|
||||||
|
|
||||||
clip: true
|
spacing: 0
|
||||||
interactive: false
|
|
||||||
|
|
||||||
model: Socks5ProxyConfigModel
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
onFocusChanged: {
|
headerText: qsTr("SOCKS5 settings")
|
||||||
if (focus) {
|
}
|
||||||
listview.currentItem.focusItemId.forceActiveFocus()
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 32
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Host")
|
||||||
|
descriptionText: ServersModel.getProcessedServerData("hostName")
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Item {
|
LabelWithButtonType {
|
||||||
implicitWidth: listview.width
|
Layout.fillWidth: true
|
||||||
implicitHeight: content.implicitHeight
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
property alias focusItemId: hostLabel.rightButton
|
text: qsTr("Port")
|
||||||
|
descriptionText: port
|
||||||
|
|
||||||
ColumnLayout {
|
descriptionOnTop: true
|
||||||
id: content
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("User name")
|
||||||
|
descriptionText: username
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Password")
|
||||||
|
descriptionText: password
|
||||||
|
|
||||||
|
descriptionOnTop: true
|
||||||
|
|
||||||
|
rightImageSource: "qrc:/images/controls/copy.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(descriptionText)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawerType2 {
|
||||||
|
id: changeSettingsDrawer
|
||||||
|
parent: root
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
expandedHeight: root.height * 0.9
|
||||||
|
|
||||||
|
expandedStateContent: ColumnLayout {
|
||||||
|
property string tempPort: port
|
||||||
|
property string tempUsername: username
|
||||||
|
property string tempPassword: password
|
||||||
|
|
||||||
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: 32
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: changeSettingsDrawer
|
||||||
|
function onOpened() {
|
||||||
|
tempPort = port
|
||||||
|
tempUsername = username
|
||||||
|
tempPassword = password
|
||||||
|
}
|
||||||
|
function onClosed() {
|
||||||
|
port = tempPort
|
||||||
|
username = tempUsername
|
||||||
|
password = tempPassword
|
||||||
|
portTextField.textField.text = port
|
||||||
|
usernameTextField.textField.text = username
|
||||||
|
passwordTextField.textField.text = password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("SOCKS5 settings")
|
headerText: qsTr("SOCKS5 settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
TextFieldWithHeaderType {
|
||||||
id: hostLabel
|
id: portTextField
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 40
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
parentFlickable: fl
|
headerText: qsTr("Port")
|
||||||
|
textField.text: port
|
||||||
|
textField.maximumLength: 5
|
||||||
|
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||||
|
|
||||||
text: qsTr("Host")
|
textField.onEditingFinished: {
|
||||||
descriptionText: ServersModel.getProcessedServerData("hostName")
|
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||||
|
if (textField.text !== port) {
|
||||||
descriptionOnTop: true
|
port = textField.text
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
TextFieldWithHeaderType {
|
||||||
id: portLabel
|
id: usernameTextField
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
text: qsTr("Port")
|
headerText: qsTr("Username")
|
||||||
descriptionText: port
|
textField.placeholderText: "username"
|
||||||
|
textField.text: username
|
||||||
|
textField.maximumLength: 32
|
||||||
|
|
||||||
descriptionOnTop: true
|
textField.onEditingFinished: {
|
||||||
|
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||||
parentFlickable: fl
|
if (textField.text !== username) {
|
||||||
|
username = textField.text
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
TextFieldWithHeaderType {
|
||||||
id: usernameLabel
|
id: passwordTextField
|
||||||
|
|
||||||
|
property bool hidePassword: true
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
text: qsTr("User name")
|
headerText: qsTr("Password")
|
||||||
descriptionText: username
|
textField.placeholderText: "password"
|
||||||
|
textField.text: password
|
||||||
|
textField.maximumLength: 32
|
||||||
|
|
||||||
descriptionOnTop: true
|
textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
|
||||||
|
buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
|
||||||
|
: ""
|
||||||
|
|
||||||
parentFlickable: fl
|
clickedFunc: function() {
|
||||||
|
hidePassword = !hidePassword
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
textField.onFocusChanged: {
|
||||||
id: passwordLabel
|
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
||||||
Layout.fillWidth: true
|
if (textField.text !== password) {
|
||||||
|
password = textField.text
|
||||||
text: qsTr("Password")
|
|
||||||
descriptionText: password
|
|
||||||
|
|
||||||
descriptionOnTop: true
|
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
rightImageSource: "qrc:/images/controls/copy.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
GC.copyToClipBoard(descriptionText)
|
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawerType2 {
|
|
||||||
id: changeSettingsDrawer
|
|
||||||
parent: root
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
expandedHeight: root.height * 0.9
|
|
||||||
|
|
||||||
expandedStateContent: ColumnLayout {
|
|
||||||
property string tempPort: port
|
|
||||||
property string tempUsername: username
|
|
||||||
property string tempPassword: password
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.topMargin: 32
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: changeSettingsDrawer
|
|
||||||
function onOpened() {
|
|
||||||
tempPort = port
|
|
||||||
tempUsername = username
|
|
||||||
tempPassword = password
|
|
||||||
}
|
|
||||||
function onClosed() {
|
|
||||||
port = tempPort
|
|
||||||
username = tempUsername
|
|
||||||
password = tempPassword
|
|
||||||
portTextField.textField.text = port
|
|
||||||
usernameTextField.textField.text = username
|
|
||||||
passwordTextField.textField.text = password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
headerText: qsTr("SOCKS5 settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: portTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 40
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
headerText: qsTr("Port")
|
|
||||||
textField.text: port
|
|
||||||
textField.maximumLength: 5
|
|
||||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
|
||||||
if (textField.text !== port) {
|
|
||||||
port = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: usernameTextField
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
headerText: qsTr("Username")
|
|
||||||
textField.placeholderText: "username"
|
|
||||||
textField.text: username
|
|
||||||
textField.maximumLength: 32
|
|
||||||
|
|
||||||
textField.onEditingFinished: {
|
|
||||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
|
||||||
if (textField.text !== username) {
|
|
||||||
username = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: passwordTextField
|
|
||||||
|
|
||||||
property bool hidePassword: true
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 16
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
headerText: qsTr("Password")
|
|
||||||
textField.placeholderText: "password"
|
|
||||||
textField.text: password
|
|
||||||
textField.maximumLength: 32
|
|
||||||
|
|
||||||
textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
|
|
||||||
buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
|
|
||||||
: ""
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
hidePassword = !hidePassword
|
|
||||||
}
|
|
||||||
|
|
||||||
textField.onFocusChanged: {
|
|
||||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
|
|
||||||
if (textField.text !== password) {
|
|
||||||
password = textField.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: saveButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
text: qsTr("Change connection settings")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
forceActiveFocus()
|
|
||||||
|
|
||||||
if (!portTextField.textField.acceptableInput) {
|
|
||||||
portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (usernameTextField.textField.text && passwordTextField.textField.text === "") {
|
|
||||||
passwordTextField.errorText = qsTr("Password cannot be empty")
|
|
||||||
return
|
|
||||||
} else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) {
|
|
||||||
usernameTextField.errorText = qsTr("Username cannot be empty")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
|
||||||
InstallController.updateContainer(Socks5ProxyConfigModel.getConfig())
|
|
||||||
tempPort = portTextField.textField.text
|
|
||||||
tempUsername = usernameTextField.textField.text
|
|
||||||
tempPassword = passwordTextField.textField.text
|
|
||||||
changeSettingsDrawer.closeTriggered()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: changeSettingsButton
|
id: saveButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.bottomMargin: 24
|
Layout.bottomMargin: 24
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Change connection settings")
|
text: qsTr("Change connection settings")
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
forceActiveFocus()
|
if (!portTextField.textField.acceptableInput) {
|
||||||
changeSettingsDrawer.openTriggered()
|
portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (usernameTextField.textField.text && passwordTextField.textField.text === "") {
|
||||||
|
passwordTextField.errorText = qsTr("Password cannot be empty")
|
||||||
|
return
|
||||||
|
} else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) {
|
||||||
|
usernameTextField.errorText = qsTr("Username cannot be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||||
|
InstallController.updateContainer(Socks5ProxyConfigModel.getConfig())
|
||||||
|
tempPort = portTextField.textField.text
|
||||||
|
tempUsername = usernameTextField.textField.text
|
||||||
|
tempPassword = passwordTextField.textField.text
|
||||||
|
changeSettingsDrawer.closeTriggered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: changeSettingsButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Change connection settings")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
changeSettingsDrawer.openTriggered()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,34 +25,25 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: backButtonLayout
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
BackButtonType {
|
|
||||||
id: backButton
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: backButtonLayout.bottom
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
ColumnLayout {
|
header: ColumnLayout {
|
||||||
id: content
|
width: listView.width
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -61,11 +52,19 @@ PageType {
|
||||||
|
|
||||||
headerText: qsTr("Tor website settings")
|
headerText: qsTr("Tor website settings")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: websiteName
|
id: websiteName
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 32
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
text: qsTr("Website address")
|
text: qsTr("Website address")
|
||||||
descriptionText: {
|
descriptionText: {
|
||||||
|
|
@ -83,15 +82,16 @@ PageType {
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
GC.copyToClipBoard(descriptionText)
|
GC.copyToClipBoard(descriptionText)
|
||||||
PageController.showNotificationMessage(qsTr("Copied"))
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
if (!GC.isMobile()) {
|
|
||||||
this.rightButton.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
ParagraphTextType {
|
ParagraphTextType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 40
|
Layout.topMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,156 +1,167 @@
|
||||||
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"
|
||||||
|
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.fill: parent
|
||||||
contentHeight: content.height
|
|
||||||
|
header: ColumnLayout {
|
||||||
ColumnLayout {
|
width: listView.width
|
||||||
id: content
|
|
||||||
|
BaseHeaderType {
|
||||||
anchors.top: parent.top
|
id: header
|
||||||
anchors.left: parent.left
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
Layout.topMargin: 24
|
||||||
|
Layout.bottomMargin: 16
|
||||||
spacing: 0
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
BaseHeaderType {
|
|
||||||
id: header
|
headerText: qsTr("Settings")
|
||||||
Layout.fillWidth: true
|
}
|
||||||
Layout.topMargin: 24
|
}
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
model: settingsEntries
|
||||||
|
|
||||||
headerText: qsTr("Settings")
|
delegate: ColumnLayout {
|
||||||
}
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
spacing: 0
|
||||||
id: account
|
|
||||||
Layout.fillWidth: true
|
LabelWithButtonType {
|
||||||
Layout.topMargin: 16
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
text: qsTr("Servers")
|
Layout.rightMargin: 16
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
|
||||||
leftImageSource: "qrc:/images/controls/server.svg"
|
visible: isVisible
|
||||||
|
|
||||||
clickedFunction: function() {
|
text: title
|
||||||
PageController.goToPage(PageEnum.PageSettingsServersList)
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
}
|
leftImageSource: leftImagePath
|
||||||
}
|
|
||||||
|
clickedFunction: clickedHandler
|
||||||
DividerType {}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
DividerType {
|
||||||
id: connection
|
visible: isVisible
|
||||||
Layout.fillWidth: true
|
}
|
||||||
|
}
|
||||||
text: qsTr("Connection")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
footer: ColumnLayout {
|
||||||
leftImageSource: "qrc:/images/controls/radio.svg"
|
width: listView.width
|
||||||
|
|
||||||
clickedFunction: function() {
|
LabelWithButtonType {
|
||||||
PageController.goToPage(PageEnum.PageSettingsConnection)
|
id: close
|
||||||
}
|
|
||||||
}
|
visible: GC.isDesktop()
|
||||||
|
Layout.fillWidth: true
|
||||||
DividerType {}
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
LabelWithButtonType {
|
|
||||||
id: application
|
text: qsTr("Close application")
|
||||||
Layout.fillWidth: true
|
leftImageSource: "qrc:/images/controls/x-circle.svg"
|
||||||
|
isLeftImageHoverEnabled: false
|
||||||
text: qsTr("Application")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
clickedFunction: function() {
|
||||||
leftImageSource: "qrc:/images/controls/app.svg"
|
PageController.closeApplication()
|
||||||
|
}
|
||||||
clickedFunction: function() {
|
}
|
||||||
PageController.goToPage(PageEnum.PageSettingsApplication)
|
|
||||||
}
|
DividerType {
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
DividerType {}
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
LabelWithButtonType {
|
visible: GC.isDesktop()
|
||||||
id: backup
|
}
|
||||||
Layout.fillWidth: true
|
}
|
||||||
|
}
|
||||||
text: qsTr("Backup")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
property list<QtObject> settingsEntries: [
|
||||||
leftImageSource: "qrc:/images/controls/save.svg"
|
servers,
|
||||||
|
connection,
|
||||||
clickedFunction: function() {
|
application,
|
||||||
PageController.goToPage(PageEnum.PageSettingsBackup)
|
backup,
|
||||||
}
|
about,
|
||||||
}
|
devConsole
|
||||||
|
]
|
||||||
DividerType {}
|
|
||||||
|
QtObject {
|
||||||
LabelWithButtonType {
|
id: servers
|
||||||
id: about
|
|
||||||
Layout.fillWidth: true
|
property string title: qsTr("Servers")
|
||||||
|
readonly property string leftImagePath: "qrc:/images/controls/server.svg"
|
||||||
text: qsTr("About AmneziaVPN")
|
property bool isVisible: true
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
readonly property var clickedHandler: function() {
|
||||||
leftImageSource: "qrc:/images/controls/amnezia.svg"
|
PageController.goToPage(PageEnum.PageSettingsServersList)
|
||||||
|
}
|
||||||
clickedFunction: function() {
|
}
|
||||||
PageController.goToPage(PageEnum.PageSettingsAbout)
|
|
||||||
}
|
QtObject {
|
||||||
}
|
id: connection
|
||||||
|
|
||||||
DividerType {}
|
property string title: qsTr("Connection")
|
||||||
|
readonly property string leftImagePath: "qrc:/images/controls/radio.svg"
|
||||||
LabelWithButtonType {
|
property bool isVisible: true
|
||||||
id: devConsole
|
readonly property var clickedHandler: function() {
|
||||||
visible: SettingsController.isDevModeEnabled
|
PageController.goToPage(PageEnum.PageSettingsConnection)
|
||||||
Layout.fillWidth: true
|
}
|
||||||
|
}
|
||||||
text: qsTr("Dev console")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
QtObject {
|
||||||
leftImageSource: "qrc:/images/controls/bug.svg"
|
id: application
|
||||||
|
|
||||||
clickedFunction: function() {
|
property string title: qsTr("Application")
|
||||||
PageController.goToPage(PageEnum.PageDevMenu)
|
readonly property string leftImagePath: "qrc:/images/controls/app.svg"
|
||||||
}
|
property bool isVisible: true
|
||||||
}
|
readonly property var clickedHandler: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsApplication)
|
||||||
DividerType {
|
}
|
||||||
visible: SettingsController.isDevModeEnabled
|
}
|
||||||
}
|
|
||||||
|
QtObject {
|
||||||
LabelWithButtonType {
|
id: backup
|
||||||
id: close
|
|
||||||
visible: GC.isDesktop()
|
property string title: qsTr("Backup")
|
||||||
Layout.fillWidth: true
|
readonly property string leftImagePath: "qrc:/images/controls/save.svg"
|
||||||
Layout.preferredHeight: about.height
|
property bool isVisible: true
|
||||||
|
readonly property var clickedHandler: function() {
|
||||||
text: qsTr("Close application")
|
PageController.goToPage(PageEnum.PageSettingsBackup)
|
||||||
leftImageSource: "qrc:/images/controls/x-circle.svg"
|
}
|
||||||
isLeftImageHoverEnabled: false
|
}
|
||||||
|
|
||||||
clickedFunction: function() {
|
QtObject {
|
||||||
PageController.closeApplication()
|
id: about
|
||||||
}
|
|
||||||
}
|
property string title: qsTr("About AmneziaVPN")
|
||||||
|
readonly property string leftImagePath: "qrc:/images/controls/amnezia.svg"
|
||||||
DividerType {
|
property bool isVisible: true
|
||||||
visible: GC.isDesktop()
|
readonly property var clickedHandler: function() {
|
||||||
}
|
PageController.goToPage(PageEnum.PageSettingsAbout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
QtObject {
|
||||||
|
id: devConsole
|
||||||
|
|
||||||
|
property string title: qsTr("Dev console")
|
||||||
|
readonly property string leftImagePath: "qrc:/images/controls/bug.svg"
|
||||||
|
property bool isVisible: SettingsController.isDevModeEnabled
|
||||||
|
readonly property var clickedHandler: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageDevMenu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,58 +29,7 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
ListViewType {
|
||||||
id: telegramGroup
|
|
||||||
|
|
||||||
readonly property string title: qsTr("Telegram group")
|
|
||||||
readonly property string description: qsTr("To discuss features")
|
|
||||||
readonly property string imageSource: "qrc:/images/controls/telegram.svg"
|
|
||||||
readonly property var handler: function() {
|
|
||||||
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: mail
|
|
||||||
|
|
||||||
readonly property string title: qsTr("support@amnezia.org")
|
|
||||||
readonly property string description: qsTr("For reviews and bug reports")
|
|
||||||
readonly property string imageSource: "qrc:/images/controls/mail.svg"
|
|
||||||
readonly property var handler: function() {
|
|
||||||
Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: github
|
|
||||||
|
|
||||||
readonly property string title: qsTr("GitHub")
|
|
||||||
readonly property string description: qsTr("Discover the source code")
|
|
||||||
readonly property string imageSource: "qrc:/images/controls/github.svg"
|
|
||||||
readonly property var handler: function() {
|
|
||||||
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: website
|
|
||||||
|
|
||||||
readonly property string title: qsTr("Website")
|
|
||||||
readonly property string description: qsTr("Visit official website")
|
|
||||||
readonly property string imageSource: "qrc:/images/controls/amnezia.svg"
|
|
||||||
readonly property var handler: function() {
|
|
||||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property list<QtObject> contacts: [
|
|
||||||
telegramGroup,
|
|
||||||
mail,
|
|
||||||
github,
|
|
||||||
website
|
|
||||||
]
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
|
|
@ -88,38 +37,6 @@ PageType {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
model: contacts
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
|
|
@ -170,6 +87,8 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model: contacts
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
|
|
@ -257,4 +176,55 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: telegramGroup
|
||||||
|
|
||||||
|
readonly property string title: qsTr("Telegram group")
|
||||||
|
readonly property string description: qsTr("To discuss features")
|
||||||
|
readonly property string imageSource: "qrc:/images/controls/telegram.svg"
|
||||||
|
readonly property var handler: function() {
|
||||||
|
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: mail
|
||||||
|
|
||||||
|
readonly property string title: qsTr("support@amnezia.org")
|
||||||
|
readonly property string description: qsTr("For reviews and bug reports")
|
||||||
|
readonly property string imageSource: "qrc:/images/controls/mail.svg"
|
||||||
|
readonly property var handler: function() {
|
||||||
|
Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: github
|
||||||
|
|
||||||
|
readonly property string title: qsTr("GitHub")
|
||||||
|
readonly property string description: qsTr("Discover the source code")
|
||||||
|
readonly property string imageSource: "qrc:/images/controls/github.svg"
|
||||||
|
readonly property var handler: function() {
|
||||||
|
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: website
|
||||||
|
|
||||||
|
readonly property string title: qsTr("Website")
|
||||||
|
readonly property string description: qsTr("Visit official website")
|
||||||
|
readonly property string imageSource: "qrc:/images/controls/amnezia.svg"
|
||||||
|
readonly property var handler: function() {
|
||||||
|
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property list<QtObject> contacts: [
|
||||||
|
telegramGroup,
|
||||||
|
mail,
|
||||||
|
github,
|
||||||
|
website
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,220 +1,236 @@
|
||||||
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")
|
||||||
|
|
||||||
ListViewType {
|
BackButtonType {
|
||||||
id: listView
|
id: backButton
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 20
|
anchors.left: parent.left
|
||||||
anchors.bottomMargin: 24
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 20
|
||||||
model: ApiCountryModel
|
}
|
||||||
|
|
||||||
header: ColumnLayout {
|
ListViewType {
|
||||||
width: listView.width
|
id: listView
|
||||||
|
|
||||||
BackButtonType {
|
anchors.top: backButton.bottom
|
||||||
id: backButton
|
anchors.bottom: parent.bottom
|
||||||
}
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
BaseHeaderType {
|
|
||||||
id: header
|
model: ApiCountryModel
|
||||||
|
|
||||||
Layout.fillWidth: true
|
header: ColumnLayout {
|
||||||
Layout.rightMargin: 16
|
width: listView.width
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
BaseHeaderType {
|
||||||
headerText: qsTr("Configuration Files")
|
id: header
|
||||||
descriptionText: qsTr("For router setup or the AmneziaWG app")
|
|
||||||
}
|
Layout.fillWidth: true
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
delegate: ColumnLayout {
|
|
||||||
width: listView.width
|
headerText: qsTr("Configuration Files")
|
||||||
|
descriptionText: qsTr("For router setup or the AmneziaWG app")
|
||||||
LabelWithButtonType {
|
}
|
||||||
Layout.fillWidth: true
|
}
|
||||||
Layout.topMargin: 6
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
text: countryName
|
width: listView.width
|
||||||
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
|
|
||||||
descriptionColor: AmneziaStyle.color.vibrantRed
|
LabelWithButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
|
Layout.topMargin: 6
|
||||||
rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg"
|
|
||||||
|
text: countryName
|
||||||
clickedFunction: function() {
|
descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : ""
|
||||||
if (isIssued) {
|
descriptionColor: AmneziaStyle.color.vibrantRed
|
||||||
moreOptionsDrawer.countryName = countryName
|
|
||||||
moreOptionsDrawer.countryCode = countryCode
|
leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
|
||||||
moreOptionsDrawer.openTriggered()
|
rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg"
|
||||||
} else {
|
|
||||||
issueConfig(countryCode)
|
clickedFunction: function() {
|
||||||
}
|
if (isIssued) {
|
||||||
}
|
moreOptionsDrawer.countryName = countryName
|
||||||
}
|
moreOptionsDrawer.countryCode = countryCode
|
||||||
|
moreOptionsDrawer.openTriggered()
|
||||||
DividerType {}
|
} else {
|
||||||
}
|
issueConfig(countryCode)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
DrawerType2 {
|
}
|
||||||
id: moreOptionsDrawer
|
|
||||||
|
DividerType {}
|
||||||
property string countryName
|
}
|
||||||
property string countryCode
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
DrawerType2 {
|
||||||
expandedHeight: parent.height * 0.4375
|
id: moreOptionsDrawer
|
||||||
|
|
||||||
expandedStateContent: Item {
|
property string countryName
|
||||||
implicitHeight: moreOptionsDrawer.expandedHeight
|
property string countryCode
|
||||||
|
|
||||||
BackButtonType {
|
anchors.fill: parent
|
||||||
id: moreOptionsDrawerBackButton
|
expandedHeight: parent.height * 0.4375
|
||||||
|
|
||||||
anchors.top: parent.top
|
expandedStateContent: Item {
|
||||||
anchors.left: parent.left
|
implicitHeight: moreOptionsDrawer.expandedHeight
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.topMargin: 16
|
BackButtonType {
|
||||||
|
id: moreOptionsDrawerBackButton
|
||||||
backButtonFunction: function() {
|
|
||||||
moreOptionsDrawer.closeTriggered()
|
anchors.top: parent.top
|
||||||
}
|
anchors.left: parent.left
|
||||||
}
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 16
|
||||||
FlickableType {
|
|
||||||
anchors.top: moreOptionsDrawerBackButton.bottom
|
backButtonFunction: function() {
|
||||||
anchors.left: parent.left
|
moreOptionsDrawer.closeTriggered()
|
||||||
anchors.right: parent.right
|
}
|
||||||
anchors.bottom: parent.bottom
|
}
|
||||||
|
|
||||||
contentHeight: moreOptionsDrawerContent.height
|
ListViewType {
|
||||||
|
id: drawerListView
|
||||||
ColumnLayout {
|
|
||||||
id: moreOptionsDrawerContent
|
anchors.top: moreOptionsDrawerBackButton.bottom
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
anchors.top: parent.top
|
anchors.left: parent.left
|
||||||
anchors.left: parent.left
|
anchors.right: parent.right
|
||||||
anchors.right: parent.right
|
|
||||||
|
header: ColumnLayout {
|
||||||
Header2Type {
|
width: drawerListView.width
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: 16
|
Header2Type {
|
||||||
|
Layout.fillWidth: true
|
||||||
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
|
Layout.margins: 16
|
||||||
}
|
|
||||||
|
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
|
||||||
LabelWithButtonType {
|
}
|
||||||
Layout.fillWidth: true
|
}
|
||||||
|
|
||||||
text: qsTr("Generate a new configuration file")
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
descriptionText: qsTr("The previously created one will stop working")
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
clickedFunction: function() {
|
width: drawerListView.width
|
||||||
showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
|
||||||
}
|
LabelWithButtonType {
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
DividerType {}
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
LabelWithButtonType {
|
text: qsTr("Generate a new configuration file")
|
||||||
Layout.fillWidth: true
|
descriptionText: qsTr("The previously created one will stop working")
|
||||||
text: qsTr("Revoke the current configuration file")
|
|
||||||
|
clickedFunction: function() {
|
||||||
clickedFunction: function() {
|
showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
||||||
showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
DividerType {}
|
||||||
DividerType {}
|
}
|
||||||
}
|
|
||||||
}
|
footer: ColumnLayout {
|
||||||
}
|
width: drawerListView.width
|
||||||
}
|
|
||||||
|
LabelWithButtonType {
|
||||||
function issueConfig(countryCode) {
|
Layout.fillWidth: true
|
||||||
var fileName = ""
|
Layout.leftMargin: 16
|
||||||
if (GC.isMobile()) {
|
Layout.rightMargin: 16
|
||||||
fileName = countryCode + configExtension
|
|
||||||
} else {
|
text: qsTr("Revoke the current configuration file")
|
||||||
fileName = SystemController.getFileName(configCaption,
|
|
||||||
qsTr("Config files (*" + configExtension + ")"),
|
clickedFunction: function() {
|
||||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode,
|
showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName)
|
||||||
true,
|
}
|
||||||
configExtension)
|
}
|
||||||
}
|
|
||||||
if (fileName !== "") {
|
DividerType {}
|
||||||
PageController.showBusyIndicator(true)
|
}
|
||||||
let result = ApiConfigsController.exportNativeConfig(countryCode, fileName)
|
}
|
||||||
if (result) {
|
}
|
||||||
ApiSettingsController.getAccountInfo(true)
|
}
|
||||||
}
|
|
||||||
|
function issueConfig(countryCode) {
|
||||||
PageController.showBusyIndicator(false)
|
var fileName = ""
|
||||||
if (result) {
|
if (GC.isMobile()) {
|
||||||
PageController.showNotificationMessage(qsTr("Config file saved"))
|
fileName = countryCode + configExtension
|
||||||
}
|
} else {
|
||||||
}
|
fileName = SystemController.getFileName(configCaption,
|
||||||
}
|
qsTr("Config files (*" + configExtension + ")"),
|
||||||
|
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode,
|
||||||
function revokeConfig(countryCode) {
|
true,
|
||||||
PageController.showBusyIndicator(true)
|
configExtension)
|
||||||
let result = ApiConfigsController.revokeNativeConfig(countryCode)
|
}
|
||||||
if (result) {
|
if (fileName !== "") {
|
||||||
ApiSettingsController.getAccountInfo(true)
|
PageController.showBusyIndicator(true)
|
||||||
}
|
let result = ApiConfigsController.exportNativeConfig(countryCode, fileName)
|
||||||
PageController.showBusyIndicator(false)
|
if (result) {
|
||||||
|
ApiSettingsController.getAccountInfo(true)
|
||||||
if (result) {
|
}
|
||||||
PageController.showNotificationMessage(qsTr("The config has been revoked"))
|
|
||||||
}
|
PageController.showBusyIndicator(false)
|
||||||
}
|
if (result) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Config file saved"))
|
||||||
function showQuestion(isConfigIssue, countryCode, countryName) {
|
}
|
||||||
var headerText
|
}
|
||||||
if (isConfigIssue) {
|
}
|
||||||
headerText = qsTr("Generate a new %1 configuration file?").arg(countryName)
|
|
||||||
} else {
|
function revokeConfig(countryCode) {
|
||||||
headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName)
|
PageController.showBusyIndicator(true)
|
||||||
}
|
let result = ApiConfigsController.revokeNativeConfig(countryCode)
|
||||||
|
if (result) {
|
||||||
var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it")
|
ApiSettingsController.getAccountInfo(true)
|
||||||
var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue")
|
}
|
||||||
var noButtonText = qsTr("Cancel")
|
PageController.showBusyIndicator(false)
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
if (result) {
|
||||||
if (isConfigIssue) {
|
PageController.showNotificationMessage(qsTr("The config has been revoked"))
|
||||||
issueConfig(countryCode)
|
}
|
||||||
} else {
|
}
|
||||||
revokeConfig(countryCode)
|
|
||||||
}
|
function showQuestion(isConfigIssue, countryCode, countryName) {
|
||||||
moreOptionsDrawer.closeTriggered()
|
var headerText
|
||||||
}
|
if (isConfigIssue) {
|
||||||
var noButtonFunction = function() {
|
headerText = qsTr("Generate a new %1 configuration file?").arg(countryName)
|
||||||
}
|
} else {
|
||||||
|
headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName)
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
}
|
||||||
}
|
|
||||||
}
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,32 +158,6 @@ PageType {
|
||||||
|
|
||||||
readonly property bool isVisibleForAmneziaFree: ApiAccountInfoModel.data("isComponentVisible")
|
readonly property bool isVisibleForAmneziaFree: ApiAccountInfoModel.data("isComponentVisible")
|
||||||
|
|
||||||
SwitcherType {
|
|
||||||
id: switcher
|
|
||||||
|
|
||||||
readonly property bool isVlessProtocol: ApiConfigsController.isVlessProtocol()
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
|
|
||||||
visible: ApiAccountInfoModel.data("isProtocolSelectionSupported")
|
|
||||||
|
|
||||||
text: qsTr("Use VLESS protocol")
|
|
||||||
checked: switcher.isVlessProtocol
|
|
||||||
onToggled: function() {
|
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Cannot change protocol during active connection"))
|
|
||||||
} else {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
ApiConfigsController.setCurrentProtocol(switcher.isVlessProtocol ? "awg" : "vless")
|
|
||||||
ApiConfigsController.updateServiceFromGateway(ServersModel.processedIndex, "", "", true)
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WarningType {
|
WarningType {
|
||||||
id: warning
|
id: warning
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ PageType {
|
||||||
readonly property string name: qsTr("Only the apps from the list should have access via VPN")
|
readonly property string name: qsTr("Only the apps from the list should have access via VPN")
|
||||||
readonly property int type: routeMode.onlyForwardApps
|
readonly property int type: routeMode.onlyForwardApps
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: allExceptApps
|
id: allExceptApps
|
||||||
|
|
||||||
|
|
@ -146,77 +147,56 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
|
id: listView
|
||||||
|
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
anchors.topMargin: 16
|
anchors.bottom: addAppButton.top
|
||||||
contentHeight: col.implicitHeight + addAppButton.implicitHeight + addAppButton.anchors.bottomMargin + addAppButton.anchors.topMargin
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
enabled: root.pageEnabled
|
model: SortFilterProxyModel {
|
||||||
|
id: proxyAppSplitTunnelingModel
|
||||||
|
sourceModel: AppSplitTunnelingModel
|
||||||
|
filters: RegExpFilter {
|
||||||
|
roleName: "appPath"
|
||||||
|
pattern: ".*" + searchField.textField.text + ".*"
|
||||||
|
caseSensitivity: Qt.CaseInsensitive
|
||||||
|
}
|
||||||
|
sorters: [
|
||||||
|
RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
delegate: ColumnLayout {
|
||||||
id: col
|
width: listView.width
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
ListView {
|
LabelWithButtonType {
|
||||||
id: apps
|
Layout.fillWidth: true
|
||||||
width: parent.width
|
|
||||||
height: apps.contentItem.height
|
|
||||||
|
|
||||||
model: SortFilterProxyModel {
|
Layout.leftMargin: 16
|
||||||
id: proxyAppSplitTunnelingModel
|
Layout.rightMargin: 16
|
||||||
sourceModel: AppSplitTunnelingModel
|
|
||||||
filters: RegExpFilter {
|
text: appPath
|
||||||
roleName: "appPath"
|
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||||
pattern: ".*" + searchField.textField.text + ".*"
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
caseSensitivity: Qt.CaseInsensitive
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var headerText = qsTr("Remove ") + appPath + "?"
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index))
|
||||||
}
|
}
|
||||||
sorters: [
|
var noButtonFunction = function() {
|
||||||
RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
interactive: false
|
|
||||||
|
|
||||||
delegate: Item {
|
|
||||||
implicitWidth: apps.width
|
|
||||||
implicitHeight: delegateContent.implicitHeight
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: delegateContent
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: appPath
|
|
||||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
var headerText = qsTr("Remove ") + appPath + "?"
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index))
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,20 +23,16 @@ PageType {
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.height
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
ColumnLayout {
|
header: ColumnLayout {
|
||||||
id: content
|
width: listView.width
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -45,9 +41,17 @@ PageType {
|
||||||
|
|
||||||
headerText: qsTr("Application")
|
headerText: qsTr("Application")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcher
|
id: switcherAllowScreenshots
|
||||||
|
|
||||||
visible: GC.isMobile()
|
visible: GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -61,10 +65,6 @@ PageType {
|
||||||
SettingsController.toggleScreenshotsEnabled(checked)
|
SettingsController.toggleScreenshotsEnabled(checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
|
|
||||||
// labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
|
|
||||||
parentFlickable: fl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
|
|
@ -73,15 +73,15 @@ PageType {
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonNotification
|
id: labelWithButtonNotification
|
||||||
|
|
||||||
visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted
|
visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Enable notifications")
|
text: qsTr("Enable notifications")
|
||||||
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
|
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
SettingsController.requestNotificationPermission()
|
SettingsController.requestNotificationPermission()
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +93,7 @@ PageType {
|
||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcherAutoStart
|
id: switcherAutoStart
|
||||||
|
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -101,8 +102,6 @@ PageType {
|
||||||
text: qsTr("Auto start")
|
text: qsTr("Auto start")
|
||||||
descriptionText: qsTr("Launch the application every time the device is starts")
|
descriptionText: qsTr("Launch the application every time the device is starts")
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
checked: SettingsController.isAutoStartEnabled()
|
checked: SettingsController.isAutoStartEnabled()
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (checked !== SettingsController.isAutoStartEnabled()) {
|
if (checked !== SettingsController.isAutoStartEnabled()) {
|
||||||
|
|
@ -117,6 +116,7 @@ PageType {
|
||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcherAutoConnect
|
id: switcherAutoConnect
|
||||||
|
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -125,8 +125,6 @@ PageType {
|
||||||
text: qsTr("Auto connect")
|
text: qsTr("Auto connect")
|
||||||
descriptionText: qsTr("Connect to VPN on app start")
|
descriptionText: qsTr("Connect to VPN on app start")
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
checked: SettingsController.isAutoConnectEnabled()
|
checked: SettingsController.isAutoConnectEnabled()
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (checked !== SettingsController.isAutoConnectEnabled()) {
|
if (checked !== SettingsController.isAutoConnectEnabled()) {
|
||||||
|
|
@ -141,6 +139,7 @@ PageType {
|
||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: switcherStartMinimized
|
id: switcherStartMinimized
|
||||||
|
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -149,8 +148,6 @@ PageType {
|
||||||
text: qsTr("Start minimized")
|
text: qsTr("Start minimized")
|
||||||
descriptionText: qsTr("Launch application minimized")
|
descriptionText: qsTr("Launch application minimized")
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
checked: SettingsController.isStartMinimizedEnabled()
|
checked: SettingsController.isStartMinimizedEnabled()
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (checked !== SettingsController.isStartMinimizedEnabled()) {
|
if (checked !== SettingsController.isStartMinimizedEnabled()) {
|
||||||
|
|
@ -162,17 +159,21 @@ PageType {
|
||||||
DividerType {
|
DividerType {
|
||||||
visible: !GC.isMobile()
|
visible: !GC.isMobile()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonLanguage
|
id: labelWithButtonLanguage
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Language")
|
text: qsTr("Language")
|
||||||
descriptionText: LanguageModel.currentLanguageName
|
descriptionText: LanguageModel.currentLanguageName
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
selectLanguageDrawer.openTriggered()
|
selectLanguageDrawer.openTriggered()
|
||||||
}
|
}
|
||||||
|
|
@ -182,14 +183,13 @@ PageType {
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonLogging
|
id: labelWithButtonLogging
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Logging")
|
text: qsTr("Logging")
|
||||||
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsLogging)
|
PageController.goToPage(PageEnum.PageSettingsLogging)
|
||||||
}
|
}
|
||||||
|
|
@ -199,14 +199,13 @@ PageType {
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButtonReset
|
id: labelWithButtonReset
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Reset settings and remove all data from the application")
|
text: qsTr("Reset settings and remove all data from the application")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
var headerText = qsTr("Reset settings and remove all data from the application?")
|
var headerText = qsTr("Reset settings and remove all data from the application?")
|
||||||
var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
|
var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
|
||||||
|
|
|
||||||
|
|
@ -43,49 +43,60 @@ PageType {
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.height
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
ColumnLayout {
|
header: ColumnLayout {
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
width: listView.width
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Back up your configuration")
|
headerText: qsTr("Back up your configuration")
|
||||||
descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.")
|
descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
WarningType {
|
WarningType {
|
||||||
Layout.topMargin: 16
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
textString: qsTr("The backup will contain your passwords and private keys for all servers added " +
|
textString: qsTr("The backup will contain your passwords and private keys for all servers added " +
|
||||||
"to AmneziaVPN. Keep this information in a secure place.")
|
"to AmneziaVPN. Keep this information in a secure place.")
|
||||||
|
|
||||||
iconPath: "qrc:/images/controls/alert-circle.svg"
|
iconPath: "qrc:/images/controls/alert-circle.svg"
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: makeBackupButton
|
id: makeBackupButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 14
|
Layout.topMargin: 14
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Make a backup")
|
text: qsTr("Make a backup")
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
var fileName = ""
|
var fileName = ""
|
||||||
if (GC.isMobile()) {
|
if (GC.isMobile()) {
|
||||||
|
|
@ -108,8 +119,11 @@ PageType {
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: restoreBackupButton
|
id: restoreBackupButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: -8
|
Layout.topMargin: -8
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
|
@ -120,8 +134,6 @@ PageType {
|
||||||
|
|
||||||
text: qsTr("Restore from backup")
|
text: qsTr("Restore from backup")
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
var filePath = SystemController.getFileName(qsTr("Open backup file"),
|
var filePath = SystemController.getFileName(qsTr("Open backup file"),
|
||||||
qsTr("Backup files (*.backup)"))
|
qsTr("Backup files (*.backup)"))
|
||||||
|
|
|
||||||
|
|
@ -23,18 +23,17 @@ PageType {
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.height
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
ColumnLayout {
|
header: ColumnLayout {
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
width: listView.width
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -43,9 +42,17 @@ PageType {
|
||||||
|
|
||||||
headerText: qsTr("Connection")
|
headerText: qsTr("Connection")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
SwitcherType {
|
SwitcherType {
|
||||||
id: amneziaDnsSwitch
|
id: amneziaDnsSwitch
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: 16
|
Layout.margins: 16
|
||||||
|
|
||||||
|
|
@ -64,14 +71,13 @@ PageType {
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: dnsServersButton
|
id: dnsServersButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("DNS servers")
|
text: qsTr("DNS servers")
|
||||||
descriptionText: qsTr("When AmneziaDNS is not used or installed")
|
descriptionText: qsTr("When AmneziaDNS is not used or installed")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsDns)
|
PageController.goToPage(PageEnum.PageSettingsDns)
|
||||||
}
|
}
|
||||||
|
|
@ -81,14 +87,13 @@ PageType {
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: splitTunnelingButton
|
id: splitTunnelingButton
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Site-based split tunneling")
|
text: qsTr("Site-based split tunneling")
|
||||||
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
|
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||||
}
|
}
|
||||||
|
|
@ -96,8 +101,15 @@ PageType {
|
||||||
|
|
||||||
DividerType {}
|
DividerType {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: splitTunnelingButton2
|
id: splitTunnelingButton2
|
||||||
|
|
||||||
visible: root.isAppSplitTinnelingEnabled
|
visible: root.isAppSplitTinnelingEnabled
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -106,8 +118,6 @@ PageType {
|
||||||
descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
|
descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||||
}
|
}
|
||||||
|
|
@ -127,8 +137,6 @@ PageType {
|
||||||
descriptionText: qsTr("Blocks network connections without VPN")
|
descriptionText: qsTr("Blocks network connections without VPN")
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
PageController.goToPage(PageEnum.PageSettingsKillSwitch)
|
PageController.goToPage(PageEnum.PageSettingsKillSwitch)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,140 +1,167 @@
|
||||||
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
|
||||||
}
|
|
||||||
|
onFocusChanged: {
|
||||||
FlickableType {
|
if (this.activeFocus) {
|
||||||
id: fl
|
listView.positionViewAtBeginning()
|
||||||
anchors.top: backButton.bottom
|
}
|
||||||
anchors.bottom: parent.bottom
|
}
|
||||||
contentHeight: content.height
|
}
|
||||||
|
|
||||||
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
|
ListViewType {
|
||||||
|
id: listView
|
||||||
enabled: !isServerFromApi
|
|
||||||
|
anchors.top: backButton.bottom
|
||||||
Component.onCompleted: {
|
anchors.bottom: parent.bottom
|
||||||
if (isServerFromApi) {
|
anchors.right: parent.right
|
||||||
PageController.showNotificationMessage(qsTr("Default server does not support custom DNS"))
|
anchors.left: parent.left
|
||||||
}
|
|
||||||
}
|
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
|
||||||
|
|
||||||
ColumnLayout {
|
enabled: !isServerFromApi
|
||||||
id: content
|
|
||||||
|
Component.onCompleted: {
|
||||||
anchors.top: parent.top
|
if (isServerFromApi) {
|
||||||
anchors.left: parent.left
|
PageController.showNotificationMessage(qsTr("Default server does not support custom DNS"))
|
||||||
anchors.right: parent.right
|
}
|
||||||
anchors.leftMargin: 16
|
}
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
header: ColumnLayout {
|
||||||
spacing: 16
|
width: listView.width
|
||||||
|
spacing: 16
|
||||||
BaseHeaderType {
|
|
||||||
Layout.fillWidth: true
|
BaseHeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
headerText: qsTr("DNS servers")
|
Layout.leftMargin: 16
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
ParagraphTextType {
|
headerText: qsTr("DNS servers")
|
||||||
Layout.fillWidth: true
|
}
|
||||||
text: qsTr("If AmneziaDNS is not used or installed")
|
|
||||||
}
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
TextFieldWithHeaderType {
|
Layout.leftMargin: 16
|
||||||
id: primaryDns
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
Layout.fillWidth: true
|
text: qsTr("If AmneziaDNS is not used or installed")
|
||||||
headerText: qsTr("Primary DNS")
|
}
|
||||||
|
|
||||||
textField.text: SettingsController.primaryDns
|
TextFieldWithHeaderType {
|
||||||
textField.validator: RegularExpressionValidator {
|
id: primaryDns
|
||||||
regularExpression: InstallController.ipAddressRegExp()
|
|
||||||
}
|
Layout.fillWidth: true
|
||||||
}
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
TextFieldWithHeaderType {
|
|
||||||
id: secondaryDns
|
headerText: qsTr("Primary DNS")
|
||||||
|
|
||||||
Layout.fillWidth: true
|
textField.text: SettingsController.primaryDns
|
||||||
headerText: qsTr("Secondary DNS")
|
textField.validator: RegularExpressionValidator {
|
||||||
|
regularExpression: InstallController.ipAddressRegExp()
|
||||||
textField.text: SettingsController.secondaryDns
|
}
|
||||||
textField.validator: RegularExpressionValidator {
|
}
|
||||||
regularExpression: InstallController.ipAddressRegExp()
|
|
||||||
}
|
TextFieldWithHeaderType {
|
||||||
}
|
id: secondaryDns
|
||||||
|
|
||||||
BasicButtonType {
|
Layout.fillWidth: true
|
||||||
id: restoreDefaultButton
|
Layout.leftMargin: 16
|
||||||
Layout.fillWidth: true
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
headerText: qsTr("Secondary DNS")
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
|
||||||
pressedColor: AmneziaStyle.color.sheerWhite
|
textField.text: SettingsController.secondaryDns
|
||||||
disabledColor: AmneziaStyle.color.mutedGray
|
textField.validator: RegularExpressionValidator {
|
||||||
textColor: AmneziaStyle.color.paleGray
|
regularExpression: InstallController.ipAddressRegExp()
|
||||||
borderWidth: 1
|
}
|
||||||
|
}
|
||||||
text: qsTr("Restore default")
|
}
|
||||||
|
|
||||||
clickedFunc: function() {
|
model: 1 // fake model to force the ListView to be created without a model
|
||||||
var headerText = qsTr("Restore default DNS settings?")
|
spacing: 16
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
var yesButtonFunction = function() {
|
|
||||||
SettingsController.primaryDns = "1.1.1.1"
|
BasicButtonType {
|
||||||
primaryDns.textField.text = SettingsController.primaryDns
|
id: restoreDefaultButton
|
||||||
SettingsController.secondaryDns = "1.0.0.1"
|
|
||||||
secondaryDns.textField.text = SettingsController.secondaryDns
|
Layout.fillWidth: true
|
||||||
PageController.showNotificationMessage(qsTr("Settings have been reset"))
|
Layout.topMargin: 16
|
||||||
}
|
Layout.leftMargin: 16
|
||||||
var noButtonFunction = function() {
|
Layout.rightMargin: 16
|
||||||
}
|
|
||||||
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
}
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
}
|
disabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
textColor: AmneziaStyle.color.paleGray
|
||||||
BasicButtonType {
|
borderWidth: 1
|
||||||
id: saveButton
|
|
||||||
|
text: qsTr("Restore default")
|
||||||
Layout.fillWidth: true
|
|
||||||
|
clickedFunc: function() {
|
||||||
text: qsTr("Save")
|
var headerText = qsTr("Restore default DNS settings?")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
clickedFunc: function() {
|
var noButtonText = qsTr("Cancel")
|
||||||
if (primaryDns.textField.text !== SettingsController.primaryDns) {
|
|
||||||
SettingsController.primaryDns = primaryDns.textField.text
|
var yesButtonFunction = function() {
|
||||||
}
|
SettingsController.primaryDns = "1.1.1.1"
|
||||||
if (secondaryDns.textField.text !== SettingsController.secondaryDns) {
|
primaryDns.textField.text = SettingsController.primaryDns
|
||||||
SettingsController.secondaryDns = secondaryDns.textField.text
|
SettingsController.secondaryDns = "1.0.0.1"
|
||||||
}
|
secondaryDns.textField.text = SettingsController.secondaryDns
|
||||||
PageController.showNotificationMessage(qsTr("Settings saved"))
|
PageController.showNotificationMessage(qsTr("Settings have been reset"))
|
||||||
}
|
}
|
||||||
}
|
var noButtonFunction = function() {
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,7 @@ PageType {
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
visible: false
|
visible: false
|
||||||
enabled: false
|
enabled: false //SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||||
// enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
|
||||||
checked: SettingsController.strictKillSwitchEnabled
|
checked: SettingsController.strictKillSwitchEnabled
|
||||||
|
|
||||||
text: qsTr("Strict KillSwitch")
|
text: qsTr("Strict KillSwitch")
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ PageType {
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
|
|
@ -33,10 +33,6 @@ PageType {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
|
|
@ -101,8 +97,7 @@ PageType {
|
||||||
}
|
}
|
||||||
|
|
||||||
model: logTypes
|
model: logTypes
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
snapMode: ListView.SnapOneItem
|
snapMode: ListView.SnapOneItem
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,6 @@ PageType {
|
||||||
|
|
||||||
signal lastItemTabClickedSignal()
|
signal lastItemTabClickedSignal()
|
||||||
|
|
||||||
onFocusChanged: content.isServerWithWriteAccess ?
|
|
||||||
labelWithButton.forceActiveFocus() :
|
|
||||||
labelWithButton3.forceActiveFocus()
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: InstallController
|
target: InstallController
|
||||||
|
|
||||||
|
|
@ -63,218 +59,194 @@ PageType {
|
||||||
target: ServersModel
|
target: ServersModel
|
||||||
|
|
||||||
function onProcessedServerIndexChanged() {
|
function onProcessedServerIndexChanged() {
|
||||||
content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
|
listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
id: fl
|
id: listView
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
contentHeight: content.height
|
|
||||||
|
|
||||||
ColumnLayout {
|
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.fill: parent
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
|
model: serverActions
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: labelWithButton
|
|
||||||
visible: content.isServerWithWriteAccess
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Check the server for previously installed Amnezia services")
|
visible: isVisible
|
||||||
descriptionText: qsTr("Add them to the application if they were not displayed")
|
|
||||||
|
text: title
|
||||||
|
descriptionText: description
|
||||||
|
textColor: tColor
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
|
clickedHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: isVisible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property list<QtObject> serverActions: [
|
||||||
|
check,
|
||||||
|
reboot,
|
||||||
|
remove,
|
||||||
|
clear,
|
||||||
|
reset,
|
||||||
|
switch_to_premium,
|
||||||
|
]
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: check
|
||||||
|
|
||||||
|
property bool isVisible: true
|
||||||
|
readonly property string title: qsTr("Check the server for previously installed Amnezia services")
|
||||||
|
readonly property string description: qsTr("Add them to the application if they were not displayed")
|
||||||
|
readonly property var tColor: AmneziaStyle.color.paleGray
|
||||||
|
readonly property var clickedHandler: function() {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.scanServerForInstalledContainers()
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: reboot
|
||||||
|
|
||||||
|
property bool isVisible: true
|
||||||
|
readonly property string title: qsTr("Reboot server")
|
||||||
|
readonly property string description: ""
|
||||||
|
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||||
|
readonly property var clickedHandler: function() {
|
||||||
|
var headerText = qsTr("Do you want to reboot the server?")
|
||||||
|
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection"))
|
||||||
|
} else {
|
||||||
PageController.showBusyIndicator(true)
|
PageController.showBusyIndicator(true)
|
||||||
InstallController.scanServerForInstalledContainers()
|
InstallController.rebootProcessedServer()
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: content.isServerWithWriteAccess
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
id: labelWithButton2
|
}
|
||||||
visible: content.isServerWithWriteAccess
|
}
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Reboot server")
|
QtObject {
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
id: remove
|
||||||
|
|
||||||
clickedFunction: function() {
|
property bool isVisible: true
|
||||||
var headerText = qsTr("Do you want to reboot the server?")
|
readonly property string title: qsTr("Remove server from application")
|
||||||
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
|
readonly property string description: ""
|
||||||
var yesButtonText = qsTr("Continue")
|
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||||
var noButtonText = qsTr("Cancel")
|
readonly property var clickedHandler: function() {
|
||||||
|
var headerText = qsTr("Do you want to remove the server from application?")
|
||||||
|
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection"))
|
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
||||||
} else {
|
} else {
|
||||||
PageController.showBusyIndicator(true)
|
PageController.showBusyIndicator(true)
|
||||||
InstallController.rebootProcessedServer()
|
InstallController.removeProcessedServer()
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
}
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton5.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton2.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: content.isServerWithWriteAccess
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
id: labelWithButton3
|
}
|
||||||
Layout.fillWidth: true
|
}
|
||||||
|
|
||||||
text: qsTr("Remove server from application")
|
QtObject {
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
id: clear
|
||||||
|
|
||||||
clickedFunction: function() {
|
property bool isVisible: true
|
||||||
var headerText = qsTr("Do you want to remove the server from application?")
|
readonly property string title: qsTr("Clear server from Amnezia software")
|
||||||
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
|
readonly property string description: ""
|
||||||
var yesButtonText = qsTr("Continue")
|
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||||
var noButtonText = qsTr("Cancel")
|
readonly property var clickedHandler: function() {
|
||||||
|
var headerText = qsTr("Do you want to clear server from Amnezia software?")
|
||||||
|
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection"))
|
||||||
} else {
|
} else {
|
||||||
PageController.showBusyIndicator(true)
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
InstallController.removeProcessedServer()
|
InstallController.removeAllContainers()
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton5.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton3.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
|
||||||
DividerType {}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
id: labelWithButton4
|
}
|
||||||
visible: content.isServerWithWriteAccess
|
}
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Clear server from Amnezia software")
|
QtObject {
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
id: reset
|
||||||
|
|
||||||
clickedFunction: function() {
|
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||||
var headerText = qsTr("Do you want to clear server from Amnezia software?")
|
readonly property string title: qsTr("Reset API config")
|
||||||
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
|
readonly property string description: ""
|
||||||
var yesButtonText = qsTr("Continue")
|
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||||
var noButtonText = qsTr("Cancel")
|
readonly property var clickedHandler: function() {
|
||||||
|
var headerText = qsTr("Do you want to reset API config?")
|
||||||
|
var descriptionText = ""
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
var yesButtonFunction = function() {
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection"))
|
PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection"))
|
||||||
} else {
|
} else {
|
||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
PageController.showBusyIndicator(true)
|
||||||
InstallController.removeAllContainers()
|
InstallController.removeApiConfig(ServersModel.processedIndex)
|
||||||
}
|
PageController.showBusyIndicator(false)
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton5.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton4.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: content.isServerWithWriteAccess
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelWithButtonType {
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
id: labelWithButton5
|
}
|
||||||
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
}
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Reset API config")
|
QtObject {
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
id: switch_to_premium
|
||||||
|
|
||||||
clickedFunction: function() {
|
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||||
var headerText = qsTr("Do you want to reset API config?")
|
readonly property string title: qsTr("Switch to the new Amnezia Premium subscription")
|
||||||
var descriptionText = ""
|
readonly property string description: ""
|
||||||
var yesButtonText = qsTr("Continue")
|
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||||
var noButtonText = qsTr("Cancel")
|
readonly property var clickedHandler: function() {
|
||||||
|
PageController.goToPageHome()
|
||||||
var yesButtonFunction = function() {
|
ApiPremV1MigrationController.showMigrationDrawer()
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection"))
|
|
||||||
} else {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
InstallController.removeApiConfig(ServersModel.processedIndex)
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton5.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
labelWithButton5.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: labelWithButton6
|
|
||||||
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Switch to the new Amnezia Premium subscription")
|
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
PageController.goToPageHome()
|
|
||||||
ApiPremV1MigrationController.showMigrationDrawer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,249 +21,205 @@ PageType {
|
||||||
|
|
||||||
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
|
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
|
||||||
|
|
||||||
ColumnLayout {
|
BackButtonType {
|
||||||
id: header
|
id: backButton
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
BackButtonType {
|
ListViewType {
|
||||||
id: backButton
|
id: listView
|
||||||
}
|
|
||||||
|
|
||||||
BaseHeaderType {
|
anchors.top: backButton.bottom
|
||||||
Layout.fillWidth: true
|
anchors.bottom: parent.bottom
|
||||||
Layout.leftMargin: 16
|
anchors.right: parent.right
|
||||||
Layout.rightMargin: 16
|
anchors.left: parent.left
|
||||||
Layout.bottomMargin: 32
|
|
||||||
|
|
||||||
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
header: ColumnLayout {
|
||||||
}
|
width: listView.width
|
||||||
|
|
||||||
ListView {
|
BaseHeaderType {
|
||||||
id: protocols
|
Layout.fillWidth: true
|
||||||
Layout.fillWidth: true
|
Layout.leftMargin: 16
|
||||||
height: protocols.contentItem.height
|
Layout.rightMargin: 16
|
||||||
clip: true
|
Layout.bottomMargin: 32
|
||||||
interactive: true
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
model: ProtocolsModel
|
|
||||||
|
|
||||||
delegate: Item {
|
|
||||||
implicitWidth: protocols.width
|
|
||||||
implicitHeight: delegateContent.implicitHeight
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: delegateContent
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg
|
|
||||||
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: clientSettings
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: protocolName + qsTr(" connection settings")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
|
||||||
visible: delegateContent.isClientSettingsVisible
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
if (isClientProtocolExists) {
|
|
||||||
switch (protocolIndex) {
|
|
||||||
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
}
|
|
||||||
PageController.goToPage(clientProtocolPage);
|
|
||||||
} else {
|
|
||||||
PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: clientSettings
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: delegateContent.isClientSettingsVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: serverSettings
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: protocolName + qsTr(" server settings")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
|
||||||
visible: delegateContent.isServerSettingsVisible
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
switch (protocolIndex) {
|
|
||||||
case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
|
||||||
}
|
|
||||||
PageController.goToPage(serverProtocolPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: serverSettings
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
visible: delegateContent.isServerSettingsVisible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: ColumnLayout {
|
|
||||||
width: header.width
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: clearCacheButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
visible: root.isClearCacheVisible
|
|
||||||
|
|
||||||
text: qsTr("Clear profile")
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
|
|
||||||
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
|
|
||||||
PageController.showNotificationMessage(message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
InstallController.clearCachedProfile()
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
// if (!GC.isMobile()) {
|
|
||||||
// focusItem.forceActiveFocus()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: clearCacheButton
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
visible: root.isClearCacheVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelWithButtonType {
|
|
||||||
id: removeButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
|
||||||
|
|
||||||
text: qsTr("Remove ")
|
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
|
||||||
|
|
||||||
clickedFunction: function() {
|
|
||||||
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
|
||||||
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
|
|
||||||
var yesButtonText = qsTr("Continue")
|
|
||||||
var noButtonText = qsTr("Cancel")
|
|
||||||
|
|
||||||
var yesButtonFunction = function() {
|
|
||||||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
|
||||||
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
|
||||||
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
PageController.goToPage(PageEnum.PageDeinstalling)
|
|
||||||
InstallController.removeProcessedContainer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var noButtonFunction = function() {
|
|
||||||
if (!GC.isMobile()) {
|
|
||||||
focusItem.forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: removeButton
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
enabled: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerType {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 16
|
|
||||||
Layout.rightMargin: 16
|
|
||||||
|
|
||||||
visible: ServersModel.isProcessedServerHasWriteAccess()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model: ProtocolsModel
|
||||||
|
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
id: delegateContent
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg
|
||||||
|
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: clientSettings
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: protocolName + qsTr(" connection settings")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
visible: delegateContent.isClientSettingsVisible
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
if (isClientProtocolExists) {
|
||||||
|
switch (protocolIndex) {
|
||||||
|
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
}
|
||||||
|
PageController.goToPage(clientProtocolPage);
|
||||||
|
} else {
|
||||||
|
PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: clientSettings
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: delegateContent.isClientSettingsVisible
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: serverSettings
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: protocolName + qsTr(" server settings")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
visible: delegateContent.isServerSettingsVisible
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
switch (protocolIndex) {
|
||||||
|
case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break;
|
||||||
|
}
|
||||||
|
PageController.goToPage(serverProtocolPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: serverSettings
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: delegateContent.isServerSettingsVisible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: clearCacheButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: root.isClearCacheVisible
|
||||||
|
|
||||||
|
text: qsTr("Clear profile")
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
|
||||||
|
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
|
||||||
|
PageController.showNotificationMessage(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
InstallController.clearCachedProfile()
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: clearCacheButton
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: root.isClearCacheVisible
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
id: removeButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
|
||||||
|
text: qsTr("Remove ")
|
||||||
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
|
||||||
|
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
|
var noButtonText = qsTr("Cancel")
|
||||||
|
|
||||||
|
var yesButtonFunction = function() {
|
||||||
|
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
||||||
|
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||||
|
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
PageController.goToPage(PageEnum.PageDeinstalling)
|
||||||
|
InstallController.removeProcessedContainer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var noButtonFunction = function() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: removeButton
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: ServersModel.isProcessedServerHasWriteAccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,25 +40,20 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: servers
|
id: servers
|
||||||
objectName: "servers"
|
objectName: "servers"
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
anchors.topMargin: 16
|
anchors.topMargin: 16
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
height: 500
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
model: ServersModel
|
model: ServersModel
|
||||||
|
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
implicitWidth: servers.width
|
implicitWidth: servers.width
|
||||||
implicitHeight: delegateContent.implicitHeight
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
|
||||||
|
|
@ -1,445 +1,450 @@
|
||||||
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 ProtocolEnum 1.0
|
import ProtocolEnum 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 "../Config"
|
import "../Config"
|
||||||
import "../Components"
|
import "../Components"
|
||||||
|
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var isServerFromTelegramApi: ServersModel.getDefaultServerData("isServerFromTelegramApi")
|
property var isServerFromTelegramApi: ServersModel.getDefaultServerData("isServerFromTelegramApi")
|
||||||
|
|
||||||
property bool pageEnabled
|
property bool pageEnabled
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (ConnectionController.isConnected) {
|
if (ConnectionController.isConnected) {
|
||||||
PageController.showNotificationMessage(qsTr("Cannot change split tunneling settings during active connection"))
|
PageController.showNotificationMessage(qsTr("Cannot change split tunneling settings during active connection"))
|
||||||
root.pageEnabled = false
|
root.pageEnabled = false
|
||||||
} else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling) {
|
} else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling) {
|
||||||
PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function"))
|
PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function"))
|
||||||
root.pageEnabled = false
|
root.pageEnabled = false
|
||||||
} else {
|
} else {
|
||||||
root.pageEnabled = true
|
root.pageEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SitesController
|
target: SitesController
|
||||||
|
|
||||||
function onFinished(message) {
|
function onFinished(message) {
|
||||||
PageController.showNotificationMessage(message)
|
PageController.showNotificationMessage(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onErrorOccurred(errorMessage) {
|
function onErrorOccurred(errorMessage) {
|
||||||
PageController.showErrorMessage(errorMessage)
|
PageController.showErrorMessage(errorMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: routeMode
|
id: routeMode
|
||||||
property int allSites: 0
|
property int allSites: 0
|
||||||
property int onlyForwardSites: 1
|
property int onlyForwardSites: 1
|
||||||
property int allExceptSites: 2
|
property int allExceptSites: 2
|
||||||
}
|
}
|
||||||
|
|
||||||
property list<QtObject> routeModesModel: [
|
property list<QtObject> routeModesModel: [
|
||||||
onlyForwardSites,
|
onlyForwardSites,
|
||||||
allExceptSites
|
allExceptSites
|
||||||
]
|
]
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: onlyForwardSites
|
id: onlyForwardSites
|
||||||
property string name: qsTr("Only the sites listed here will be accessed through the VPN")
|
property string name: qsTr("Only the sites listed here will be accessed through the VPN")
|
||||||
property int type: routeMode.onlyForwardSites
|
property int type: routeMode.onlyForwardSites
|
||||||
}
|
}
|
||||||
QtObject {
|
QtObject {
|
||||||
id: allExceptSites
|
id: allExceptSites
|
||||||
property string name: qsTr("Addresses from the list should not be accessed via VPN")
|
property string name: qsTr("Addresses from the list should not be accessed via VPN")
|
||||||
property int type: routeMode.allExceptSites
|
property int type: routeMode.allExceptSites
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRouteModesModelIndex() {
|
function getRouteModesModelIndex() {
|
||||||
var currentRouteMode = SitesModel.routeMode
|
var currentRouteMode = SitesModel.routeMode
|
||||||
if ((routeMode.onlyForwardSites === currentRouteMode) || (routeMode.allSites === currentRouteMode)) {
|
if ((routeMode.onlyForwardSites === currentRouteMode) || (routeMode.allSites === currentRouteMode)) {
|
||||||
return 0
|
return 0
|
||||||
} else if (routeMode.allExceptSites === currentRouteMode) {
|
} else if (routeMode.allExceptSites === currentRouteMode) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
BackButtonType {
|
BackButtonType {
|
||||||
id: backButton
|
id: backButton
|
||||||
}
|
}
|
||||||
|
|
||||||
HeaderTypeWithSwitcher {
|
HeaderTypeWithSwitcher {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Split tunneling")
|
headerText: qsTr("Split tunneling")
|
||||||
|
|
||||||
enabled: root.pageEnabled
|
enabled: root.pageEnabled
|
||||||
showSwitcher: true
|
showSwitcher: true
|
||||||
switcher {
|
switcher {
|
||||||
checked: SitesModel.isTunnelingEnabled
|
checked: SitesModel.isTunnelingEnabled
|
||||||
enabled: root.pageEnabled
|
enabled: root.pageEnabled
|
||||||
}
|
}
|
||||||
switcherFunction: function(checked) {
|
switcherFunction: function(checked) {
|
||||||
SitesModel.toggleSplitTunneling(checked)
|
SitesModel.toggleSplitTunneling(checked)
|
||||||
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DropDownType {
|
DropDownType {
|
||||||
id: selector
|
id: selector
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 32
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
drawerHeight: 0.4375
|
drawerHeight: 0.4375
|
||||||
drawerParent: root
|
drawerParent: root
|
||||||
|
|
||||||
enabled: root.pageEnabled
|
enabled: root.pageEnabled
|
||||||
|
|
||||||
headerText: qsTr("Mode")
|
headerText: qsTr("Mode")
|
||||||
|
|
||||||
listView: ListViewWithRadioButtonType {
|
listView: ListViewWithRadioButtonType {
|
||||||
rootWidth: root.width
|
rootWidth: root.width
|
||||||
|
|
||||||
model: root.routeModesModel
|
model: root.routeModesModel
|
||||||
|
|
||||||
selectedIndex: getRouteModesModelIndex()
|
selectedIndex: getRouteModesModelIndex()
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
selector.text = selectedText
|
selector.text = selectedText
|
||||||
selector.closeTriggered()
|
selector.closeTriggered()
|
||||||
if (SitesModel.routeMode !== root.routeModesModel[selectedIndex].type) {
|
if (SitesModel.routeMode !== root.routeModesModel[selectedIndex].type) {
|
||||||
SitesModel.routeMode = root.routeModesModel[selectedIndex].type
|
SitesModel.routeMode = root.routeModesModel[selectedIndex].type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (root.routeModesModel[selectedIndex].type === SitesModel.routeMode) {
|
if (root.routeModesModel[selectedIndex].type === SitesModel.routeMode) {
|
||||||
selector.text = selectedText
|
selector.text = selectedText
|
||||||
} else {
|
} else {
|
||||||
selector.text = root.routeModesModel[0].name
|
selector.text = root.routeModesModel[0].name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SitesModel
|
target: SitesModel
|
||||||
function onRouteModeChanged() {
|
function onRouteModeChanged() {
|
||||||
selectedIndex = getRouteModesModelIndex()
|
selectedIndex = getRouteModesModelIndex()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
anchors.topMargin: 16
|
anchors.topMargin: 16
|
||||||
anchors.bottom: addSiteButton.top
|
anchors.bottom: addSiteButton.top
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
enabled: root.pageEnabled
|
enabled: root.pageEnabled
|
||||||
|
|
||||||
property bool isFocusable: true
|
model: SortFilterProxyModel {
|
||||||
|
id: proxySitesModel
|
||||||
model: SortFilterProxyModel {
|
sourceModel: SitesModel
|
||||||
id: proxySitesModel
|
filters: [
|
||||||
sourceModel: SitesModel
|
AnyOf {
|
||||||
filters: [
|
RegExpFilter {
|
||||||
AnyOf {
|
roleName: "url"
|
||||||
RegExpFilter {
|
pattern: ".*" + searchField.textField.text + ".*"
|
||||||
roleName: "url"
|
caseSensitivity: Qt.CaseInsensitive
|
||||||
pattern: ".*" + searchField.textField.text + ".*"
|
}
|
||||||
caseSensitivity: Qt.CaseInsensitive
|
RegExpFilter {
|
||||||
}
|
roleName: "ip"
|
||||||
RegExpFilter {
|
pattern: ".*" + searchField.textField.text + ".*"
|
||||||
roleName: "ip"
|
caseSensitivity: Qt.CaseInsensitive
|
||||||
pattern: ".*" + searchField.textField.text + ".*"
|
}
|
||||||
caseSensitivity: Qt.CaseInsensitive
|
}
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
clip: true
|
|
||||||
|
LabelWithButtonType {
|
||||||
reuseItems: true
|
id: site
|
||||||
|
Layout.fillWidth: true
|
||||||
delegate: ColumnLayout {
|
|
||||||
id: delegateContent
|
text: url
|
||||||
|
descriptionText: ip
|
||||||
width: listView.width
|
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||||
|
rightImageColor: AmneziaStyle.color.paleGray
|
||||||
LabelWithButtonType {
|
|
||||||
id: site
|
clickedFunction: function() {
|
||||||
Layout.fillWidth: true
|
var headerText = qsTr("Remove ") + url + "?"
|
||||||
|
var yesButtonText = qsTr("Continue")
|
||||||
text: url
|
var noButtonText = qsTr("Cancel")
|
||||||
descriptionText: ip
|
|
||||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
var yesButtonFunction = function() {
|
||||||
rightImageColor: AmneziaStyle.color.paleGray
|
SitesController.removeSite(proxySitesModel.mapToSource(index))
|
||||||
|
if (!GC.isMobile()) {
|
||||||
clickedFunction: function() {
|
site.rightButton.forceActiveFocus()
|
||||||
var headerText = qsTr("Remove ") + url + "?"
|
}
|
||||||
var yesButtonText = qsTr("Continue")
|
}
|
||||||
var noButtonText = qsTr("Cancel")
|
var noButtonFunction = function() {
|
||||||
|
if (!GC.isMobile()) {
|
||||||
var yesButtonFunction = function() {
|
site.rightButton.forceActiveFocus()
|
||||||
SitesController.removeSite(proxySitesModel.mapToSource(index))
|
}
|
||||||
if (!GC.isMobile()) {
|
}
|
||||||
site.rightButton.forceActiveFocus()
|
|
||||||
}
|
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||||
}
|
}
|
||||||
var noButtonFunction = function() {
|
}
|
||||||
if (!GC.isMobile()) {
|
|
||||||
site.rightButton.forceActiveFocus()
|
DividerType {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
Rectangle {
|
||||||
}
|
anchors.fill: addSiteButton
|
||||||
}
|
anchors.bottomMargin: -24
|
||||||
|
color: AmneziaStyle.color.midnightBlack
|
||||||
DividerType {}
|
opacity: 0.8
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
RowLayout {
|
||||||
|
id: addSiteButton
|
||||||
Rectangle {
|
|
||||||
anchors.fill: addSiteButton
|
enabled: root.pageEnabled
|
||||||
anchors.bottomMargin: -24
|
|
||||||
color: AmneziaStyle.color.midnightBlack
|
anchors.bottom: parent.bottom
|
||||||
opacity: 0.8
|
anchors.left: parent.left
|
||||||
}
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 24
|
||||||
RowLayout {
|
anchors.rightMargin: 16
|
||||||
id: addSiteButton
|
anchors.leftMargin: 16
|
||||||
|
anchors.bottomMargin: 24
|
||||||
enabled: root.pageEnabled
|
|
||||||
|
TextFieldWithHeaderType {
|
||||||
anchors.bottom: parent.bottom
|
id: searchField
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
Layout.fillWidth: true
|
||||||
anchors.topMargin: 24
|
rightButtonClickedOnEnter: true
|
||||||
anchors.rightMargin: 16
|
|
||||||
anchors.leftMargin: 16
|
textField.placeholderText: qsTr("website or IP")
|
||||||
anchors.bottomMargin: 24
|
buttonImageSource: "qrc:/images/controls/plus.svg"
|
||||||
|
|
||||||
TextFieldWithHeaderType {
|
clickedFunc: function() {
|
||||||
id: searchField
|
PageController.showBusyIndicator(true)
|
||||||
|
SitesController.addSite(textField.text)
|
||||||
Layout.fillWidth: true
|
textField.text = ""
|
||||||
rightButtonClickedOnEnter: true
|
PageController.showBusyIndicator(false)
|
||||||
|
}
|
||||||
textField.placeholderText: qsTr("website or IP")
|
}
|
||||||
buttonImageSource: "qrc:/images/controls/plus.svg"
|
|
||||||
|
ImageButtonType {
|
||||||
clickedFunc: function() {
|
id: addSiteButtonImage
|
||||||
PageController.showBusyIndicator(true)
|
implicitWidth: 56
|
||||||
SitesController.addSite(textField.text)
|
implicitHeight: 56
|
||||||
textField.text = ""
|
|
||||||
PageController.showBusyIndicator(false)
|
image: "qrc:/images/controls/more-vertical.svg"
|
||||||
}
|
imageColor: AmneziaStyle.color.paleGray
|
||||||
}
|
|
||||||
|
onClicked: function () {
|
||||||
ImageButtonType {
|
moreActionsDrawer.openTriggered()
|
||||||
id: addSiteButtonImage
|
}
|
||||||
implicitWidth: 56
|
|
||||||
implicitHeight: 56
|
Keys.onReturnPressed: addSiteButtonImage.clicked()
|
||||||
|
Keys.onEnterPressed: addSiteButtonImage.clicked()
|
||||||
image: "qrc:/images/controls/more-vertical.svg"
|
}
|
||||||
imageColor: AmneziaStyle.color.paleGray
|
}
|
||||||
|
|
||||||
onClicked: function () {
|
DrawerType2 {
|
||||||
moreActionsDrawer.openTriggered()
|
id: moreActionsDrawer
|
||||||
}
|
|
||||||
|
anchors.fill: parent
|
||||||
Keys.onReturnPressed: addSiteButtonImage.clicked()
|
expandedHeight: parent.height * 0.4375
|
||||||
Keys.onEnterPressed: addSiteButtonImage.clicked()
|
|
||||||
}
|
expandedStateContent: ColumnLayout {
|
||||||
}
|
id: moreActionsDrawerContent
|
||||||
|
|
||||||
DrawerType2 {
|
anchors.top: parent.top
|
||||||
id: moreActionsDrawer
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
anchors.fill: parent
|
|
||||||
expandedHeight: parent.height * 0.4375
|
Header2Type {
|
||||||
|
Layout.fillWidth: true
|
||||||
expandedStateContent: ColumnLayout {
|
Layout.margins: 16
|
||||||
id: moreActionsDrawerContent
|
|
||||||
|
headerText: qsTr("Import / Export Sites")
|
||||||
anchors.top: parent.top
|
}
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
LabelWithButtonType {
|
||||||
|
id: importSitesButton
|
||||||
Header2Type {
|
Layout.fillWidth: true
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: 16
|
text: qsTr("Import")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
headerText: qsTr("Import / Export Sites")
|
|
||||||
}
|
clickedFunction: function() {
|
||||||
|
importSitesDrawer.openTriggered()
|
||||||
LabelWithButtonType {
|
}
|
||||||
id: importSitesButton
|
}
|
||||||
Layout.fillWidth: true
|
|
||||||
|
DividerType {}
|
||||||
text: qsTr("Import")
|
|
||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
LabelWithButtonType {
|
||||||
|
id: exportSitesButton
|
||||||
clickedFunction: function() {
|
Layout.fillWidth: true
|
||||||
importSitesDrawer.openTriggered()
|
text: qsTr("Save site list")
|
||||||
}
|
|
||||||
}
|
clickedFunction: function() {
|
||||||
|
var fileName = ""
|
||||||
DividerType {}
|
if (GC.isMobile()) {
|
||||||
|
fileName = "amnezia_sites.json"
|
||||||
LabelWithButtonType {
|
} else {
|
||||||
id: exportSitesButton
|
fileName = SystemController.getFileName(qsTr("Save sites"),
|
||||||
Layout.fillWidth: true
|
qsTr("Sites files (*.json)"),
|
||||||
text: qsTr("Save site list")
|
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_sites",
|
||||||
|
true,
|
||||||
clickedFunction: function() {
|
".json")
|
||||||
var fileName = ""
|
}
|
||||||
if (GC.isMobile()) {
|
if (fileName !== "") {
|
||||||
fileName = "amnezia_sites.json"
|
PageController.showBusyIndicator(true)
|
||||||
} else {
|
SitesController.exportSites(fileName)
|
||||||
fileName = SystemController.getFileName(qsTr("Save sites"),
|
moreActionsDrawer.closeTriggered()
|
||||||
qsTr("Sites files (*.json)"),
|
PageController.showBusyIndicator(false)
|
||||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_sites",
|
}
|
||||||
true,
|
}
|
||||||
".json")
|
}
|
||||||
}
|
|
||||||
if (fileName !== "") {
|
DividerType {}
|
||||||
PageController.showBusyIndicator(true)
|
}
|
||||||
SitesController.exportSites(fileName)
|
}
|
||||||
moreActionsDrawer.closeTriggered()
|
|
||||||
PageController.showBusyIndicator(false)
|
DrawerType2 {
|
||||||
}
|
id: importSitesDrawer
|
||||||
}
|
|
||||||
}
|
anchors.fill: parent
|
||||||
|
expandedHeight: parent.height * 0.4375
|
||||||
DividerType {}
|
|
||||||
}
|
expandedStateContent: Item {
|
||||||
}
|
implicitHeight: importSitesDrawer.expandedHeight
|
||||||
|
|
||||||
DrawerType2 {
|
BackButtonType {
|
||||||
id: importSitesDrawer
|
id: importSitesDrawerBackButton
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.top: parent.top
|
||||||
expandedHeight: parent.height * 0.4375
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
expandedStateContent: Item {
|
anchors.topMargin: 16
|
||||||
implicitHeight: importSitesDrawer.expandedHeight
|
|
||||||
|
backButtonFunction: function() {
|
||||||
BackButtonType {
|
importSitesDrawer.closeTriggered()
|
||||||
id: importSitesDrawerBackButton
|
}
|
||||||
|
}
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
ListViewType {
|
||||||
anchors.right: parent.right
|
id: importSitesDrawerListView
|
||||||
anchors.topMargin: 16
|
|
||||||
|
anchors.top: importSitesDrawerBackButton.bottom
|
||||||
backButtonFunction: function() {
|
anchors.left: parent.left
|
||||||
importSitesDrawer.closeTriggered()
|
anchors.right: parent.right
|
||||||
}
|
anchors.bottom: parent.bottom
|
||||||
}
|
|
||||||
|
header: ColumnLayout {
|
||||||
FlickableType {
|
width: importSitesDrawerListView.width
|
||||||
anchors.top: importSitesDrawerBackButton.bottom
|
|
||||||
anchors.left: parent.left
|
Header2Type {
|
||||||
anchors.right: parent.right
|
Layout.fillWidth: true
|
||||||
anchors.bottom: parent.bottom
|
Layout.margins: 16
|
||||||
|
|
||||||
contentHeight: importSitesDrawerContent.height
|
headerText: qsTr("Import a list of sites")
|
||||||
|
}
|
||||||
ColumnLayout {
|
}
|
||||||
id: importSitesDrawerContent
|
|
||||||
|
model: importOptions
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.left: parent.left
|
delegate: ColumnLayout {
|
||||||
anchors.right: parent.right
|
width: importSitesDrawerListView.width
|
||||||
|
|
||||||
Header2Type {
|
LabelWithButtonType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: 16
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
headerText: qsTr("Import a list of sites")
|
|
||||||
}
|
text: title
|
||||||
|
|
||||||
LabelWithButtonType {
|
clickedFunction: function() {
|
||||||
id: importSitesButton2
|
clickedHandler()
|
||||||
Layout.fillWidth: true
|
}
|
||||||
|
}
|
||||||
text: qsTr("Replace site list")
|
|
||||||
|
DividerType {}
|
||||||
clickedFunction: function() {
|
}
|
||||||
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
}
|
||||||
qsTr("Sites files (*.json)"))
|
}
|
||||||
if (fileName !== "") {
|
}
|
||||||
importSitesDrawerContent.importSites(fileName, true)
|
|
||||||
}
|
property list<QtObject> importOptions: [
|
||||||
}
|
replaceOption,
|
||||||
}
|
addOption,
|
||||||
|
]
|
||||||
DividerType {}
|
|
||||||
|
QtObject {
|
||||||
LabelWithButtonType {
|
id: replaceOption
|
||||||
id: importSitesButton3
|
|
||||||
Layout.fillWidth: true
|
readonly property string title: qsTr("Replace site list")
|
||||||
text: qsTr("Add imported sites to existing ones")
|
readonly property var clickedHandler: function() {
|
||||||
|
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
||||||
clickedFunction: function() {
|
qsTr("Sites files (*.json)"))
|
||||||
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
if (fileName !== "") {
|
||||||
qsTr("Sites files (*.json)"))
|
root.importSites(fileName, true)
|
||||||
if (fileName !== "") {
|
}
|
||||||
importSitesDrawerContent.importSites(fileName, false)
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
QtObject {
|
||||||
|
id: addOption
|
||||||
function importSites(fileName, replaceExistingSites) {
|
|
||||||
PageController.showBusyIndicator(true)
|
readonly property string title: qsTr("Add imported sites to existing ones")
|
||||||
SitesController.importSites(fileName, replaceExistingSites)
|
readonly property var clickedHandler: function() {
|
||||||
PageController.showBusyIndicator(false)
|
var fileName = SystemController.getFileName(qsTr("Open sites file"),
|
||||||
importSitesDrawer.closeTriggered()
|
qsTr("Sites files (*.json)"))
|
||||||
moreActionsDrawer.closeTriggered()
|
if (fileName !== "") {
|
||||||
}
|
root.importSites(fileName, false)
|
||||||
|
}
|
||||||
DividerType {}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
function importSites(fileName, replaceExistingSites) {
|
||||||
}
|
PageController.showBusyIndicator(true)
|
||||||
}
|
SitesController.importSites(fileName, replaceExistingSites)
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
importSitesDrawer.closeTriggered()
|
||||||
|
moreActionsDrawer.closeTriggered()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,146 +1,177 @@
|
||||||
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
|
||||||
|
|
||||||
FlickableType {
|
BackButtonType {
|
||||||
id: fl
|
id: backButton
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.top: parent.top
|
||||||
contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
ColumnLayout {
|
anchors.topMargin: 20
|
||||||
id: content
|
|
||||||
|
onFocusChanged: {
|
||||||
anchors.top: parent.top
|
if (this.activeFocus) {
|
||||||
anchors.left: parent.left
|
listView.positionViewAtBeginning()
|
||||||
anchors.right: parent.right
|
}
|
||||||
|
}
|
||||||
spacing: 0
|
}
|
||||||
|
|
||||||
BackButtonType {
|
ListViewType {
|
||||||
id: backButton
|
id: listView
|
||||||
Layout.topMargin: 20
|
|
||||||
}
|
anchors.top: backButton.bottom
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
BaseHeaderType {
|
anchors.right: parent.right
|
||||||
Layout.fillWidth: true
|
anchors.left: parent.left
|
||||||
Layout.topMargin: 8
|
|
||||||
Layout.rightMargin: 16
|
header: ColumnLayout {
|
||||||
Layout.leftMargin: 16
|
width: listView.width
|
||||||
Layout.bottomMargin: 32
|
|
||||||
|
BaseHeaderType {
|
||||||
headerText: ApiServicesModel.getSelectedServiceData("name")
|
Layout.fillWidth: true
|
||||||
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
|
Layout.topMargin: 8
|
||||||
}
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
LabelWithImageType {
|
Layout.bottomMargin: 32
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: 16
|
headerText: ApiServicesModel.getSelectedServiceData("name")
|
||||||
|
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
|
||||||
imageSource: "qrc:/images/controls/map-pin.svg"
|
}
|
||||||
leftText: qsTr("For the region")
|
}
|
||||||
rightText: ApiServicesModel.getSelectedServiceData("region")
|
|
||||||
}
|
model: inputFields
|
||||||
|
spacing: 0
|
||||||
LabelWithImageType {
|
|
||||||
Layout.fillWidth: true
|
delegate: ColumnLayout {
|
||||||
Layout.margins: 16
|
width: listView.width
|
||||||
|
|
||||||
imageSource: "qrc:/images/controls/tag.svg"
|
LabelWithImageType {
|
||||||
leftText: qsTr("Price")
|
Layout.fillWidth: true
|
||||||
rightText: ApiServicesModel.getSelectedServiceData("price")
|
Layout.margins: 16
|
||||||
}
|
|
||||||
|
imageSource: imagePath
|
||||||
LabelWithImageType {
|
leftText: lText
|
||||||
Layout.fillWidth: true
|
rightText: rText
|
||||||
Layout.margins: 16
|
}
|
||||||
|
}
|
||||||
imageSource: "qrc:/images/controls/history.svg"
|
|
||||||
leftText: qsTr("Work period")
|
footer: ColumnLayout {
|
||||||
rightText: ApiServicesModel.getSelectedServiceData("timeLimit")
|
width: listView.width
|
||||||
|
|
||||||
visible: rightText !== ""
|
spacing: 0
|
||||||
}
|
|
||||||
|
ParagraphTextType {
|
||||||
LabelWithImageType {
|
Layout.fillWidth: true
|
||||||
Layout.fillWidth: true
|
Layout.rightMargin: 16
|
||||||
Layout.margins: 16
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
imageSource: "qrc:/images/controls/gauge.svg"
|
onLinkActivated: function(link) {
|
||||||
leftText: qsTr("Speed")
|
Qt.openUrlExternally(link)
|
||||||
rightText: ApiServicesModel.getSelectedServiceData("speed")
|
}
|
||||||
}
|
textFormat: Text.RichText
|
||||||
|
text: {
|
||||||
LabelWithImageType {
|
var text = ApiServicesModel.getSelectedServiceData("features")
|
||||||
Layout.fillWidth: true
|
return text.replace("%1", LanguageModel.getCurrentSiteUrl())
|
||||||
Layout.margins: 16
|
}
|
||||||
|
|
||||||
imageSource: "qrc:/images/controls/info.svg"
|
MouseArea {
|
||||||
leftText: qsTr("Features")
|
anchors.fill: parent
|
||||||
rightText: ""
|
acceptedButtons: Qt.NoButton
|
||||||
}
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
}
|
||||||
ParagraphTextType {
|
}
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: 16
|
BasicButtonType {
|
||||||
Layout.leftMargin: 16
|
id: continueButton
|
||||||
|
|
||||||
onLinkActivated: function(link) {
|
Layout.fillWidth: true
|
||||||
Qt.openUrlExternally(link)
|
Layout.topMargin: 32
|
||||||
}
|
Layout.bottomMargin: 32
|
||||||
textFormat: Text.RichText
|
Layout.leftMargin: 16
|
||||||
text: {
|
Layout.rightMargin: 16
|
||||||
var text = ApiServicesModel.getSelectedServiceData("features")
|
|
||||||
return text.replace("%1", LanguageModel.getCurrentSiteUrl())
|
text: qsTr("Connect")
|
||||||
}
|
|
||||||
|
clickedFunc: function() {
|
||||||
MouseArea {
|
var endpoint = ApiServicesModel.getStoreEndpoint()
|
||||||
anchors.fill: parent
|
if (endpoint !== undefined && endpoint !== "") {
|
||||||
acceptedButtons: Qt.NoButton
|
Qt.openUrlExternally(endpoint)
|
||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
PageController.closePage()
|
||||||
}
|
PageController.closePage()
|
||||||
}
|
} else {
|
||||||
}
|
PageController.showBusyIndicator(true)
|
||||||
}
|
ApiConfigsController.importServiceFromGateway()
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
BasicButtonType {
|
}
|
||||||
id: continueButton
|
}
|
||||||
|
}
|
||||||
anchors.right: parent.right
|
}
|
||||||
anchors.left: parent.left
|
}
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
|
property list<QtObject> inputFields: [
|
||||||
anchors.topMargin: 32
|
region,
|
||||||
anchors.rightMargin: 16
|
price,
|
||||||
anchors.leftMargin: 16
|
timeLimit,
|
||||||
anchors.bottomMargin: 32
|
speed,
|
||||||
|
features
|
||||||
text: qsTr("Connect")
|
]
|
||||||
|
|
||||||
clickedFunc: function() {
|
QtObject {
|
||||||
var endpoint = ApiServicesModel.getStoreEndpoint()
|
id: region
|
||||||
if (endpoint !== undefined && endpoint !== "") {
|
|
||||||
Qt.openUrlExternally(endpoint)
|
readonly property string imagePath: "qrc:/images/controls/map-pin.svg"
|
||||||
PageController.closePage()
|
readonly property string lText: qsTr("For the region")
|
||||||
PageController.closePage()
|
readonly property string rText: ApiServicesModel.getSelectedServiceData("region")
|
||||||
} else {
|
property bool isVisible: true
|
||||||
PageController.showBusyIndicator(true)
|
}
|
||||||
ApiConfigsController.importServiceFromGateway()
|
|
||||||
PageController.showBusyIndicator(false)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: servicesListView
|
id: servicesListView
|
||||||
|
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
|
|
@ -48,17 +48,11 @@ PageType {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.topMargin: 16
|
anchors.topMargin: 16
|
||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
model: ApiServicesModel
|
model: ApiServicesModel
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
implicitWidth: servicesListView.width
|
implicitWidth: servicesListView.width
|
||||||
implicitHeight: delegateContent.implicitHeight
|
implicitHeight: delegateContent.implicitHeight
|
||||||
|
|
|
||||||
|
|
@ -27,21 +27,13 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
model: variants
|
model: variants
|
||||||
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,41 +28,14 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListViewType {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
property bool isFocusable: true
|
|
||||||
|
|
||||||
Keys.onTabPressed: {
|
|
||||||
FocusController.nextKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onBacktabPressed: {
|
|
||||||
FocusController.previousKeyTabItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
|
||||||
FocusController.nextKeyUpItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onDownPressed: {
|
|
||||||
FocusController.nextKeyDownItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onLeftPressed: {
|
|
||||||
FocusController.nextKeyLeftItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: {
|
|
||||||
FocusController.nextKeyRightItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBarType {}
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
header: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
||||||
|
|
@ -78,8 +51,6 @@ PageType {
|
||||||
|
|
||||||
model: inputFields
|
model: inputFields
|
||||||
spacing: 16
|
spacing: 16
|
||||||
clip: true
|
|
||||||
reuseItems: true
|
|
||||||
|
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
width: listView.width
|
width: listView.width
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ PageType {
|
||||||
|
|
||||||
SortFilterProxyModel {
|
SortFilterProxyModel {
|
||||||
id: proxyContainersModel
|
id: proxyContainersModel
|
||||||
|
|
||||||
sourceModel: ContainersModel
|
sourceModel: ContainersModel
|
||||||
filters: [
|
filters: [
|
||||||
ValueFilter {
|
ValueFilter {
|
||||||
|
|
@ -42,102 +43,95 @@ PageType {
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ButtonGroup {
|
||||||
id: fl
|
id: buttonGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
ListViewType {
|
||||||
|
id: listView
|
||||||
|
|
||||||
|
property int dockerContainer
|
||||||
|
property int containerDefaultPort
|
||||||
|
property int containerDefaultTransportProto
|
||||||
|
|
||||||
anchors.top: backButton.bottom
|
anchors.top: backButton.bottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
contentHeight: content.implicitHeight + setupLaterButton.anchors.bottomMargin
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
Column {
|
spacing: 16
|
||||||
|
|
||||||
|
header: ColumnLayout {
|
||||||
id: content
|
id: content
|
||||||
|
|
||||||
anchors.top: parent.top
|
width: listView.width
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
anchors.leftMargin: 16
|
|
||||||
|
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
BaseHeaderType {
|
BaseHeaderType {
|
||||||
id: header
|
id: header
|
||||||
|
|
||||||
implicitWidth: parent.width
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
headerTextMaximumLineCount: 10
|
headerTextMaximumLineCount: 10
|
||||||
|
|
||||||
headerText: qsTr("Choose Installation Type")
|
headerText: qsTr("Choose Installation Type")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ButtonGroup {
|
model: proxyContainersModel
|
||||||
id: buttonGroup
|
currentIndex: 0
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
delegate: ColumnLayout {
|
||||||
id: containers
|
|
||||||
width: parent.width
|
|
||||||
height: containers.contentItem.height
|
|
||||||
spacing: 16
|
|
||||||
|
|
||||||
currentIndex: 0
|
width: listView.width
|
||||||
clip: true
|
|
||||||
interactive: false
|
|
||||||
model: proxyContainersModel
|
|
||||||
|
|
||||||
property int dockerContainer
|
CardType {
|
||||||
property int containerDefaultPort
|
id: card
|
||||||
property int containerDefaultTransportProto
|
|
||||||
|
|
||||||
property bool isFocusable: true
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
delegate: Item {
|
headerText: easySetupHeader
|
||||||
implicitWidth: containers.width
|
bodyText: easySetupDescription
|
||||||
implicitHeight: delegateContent.implicitHeight
|
|
||||||
|
|
||||||
ColumnLayout {
|
ButtonGroup.group: buttonGroup
|
||||||
id: delegateContent
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
onClicked: function() {
|
||||||
anchors.left: parent.left
|
checked = true
|
||||||
anchors.right: parent.right
|
isEasySetup = true
|
||||||
|
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
|
||||||
|
|
||||||
CardType {
|
listView.dockerContainer = dockerContainer
|
||||||
id: card
|
listView.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
|
||||||
|
listView.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
headerText: easySetupHeader
|
|
||||||
bodyText: easySetupDescription
|
|
||||||
|
|
||||||
ButtonGroup.group: buttonGroup
|
|
||||||
|
|
||||||
onClicked: function() {
|
|
||||||
isEasySetup = true
|
|
||||||
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
|
|
||||||
|
|
||||||
containers.dockerContainer = dockerContainer
|
|
||||||
containers.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
|
|
||||||
containers.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Keys.onReturnPressed: this.clicked()
|
||||||
var item = containers.itemAtIndex(containers.currentIndex)
|
Keys.onEnterPressed: this.clicked()
|
||||||
if (item !== null) {
|
|
||||||
var button = item.children[0].children[0]
|
|
||||||
button.checked = true
|
|
||||||
button.clicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
|
||||||
|
width: listView.width
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
DividerType {
|
DividerType {
|
||||||
implicitWidth: parent.width
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
}
|
}
|
||||||
|
|
||||||
CardType {
|
CardType {
|
||||||
implicitWidth: parent.width
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Manual")
|
headerText: qsTr("Manual")
|
||||||
bodyText: qsTr("Choose a VPN protocol")
|
bodyText: qsTr("Choose a VPN protocol")
|
||||||
|
|
@ -146,25 +140,29 @@ PageType {
|
||||||
|
|
||||||
onClicked: function() {
|
onClicked: function() {
|
||||||
isEasySetup = false
|
isEasySetup = false
|
||||||
|
checked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: this.clicked()
|
||||||
|
Keys.onEnterPressed: this.clicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: continueButton
|
id: continueButton
|
||||||
|
|
||||||
implicitWidth: parent.width
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Continue")
|
text: qsTr("Continue")
|
||||||
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
if (root.isEasySetup) {
|
if (root.isEasySetup) {
|
||||||
ContainersModel.setProcessedContainerIndex(containers.dockerContainer)
|
ContainersModel.setProcessedContainerIndex(listView.dockerContainer)
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||||
InstallController.install(containers.dockerContainer,
|
InstallController.install(listView.dockerContainer,
|
||||||
containers.containerDefaultPort,
|
listView.containerDefaultPort,
|
||||||
containers.containerDefaultTransportProto)
|
listView.containerDefaultTransportProto)
|
||||||
} else {
|
} else {
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardProtocols)
|
PageController.goToPage(PageEnum.PageSetupWizardProtocols)
|
||||||
}
|
}
|
||||||
|
|
@ -174,9 +172,11 @@ PageType {
|
||||||
BasicButtonType {
|
BasicButtonType {
|
||||||
id: setupLaterButton
|
id: setupLaterButton
|
||||||
|
|
||||||
implicitWidth: parent.width
|
Layout.fillWidth: true
|
||||||
anchors.topMargin: 8
|
Layout.topMargin: 8
|
||||||
anchors.bottomMargin: 24
|
Layout.bottomMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
defaultColor: AmneziaStyle.color.transparent
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
|
@ -185,9 +185,6 @@ PageType {
|
||||||
textColor: AmneziaStyle.color.paleGray
|
textColor: AmneziaStyle.color.paleGray
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
|
|
||||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
|
||||||
parentFlickable: fl
|
|
||||||
|
|
||||||
visible: {
|
visible: {
|
||||||
if (PageController.isTriggeredByConnectButton()) {
|
if (PageController.isTriggeredByConnectButton()) {
|
||||||
PageController.setTriggeredByConnectButton(false)
|
PageController.setTriggeredByConnectButton(false)
|
||||||
|
|
@ -205,5 +202,15 @@ PageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
var item = listView.itemAtIndex(listView.currentIndex)
|
||||||
|
if (item !== null) {
|
||||||
|
var button = item.children[0]
|
||||||
|
button.checked = true
|
||||||
|
button.clicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,92 +85,76 @@ PageType {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
FlickableType {
|
ListViewType {
|
||||||
|
id: listView
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
contentHeight: content.height
|
|
||||||
|
|
||||||
Column {
|
currentIndex: -1
|
||||||
id: content
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
model: proxyContainersModel
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
spacing: 16
|
delegate: ColumnLayout {
|
||||||
|
width: listView.width
|
||||||
|
|
||||||
ListView {
|
BaseHeaderType {
|
||||||
id: container
|
Layout.fillWidth: true
|
||||||
width: parent.width
|
Layout.topMargin: 20
|
||||||
height: container.contentItem.height
|
Layout.leftMargin: 16
|
||||||
currentIndex: -1
|
Layout.rightMargin: 16
|
||||||
clip: true
|
|
||||||
interactive: false
|
|
||||||
model: proxyContainersModel
|
|
||||||
|
|
||||||
delegate: Item {
|
headerText: qsTr("Installing")
|
||||||
implicitWidth: container.width
|
descriptionText: name
|
||||||
implicitHeight: delegateContent.implicitHeight
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ProgressBarType {
|
||||||
id: delegateContent
|
id: progressBar
|
||||||
|
|
||||||
anchors.fill: parent
|
Layout.fillWidth: true
|
||||||
anchors.rightMargin: 16
|
Layout.topMargin: 32
|
||||||
anchors.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
BaseHeaderType {
|
Timer {
|
||||||
Layout.fillWidth: true
|
id: timer
|
||||||
Layout.topMargin: 20
|
|
||||||
|
|
||||||
headerText: qsTr("Installing")
|
interval: 300
|
||||||
descriptionText: name
|
repeat: true
|
||||||
}
|
running: root.isTimerRunning
|
||||||
|
onTriggered: {
|
||||||
ProgressBarType {
|
progressBar.value += 0.003
|
||||||
id: progressBar
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 32
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: timer
|
|
||||||
|
|
||||||
interval: 300
|
|
||||||
repeat: true
|
|
||||||
running: root.isTimerRunning
|
|
||||||
onTriggered: {
|
|
||||||
progressBar.value += 0.003
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParagraphTextType {
|
|
||||||
id: progressText
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 8
|
|
||||||
|
|
||||||
text: root.progressBarText
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicButtonType {
|
|
||||||
id: cancelIntallationButton
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: 24
|
|
||||||
|
|
||||||
visible: root.isCancelButtonVisible
|
|
||||||
|
|
||||||
text: qsTr("Cancel installation")
|
|
||||||
|
|
||||||
clickedFunc: function() {
|
|
||||||
InstallController.cancelInstallation()
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
id: progressText
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: root.progressBarText
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: cancelIntallationButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 24
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
visible: root.isCancelButtonVisible
|
||||||
|
|
||||||
|
text: qsTr("Cancel installation")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
InstallController.cancelInstallation()
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue