diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 64a4986d..0ce8d576 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -256,7 +256,7 @@ jobs:
- name: 'Setup xcode'
uses: maxim-lobanov/setup-xcode@v1
with:
- xcode-version: '14.3.1'
+ xcode-version: '15.4.0'
- name: 'Install Qt'
uses: jurplel/install-qt-action@v3
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b5e64e32..cb695631 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
-project(${PROJECT} VERSION 4.8.2.3
+project(${PROJECT} VERSION 4.8.2.4
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
-set(APP_ANDROID_VERSION_CODE 2069)
+set(APP_ANDROID_VERSION_CODE 2071)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
diff --git a/README.md b/README.md
index eed800f5..27a29edf 100644
--- a/README.md
+++ b/README.md
@@ -4,21 +4,21 @@
[](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
-Amnezia is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
+[Amnezia](https://amnezia.org) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
-
+[](https://amnezia.org)
-
+### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/kldscp/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
-
-
-
+> [!TIP]
+> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/kldscp/amnezia.org).
-[Alternative download link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org/downloads)
+
+
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
-
+
@@ -33,7 +33,8 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
## Links
-- [https://amnezia.org](https://amnezia.org) - project website | [Alternative link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org)
+- [https://amnezia.org](https://amnezia.org) - Project website | [Alternative link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org)
+- [https://docs.amnezia.org](https://docs.amnezia.org) - Documentation
- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Telegram support channel (English)
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml
index 179def86..9e44e022 100644
--- a/client/android/AndroidManifest.xml
+++ b/client/android/AndroidManifest.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
index e93834f4..80cab96d 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
@@ -1,11 +1,12 @@
package org.amnezia.vpn.protocol.wireguard
import android.net.VpnService.Builder
-import java.io.IOException
-import java.util.Locale
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.launch
import org.amnezia.awg.GoBackend
import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
@@ -27,6 +28,8 @@ open class Wireguard : Protocol() {
private var tunnelHandle: Int = -1
protected open val ifName: String = "amn0"
+ private lateinit var scope: CoroutineScope
+ private var statusJob: Job? = null
override val statistics: Statistics
get() {
@@ -49,46 +52,17 @@ open class Wireguard : Protocol() {
override fun internalInit() {
if (!isInitialized) loadSharedLibrary(context, "wg-go")
+ if (this::scope.isInitialized) {
+ scope.cancel()
+ }
+ scope = CoroutineScope(Dispatchers.IO)
}
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
val wireguardConfig = parseConfig(config)
- val startTime = System.currentTimeMillis()
start(wireguardConfig, vpnBuilder, protect)
- waitForConnection(startTime)
- state.value = CONNECTED
}
- private suspend fun waitForConnection(startTime: Long) {
- Log.d(TAG, "Waiting for connection")
- withContext(Dispatchers.IO) {
- val time = String.format(Locale.ROOT,"%.3f", startTime / 1000.0)
- try {
- delay(1000)
- var log = getLogcat(time)
- Log.v(TAG, "First waiting log: $log")
- // check that there is a connection log,
- // to avoid infinite connection
- if (!log.contains("Attaching to interface")) {
- Log.w(TAG, "Logs do not contain a connection log")
- return@withContext
- }
- while (!log.contains("Received handshake response")) {
- delay(1000)
- log = getLogcat(time)
- }
- } catch (e: IOException) {
- Log.e(TAG, "Failed to get logcat: $e")
- }
- }
- }
-
- private fun getLogcat(time: String): String =
- ProcessBuilder("logcat", "--buffer=main", "--format=raw", "*:S AmneziaWG/awg0", "-t", time)
- .redirectErrorStream(true)
- .start()
- .inputStream.reader().readText()
-
protected open fun parseConfig(config: JSONObject): WireguardConfig {
val configData = config.getJSONObject("wireguard_config_data")
return WireguardConfig.build {
@@ -178,6 +152,43 @@ open class Wireguard : Protocol() {
tunnelHandle = -1
throw VpnStartException("Protect VPN interface: permission not granted or revoked")
}
+ launchStatusJob()
+ }
+
+ private fun launchStatusJob() {
+ Log.d(TAG, "Launch status job")
+ statusJob = scope.launch {
+ while (true) {
+ val lastHandshake = getLastHandshake()
+ Log.v(TAG, "lastHandshake=$lastHandshake")
+ if (lastHandshake == 0L) {
+ delay(1000)
+ continue
+ }
+ if (lastHandshake == -2L || lastHandshake > 0L) state.value = CONNECTED
+ else if (lastHandshake == -1L) state.value = DISCONNECTED
+ statusJob = null
+ break
+ }
+ }
+ }
+
+ private fun getLastHandshake(): Long {
+ if (tunnelHandle == -1) {
+ Log.e(TAG, "Trying to get config of a non-existent tunnel")
+ return -1
+ }
+ val config = GoBackend.awgGetConfig(tunnelHandle)
+ if (config == null) {
+ Log.e(TAG, "Failed to get tunnel config")
+ return -2
+ }
+ val lastHandshake = config.lines().find { it.startsWith("last_handshake_time_sec=") }?.substring(24)?.toLong()
+ if (lastHandshake == null) {
+ Log.e(TAG, "Failed to get last_handshake_time_sec")
+ return -2
+ }
+ return lastHandshake
}
override fun stopVpn() {
@@ -185,6 +196,8 @@ open class Wireguard : Protocol() {
Log.w(TAG, "Tunnel already down")
return
}
+ statusJob?.cancel()
+ statusJob = null
val handleToClose = tunnelHandle
tunnelHandle = -1
GoBackend.awgTurnOff(handleToClose)
diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp
index 306e7f38..ae0804cb 100755
--- a/client/ui/controllers/installController.cpp
+++ b/client/ui/controllers/installController.cpp
@@ -848,7 +848,6 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
newServerConfig.insert(configKey::apiConfig, newApiConfig);
newServerConfig.insert(configKey::authData, authData);
- newServerConfig.insert(config_key::crc, serverConfig.value(config_key::crc));
m_serversModel->editServer(newServerConfig, serverIndex);
if (reloadServiceConfig) {
diff --git a/client/ui/qml/Components/ShareConnectionDrawer.qml b/client/ui/qml/Components/ShareConnectionDrawer.qml
index 3235ad0a..d2bf28ab 100644
--- a/client/ui/qml/Components/ShareConnectionDrawer.qml
+++ b/client/ui/qml/Components/ShareConnectionDrawer.qml
@@ -84,7 +84,7 @@ DrawerType2 {
Layout.topMargin: 16
text: qsTr("Share")
- imageSource: "qrc:/images/controls/share-2.svg"
+ leftImageSource: "qrc:/images/controls/share-2.svg"
KeyNavigation.tab: copyConfigTextButton
@@ -120,7 +120,7 @@ DrawerType2 {
borderWidth: 1
text: qsTr("Copy")
- imageSource: "qrc:/images/controls/copy.svg"
+ leftImageSource: "qrc:/images/controls/copy.svg"
Keys.onReturnPressed: { copyConfigTextButton.clicked() }
Keys.onEnterPressed: { copyConfigTextButton.clicked() }
@@ -143,7 +143,7 @@ DrawerType2 {
borderWidth: 1
text: qsTr("Copy config string")
- imageSource: "qrc:/images/controls/copy.svg"
+ leftImageSource: "qrc:/images/controls/copy.svg"
KeyNavigation.tab: showSettingsButton
}
diff --git a/client/ui/qml/Controls2/BasicButtonType.qml b/client/ui/qml/Controls2/BasicButtonType.qml
index 5c599013..828c32bc 100644
--- a/client/ui/qml/Controls2/BasicButtonType.qml
+++ b/client/ui/qml/Controls2/BasicButtonType.qml
@@ -22,9 +22,10 @@ Button {
property int borderWidth: 0
property int borderFocusedWidth: 1
- property string imageSource
+ property string leftImageSource
property string rightImageSource
- property string leftImageColor: textColor
+ property string leftImageColor
+ property bool changeLeftImageSize: true
property bool squareLeftSide: false
@@ -127,18 +128,23 @@ Button {
anchors.centerIn: parent
Image {
- Layout.preferredHeight: 20
- Layout.preferredWidth: 20
-
- source: root.imageSource
- visible: root.imageSource === "" ? false : true
+ id: leftImage
+ source: root.leftImageSource
+ visible: root.leftImageSource === "" ? false : true
layer {
- enabled: true
+ enabled: leftImageColor !== "" ? true : false
effect: ColorOverlay {
color: leftImageColor
}
}
+
+ Component.onCompleted: {
+ if (root.changeLeftImageSize) {
+ leftImage.Layout.preferredHeight = 20
+ leftImage.Layout.preferredWidth = 20
+ }
+ }
}
ButtonTextType {
diff --git a/client/ui/qml/Controls2/BusyIndicatorType.qml b/client/ui/qml/Controls2/BusyIndicatorType.qml
index 55af280f..480f25c1 100644
--- a/client/ui/qml/Controls2/BusyIndicatorType.qml
+++ b/client/ui/qml/Controls2/BusyIndicatorType.qml
@@ -14,7 +14,7 @@ Popup {
visible: false
Overlay.modal: Rectangle {
- color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+ color: AmneziaStyle.color.translucentMidnightBlack
}
background: Rectangle {
diff --git a/client/ui/qml/Controls2/CardType.qml b/client/ui/qml/Controls2/CardType.qml
index 50f84dbf..f584a8fc 100644
--- a/client/ui/qml/Controls2/CardType.qml
+++ b/client/ui/qml/Controls2/CardType.qml
@@ -19,7 +19,7 @@ RadioButton {
property string textColor: AmneziaStyle.color.midnightBlack
- property string pressedBorderColor: Qt.rgba(251/255, 178/255, 106/255, 0.3)
+ property string pressedBorderColor: AmneziaStyle.color.softGoldenApricot
property string selectedBorderColor: AmneziaStyle.color.goldenApricot
property string defaultBodredColor: AmneziaStyle.color.transparent
property int borderWidth: 0
diff --git a/client/ui/qml/Controls2/CardWithIconsType.qml b/client/ui/qml/Controls2/CardWithIconsType.qml
index fea65116..18a29b87 100644
--- a/client/ui/qml/Controls2/CardWithIconsType.qml
+++ b/client/ui/qml/Controls2/CardWithIconsType.qml
@@ -145,6 +145,7 @@ Button {
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
+ enabled: root.enabled
onEntered: {
backgroundRect.color = root.hoveredColor
diff --git a/client/ui/qml/Controls2/DrawerType2.qml b/client/ui/qml/Controls2/DrawerType2.qml
index 6647bc88..c4b584c1 100644
--- a/client/ui/qml/Controls2/DrawerType2.qml
+++ b/client/ui/qml/Controls2/DrawerType2.qml
@@ -92,7 +92,7 @@ Item {
id: background
anchors.fill: parent
- color: root.isCollapsed ? AmneziaStyle.color.transparent : Qt.rgba(14/255, 14/255, 17/255, 0.8)
+ color: root.isCollapsed ? AmneziaStyle.color.transparent : AmneziaStyle.color.translucentMidnightBlack
Behavior on color {
PropertyAnimation { duration: 200 }
diff --git a/client/ui/qml/Controls2/PopupType.qml b/client/ui/qml/Controls2/PopupType.qml
index bd4aa4fb..7a6a770e 100644
--- a/client/ui/qml/Controls2/PopupType.qml
+++ b/client/ui/qml/Controls2/PopupType.qml
@@ -24,7 +24,7 @@ Popup {
Overlay.modal: Rectangle {
visible: root.closeButtonVisible
- color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+ color: AmneziaStyle.color.translucentMidnightBlack
}
onOpened: {
diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
index 4ec0976b..365faa94 100644
--- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
+++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml
@@ -183,7 +183,7 @@ Item {
focusPolicy: Qt.NoFocus
text: root.buttonText
- imageSource: root.buttonImageSource
+ leftImageSource: root.buttonImageSource
anchors.top: content.top
anchors.bottom: content.bottom
diff --git a/client/ui/qml/Controls2/TopCloseButtonType.qml b/client/ui/qml/Controls2/TopCloseButtonType.qml
index 1bd7fef6..3a652da6 100644
--- a/client/ui/qml/Controls2/TopCloseButtonType.qml
+++ b/client/ui/qml/Controls2/TopCloseButtonType.qml
@@ -14,7 +14,7 @@ Popup {
visible: false
Overlay.modal: Rectangle {
- color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+ color: AmneziaStyle.color.translucentMidnightBlack
}
background: Rectangle {
diff --git a/client/ui/qml/Modules/Style/AmneziaStyle.qml b/client/ui/qml/Modules/Style/AmneziaStyle.qml
index c0038246..1abfbe3a 100644
--- a/client/ui/qml/Modules/Style/AmneziaStyle.qml
+++ b/client/ui/qml/Modules/Style/AmneziaStyle.qml
@@ -22,5 +22,9 @@ QtObject {
readonly property color sheerWhite: Qt.rgba(1, 1, 1, 0.12)
readonly property color translucentWhite: Qt.rgba(1, 1, 1, 0.08)
readonly property color barelyTranslucentWhite: Qt.rgba(1, 1, 1, 0.05)
+ readonly property color translucentMidnightBlack: Qt.rgba(14/255, 14/255, 17/255, 0.8)
+ readonly property color softGoldenApricot: Qt.rgba(251/255, 178/255, 106/255, 0.3)
+ readonly property color mistyGray: Qt.rgba(215/255, 216/255, 219/255, 0.8)
+ readonly property color cloudyGray: Qt.rgba(215/255, 216/255, 219/255, 0.65)
}
}
diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml
index 8074337a..8422a10f 100644
--- a/client/ui/qml/Pages2/PageHome.qml
+++ b/client/ui/qml/Pages2/PageHome.qml
@@ -98,7 +98,6 @@ PageType {
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.mutedGray
- leftImageColor: AmneziaStyle.color.transparent
borderWidth: 0
buttonTextLabel.lineHeight: 20
@@ -110,7 +109,7 @@ PageType {
text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
- imageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
+ leftImageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
rightImageSource: "qrc:/images/controls/chevron-down.svg"
Keys.onEnterPressed: splitTunnelingButton.clicked()
@@ -166,6 +165,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
+ spacing: 0
Component.onCompleted: {
drawer.collapsedHeight = collapsed.implicitHeight
@@ -267,18 +267,39 @@ PageType {
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
- Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
+ Layout.topMargin: 8
+ Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16
spacing: 0
- Image {
- Layout.rightMargin: 8
- visible: source !== ""
- source: ServersModel.defaultServerImagePathCollapsed
- }
+ BasicButtonType {
+ enabled: (ServersModel.defaultServerImagePathCollapsed !== "") && drawer.isCollapsed
+ hoverEnabled: enabled
+
+ implicitHeight: 36
+
+ leftPadding: 16
+ rightPadding: 16
+
+ defaultColor: AmneziaStyle.color.transparent
+ hoveredColor: AmneziaStyle.color.translucentWhite
+ pressedColor: AmneziaStyle.color.sheerWhite
+ disabledColor: AmneziaStyle.color.transparent
+ textColor: AmneziaStyle.color.mutedGray
+
+ buttonTextLabel.lineHeight: 16
+ buttonTextLabel.font.pixelSize: 13
+ buttonTextLabel.font.weight: 400
- LabelTextType {
- id: collapsedServerMenuDescription
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
+ leftImageSource: ServersModel.defaultServerImagePathCollapsed
+ changeLeftImageSize: false
+
+ rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : ""
+
+ onClicked: {
+ ServersModel.processedIndex = ServersModel.defaultIndex
+ PageController.goToPage(PageEnum.PageSettingsServerInfo)
+ }
}
}
}
@@ -316,8 +337,8 @@ PageType {
rootButtonImageColor: AmneziaStyle.color.midnightBlack
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
- rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
- rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
+ rootButtonBackgroundHoveredColor: AmneziaStyle.color.mistyGray
+ rootButtonBackgroundPressedColor: AmneziaStyle.color.cloudyGray
rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
rootButtonDefaultBorderColor: AmneziaStyle.color.transparent
rootButtonTextTopMargin: 8
diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
index f23e36d9..2d6c1d9b 100644
--- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
+++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml
@@ -132,8 +132,8 @@ PageType {
implicitHeight: 32
defaultColor: "transparent"
- hoveredColor: Qt.rgba(1, 1, 1, 0.08)
- pressedColor: Qt.rgba(1, 1, 1, 0.12)
+ hoveredColor: AmneziaStyle.color.translucentWhite
+ pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.vibrantRed
text: qsTr("Reload API config")
@@ -172,8 +172,8 @@ PageType {
implicitHeight: 32
defaultColor: "transparent"
- hoveredColor: Qt.rgba(1, 1, 1, 0.08)
- pressedColor: Qt.rgba(1, 1, 1, 0.12)
+ hoveredColor: AmneziaStyle.color.translucentWhite
+ pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.vibrantRed
text: qsTr("Remove from application")
diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
index 85a50393..f726cd49 100644
--- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
+++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml
@@ -16,83 +16,82 @@ PageType {
defaultActiveFocusItem: focusItem
- FlickableType {
- id: fl
+ ColumnLayout {
+ id: header
+
anchors.top: parent.top
- anchors.bottom: parent.bottom
- contentHeight: content.height
+ anchors.left: parent.left
+ anchors.right: parent.right
- ColumnLayout {
- id: content
+ spacing: 0
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.right: parent.right
+ Item {
+ id: focusItem
+ KeyNavigation.tab: backButton
+ }
- spacing: 0
-
- Item {
- id: focusItem
- KeyNavigation.tab: backButton
- }
-
- BackButtonType {
- id: backButton
- Layout.topMargin: 20
+ BackButtonType {
+ id: backButton
+ Layout.topMargin: 20
// KeyNavigation.tab: fileButton.rightButton
- }
+ }
- HeaderType {
- Layout.fillWidth: true
- Layout.topMargin: 8
- Layout.rightMargin: 16
- Layout.leftMargin: 16
- Layout.bottomMargin: 32
+ HeaderType {
+ Layout.fillWidth: true
+ Layout.topMargin: 8
+ Layout.rightMargin: 16
+ Layout.leftMargin: 16
+ Layout.bottomMargin: 16
- headerText: qsTr("VPN by Amnezia")
- descriptionText: qsTr("Choose a VPN service that suits your needs.")
- }
+ headerText: qsTr("VPN by Amnezia")
+ descriptionText: qsTr("Choose a VPN service that suits your needs.")
+ }
+ }
- ListView {
- id: containers
- width: parent.width
- height: containers.contentItem.height
- spacing: 16
+ ListView {
+ id: servicesListView
+ anchors.top: header.bottom
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.topMargin: 16
+ spacing: 0
- currentIndex: 1
- interactive: false
- model: ApiServicesModel
+ currentIndex: 1
+ clip: true
+ model: ApiServicesModel
- delegate: Item {
- implicitWidth: containers.width
- implicitHeight: delegateContent.implicitHeight
+ ScrollBar.vertical: ScrollBar {}
- ColumnLayout {
- id: delegateContent
+ delegate: Item {
+ implicitWidth: servicesListView.width
+ implicitHeight: delegateContent.implicitHeight
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.right: parent.right
+ ColumnLayout {
+ id: delegateContent
- CardWithIconsType {
- id: card
+ anchors.fill: parent
- Layout.fillWidth: true
- Layout.rightMargin: 16
- Layout.leftMargin: 16
+ CardWithIconsType {
+ id: card
- headerText: name
- bodyText: cardDescription
- footerText: price
+ Layout.fillWidth: true
+ Layout.rightMargin: 16
+ Layout.leftMargin: 16
+ Layout.bottomMargin: 16
- rightImageSource: "qrc:/images/controls/chevron-right.svg"
+ headerText: name
+ bodyText: cardDescription
+ footerText: price
- onClicked: {
- if (isServiceAvailable) {
- ApiServicesModel.setServiceIndex(index)
- PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
- }
- }
+ rightImageSource: "qrc:/images/controls/chevron-right.svg"
+
+ enabled: isServiceAvailable
+
+ onClicked: {
+ if (isServiceAvailable) {
+ ApiServicesModel.setServiceIndex(index)
+ PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
}
}
}
diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
index 7c031997..f973c89c 100644
--- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
+++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
@@ -47,7 +47,6 @@ PageType {
KeyNavigation.tab: textKey.textField
}
-
HeaderType {
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml
index c7dbb425..d6ce7848 100644
--- a/client/ui/qml/Pages2/PageShare.qml
+++ b/client/ui/qml/Pages2/PageShare.qml
@@ -573,7 +573,7 @@ PageType {
visible: accessTypeSelector.currentIndex === 0
text: qsTr("Share")
- imageSource: "qrc:/images/controls/share-2.svg"
+ leftImageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml
index 2a565230..404ba563 100644
--- a/client/ui/qml/Pages2/PageShareFullAccess.qml
+++ b/client/ui/qml/Pages2/PageShareFullAccess.qml
@@ -135,7 +135,7 @@ PageType {
Layout.topMargin: 40
text: qsTr("Share")
- imageSource: "qrc:/images/controls/share-2.svg"
+ leftImageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
diff --git a/deploy/data/linux/post_install.sh b/deploy/data/linux/post_install.sh
index b3345bac..324462d9 100755
--- a/deploy/data/linux/post_install.sh
+++ b/deploy/data/linux/post_install.sh
@@ -19,6 +19,11 @@ date > $LOG_FILE
echo "Script started" >> $LOG_FILE
sudo killall -9 $APP_NAME 2>> $LOG_FILE
+if command -v steamos-readonly &> /dev/null; then
+ sudo steamos-readonly disable >> $LOG_FILE
+ echo "steamos-readonly disabled" >> $LOG_FILE
+fi
+
if sudo systemctl is-active --quiet $APP_NAME; then
sudo systemctl stop $APP_NAME >> $LOG_FILE
sudo systemctl disable $APP_NAME >> $LOG_FILE
@@ -42,6 +47,11 @@ sudo chmod 555 /usr/share/applications/$APP_NAME.desktop >> $LOG_FILE
echo "user desktop creation loop ended" >> $LOG_FILE
+if command -v steamos-readonly &> /dev/null; then
+ sudo steamos-readonly enable >> $LOG_FILE
+ echo "steamos-readonly enabled" >> $LOG_FILE
+fi
+
date >> $LOG_FILE
echo "Service status:" >> $LOG_FILE
sudo systemctl status $APP_NAME >> $LOG_FILE
diff --git a/deploy/data/linux/post_uninstall.sh b/deploy/data/linux/post_uninstall.sh
index 5849a90e..98090d20 100755
--- a/deploy/data/linux/post_uninstall.sh
+++ b/deploy/data/linux/post_uninstall.sh
@@ -13,6 +13,11 @@ date >> $LOG_FILE
echo "Uninstall Script started" >> $LOG_FILE
sudo killall -9 $APP_NAME 2>> $LOG_FILE
+if command -v steamos-readonly &> /dev/null; then
+ sudo steamos-readonly disable >> $LOG_FILE
+ echo "steamos-readonly disabled" >> $LOG_FILE
+fi
+
ls /opt/AmneziaVPN/client/lib/* | while IFS=: read -r dir; do
sudo unlink $dir >> $LOG_FILE
done
@@ -59,6 +64,11 @@ if test -f /usr/share/pixmaps/$APP_NAME.png; then
fi
+if command -v steamos-readonly &> /dev/null; then
+ sudo steamos-readonly enable >> $LOG_FILE
+ echo "steamos-readonly enabled" >> $LOG_FILE
+fi
+
date >> $LOG_FILE
echo "Service after uninstall status:" >> $LOG_FILE
sudo systemctl status $APP_NAME >> $LOG_FILE
diff --git a/metadata/img-readme/apl.png b/metadata/img-readme/apl.png
deleted file mode 100644
index 6dedfa12..00000000
Binary files a/metadata/img-readme/apl.png and /dev/null differ
diff --git a/metadata/img-readme/download-alt.svg b/metadata/img-readme/download-alt.svg
new file mode 100644
index 00000000..f97c9c3d
--- /dev/null
+++ b/metadata/img-readme/download-alt.svg
@@ -0,0 +1,8 @@
+
diff --git a/metadata/img-readme/download-website.svg b/metadata/img-readme/download-website.svg
new file mode 100644
index 00000000..d0cf8375
--- /dev/null
+++ b/metadata/img-readme/download-website.svg
@@ -0,0 +1,8 @@
+
diff --git a/metadata/img-readme/download.png b/metadata/img-readme/download.png
deleted file mode 100644
index 0e6a8850..00000000
Binary files a/metadata/img-readme/download.png and /dev/null differ
diff --git a/metadata/img-readme/play.png b/metadata/img-readme/play.png
deleted file mode 100644
index 2fb316c8..00000000
Binary files a/metadata/img-readme/play.png and /dev/null differ