diff --git a/CMakeLists.txt b/CMakeLists.txt index 49b8fa16..f7ada65a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) -project(${PROJECT} VERSION 4.0.5.1 +project(${PROJECT} VERSION 4.0.6.1 DESCRIPTION "AmneziaVPN" HOMEPAGE_URL "https://amnezia.org/" ) -set(RELEASE_DATE "2023-09-11") +set(RELEASE_DATE "2023-09-17") set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/client/ui/qml/Controls2/DropDownType.qml b/client/ui/qml/Controls2/DropDownType.qml index c21fa48f..2feb5e17 100644 --- a/client/ui/qml/Controls2/DropDownType.qml +++ b/client/ui/qml/Controls2/DropDownType.qml @@ -10,6 +10,8 @@ Item { property string text property string textColor: "#d7d8db" property string textDisabledColor: "#878B91" + property int textMaximumLineCount: 2 + property int textElide: Qt.ElideRight property string descriptionText property string descriptionTextColor: "#878B91" @@ -102,6 +104,8 @@ Item { color: root.enabled ? root.textColor : root.textDisabledColor text: root.text + maximumLineCount: root.textMaximumLineCount + elide: root.textElide } } diff --git a/client/ui/qml/Controls2/HeaderType.qml b/client/ui/qml/Controls2/HeaderType.qml index 19958205..b4af3784 100644 --- a/client/ui/qml/Controls2/HeaderType.qml +++ b/client/ui/qml/Controls2/HeaderType.qml @@ -10,6 +10,9 @@ Item { property var actionButtonFunction property string headerText + property int headerTextMaximumLineCount: 2 + property int headerTextElide: Qt.ElideRight + property string descriptionText implicitWidth: content.implicitWidth @@ -26,6 +29,8 @@ Item { Layout.fillWidth: true text: root.headerText + maximumLineCount: root.headerTextMaximumLineCount + elide: root.headerTextElide } ImageButtonType { diff --git a/client/ui/qml/Controls2/LabelWithButtonType.qml b/client/ui/qml/Controls2/LabelWithButtonType.qml index 82aef55a..7a1489c0 100644 --- a/client/ui/qml/Controls2/LabelWithButtonType.qml +++ b/client/ui/qml/Controls2/LabelWithButtonType.qml @@ -8,6 +8,9 @@ Item { id: root property string text + property int textMaximumLineCount: 2 + property int textElide: Qt.ElideRight + property string descriptionText property var clickedFunction @@ -68,6 +71,8 @@ Item { ListItemTitleType { text: root.text color: root.descriptionOnTop ? root.descriptionColor : root.textColor + maximumLineCount: root.textMaximumLineCount + elide: root.textElide opacity: root.textOpacity diff --git a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml index f7f99dec..4138c087 100644 --- a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml +++ b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml @@ -5,12 +5,15 @@ import QtQuick.Layouts import "TextTypes" ListView { - id: menuContent + id: root property var rootWidth property var selectedText + property int textMaximumLineCount: 2 + property int textElide: Qt.ElideRight + property string imageSource: "qrc:/images/controls/check.svg" property var clickedFunction @@ -18,7 +21,7 @@ ListView { currentIndex: 0 width: rootWidth - height: menuContent.contentItem.height + height: root.contentItem.height clip: true interactive: false @@ -27,6 +30,12 @@ ListView { id: buttonGroup } + function triggerCurrentItem() { + var item = root.itemAtIndex(currentIndex) + var radioButton = item.children[0].children[0] + radioButton.clicked() + } + delegate: Item { implicitWidth: rootWidth implicitHeight: content.implicitHeight @@ -74,6 +83,9 @@ ListView { Layout.bottomMargin: 20 text: name + maximumLineCount: root.textMaximumLineCount + elide: root.textElide + } Image { @@ -88,11 +100,11 @@ ListView { } ButtonGroup.group: buttonGroup - checked: menuContent.currentIndex === index + checked: root.currentIndex === index onClicked: { - menuContent.currentIndex = index - menuContent.selectedText = name + root.currentIndex = index + root.selectedText = name if (clickedFunction && typeof clickedFunction === "function") { clickedFunction() } @@ -101,8 +113,8 @@ ListView { } Component.onCompleted: { - if (menuContent.currentIndex === index) { - menuContent.selectedText = name + if (root.currentIndex === index) { + root.selectedText = name } } } diff --git a/client/ui/qml/Controls2/VerticalRadioButton.qml b/client/ui/qml/Controls2/VerticalRadioButton.qml index 8229c959..dd9a5590 100644 --- a/client/ui/qml/Controls2/VerticalRadioButton.qml +++ b/client/ui/qml/Controls2/VerticalRadioButton.qml @@ -8,6 +8,8 @@ import "TextTypes" RadioButton { id: root + property int textMaximumLineCount: 2 + property int textElide: Qt.ElideRight property string descriptionText property string hoveredColor: Qt.rgba(1, 1, 1, 0.05) @@ -104,6 +106,8 @@ RadioButton { ListItemTitleType { text: root.text + maximumLineCount: root.textMaximumLineCount + elide: root.textElide color: { if (root.checked) { diff --git a/client/ui/qml/Pages2/PageHome.qml b/client/ui/qml/Pages2/PageHome.qml index c5ba89d0..d8796524 100644 --- a/client/ui/qml/Pages2/PageHome.qml +++ b/client/ui/qml/Pages2/PageHome.qml @@ -75,12 +75,20 @@ PageType { RowLayout { Layout.topMargin: 24 + Layout.leftMargin: 24 + Layout.rightMargin: 24 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter spacing: 0 Header1TextType { + Layout.maximumWidth: buttonContent.width - 48 - 18 - 12 // todo + + maximumLineCount: 2 + elide: Qt.ElideRight + text: root.defaultServerName + horizontalAlignment: Qt.AlignHCenter } Image { @@ -148,10 +156,15 @@ PageType { anchors.left: parent.left Header1TextType { + Layout.fillWidth: true Layout.topMargin: 24 - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: root.defaultServerName + horizontalAlignment: Qt.AlignHCenter + maximumLineCount: 2 + elide: Qt.ElideRight } LabelTextType { diff --git a/client/ui/qml/Pages2/PageSettingsServerInfo.qml b/client/ui/qml/Pages2/PageSettingsServerInfo.qml index 62a7a67b..e2e7868c 100644 --- a/client/ui/qml/Pages2/PageSettingsServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsServerInfo.qml @@ -101,7 +101,7 @@ PageType { Layout.fillWidth: true headerText: qsTr("Server name") textFieldText: name - textField.maximumLength: 20 + textField.maximumLength: 30 } BasicButtonType { diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 135c7fbc..67083949 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -173,19 +173,22 @@ PageType { DropDownType { id: serverSelector + signal severSelectorIndexChanged + property int currentIndex: 0 + Layout.fillWidth: true Layout.topMargin: 16 drawerHeight: 0.4375 - descriptionText: accessTypeSelector.currentIndex === 0 ? qsTr("Server and service") : qsTr("Server") + descriptionText: qsTr("Servers") headerText: qsTr("Server") - listView: ListViewWithLabelsType { - rootWidth: root.width - dividerVisible: true + listView: ListViewWithRadioButtonType { + id: serverSelectorListView - imageSource: "qrc:/images/controls/chevron-right.svg" + rootWidth: root.width + imageSource: "qrc:/images/controls/check.svg" model: SortFilterProxyModel { id: proxyServersModel @@ -203,14 +206,16 @@ PageType { clickedFunction: function() { handler() - if (accessTypeSelector.currentIndex === 0) { - protocolSelector.visible = true - root.shareButtonEnabled = false - } else { + if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) { + serverSelector.currentIndex = serverSelectorListView.currentIndex + serverSelector.severSelectorIndexChanged() + } + + if (accessTypeSelector.currentIndex !== 0) { shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text - serverSelector.menuVisible = false } + serverSelector.menuVisible = false } Component.onCompleted: { @@ -224,117 +229,90 @@ PageType { ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex) } } + } - DrawerType { - id: protocolSelector + DropDownType { + id: protocolSelector - width: parent.width - height: parent.height * 0.5 + Layout.fillWidth: true + Layout.topMargin: 16 - ColumnLayout { - id: protocolSelectorHeader + drawerHeight: 0.5 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 + descriptionText: qsTr("Protocols") + headerText: qsTr("Protocol") - BackButtonType { - backButtonImage: "qrc:/images/controls/arrow-left.svg" - backButtonFunction: function() { - protocolSelector.visible = false + listView: ListViewWithRadioButtonType { + id: protocolSelectorListView + + rootWidth: root.width + imageSource: "qrc:/images/controls/check.svg" + + model: SortFilterProxyModel { + id: proxyContainersModel + sourceModel: ContainersModel + filters: [ + ValueFilter { + roleName: "isInstalled" + value: true + }, + ValueFilter { + roleName: "isShareable" + value: true } + ] + } + + currentIndex: 0 + + clickedFunction: function() { + handler() + + protocolSelector.menuVisible = false + } + + Component.onCompleted: { + if (accessTypeSelector.currentIndex === 0) { + handler() } } - FlickableType { - anchors.top: protocolSelectorHeader.bottom - anchors.topMargin: 16 - contentHeight: protocolSelectorContent.implicitHeight + Connections { + target: serverSelector - Column { - id: protocolSelectorContent - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + function onSeverSelectorIndexChanged() { + protocolSelectorListView.currentIndex = 0 + protocolSelectorListView.triggerCurrentItem() + } + } - spacing: 16 + function handler() { + if (!proxyContainersModel.count) { + root.shareButtonEnabled = false + return + } else { + root.shareButtonEnabled = true + } - Header2TextType { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 + protocolSelector.text = selectedText + root.connectionServerSelectorText = serverSelector.text - text: qsTr("Protocols and services") - wrapMode: Text.WordWrap - } + shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text + shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text + ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex)) - ListViewWithRadioButtonType { - rootWidth: root.width + fillConnectionTypeModel() + } - imageSource: "qrc:/images/controls/check.svg" + function fillConnectionTypeModel() { + root.connectionTypesModel = [amneziaConnectionFormat] - model: SortFilterProxyModel { - id: proxyContainersModel - sourceModel: ContainersModel - filters: [ - ValueFilter { - roleName: "isInstalled" - value: true - }, - ValueFilter { - roleName: "isShareable" - value: true - } - ] - } + var index = proxyContainersModel.mapToSource(currentIndex) - currentIndex: 0 - - clickedFunction: function() { - handler() - - protocolSelector.visible = false - serverSelector.menuVisible = false - } - - Component.onCompleted: { - if (accessTypeSelector.currentIndex === 0) { - handler() - } - } - - function handler() { - if (!proxyContainersModel.count) { - root.shareButtonEnabled = false - return - } else { - root.shareButtonEnabled = true - } - - serverSelector.text += ", " + selectedText - root.connectionServerSelectorText = serverSelector.text - - shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text - ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex)) - - fillConnectionTypeModel() - } - - function fillConnectionTypeModel() { - root.connectionTypesModel = [amneziaConnectionFormat] - - var index = proxyContainersModel.mapToSource(currentIndex) - - if (index === ContainerProps.containerFromString("amnezia-openvpn")) { - root.connectionTypesModel.push(openVpnConnectionFormat) - } else if (index === ContainerProps.containerFromString("amnezia-wireguard")) { - root.connectionTypesModel.push(wireGuardConnectionFormat) - } - } - } + if (index === ContainerProps.containerFromString("amnezia-openvpn")) { + root.connectionTypesModel.push(openVpnConnectionFormat) + } else if (index === ContainerProps.containerFromString("amnezia-wireguard")) { + root.connectionTypesModel.push(wireGuardConnectionFormat) } } }