diff --git a/client/ui/controllers/listViewFocusController.cpp b/client/ui/controllers/listViewFocusController.cpp index 9fa232ca..6e91b78a 100644 --- a/client/ui/controllers/listViewFocusController.cpp +++ b/client/ui/controllers/listViewFocusController.cpp @@ -37,7 +37,7 @@ void ListViewFocusController::viewAtCurrentIndex() const } case Section::Delegate: { 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; } case Section::Footer: { diff --git a/client/ui/qml/Components/HomeContainersListView.qml b/client/ui/qml/Components/HomeContainersListView.qml index 1cbdd82d..54cb27e2 100644 --- a/client/ui/qml/Components/HomeContainersListView.qml +++ b/client/ui/qml/Components/HomeContainersListView.qml @@ -10,8 +10,7 @@ import ProtocolEnum 1.0 import "../Controls2" import "../Controls2/TextTypes" - -ListView { +ListViewType { id: menuContent property var rootWidth @@ -21,13 +20,6 @@ ListView { anchors.top: parent.top anchors.bottom: parent.bottom - clip: true - snapMode: ListView.SnapToItem - - ScrollBar.vertical: ScrollBarType {} - - property bool isFocusable: true - ButtonGroup { id: containersRadioButtonGroup } diff --git a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml index 097274a4..6fdb6852 100644 --- a/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml +++ b/client/ui/qml/Components/HomeSplitTunnelingDrawer.qml @@ -1,97 +1,97 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import PageEnum 1.0 - -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" - -DrawerType2 { - id: root - - property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android" - - anchors.fill: parent - expandedHeight: parent.height * 0.9 - - expandedStateContent: ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - spacing: 0 - - Header2Type { - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: 16 - - headerText: qsTr("Split tunneling") - descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others") - } - - LabelWithButtonType { - id: splitTunnelingSwitch - Layout.fillWidth: true - Layout.topMargin: 16 - - visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling - - text: qsTr("Split tunneling on the server") - descriptionText: qsTr("Enabled \nCan't be disabled for current server") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsSplitTunneling) - root.closeTriggered() - } - } - - DividerType { - visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling - } - - LabelWithButtonType { - id: siteBasedSplitTunnelingSwitch - Layout.fillWidth: true - Layout.topMargin: 16 - - text: qsTr("Site-based split tunneling") - descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsSplitTunneling) - root.closeTriggered() - } - } - - DividerType { - } - - LabelWithButtonType { - id: appSplitTunnelingSwitch - visible: isAppSplitTinnelingEnabled - - Layout.fillWidth: true - - text: qsTr("App-based split tunneling") - descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) - root.closeTriggered() - } - } - - DividerType { - visible: isAppSplitTinnelingEnabled - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import PageEnum 1.0 + +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" + +DrawerType2 { + id: root + + property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android" + + anchors.fill: parent + expandedHeight: parent.height * 0.9 + + expandedStateContent: ColumnLayout { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + spacing: 0 + + Header2Type { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + + headerText: qsTr("Split tunneling") + descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others") + } + + LabelWithButtonType { + id: splitTunnelingSwitch + Layout.fillWidth: true + Layout.topMargin: 16 + + visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling + + text: qsTr("Split tunneling on the server") + descriptionText: qsTr("Enabled \nCan't be disabled for current server") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + clickedFunction: function() { + PageController.goToPage(PageEnum.PageSettingsSplitTunneling) + root.closeTriggered() + } + } + + DividerType { + visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling + } + + LabelWithButtonType { + id: siteBasedSplitTunnelingSwitch + Layout.fillWidth: true + Layout.topMargin: 16 + + text: qsTr("Site-based split tunneling") + descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + clickedFunction: function() { + PageController.goToPage(PageEnum.PageSettingsSplitTunneling) + root.closeTriggered() + } + } + + DividerType { + } + + LabelWithButtonType { + id: appSplitTunnelingSwitch + visible: isAppSplitTinnelingEnabled + + Layout.fillWidth: true + + text: qsTr("App-based split tunneling") + descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + + clickedFunction: function() { + PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) + root.closeTriggered() + } + } + + DividerType { + visible: isAppSplitTinnelingEnabled + } + } +} diff --git a/client/ui/qml/Components/InstalledAppsDrawer.qml b/client/ui/qml/Components/InstalledAppsDrawer.qml index ce8ef837..ccf8951e 100644 --- a/client/ui/qml/Components/InstalledAppsDrawer.qml +++ b/client/ui/qml/Components/InstalledAppsDrawer.qml @@ -57,7 +57,7 @@ DrawerType2 { headerText: qsTr("Choose application") } - ListView { + ListViewType { id: listView Layout.fillWidth: true @@ -66,11 +66,6 @@ DrawerType2 { Layout.rightMargin: 16 Layout.leftMargin: 16 - clip: true - interactive: true - - property bool isFocusable: true - model: SortFilterProxyModel { id: proxyInstalledAppsModel sourceModel: installedAppsModel @@ -81,44 +76,35 @@ DrawerType2 { } } - ScrollBar.vertical: ScrollBarType {} - ButtonGroup { id: buttonGroup } - delegate: Item { - implicitWidth: root.width - implicitHeight: delegateContent.implicitHeight + delegate: ColumnLayout { + width: listView.width - ColumnLayout { - id: delegateContent + RowLayout { + CheckBoxType { + Layout.fillWidth: true - anchors.fill: parent - - RowLayout { - CheckBoxType { - Layout.fillWidth: true - - 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 + text: appName + checked: isAppSelected + onCheckedChanged: { + installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked) } } - DividerType {} + Image { + source: "image://installedAppImage/" + appIcon + + sourceSize.width: 24 + sourceSize.height: 24 + + Layout.rightMargin: 48 + } } + + DividerType {} } } } diff --git a/client/ui/qml/Components/SelectLanguageDrawer.qml b/client/ui/qml/Components/SelectLanguageDrawer.qml index 2c026848..09829fa7 100644 --- a/client/ui/qml/Components/SelectLanguageDrawer.qml +++ b/client/ui/qml/Components/SelectLanguageDrawer.qml @@ -49,7 +49,7 @@ DrawerType2 { } } - ListView { + ListViewType { id: listView anchors.top: backButtonLayout.bottom @@ -57,14 +57,8 @@ DrawerType2 { anchors.right: parent.right anchors.bottom: parent.bottom - property bool isFocusable: true property int selectedIndex: LanguageModel.currentLanguageIndex - clip: true - reuseItems: true - - ScrollBar.vertical: ScrollBarType {} - model: LanguageModel ButtonGroup { diff --git a/client/ui/qml/Components/ServersListView.qml b/client/ui/qml/Components/ServersListView.qml index d0567a8c..4417e0b2 100644 --- a/client/ui/qml/Components/ServersListView.qml +++ b/client/ui/qml/Components/ServersListView.qml @@ -15,7 +15,7 @@ import "../Controls2" import "../Controls2/TextTypes" import "../Config" -ListView { +ListViewType { id: root property int selectedIndex: ServersModel.defaultIndex @@ -28,10 +28,6 @@ ListView { model: ServersModel - ScrollBar.vertical: ScrollBarType {} - - property bool isFocusable: true - Connections { target: ServersModel function onDefaultServerIndexChanged(serverIndex) { @@ -39,9 +35,6 @@ ListView { } } - clip: true - reuseItems: true - delegate: Item { id: menuContentDelegate objectName: "menuContentDelegate" diff --git a/client/ui/qml/Components/SettingsContainersListView.qml b/client/ui/qml/Components/SettingsContainersListView.qml index 4b551cbb..ccf60917 100644 --- a/client/ui/qml/Components/SettingsContainersListView.qml +++ b/client/ui/qml/Components/SettingsContainersListView.qml @@ -16,75 +16,61 @@ import "../Controls2/TextTypes" ListViewType { id: root - width: parent.width - height: root.contentItem.height + anchors.fill: parent - clip: true - reuseItems: true + delegate: ColumnLayout { + width: root.width - property bool isFocusable: false + LabelWithButtonType { + Layout.fillWidth: true - delegate: Item { - implicitWidth: root.width - implicitHeight: delegateContent.implicitHeight + text: name + descriptionText: description + rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg" - ColumnLayout { - id: delegateContent + clickedFunction: function() { + if (isInstalled) { + var containerIndex = root.model.mapToSource(index) + ContainersModel.setProcessedContainerIndex(containerIndex) - anchors.fill: parent - - 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: { + if (serviceType !== ProtocolEnum.Other) { + if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) { ProtocolsModel.updateModel(config) 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 { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - enabled: false + switch (containerIndex) { + case ContainerEnum.Ipsec: { + ProtocolsModel.updateModel(config) + 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 {} } } diff --git a/client/ui/qml/Controls2/BasicButtonType.qml b/client/ui/qml/Controls2/BasicButtonType.qml index b60e96cf..914fc267 100644 --- a/client/ui/qml/Controls2/BasicButtonType.qml +++ b/client/ui/qml/Controls2/BasicButtonType.qml @@ -1,220 +1,210 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - -import Style 1.0 - -import "TextTypes" - -Button { - id: root - - property string hoveredColor: AmneziaStyle.color.lightGray - property string defaultColor: AmneziaStyle.color.paleGray - property string disabledColor: AmneziaStyle.color.charcoalGray - property string pressedColor: AmneziaStyle.color.mutedGray - - property string textColor: AmneziaStyle.color.midnightBlack - - property string borderColor: AmneziaStyle.color.paleGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - property int borderWidth: 0 - property int borderFocusedWidth: 1 - - property string leftImageSource - property string rightImageSource - property string leftImageColor: textColor - property bool changeLeftImageSize: true - - property bool squareLeftSide: false - - property FlickableType parentFlickable - - property var clickedFunc - - property alias buttonTextLabel: buttonText - - 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() - } - - implicitHeight: 56 - - hoverEnabled: true - - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(this) - } - } - } - - background: Rectangle { - id: focusBorder - - color: AmneziaStyle.color.transparent - border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent - border.width: root.activeFocus ? root.borderFocusedWidth : 0 - - anchors.fill: parent - - radius: 16 - - Rectangle { - id: background - - anchors.fill: focusBorder - anchors.margins: root.activeFocus ? 2 : 0 - - radius: root.activeFocus ? 14 : 16 - color: { - if (root.enabled) { - if (root.pressed) { - return pressedColor - } - return root.hovered ? hoveredColor : defaultColor - } else { - return disabledColor - } - } - border.color: borderColor - border.width: borderWidth - - Behavior on color { - PropertyAnimation { duration: 200 } - } - - Rectangle { - visible: root.squareLeftSide - - z: 1 - - width: parent.radius - height: parent.radius - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - color: { - if (root.enabled) { - if (root.pressed) { - return pressedColor - } - return root.hovered ? hoveredColor : defaultColor - } else { - return disabledColor - } - } - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - } - } - - MouseArea { - anchors.fill: focusBorder - enabled: false - cursorShape: Qt.PointingHandCursor - } - - contentItem: Item { - anchors.fill: focusBorder - - implicitWidth: content.implicitWidth - implicitHeight: content.implicitHeight - - RowLayout { - id: content - anchors.centerIn: parent - - Image { - id: leftImage - source: root.leftImageSource - visible: root.leftImageSource === "" ? false : true - - layer { - enabled: leftImageColor !== "" ? true : false - effect: ColorOverlay { - color: leftImageColor - } - } - - Component.onCompleted: { - if (root.changeLeftImageSize) { - leftImage.Layout.preferredHeight = 20 - leftImage.Layout.preferredWidth = 20 - } - } - } - - ButtonTextType { - id: buttonText - - color: root.textColor - text: root.text - visible: root.text === "" ? false : true - - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - } - - Image { - Layout.preferredHeight: 20 - Layout.preferredWidth: 20 - - source: root.rightImageSource - visible: root.rightImageSource === "" ? false : true - - layer { - enabled: true - effect: ColorOverlay { - color: textColor - } - } - } - } - } - - Keys.onEnterPressed: { - 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() - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects + +import Style 1.0 + +import "TextTypes" + +Button { + id: root + + property string hoveredColor: AmneziaStyle.color.lightGray + property string defaultColor: AmneziaStyle.color.paleGray + property string disabledColor: AmneziaStyle.color.charcoalGray + property string pressedColor: AmneziaStyle.color.mutedGray + + property string textColor: AmneziaStyle.color.midnightBlack + + property string borderColor: AmneziaStyle.color.paleGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + property int borderWidth: 0 + property int borderFocusedWidth: 1 + + property string leftImageSource + property string rightImageSource + property string leftImageColor: textColor + property bool changeLeftImageSize: true + + property bool squareLeftSide: false + + property var clickedFunc + + property alias buttonTextLabel: buttonText + + 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() + } + + implicitHeight: 56 + + hoverEnabled: true + + background: Rectangle { + id: focusBorder + + color: AmneziaStyle.color.transparent + border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent + border.width: root.activeFocus ? root.borderFocusedWidth : 0 + + anchors.fill: parent + + radius: 16 + + Rectangle { + id: background + + anchors.fill: focusBorder + anchors.margins: root.activeFocus ? 2 : 0 + + radius: root.activeFocus ? 14 : 16 + color: { + if (root.enabled) { + if (root.pressed) { + return pressedColor + } + return root.hovered ? hoveredColor : defaultColor + } else { + return disabledColor + } + } + border.color: borderColor + border.width: borderWidth + + Behavior on color { + PropertyAnimation { duration: 200 } + } + + Rectangle { + visible: root.squareLeftSide + + z: 1 + + width: parent.radius + height: parent.radius + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + color: { + if (root.enabled) { + if (root.pressed) { + return pressedColor + } + return root.hovered ? hoveredColor : defaultColor + } else { + return disabledColor + } + } + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + } + } + + MouseArea { + anchors.fill: focusBorder + enabled: false + cursorShape: Qt.PointingHandCursor + } + + contentItem: Item { + anchors.fill: focusBorder + + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight + + RowLayout { + id: content + anchors.centerIn: parent + + Image { + id: leftImage + source: root.leftImageSource + visible: root.leftImageSource === "" ? false : true + + layer { + enabled: leftImageColor !== "" ? true : false + effect: ColorOverlay { + color: leftImageColor + } + } + + Component.onCompleted: { + if (root.changeLeftImageSize) { + leftImage.Layout.preferredHeight = 20 + leftImage.Layout.preferredWidth = 20 + } + } + } + + ButtonTextType { + id: buttonText + + color: root.textColor + text: root.text + visible: root.text === "" ? false : true + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + + Image { + Layout.preferredHeight: 20 + Layout.preferredWidth: 20 + + source: root.rightImageSource + visible: root.rightImageSource === "" ? false : true + + layer { + enabled: true + effect: ColorOverlay { + color: textColor + } + } + } + } + } + + Keys.onEnterPressed: { + 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() + } + } +} diff --git a/client/ui/qml/Controls2/CardWithIconsType.qml b/client/ui/qml/Controls2/CardWithIconsType.qml index 4277d735..02d033d2 100644 --- a/client/ui/qml/Controls2/CardWithIconsType.qml +++ b/client/ui/qml/Controls2/CardWithIconsType.qml @@ -1,203 +1,185 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Button { - id: root - - property string headerText - property string bodyText - property string footerText - - property string hoveredColor: AmneziaStyle.color.slateGray - property string defaultColor: AmneziaStyle.color.onyxBlack - - property string textColor: AmneziaStyle.color.midnightBlack - - property string rightImageSource - property string rightImageColor: AmneziaStyle.color.paleGray - - property string leftImageSource - - property real textOpacity: 1.0 - - property alias focusItem: rightImage - - property FlickableType parentFlickable - - hoverEnabled: true - - background: Rectangle { - id: backgroundRect - - anchors.fill: parent - radius: 16 - - color: defaultColor - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - - function ensureVisible(item) { - if (item.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - onFocusChanged: { - ensureVisible(root) - } - - focusItem.onFocusChanged: { - root.ensureVisible(focusItem) - } - - contentItem: Item { - anchors.left: parent.left - anchors.right: parent.right - - implicitHeight: content.implicitHeight - - RowLayout { - id: content - - anchors.fill: parent - - Image { - id: leftImage - source: leftImageSource - - visible: leftImageSource !== "" - - Layout.alignment: Qt.AlignLeft | Qt.AlignTop - Layout.topMargin: 24 - Layout.bottomMargin: 24 - Layout.leftMargin: 24 - } - - ColumnLayout { - - ListItemTitleType { - text: root.headerText - visible: text !== "" - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.topMargin: 16 - Layout.bottomMargin: root.bodyText !== "" ? 0 : 16 - - opacity: root.textOpacity - } - - CaptionTextType { - text: root.bodyText - visible: text !== "" - - color: AmneziaStyle.color.mutedGray - textFormat: Text.RichText - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: root.footerText !== "" ? 0 : 16 - - opacity: root.textOpacity - } - - ButtonTextType { - text: root.footerText - visible: text !== "" - - color: AmneziaStyle.color.mutedGray - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.topMargin: 16 - Layout.bottomMargin: 16 - - opacity: root.textOpacity - } - } - - ImageButtonType { - id: rightImage - - implicitWidth: 40 - implicitHeight: 40 - - hoverEnabled: false - image: rightImageSource - imageColor: rightImageColor - visible: rightImageSource ? true : false - - Layout.alignment: Qt.AlignRight | Qt.AlignTop - Layout.topMargin: 16 - Layout.bottomMargin: 16 - Layout.rightMargin: 16 - - Rectangle { - id: rightImageBackground - - anchors.fill: parent - radius: 12 - color: "transparent" - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - - onClicked: { - root.clicked() - } - } - } - } - - MouseArea { - anchors.fill: parent - - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - enabled: root.enabled - - onEntered: { - backgroundRect.color = root.hoveredColor - - if (rightImageSource) { - rightImageBackground.color = rightImage.hoveredColor - } - root.textOpacity = 0.8 - } - - 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() - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Button { + id: root + + property string headerText + property string bodyText + property string footerText + + property string hoveredColor: AmneziaStyle.color.slateGray + property string defaultColor: AmneziaStyle.color.onyxBlack + + property string textColor: AmneziaStyle.color.midnightBlack + + property string rightImageSource + property string rightImageColor: AmneziaStyle.color.paleGray + + property string leftImageSource + + property real textOpacity: 1.0 + + property alias focusItem: rightImage + + hoverEnabled: true + + background: Rectangle { + id: backgroundRect + + anchors.fill: parent + radius: 16 + + color: defaultColor + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + contentItem: Item { + anchors.left: parent.left + anchors.right: parent.right + + implicitHeight: content.implicitHeight + + RowLayout { + id: content + + anchors.fill: parent + + Image { + id: leftImage + source: leftImageSource + + visible: leftImageSource !== "" + + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 24 + } + + ColumnLayout { + + ListItemTitleType { + text: root.headerText + visible: text !== "" + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: root.bodyText !== "" ? 0 : 16 + + opacity: root.textOpacity + } + + CaptionTextType { + text: root.bodyText + visible: text !== "" + + color: AmneziaStyle.color.mutedGray + textFormat: Text.RichText + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: root.footerText !== "" ? 0 : 16 + + opacity: root.textOpacity + } + + ButtonTextType { + text: root.footerText + visible: text !== "" + + color: AmneziaStyle.color.mutedGray + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: 16 + + opacity: root.textOpacity + } + } + + ImageButtonType { + id: rightImage + + implicitWidth: 40 + implicitHeight: 40 + + hoverEnabled: false + image: rightImageSource + imageColor: rightImageColor + visible: rightImageSource ? true : false + + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.topMargin: 16 + Layout.bottomMargin: 16 + Layout.rightMargin: 16 + + Rectangle { + id: rightImageBackground + + anchors.fill: parent + radius: 12 + color: "transparent" + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + onClicked: { + root.clicked() + } + } + } + } + + MouseArea { + anchors.fill: parent + + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + enabled: root.enabled + + onEntered: { + backgroundRect.color = root.hoveredColor + + if (rightImageSource) { + rightImageBackground.color = rightImage.hoveredColor + } + root.textOpacity = 0.8 + } + + 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() + } + } +} diff --git a/client/ui/qml/Controls2/CheckBoxType.qml b/client/ui/qml/Controls2/CheckBoxType.qml index a26a68f1..451fe01d 100644 --- a/client/ui/qml/Controls2/CheckBoxType.qml +++ b/client/ui/qml/Controls2/CheckBoxType.qml @@ -1,170 +1,187 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - -import Style 1.0 - -import "TextTypes" - -CheckBox { - id: root - - property string descriptionText - property string descriptionTextColor: AmneziaStyle.color.mutedGray - property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray - - property string textColor: AmneziaStyle.color.paleGray - property string textDisabledColor: AmneziaStyle.color.mutedGray - - property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite - property string defaultColor: AmneziaStyle.color.transparent - property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite - - property string defaultBorderColor: AmneziaStyle.color.paleGray - property string checkedBorderColor: AmneziaStyle.color.goldenApricot - property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown - - property string borderFocusedColor: AmneziaStyle.color.paleGray - - property string checkedImageColor: AmneziaStyle.color.goldenApricot - property string pressedImageColor: AmneziaStyle.color.burntOrange - property string defaultImageColor: AmneziaStyle.color.transparent - property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown - - property string imageSource: "qrc:/images/controls/check.svg" - - property var parentFlickable - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - hoverEnabled: enabled ? true : false - focusPolicy: Qt.NoFocus - - background: Rectangle { - color: AmneziaStyle.color.transparent - border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent - border.width: 1 - radius: 16 - } - - indicator: Rectangle { - id: background - - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: 56 - implicitHeight: 56 - radius: 16 - - color: { - if (root.hovered) { - return hoveredColor - } - return defaultColor - } - - Behavior on color { - PropertyAnimation { duration: 200 } - } - - Rectangle { - id: imageBorder - - anchors.centerIn: parent - width: 24 - height: 24 - color: AmneziaStyle.color.transparent - border.color: root.checked ? - (root.enabled ? - checkedBorderColor : - checkedBorderDisabledColor) : - defaultBorderColor - border.width: 1 - radius: 4 - - Image { - anchors.centerIn: parent - - source: root.pressed ? imageSource : root.checked ? imageSource : "" - layer { - enabled: true - effect: ColorOverlay { - color: { - if (root.pressed) { - return root.pressedImageColor - } else if (root.checked) { - if (root.enabled) { - return root.checkedImageColor - } else { - return root.checkedDisabledImageColor - } - } else { - return root.defaultImageColor - } - } - } - } - } - } - } - - contentItem: Item { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 8 + background.width - - implicitHeight: content.implicitHeight - - ColumnLayout { - id: content - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - spacing: 4 - - ListItemTitleType { - Layout.fillWidth: true - - text: root.text - color: root.enabled ? root.textColor : root.textDisabledColor - } - - CaptionTextType { - id: description - - Layout.fillWidth: true - - text: root.descriptionText - color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor - - visible: root.descriptionText !== "" - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - enabled: false - } - - - Keys.onEnterPressed: { - root.checked = !root.checked - } - - Keys.onReturnPressed: { - root.checked = !root.checked - } - -} - - +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects + +import Style 1.0 + +import "TextTypes" + +CheckBox { + id: root + + property string descriptionText + property string descriptionTextColor: AmneziaStyle.color.mutedGray + property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray + + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray + + property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite + property string defaultColor: AmneziaStyle.color.transparent + property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite + + property string defaultBorderColor: AmneziaStyle.color.paleGray + property string checkedBorderColor: AmneziaStyle.color.goldenApricot + property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown + + property string borderFocusedColor: AmneziaStyle.color.paleGray + + property string checkedImageColor: AmneziaStyle.color.goldenApricot + property string pressedImageColor: AmneziaStyle.color.burntOrange + property string defaultImageColor: AmneziaStyle.color.transparent + property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown + + property string imageSource: "qrc:/images/controls/check.svg" + + 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() + } + + hoverEnabled: enabled ? true : false + focusPolicy: Qt.NoFocus + + background: Rectangle { + color: AmneziaStyle.color.transparent + border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent + border.width: 1 + radius: 16 + } + + indicator: Rectangle { + id: background + + anchors.verticalCenter: parent.verticalCenter + + implicitWidth: 56 + implicitHeight: 56 + radius: 16 + + color: { + if (root.hovered) { + return hoveredColor + } + return defaultColor + } + + Behavior on color { + PropertyAnimation { duration: 200 } + } + + Rectangle { + id: imageBorder + + anchors.centerIn: parent + width: 24 + height: 24 + color: AmneziaStyle.color.transparent + border.color: root.checked ? + (root.enabled ? + checkedBorderColor : + checkedBorderDisabledColor) : + defaultBorderColor + border.width: 1 + radius: 4 + + Image { + anchors.centerIn: parent + + source: root.pressed ? imageSource : root.checked ? imageSource : "" + layer { + enabled: true + effect: ColorOverlay { + color: { + if (root.pressed) { + return root.pressedImageColor + } else if (root.checked) { + if (root.enabled) { + return root.checkedImageColor + } else { + return root.checkedDisabledImageColor + } + } else { + return root.defaultImageColor + } + } + } + } + } + } + } + + contentItem: Item { + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 8 + background.width + + implicitHeight: content.implicitHeight + + ColumnLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + spacing: 4 + + ListItemTitleType { + Layout.fillWidth: true + + text: root.text + color: root.enabled ? root.textColor : root.textDisabledColor + } + + CaptionTextType { + id: description + + Layout.fillWidth: true + + text: root.descriptionText + color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor + + visible: root.descriptionText !== "" + } + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + enabled: false + } + + + Keys.onEnterPressed: { + root.checked = !root.checked + } + + Keys.onReturnPressed: { + root.checked = !root.checked + } + +} + + diff --git a/client/ui/qml/Controls2/LabelWithButtonType.qml b/client/ui/qml/Controls2/LabelWithButtonType.qml index 087415f7..56d721b9 100644 --- a/client/ui/qml/Controls2/LabelWithButtonType.qml +++ b/client/ui/qml/Controls2/LabelWithButtonType.qml @@ -1,328 +1,309 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Item { - id: root - - property string text - property int textMaximumLineCount: 2 - property int textElide: Qt.ElideRight - - property string descriptionText - - property var clickedFunction - - property string buttonImageSource - property string rightImageSource - property string leftImageSource - property bool isLeftImageHoverEnabled: true - property bool isSmallLeftImage: false - - property alias rightButton: rightImage - property alias eyeButton: eyeImage - property FlickableType parentFlickable - - property string textColor: AmneziaStyle.color.paleGray - property string textDisabledColor: AmneziaStyle.color.mutedGray - property string descriptionColor: AmneziaStyle.color.mutedGray - property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray - property real textOpacity: 1.0 - - property string borderFocusedColor: AmneziaStyle.color.paleGray - property int borderFocusedWidth: 1 - - property string rightImageColor: AmneziaStyle.color.paleGray - - property bool descriptionOnTop: false - property bool hideDescription: true - - property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } - - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } - - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } - - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin - implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin - - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - Connections { - target: rightImage - function onFocusChanged() { - if (rightImage.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: root.enabled - - onEntered: { - if (rightImageSource) { - rightImageBackground.color = rightImage.hoveredColor - } else if (leftImageSource) { - leftImageBackground.color = rightImage.hoveredColor - } - root.textOpacity = 0.8 - } - - onExited: { - if (rightImageSource) { - rightImageBackground.color = rightImage.defaultColor - } else if (leftImageSource) { - leftImageBackground.color = rightImage.defaultColor - } - root.textOpacity = 1 - } - - onPressedChanged: { - if (rightImageSource) { - rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor - } else if (leftImageSource) { - leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor - } - root.textOpacity = 0.7 - } - - onClicked: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } - } - - RowLayout { - id: content - anchors.fill: parent - anchors.leftMargin: 16 - anchors.rightMargin: 16 - anchors.topMargin: 16 - anchors.bottomMargin: 16 - - Rectangle { - id: leftImageBackground - - visible: leftImageSource ? true : false - - Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56 - Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56 - Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0 - - radius: 12 - color: AmneziaStyle.color.transparent - - Behavior on color { - PropertyAnimation { duration: 200 } - } - - Image { - id: leftImage - - anchors.centerIn: parent - source: leftImageSource - } - } - - ColumnLayout { - property real textLineHeight: 21.6 - property real descriptionTextLineHeight: 16 - - property int textPixelSize: 18 - property int descriptionTextSize: 13 - - ListItemTitleType { - text: root.text - color: { - if (root.enabled) { - return root.descriptionOnTop ? root.descriptionColor : root.textColor - } else { - return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor - } - } - - maximumLineCount: root.textMaximumLineCount - elide: root.textElide - - opacity: root.textOpacity - - Layout.fillWidth: true - - lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight - font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize - font.letterSpacing: root.descriptionOnTop ? 0.02 : 0 - - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - - Behavior on opacity { - PropertyAnimation { duration: 200 } - } - } - - - CaptionTextType { - id: description - - text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText - color: { - if (root.enabled) { - return root.descriptionOnTop ? root.textColor : root.descriptionColor - } else { - return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor - } - } - - opacity: root.textOpacity - - visible: root.descriptionText !== "" - - Layout.fillWidth: true - - lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight - font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize - font.letterSpacing: root.descriptionOnTop ? 0 : 0.02 - - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - - Behavior on opacity { - PropertyAnimation { duration: 200 } - } - - function replaceWithAsterisks(input) { - return '*'.repeat(input.length) - } - } - } - - ImageButtonType { - id: eyeImage - visible: buttonImageSource !== "" - - implicitWidth: 40 - implicitHeight: 40 - - hoverEnabled: true - image: buttonImageSource - imageColor: rightImageColor - - Layout.alignment: Qt.AlignRight - - Rectangle { - id: eyeImageBackground - anchors.fill: parent - radius: 12 - color: AmneziaStyle.color.transparent - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - - onClicked: { - hideDescription = !hideDescription - } - - Keys.onEnterPressed: { - clicked() - } - - Keys.onReturnPressed: { - clicked() - } - } - - ImageButtonType { - id: rightImage - - implicitWidth: 40 - implicitHeight: 40 - - hoverEnabled: false - image: rightImageSource - imageColor: rightImageColor - visible: rightImageSource ? true : false - - Layout.alignment: Qt.AlignRight - - Rectangle { - id: rightImageBackground - anchors.fill: parent - radius: 12 - color: AmneziaStyle.color.transparent - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - onClicked: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } - } - } - - Rectangle { - id: background - anchors.fill: root - 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 } - } - } - - Keys.onEnterPressed: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } - - Keys.onReturnPressed: { - if (clickedFunction && typeof clickedFunction === "function") { - clickedFunction() - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Item { + id: root + + // property alias focusObjectName: eyeImage.objectName + property string text + property int textMaximumLineCount: 2 + property int textElide: Qt.ElideRight + + property string descriptionText + + property var clickedFunction + + property string buttonImageSource + property string rightImageSource + property string leftImageSource + property bool isLeftImageHoverEnabled: true + property bool isSmallLeftImage: false + + property alias rightButton: rightImage + property alias eyeButton: eyeImage + + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray + property string descriptionColor: AmneziaStyle.color.mutedGray + property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray + property real textOpacity: 1.0 + + property string borderFocusedColor: AmneziaStyle.color.paleGray + property int borderFocusedWidth: 1 + + property string rightImageColor: AmneziaStyle.color.paleGray + + property bool descriptionOnTop: false + property bool hideDescription: true + + property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + Keys.onUpPressed: { + FocusController.nextKeyUpItem() + } + + Keys.onDownPressed: { + FocusController.nextKeyDownItem() + } + + Keys.onLeftPressed: { + FocusController.nextKeyLeftItem() + } + + Keys.onRightPressed: { + FocusController.nextKeyRightItem() + } + + implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin + implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: root.enabled + + onEntered: { + if (rightImageSource) { + rightImageBackground.color = rightImage.hoveredColor + } else if (leftImageSource) { + leftImageBackground.color = rightImage.hoveredColor + } + root.textOpacity = 0.8 + } + + onExited: { + if (rightImageSource) { + rightImageBackground.color = rightImage.defaultColor + } else if (leftImageSource) { + leftImageBackground.color = rightImage.defaultColor + } + root.textOpacity = 1 + } + + onPressedChanged: { + if (rightImageSource) { + rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor + } else if (leftImageSource) { + leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor + } + root.textOpacity = 0.7 + } + + onClicked: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } + } + + RowLayout { + id: content + anchors.fill: parent + anchors.leftMargin: 16 + anchors.rightMargin: 16 + anchors.topMargin: 16 + anchors.bottomMargin: 16 + + Rectangle { + id: leftImageBackground + + visible: leftImageSource ? true : false + + Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56 + Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56 + Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0 + + radius: 12 + color: AmneziaStyle.color.transparent + + Behavior on color { + PropertyAnimation { duration: 200 } + } + + Image { + id: leftImage + + anchors.centerIn: parent + source: leftImageSource + } + } + + ColumnLayout { + property real textLineHeight: 21.6 + property real descriptionTextLineHeight: 16 + + property int textPixelSize: 18 + property int descriptionTextSize: 13 + + ListItemTitleType { + text: root.text + color: { + if (root.enabled) { + return root.descriptionOnTop ? root.descriptionColor : root.textColor + } else { + return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor + } + } + + maximumLineCount: root.textMaximumLineCount + elide: root.textElide + + opacity: root.textOpacity + + Layout.fillWidth: true + + lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight + font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize + font.letterSpacing: root.descriptionOnTop ? 0.02 : 0 + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + Behavior on opacity { + PropertyAnimation { duration: 200 } + } + } + + + CaptionTextType { + id: description + + text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText + color: { + if (root.enabled) { + return root.descriptionOnTop ? root.textColor : root.descriptionColor + } else { + return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor + } + } + + opacity: root.textOpacity + + visible: root.descriptionText !== "" + + Layout.fillWidth: true + + lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight + font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize + font.letterSpacing: root.descriptionOnTop ? 0 : 0.02 + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + Behavior on opacity { + PropertyAnimation { duration: 200 } + } + + function replaceWithAsterisks(input) { + return '*'.repeat(input.length) + } + } + } + + ImageButtonType { + id: eyeImage + visible: buttonImageSource !== "" + + implicitWidth: 40 + implicitHeight: 40 + + hoverEnabled: true + image: buttonImageSource + imageColor: rightImageColor + + Layout.alignment: Qt.AlignRight + + Rectangle { + id: eyeImageBackground + anchors.fill: parent + radius: 12 + color: AmneziaStyle.color.transparent + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + + onClicked: { + hideDescription = !hideDescription + } + + Keys.onEnterPressed: { + clicked() + } + + Keys.onReturnPressed: { + clicked() + } + } + + ImageButtonType { + id: rightImage + + implicitWidth: 40 + implicitHeight: 40 + + hoverEnabled: false + image: rightImageSource + imageColor: rightImageColor + visible: rightImageSource ? true : false + + Layout.alignment: Qt.AlignRight + + Rectangle { + id: rightImageBackground + anchors.fill: parent + radius: 12 + color: AmneziaStyle.color.transparent + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + onClicked: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } + } + } + + Rectangle { + id: background + anchors.fill: root + 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 } + } + } + + Keys.onEnterPressed: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } + + Keys.onReturnPressed: { + if (clickedFunction && typeof clickedFunction === "function") { + clickedFunction() + } + } +} diff --git a/client/ui/qml/Controls2/ListViewType.qml b/client/ui/qml/Controls2/ListViewType.qml index 0de43d77..8d067537 100644 --- a/client/ui/qml/Controls2/ListViewType.qml +++ b/client/ui/qml/Controls2/ListViewType.qml @@ -6,33 +6,16 @@ ListView { 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 {} clip: 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; + } } diff --git a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml index bd7ca32e..abd4da3e 100644 --- a/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml +++ b/client/ui/qml/Controls2/ListViewWithRadioButtonType.qml @@ -6,7 +6,7 @@ import Style 1.0 import "TextTypes" -ListView { +ListViewType { id: root property var rootWidth @@ -25,13 +25,6 @@ ListView { width: rootWidth height: root.contentItem.height - clip: true - reuseItems: true - - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - ButtonGroup { id: buttonGroup } diff --git a/client/ui/qml/Controls2/SwitcherType.qml b/client/ui/qml/Controls2/SwitcherType.qml index 0651390f..db9ef755 100644 --- a/client/ui/qml/Controls2/SwitcherType.qml +++ b/client/ui/qml/Controls2/SwitcherType.qml @@ -1,172 +1,162 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Switch { - id: root - - property alias descriptionText: description.text - property string descriptionTextColor: AmneziaStyle.color.mutedGray - property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray - - property string textColor: AmneziaStyle.color.paleGray - property string textDisabledColor: AmneziaStyle.color.mutedGray - - property string checkedIndicatorColor: AmneziaStyle.color.richBrown - property string defaultIndicatorColor: AmneziaStyle.color.transparent - property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown - - property string borderFocusedColor: AmneziaStyle.color.paleGray - property int borderFocusedWidth: 1 - - property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown - property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray - property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown - - property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot - property string defaultInnerCircleColor: AmneziaStyle.color.paleGray - property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown - property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray - - property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite - property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent - - 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() - } - - hoverEnabled: enabled ? true : false - focusPolicy: Qt.TabFocus - - property FlickableType parentFlickable: null - - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - indicator: Rectangle { - id: switcher - - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: 52 - implicitHeight: 32 - - radius: 16 - color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor) - : root.defaultIndicatorColor - - border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor) - : root.defaultIndicatorBorderColor) - - Behavior on color { - PropertyAnimation { duration: 200 } - } - Behavior on border.color { - PropertyAnimation { duration: 200 } - } - - Rectangle { - id: innerCircle - - anchors.verticalCenter: parent.verticalCenter - x: root.checked ? parent.width - width - 4 : 8 - width: root.checked ? 24 : 16 - height: root.checked ? 24 : 16 - radius: 23 - color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor) - : (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor) - - Behavior on x { - PropertyAnimation { duration: 200 } - } - } - - Rectangle { - anchors.centerIn: innerCircle - width: 40 - height: 40 - radius: 23 - color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor - - Behavior on color { - PropertyAnimation { duration: 200 } - } - } - } - - contentItem: ColumnLayout { - id: content - - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - - ListItemTitleType { - Layout.fillWidth: true - rightPadding: indicator.width - - text: root.text - color: root.enabled ? root.textColor : root.textDisabledColor - } - - CaptionTextType { - id: description - - Layout.fillWidth: true - rightPadding: indicator.width - - color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor - - visible: text !== "" - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - enabled: false - } - - 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 - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Switch { + id: root + + property alias descriptionText: description.text + property string descriptionTextColor: AmneziaStyle.color.mutedGray + property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray + + property string textColor: AmneziaStyle.color.paleGray + property string textDisabledColor: AmneziaStyle.color.mutedGray + + property string checkedIndicatorColor: AmneziaStyle.color.richBrown + property string defaultIndicatorColor: AmneziaStyle.color.transparent + property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown + + property string borderFocusedColor: AmneziaStyle.color.paleGray + property int borderFocusedWidth: 1 + + property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown + property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray + property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown + + property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot + property string defaultInnerCircleColor: AmneziaStyle.color.paleGray + property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown + property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray + + property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite + property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent + + 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() + } + + hoverEnabled: enabled ? true : false + focusPolicy: Qt.TabFocus + + indicator: Rectangle { + id: switcher + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + implicitWidth: 52 + implicitHeight: 32 + + radius: 16 + color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor) + : root.defaultIndicatorColor + + border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor) + : root.defaultIndicatorBorderColor) + + Behavior on color { + PropertyAnimation { duration: 200 } + } + Behavior on border.color { + PropertyAnimation { duration: 200 } + } + + Rectangle { + id: innerCircle + + anchors.verticalCenter: parent.verticalCenter + x: root.checked ? parent.width - width - 4 : 8 + width: root.checked ? 24 : 16 + height: root.checked ? 24 : 16 + radius: 23 + color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor) + : (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor) + + Behavior on x { + PropertyAnimation { duration: 200 } + } + } + + Rectangle { + anchors.centerIn: innerCircle + width: 40 + height: 40 + radius: 23 + color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor + + Behavior on color { + PropertyAnimation { duration: 200 } + } + } + } + + contentItem: ColumnLayout { + id: content + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + ListItemTitleType { + Layout.fillWidth: true + rightPadding: indicator.width + + text: root.text + color: root.enabled ? root.textColor : root.textDisabledColor + } + + CaptionTextType { + id: description + + Layout.fillWidth: true + rightPadding: indicator.width + + color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor + + visible: text !== "" + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + enabled: false + } + + 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 + } +} diff --git a/client/ui/qml/Controls2/TextAreaType.qml b/client/ui/qml/Controls2/TextAreaType.qml index 9359fa16..7b6721dd 100644 --- a/client/ui/qml/Controls2/TextAreaType.qml +++ b/client/ui/qml/Controls2/TextAreaType.qml @@ -1,118 +1,135 @@ -import QtQuick -import QtQuick.Controls - -import Style 1.0 - -Rectangle { - id: root - - property string placeholderText - property string text - property alias textArea: textArea - property alias textAreaText: textArea.text - - property string borderHoveredColor: AmneziaStyle.color.charcoalGray - property string borderNormalColor: AmneziaStyle.color.slateGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - - height: 148 - color: AmneziaStyle.color.onyxBlack - border.width: 1 - border.color: getBorderColor(borderNormalColor) - radius: 16 - - property FlickableType parentFlickable: null - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - MouseArea { - id: parentMouse - anchors.fill: parent - cursorShape: Qt.IBeamCursor - onClicked: textArea.forceActiveFocus() - hoverEnabled: true - - FlickableType { - id: fl - interactive: false - - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: textArea.implicitHeight - TextArea { - id: textArea - - width: parent.width - - topPadding: 16 - leftPadding: 16 - anchors.topMargin: 16 - anchors.bottomMargin: 16 - - color: AmneziaStyle.color.paleGray - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - placeholderTextColor: AmneziaStyle.color.mutedGray - - font.pixelSize: 16 - font.weight: Font.Medium - font.family: "PT Root UI VF" - - placeholderText: root.placeholderText - text: root.text - - onCursorVisibleChanged: { - if (textArea.cursorVisible) { - fl.interactive = true - } else { - fl.interactive = false - } - } - - wrapMode: Text.Wrap - - MouseArea { - id: textAreaMouse - anchors.fill: parent - acceptedButtons: Qt.RightButton - hoverEnabled: true - onClicked: { - fl.interactive = true - contextMenu.open() - } - } - - onFocusChanged: { - root.border.color = getBorderColor(borderNormalColor) - } - - ContextMenuType { - id: contextMenu - textObj: textArea - } - } - } - - 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 - } -} +import QtQuick +import QtQuick.Controls + +import Style 1.0 + +Rectangle { + id: root + + property string placeholderText + property string text + property alias textArea: textArea + property alias textAreaText: textArea.text + + property string borderHoveredColor: AmneziaStyle.color.charcoalGray + property string borderNormalColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + + height: 148 + color: AmneziaStyle.color.onyxBlack + border.width: 1 + border.color: getBorderColor(borderNormalColor) + radius: 16 + + MouseArea { + id: parentMouse + anchors.fill: parent + cursorShape: Qt.IBeamCursor + onClicked: textArea.forceActiveFocus() + hoverEnabled: true + + FlickableType { + id: fl + interactive: false + + anchors.top: parent.top + anchors.bottom: parent.bottom + contentHeight: textArea.implicitHeight + TextArea { + id: textArea + + width: parent.width + + topPadding: 16 + leftPadding: 16 + anchors.topMargin: 16 + anchors.bottomMargin: 16 + + 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() + } + + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + placeholderTextColor: AmneziaStyle.color.mutedGray + + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + + placeholderText: root.placeholderText + text: root.text + + onCursorVisibleChanged: { + if (textArea.cursorVisible) { + fl.interactive = true + } else { + fl.interactive = false + } + } + + wrapMode: Text.Wrap + + MouseArea { + id: textAreaMouse + anchors.fill: parent + acceptedButtons: Qt.RightButton + hoverEnabled: true + onClicked: { + fl.interactive = true + contextMenu.open() + } + } + + onFocusChanged: { + root.border.color = getBorderColor(borderNormalColor) + } + + ContextMenuType { + id: contextMenu + textObj: textArea + } + } + } + + 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 + } +} diff --git a/client/ui/qml/Controls2/TextAreaWithFooterType.qml b/client/ui/qml/Controls2/TextAreaWithFooterType.qml index cf7b9146..2cb6a69c 100644 --- a/client/ui/qml/Controls2/TextAreaWithFooterType.qml +++ b/client/ui/qml/Controls2/TextAreaWithFooterType.qml @@ -1,180 +1,171 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Rectangle { - id: root - - property string placeholderText - property string text - property string headerText - property alias textArea: textArea - property alias textAreaText: textArea.text - - property string borderHoveredColor: AmneziaStyle.color.charcoalGray - property string borderNormalColor: AmneziaStyle.color.slateGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - - property string firstButtonImage - property string secondButtonImage - - property var firstButtonClickedFunc - property var secondButtonClickedFunc - - height: 148 - color: AmneziaStyle.color.onyxBlack - border.width: 1 - border.color: getBorderColor(borderNormalColor) - radius: 16 - - property FlickableType parentFlickable: null - onFocusChanged: { - if (root.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - - MouseArea { - id: parentMouse - anchors.fill: parent - cursorShape: Qt.IBeamCursor - onClicked: textArea.forceActiveFocus() - hoverEnabled: true - - ColumnLayout { - anchors.fill: parent - anchors.margins: 16 - spacing: 0 - - LabelTextType { - Layout.fillWidth: true - text: root.headerText - } - - TextArea { - id: textArea - - Layout.fillWidth: true - Layout.fillHeight: true - - leftPadding: 0 - Layout.bottomMargin: 16 - - color: AmneziaStyle.color.paleGray - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - placeholderTextColor: AmneziaStyle.color.mutedGray - - font.pixelSize: 16 - font.weight: Font.Medium - font.family: "PT Root UI VF" - - placeholderText: root.placeholderText - text: root.text - - onCursorVisibleChanged: { - if (textArea.cursorVisible) { - fl.interactive = true - } else { - fl.interactive = false - } - } - - wrapMode: Text.Wrap - - MouseArea { - id: textAreaMouse - anchors.fill: parent - acceptedButtons: Qt.RightButton - hoverEnabled: true - onClicked: { - fl.interactive = true - contextMenu.open() - } - } - - onFocusChanged: { - root.border.color = getBorderColor(borderNormalColor) - } - - ContextMenuType { - id: contextMenu - textObj: textArea - } - } - - RowLayout { - Layout.fillWidth: true - Layout.leftMargin: -8 - spacing: 0 - ImageButtonType { - id: firstButton - visible: root.firstButtonImage !== "" - - imageColor: AmneziaStyle.color.paleGray - - image: root.firstButtonImage - onClicked: function() { - if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") { - root.firstButtonClickedFunc() - } - } - } - - ImageButtonType { - id: secondButton - visible: root.secondButtonImage !== "" - - imageColor: AmneziaStyle.color.paleGray - - image: root.secondButtonImage - onClicked: function() { - if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") { - root.secondButtonClickedFunc() - } - } - } - - Item { - Layout.fillWidth: true - } - - ImageButtonType { - id: resetButton - imageColor: AmneziaStyle.color.paleGray - - visible: root.textAreaText !== "" - image: "qrc:/images/controls/close.svg" - - onClicked: function() { - root.textAreaText = "" - textArea.focus = true - } - } - } - } - - 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 - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Rectangle { + id: root + + property string placeholderText + property string text + property string headerText + property alias textArea: textArea + property alias textAreaText: textArea.text + + property string borderHoveredColor: AmneziaStyle.color.charcoalGray + property string borderNormalColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + + property string firstButtonImage + property string secondButtonImage + + property var firstButtonClickedFunc + property var secondButtonClickedFunc + + height: 148 + color: AmneziaStyle.color.onyxBlack + border.width: 1 + border.color: getBorderColor(borderNormalColor) + radius: 16 + + MouseArea { + id: parentMouse + anchors.fill: parent + cursorShape: Qt.IBeamCursor + onClicked: textArea.forceActiveFocus() + hoverEnabled: true + + ColumnLayout { + anchors.fill: parent + anchors.margins: 16 + spacing: 0 + + LabelTextType { + Layout.fillWidth: true + text: root.headerText + } + + TextArea { + id: textArea + + Layout.fillWidth: true + Layout.fillHeight: true + + leftPadding: 0 + Layout.bottomMargin: 16 + + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + placeholderTextColor: AmneziaStyle.color.mutedGray + + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" + + placeholderText: root.placeholderText + text: root.text + + onCursorVisibleChanged: { + if (textArea.cursorVisible) { + fl.interactive = true + } else { + fl.interactive = false + } + } + + wrapMode: Text.Wrap + + MouseArea { + id: textAreaMouse + anchors.fill: parent + acceptedButtons: Qt.RightButton + hoverEnabled: true + onClicked: { + fl.interactive = true + contextMenu.open() + } + } + + onFocusChanged: { + root.border.color = getBorderColor(borderNormalColor) + } + + ContextMenuType { + id: contextMenu + textObj: textArea + } + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: -8 + spacing: 0 + ImageButtonType { + id: firstButton + visible: root.firstButtonImage !== "" + + imageColor: AmneziaStyle.color.paleGray + + image: root.firstButtonImage + onClicked: function() { + if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") { + root.firstButtonClickedFunc() + } + } + } + + ImageButtonType { + id: secondButton + visible: root.secondButtonImage !== "" + + imageColor: AmneziaStyle.color.paleGray + + image: root.secondButtonImage + onClicked: function() { + if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") { + root.secondButtonClickedFunc() + } + } + } + + Item { + Layout.fillWidth: true + } + + ImageButtonType { + id: resetButton + imageColor: AmneziaStyle.color.paleGray + + visible: root.textAreaText !== "" + image: "qrc:/images/controls/close.svg" + + onClicked: function() { + root.textAreaText = "" + textArea.focus = true + } + } + } + } + + 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 + } +} diff --git a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml index c4ed91b3..d7697867 100644 --- a/client/ui/qml/Controls2/TextFieldWithHeaderType.qml +++ b/client/ui/qml/Controls2/TextFieldWithHeaderType.qml @@ -1,233 +1,220 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import Style 1.0 - -import "TextTypes" - -Item { - id: root - - property string headerText - property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray - property string headerTextColor: AmneziaStyle.color.mutedGray - - property alias errorText: errorField.text - property bool checkEmptyText: false - property bool rightButtonClickedOnEnter: false - - property string buttonText - property string buttonImageSource - property var clickedFunc - - property alias textField: textField - property string textFieldTextColor: AmneziaStyle.color.paleGray - property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray - - property bool textFieldEditable: true - - property string borderColor: AmneziaStyle.color.slateGray - property string borderFocusedColor: AmneziaStyle.color.paleGray - - property string backgroundColor: AmneziaStyle.color.onyxBlack - property string backgroundDisabledColor: AmneziaStyle.color.transparent - property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray - - implicitWidth: content.implicitWidth - implicitHeight: content.implicitHeight - - property FlickableType parentFlickable - - Connections { - target: textField - function onFocusChanged() { - if (textField.activeFocus) { - if (root.parentFlickable) { - root.parentFlickable.ensureVisible(root) - } - } - } - } - - ColumnLayout { - id: content - anchors.fill: parent - - Rectangle { - id: backgroud - Layout.fillWidth: true - Layout.preferredHeight: input.implicitHeight - color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor - radius: 16 - border.color: getBackgroundBorderColor(root.borderColor) - border.width: 1 - - Behavior on border.color { - PropertyAnimation { duration: 200 } - } - - RowLayout { - id: input - anchors.fill: backgroud - ColumnLayout { - Layout.margins: 16 - LabelTextType { - text: root.headerText - color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor - - visible: text !== "" - - Layout.fillWidth: true - } - - TextField { - id: textField - - property bool isFocusable: true - - Keys.onTabPressed: { - FocusController.nextKeyTabItem() - } - - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } - - enabled: root.textFieldEditable - color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor - - inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText - - placeholderTextColor: AmneziaStyle.color.charcoalGray - - selectionColor: AmneziaStyle.color.richBrown - selectedTextColor: AmneziaStyle.color.paleGray - - font.pixelSize: 16 - font.weight: 400 - font.family: "PT Root UI VF" - - height: 24 - Layout.fillWidth: true - - topPadding: 0 - rightPadding: 0 - leftPadding: 0 - bottomPadding: 0 - - background: Rectangle { - anchors.fill: parent - color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor - } - - onTextChanged: { - root.errorText = "" - } - - onActiveFocusChanged: { - if (root.checkEmptyText && text === "") { - root.errorText = qsTr("The field can't be empty") - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: contextMenu.open() - enabled: true - } - - ContextMenuType { - id: contextMenu - textObj: textField - } - - onFocusChanged: { - backgroud.border.color = getBackgroundBorderColor(root.borderColor) - } - } - } - } - } - - SmallTextType { - id: errorField - - text: root.errorText - visible: root.errorText !== "" - color: AmneziaStyle.color.vibrantRed - - Layout.fillWidth: true - } - } - - MouseArea { - anchors.fill: root - cursorShape: Qt.IBeamCursor - - hoverEnabled: true - - onPressed: function(mouse) { - textField.forceActiveFocus() - mouse.accepted = false - - backgroud.border.color = getBackgroundBorderColor(root.borderColor) - } - - onEntered: { - backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor) - } - - - onExited: { - backgroud.border.color = getBackgroundBorderColor(root.borderColor) - } - } - - BasicButtonType { - visible: (root.buttonText !== "") || (root.buttonImageSource !== "") - - focusPolicy: Qt.NoFocus - text: root.buttonText - leftImageSource: root.buttonImageSource - - anchors.top: content.top - anchors.bottom: content.bottom - anchors.right: content.right - - height: content.implicitHeight - width: content.implicitHeight - squareLeftSide: true - - clickedFunc: function() { - if (root.clickedFunc && typeof root.clickedFunc === "function") { - root.clickedFunc() - } - } - } - - function getBackgroundBorderColor(noneFocusedColor) { - return textField.focus ? root.borderFocusedColor : noneFocusedColor - } - - Keys.onEnterPressed: { - if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") { - clickedFunc() - } - - // if (KeyNavigation.tab) { - // KeyNavigation.tab.forceActiveFocus(); - // } - } - - Keys.onReturnPressed: { - if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") { - clickedFunc() - } - - // if (KeyNavigation.tab) { - // KeyNavigation.tab.forceActiveFocus(); - // } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Style 1.0 + +import "TextTypes" + +Item { + id: root + + property string headerText + property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray + property string headerTextColor: AmneziaStyle.color.mutedGray + + property alias errorText: errorField.text + property bool checkEmptyText: false + property bool rightButtonClickedOnEnter: false + + property string buttonText + property string buttonImageSource + property var clickedFunc + + property alias textField: textField + property string textFieldTextColor: AmneziaStyle.color.paleGray + property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray + + property bool textFieldEditable: true + + property string borderColor: AmneziaStyle.color.slateGray + property string borderFocusedColor: AmneziaStyle.color.paleGray + + property string backgroundColor: AmneziaStyle.color.onyxBlack + property string backgroundDisabledColor: AmneziaStyle.color.transparent + property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray + + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight + + ColumnLayout { + id: content + anchors.fill: parent + + Rectangle { + id: backgroud + Layout.fillWidth: true + Layout.preferredHeight: input.implicitHeight + color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor + radius: 16 + border.color: getBackgroundBorderColor(root.borderColor) + border.width: 1 + + Behavior on border.color { + PropertyAnimation { duration: 200 } + } + + RowLayout { + id: input + anchors.fill: backgroud + ColumnLayout { + Layout.margins: 16 + LabelTextType { + text: root.headerText + color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor + + visible: text !== "" + + Layout.fillWidth: true + } + + TextField { + id: textField + + property bool isFocusable: true + + Keys.onTabPressed: { + FocusController.nextKeyTabItem() + } + + Keys.onBacktabPressed: { + FocusController.previousKeyTabItem() + } + + enabled: root.textFieldEditable + color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor + + inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText + + placeholderTextColor: AmneziaStyle.color.charcoalGray + + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray + + font.pixelSize: 16 + font.weight: 400 + font.family: "PT Root UI VF" + + height: 24 + Layout.fillWidth: true + + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + bottomPadding: 0 + + background: Rectangle { + anchors.fill: parent + color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor + } + + onTextChanged: { + root.errorText = "" + } + + onActiveFocusChanged: { + if (root.checkEmptyText && text === "") { + root.errorText = qsTr("The field can't be empty") + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: contextMenu.open() + enabled: true + } + + ContextMenuType { + id: contextMenu + textObj: textField + } + + onFocusChanged: { + backgroud.border.color = getBackgroundBorderColor(root.borderColor) + } + } + } + } + } + + SmallTextType { + id: errorField + + text: root.errorText + visible: root.errorText !== "" + color: AmneziaStyle.color.vibrantRed + + Layout.fillWidth: true + } + } + + MouseArea { + anchors.fill: root + cursorShape: Qt.IBeamCursor + + hoverEnabled: true + + onPressed: function(mouse) { + textField.forceActiveFocus() + mouse.accepted = false + + backgroud.border.color = getBackgroundBorderColor(root.borderColor) + } + + onEntered: { + backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor) + } + + + onExited: { + backgroud.border.color = getBackgroundBorderColor(root.borderColor) + } + } + + BasicButtonType { + visible: (root.buttonText !== "") || (root.buttonImageSource !== "") + + focusPolicy: Qt.NoFocus + text: root.buttonText + leftImageSource: root.buttonImageSource + + anchors.top: content.top + anchors.bottom: content.bottom + anchors.right: content.right + + height: content.implicitHeight + width: content.implicitHeight + squareLeftSide: true + + clickedFunc: function() { + if (root.clickedFunc && typeof root.clickedFunc === "function") { + root.clickedFunc() + } + } + } + + function getBackgroundBorderColor(noneFocusedColor) { + return textField.focus ? root.borderFocusedColor : noneFocusedColor + } + + Keys.onEnterPressed: { + if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") { + clickedFunc() + } + + // if (KeyNavigation.tab) { + // KeyNavigation.tab.forceActiveFocus(); + // } + } + + Keys.onReturnPressed: { + if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") { + clickedFunc() + } + + // if (KeyNavigation.tab) { + // KeyNavigation.tab.forceActiveFocus(); + // } + } +} diff --git a/client/ui/qml/Pages2/PageDeinstalling.qml b/client/ui/qml/Pages2/PageDeinstalling.qml index 69b1f319..03d26f8d 100644 --- a/client/ui/qml/Pages2/PageDeinstalling.qml +++ b/client/ui/qml/Pages2/PageDeinstalling.qml @@ -20,7 +20,9 @@ PageType { SortFilterProxyModel { id: proxyServersModel + sourceModel: ServersModel + filters: [ ValueFilter { roleName: "isCurrentlyProcessed" @@ -29,67 +31,55 @@ PageType { ] } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.fill: parent - contentHeight: content.height - Column { - id: content + spacing: 16 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: proxyServersModel - spacing: 16 + delegate: ColumnLayout { + width: listView.width - Repeater { - model: proxyServersModel - delegate: Item { - implicitWidth: parent.width - implicitHeight: delegateContent.implicitHeight + BaseHeaderType { + Layout.fillWidth: true + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - ColumnLayout { - id: delegateContent + headerText: qsTr("Removing services from %1").arg(name) + } - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 + ProgressBarType { + id: progressBar - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 20 + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - headerText: qsTr("Removing services from %1").arg(name) - } + Timer { + id: timer - ProgressBarType { - id: progressBar - - Layout.fillWidth: true - Layout.topMargin: 32 - - 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") - } + interval: 300 + repeat: true + running: true + onTriggered: { + progressBar.value += 0.003 } } } + + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Usually it takes no more than 5 minutes") + } } } } diff --git a/client/ui/qml/Pages2/PageDevMenu.qml b/client/ui/qml/Pages2/PageDevMenu.qml index 5fccb43a..9f042fad 100644 --- a/client/ui/qml/Pages2/PageDevMenu.qml +++ b/client/ui/qml/Pages2/PageDevMenu.qml @@ -25,23 +25,17 @@ PageType { anchors.topMargin: 20 } - ListView { + ListViewType { id: listView anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - header: ColumnLayout { width: listView.width BaseHeaderType { - id: header - Layout.fillWidth: true Layout.rightMargin: 16 Layout.leftMargin: 16 @@ -50,16 +44,14 @@ PageType { } } - model: 1 - clip: true + model: 1 // fake model to force the ListView to be created without a model + spacing: 16 delegate: ColumnLayout { width: listView.width TextFieldWithHeaderType { - id: passwordTextField - Layout.fillWidth: true Layout.topMargin: 16 Layout.rightMargin: 16 @@ -87,8 +79,6 @@ PageType { width: listView.width SwitcherType { - id: switcher - Layout.fillWidth: true Layout.topMargin: 24 Layout.rightMargin: 16 diff --git a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml index d97d09e8..18db8119 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml @@ -16,349 +16,397 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - ListView { - id: listview + ListViewType { + id: listView anchors.top: backButtonLayout.bottom anchors.bottom: saveButton.top + anchors.right: parent.right + anchors.left: parent.left - width: parent.width + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - 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() + headerText: qsTr("AmneziaWG settings") + } } model: AwgConfigModel - delegate: Item { - id: delegateItem - implicitWidth: listview.width - implicitHeight: col.implicitHeight + delegate: ColumnLayout { + width: listView.width - property alias mtuTextField: mtuTextField property bool isSaveButtonEnabled: mtuTextField.errorText === "" && junkPacketMaxSizeTextField.errorText === "" && junkPacketMinSizeTextField.errorText === "" && junkPacketCountTextField.errorText === "" - ColumnLayout { - id: col + spacing: 0 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + TextFieldWithHeaderType { + id: mtuTextField - anchors.leftMargin: 16 - anchors.rightMargin: 16 + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - spacing: 0 + headerText: qsTr("MTU") + textField.text: clientMtu + textField.validator: IntValidator { bottom: 576; top: 65535 } - BaseHeaderType { - Layout.fillWidth: true - - headerText: qsTr("AmneziaWG 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: junkPacketCountTextField.textField - } - - AwgTextField { - id: junkPacketCountTextField - headerText: "Jc - Junk packet count" - textField.text: clientJunkPacketCount - - textField.onEditingFinished: { - if (textField.text !== clientJunkPacketCount) { - clientJunkPacketCount = textField.text - } - } - - KeyNavigation.tab: junkPacketMinSizeTextField.textField - } - - AwgTextField { - id: junkPacketMinSizeTextField - headerText: "Jmin - Junk packet minimum size" - 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 - } + textField.onEditingFinished: { + if (textField.text !== clientMtu) { + clientMtu = textField.text } } + checkEmptyText: true + } - AwgTextField { - id: specialJunk1TextField - headerText: qsTr("I1 - First special junk packet") - textField.text: clientSpecialJunk1 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: junkPacketCountTextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk1) { - clientSpecialJunk1 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: "Jc - Junk packet count" + textField.text: clientJunkPacketCount + + textField.onEditingFinished: { + if (textField.text !== clientJunkPacketCount) { + clientJunkPacketCount = textField.text } } + } - AwgTextField { - id: specialJunk2TextField - headerText: qsTr("I2 - Second special junk packet") - textField.text: clientSpecialJunk2 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: junkPacketMinSizeTextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk2) { - clientSpecialJunk2 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: "Jmin - Junk packet minimum size" + textField.text: clientJunkPacketMinSize + + textField.onEditingFinished: { + if (textField.text !== clientJunkPacketMinSize) { + clientJunkPacketMinSize = textField.text } } + } - AwgTextField { - id: specialJunk3TextField - headerText: qsTr("I3 - Third special junk packet") - textField.text: clientSpecialJunk3 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: junkPacketMaxSizeTextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk3) { - clientSpecialJunk3 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: "Jmax - Junk packet maximum size" + textField.text: clientJunkPacketMaxSize + + textField.onEditingFinished: { + if (textField.text !== clientJunkPacketMaxSize) { + clientJunkPacketMaxSize = textField.text } } + } - AwgTextField { - id: specialJunk4TextField - headerText: qsTr("I4 - Fourth special junk packet") - textField.text: clientSpecialJunk4 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk1TextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk4) { - clientSpecialJunk4 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("I1 - First special junk packet") + textField.text: clientSpecialJunk1 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk1) { + clientSpecialJunk1 = textField.text } } + } - AwgTextField { - id: specialJunk5TextField - headerText: qsTr("I5 - Fifth special junk packet") - textField.text: clientSpecialJunk5 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk2TextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialJunk5 ) { - clientSpecialJunk5 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("I2 - Second special junk packet") + textField.text: clientSpecialJunk2 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk2) { + clientSpecialJunk2 = textField.text } } + } - AwgTextField { - id: controlledJunk1TextField - headerText: qsTr("J1 - First controlled junk packet") - textField.text: clientControlledJunk1 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk3TextField - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk1) { - clientControlledJunk1 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + 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 { - id: controlledJunk2TextField - headerText: qsTr("J2 - Second controlled junk packet") - textField.text: clientControlledJunk2 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk4TextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk2) { - clientControlledJunk2 = textField.text - } + headerText: qsTr("I4 - Fourth special junk packet") + textField.text: clientSpecialJunk4 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk4) { + clientSpecialJunk4 = textField.text } } + } - AwgTextField { - id: controlledJunk3TextField - headerText: qsTr("J3 - Third controlled junk packet") - textField.text: clientControlledJunk3 - textField.validator: null - checkEmptyText: false + AwgTextField { + id: specialJunk5TextField - textField.onEditingFinished: { - if (textField.text !== clientControlledJunk3) { - clientControlledJunk3 = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("I5 - Fifth special junk packet") + textField.text: clientSpecialJunk5 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialJunk5 ) { + clientSpecialJunk5 = textField.text } } + } - AwgTextField { - id: iTimeTextField - headerText: qsTr("Itime - Special handshake timeout") - textField.text: clientSpecialHandshakeTimeout - checkEmptyText: false + AwgTextField { + id: controlledJunk1TextField - textField.onEditingFinished: { - if (textField.text !== clientSpecialHandshakeTimeout) { - clientSpecialHandshakeTimeout = textField.text - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("J1 - First controlled junk packet") + textField.text: clientControlledJunk1 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientControlledJunk1) { + clientControlledJunk1 = textField.text } } + } - Header2TextType { - Layout.fillWidth: true - Layout.topMargin: 16 + AwgTextField { + id: controlledJunk2TextField - text: qsTr("Server settings") + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("J2 - Second controlled junk packet") + textField.text: clientControlledJunk2 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientControlledJunk2) { + clientControlledJunk2 = textField.text + } } + } - AwgTextField { - id: portTextField - enabled: false + AwgTextField { + id: controlledJunk3TextField - headerText: qsTr("Port") - textField.text: port + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("J3 - Third controlled junk packet") + textField.text: clientControlledJunk3 + textField.validator: null + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientControlledJunk3) { + clientControlledJunk3 = textField.text + } } + } - AwgTextField { - id: initPacketJunkSizeTextField - enabled: false + AwgTextField { + id: iTimeTextField - headerText: "S1 - Init packet junk size" - textField.text: serverInitPacketJunkSize + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Itime - Special handshake timeout") + textField.text: clientSpecialHandshakeTimeout + checkEmptyText: false + + textField.onEditingFinished: { + if (textField.text !== clientSpecialHandshakeTimeout) { + clientSpecialHandshakeTimeout = textField.text + } } + } - AwgTextField { - id: responsePacketJunkSizeTextField - enabled: false + Header2TextType { + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - headerText: "S2 - Response packet junk size" - textField.text: serverResponsePacketJunkSize - } + text: qsTr("Server settings") + } - // AwgTextField { - // id: cookieReplyPacketJunkSizeTextField - // enabled: false + AwgTextField { + id: portTextField - // headerText: "S3 - Cookie Reply packet junk size" - // textField.text: serverCookieReplyPacketJunkSize - // } + Layout.leftMargin: 16 + Layout.rightMargin: 16 - // AwgTextField { - // id: transportPacketJunkSizeTextField - // enabled: false + enabled: false - // headerText: "S4 - Transport packet junk size" - // textField.text: serverTransportPacketJunkSize - // } + headerText: qsTr("Port") + textField.text: port + } - AwgTextField { - id: initPacketMagicHeaderTextField - enabled: false + AwgTextField { + id: initPacketJunkSizeTextField - headerText: "H1 - Init packet magic header" - textField.text: serverInitPacketMagicHeader - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 - AwgTextField { - id: responsePacketMagicHeaderTextField - enabled: false + enabled: false - headerText: "H2 - Response packet magic header" - textField.text: serverResponsePacketMagicHeader - } + headerText: "S1 - Init packet junk size" + textField.text: serverInitPacketJunkSize + } - AwgTextField { - id: underloadPacketMagicHeaderTextField - enabled: false + AwgTextField { + id: responsePacketJunkSizeTextField - headerText: "H3 - Underload packet magic header" - textField.text: serverUnderloadPacketMagicHeader - } + Layout.leftMargin: 16 + Layout.rightMargin: 16 - AwgTextField { - id: transportPacketMagicHeaderTextField - enabled: false + enabled: false - headerText: "H4 - Transport packet magic header" - textField.text: serverTransportPacketMagicHeader - } + headerText: "S2 - Response packet junk size" + textField.text: serverResponsePacketJunkSize + } + // AwgTextField { + // id: cookieReplyPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // enabled: false + + // headerText: "S3 - Cookie Reply packet junk size" + // textField.text: serverCookieReplyPacketJunkSize + // } + + // AwgTextField { + // id: transportPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // enabled: false + + // headerText: "S4 - Transport packet junk size" + // textField.text: serverTransportPacketJunkSize + // } + + AwgTextField { + id: initPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H1 - Init packet magic header" + textField.text: serverInitPacketMagicHeader + } + + AwgTextField { + id: responsePacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H2 - Response packet magic header" + textField.text: serverResponsePacketMagicHeader + } + + AwgTextField { + id: underloadPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H3 - Underload packet magic header" + textField.text: serverUnderloadPacketMagicHeader + } + + AwgTextField { + id: transportPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: false + + headerText: "H4 - Transport packet magic header" + textField.text: serverTransportPacketMagicHeader } } } @@ -375,18 +423,17 @@ PageType { anchors.rightMargin: 16 anchors.leftMargin: 16 - enabled: listview.currentItem.isSaveButtonEnabled + enabled: listView.currentItem.isSaveButtonEnabled text: qsTr("Save") onActiveFocusChanged: { if(activeFocus) { - listview.positionViewAtEnd() + listView.positionViewAtEnd() } } clickedFunc: function() { - forceActiveFocus() var headerText = qsTr("Save settings?") var descriptionText = qsTr("Only the settings for this device will be changed") var yesButtonText = qsTr("Continue") @@ -401,11 +448,9 @@ PageType { PageController.goToPage(PageEnum.PageSetupWizardInstalling); InstallController.updateContainer(AwgConfigModel.getConfig()) } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveButton.forceActiveFocus() - } - } + + var noButtonFunction = function() {} + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index 699ae724..2140f740 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -19,334 +19,343 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - ListView { - id: listview - - property bool isFocusable: true + ListViewType { + id: listView anchors.top: backButtonLayout.bottom anchors.bottom: parent.bottom - - 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 + anchors.left: parent.left + anchors.right: parent.right model: AwgConfigModel - delegate: Item { + delegate: ColumnLayout { id: delegateItem - implicitWidth: listview.width - implicitHeight: col.implicitHeight + + width: listView.width property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - ColumnLayout { - id: col + spacing: 0 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - anchors.leftMargin: 16 - anchors.rightMargin: 16 + headerText: qsTr("AmneziaWG settings") + } - 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 { - id: vpnAddressSubnetTextField + headerText: qsTr("VPN address subnet") + textField.text: subnetAddress - 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 - } - - AwgTextField { - id: junkPacketCountTextField - headerText: qsTr("Jc - Junk packet count") - textField.text: serverJunkPacketCount - - textField.onEditingFinished: { - if (textField.text !== serverJunkPacketCount) { - serverJunkPacketCount = textField.text - } + textField.onEditingFinished: { + if (textField.text !== subnetAddress) { + subnetAddress = textField.text } } - AwgTextField { - id: junkPacketMinSizeTextField - headerText: qsTr("Jmin - Junk packet minimum size") - textField.text: serverJunkPacketMinSize + checkEmptyText: true + } - textField.onEditingFinished: { - if (textField.text !== serverJunkPacketMinSize) { - serverJunkPacketMinSize = textField.text - } + 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 } } - AwgTextField { - id: junkPacketMaxSizeTextField - headerText: qsTr("Jmax - Junk packet maximum size") - textField.text: serverJunkPacketMaxSize + checkEmptyText: true + } - textField.onEditingFinished: { - if (textField.text !== serverJunkPacketMaxSize) { - serverJunkPacketMaxSize = textField.text - } + AwgTextField { + id: junkPacketCountTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Jc - Junk packet count") + textField.text: serverJunkPacketCount + + textField.onEditingFinished: { + if (textField.text !== serverJunkPacketCount) { + serverJunkPacketCount = textField.text + } + } + } + + AwgTextField { + id: junkPacketMinSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Jmin - Junk packet minimum size") + textField.text: serverJunkPacketMinSize + + textField.onEditingFinished: { + if (textField.text !== serverJunkPacketMinSize) { + serverJunkPacketMinSize = textField.text + } + } + } + + AwgTextField { + id: junkPacketMaxSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Jmax - Junk packet maximum size") + textField.text: serverJunkPacketMaxSize + + textField.onEditingFinished: { + if (textField.text !== serverJunkPacketMaxSize) { + serverJunkPacketMaxSize = textField.text + } + } + } + + AwgTextField { + id: initPacketJunkSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("S1 - Init packet junk size") + textField.text: serverInitPacketJunkSize + + textField.onEditingFinished: { + if (textField.text !== serverInitPacketJunkSize) { + serverInitPacketJunkSize = textField.text + } + } + } + + AwgTextField { + id: responsePacketJunkSizeTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("S2 - Response packet junk size") + textField.text: serverResponsePacketJunkSize + + textField.onEditingFinished: { + if (textField.text !== serverResponsePacketJunkSize) { + serverResponsePacketJunkSize = textField.text + } + } + } + + // AwgTextField { + // id: cookieReplyPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // headerText: qsTr("S3 - Cookie reply packet junk size") + // textField.text: serverCookieReplyPacketJunkSize + + // textField.onEditingFinished: { + // if (textField.text !== serverCookieReplyPacketJunkSize) { + // serverCookieReplyPacketJunkSize = textField.text + // } + // } + // } + + // AwgTextField { + // id: transportPacketJunkSizeTextField + + // Layout.leftMargin: 16 + // Layout.rightMargin: 16 + + // headerText: qsTr("S4 - Transport packet junk size") + // textField.text: serverTransportPacketJunkSize + + // textField.onEditingFinished: { + // if (textField.text !== serverTransportPacketJunkSize) { + // serverTransportPacketJunkSize = textField.text + // } + // } + // } + + AwgTextField { + id: initPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H1 - Init packet magic header") + textField.text: serverInitPacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverInitPacketMagicHeader) { + serverInitPacketMagicHeader = textField.text + } + } + } + + AwgTextField { + id: responsePacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H2 - Response packet magic header") + textField.text: serverResponsePacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverResponsePacketMagicHeader) { + serverResponsePacketMagicHeader = textField.text + } + } + } + + AwgTextField { + id: underloadPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H3 - Underload packet magic header") + textField.text: serverUnderloadPacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverUnderloadPacketMagicHeader) { + serverUnderloadPacketMagicHeader = textField.text + } + } + } + + AwgTextField { + id: transportPacketMagicHeaderTextField + + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("H4 - Transport packet magic header") + textField.text: serverTransportPacketMagicHeader + + textField.onEditingFinished: { + if (textField.text !== serverTransportPacketMagicHeader) { + serverTransportPacketMagicHeader = textField.text + } + } + } + + 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 === "" && + // cookieReplyHeaderJunkTextField.errorText === "" && + // transportHeaderJunkTextField.errorText === "" && + initPacketJunkSizeTextField.errorText === "" && + junkPacketMaxSizeTextField.errorText === "" && + junkPacketMinSizeTextField.errorText === "" && + junkPacketCountTextField.errorText === "" && + portTextField.errorText === "" && + vpnAddressSubnetTextField.errorText === "" + + text: qsTr("Save") + + onActiveFocusChanged: { + if(activeFocus) { + listView.positionViewAtEnd() } } - AwgTextField { - id: initPacketJunkSizeTextField - headerText: qsTr("S1 - Init packet junk size") - textField.text: serverInitPacketJunkSize - - textField.onEditingFinished: { - if (textField.text !== serverInitPacketJunkSize) { - serverInitPacketJunkSize = textField.text + 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 } - } - } - AwgTextField { - id: responsePacketJunkSizeTextField - headerText: qsTr("S2 - Response packet junk size") - textField.text: serverResponsePacketJunkSize - - textField.onEditingFinished: { - if (textField.text !== serverResponsePacketJunkSize) { - serverResponsePacketJunkSize = textField.text - } - } - } - - // AwgTextField { - // id: cookieReplyPacketJunkSizeTextField - // headerText: qsTr("S3 - Cookie reply packet junk size") - // textField.text: serverCookieReplyPacketJunkSize - - // textField.onEditingFinished: { - // if (textField.text !== serverCookieReplyPacketJunkSize) { - // serverCookieReplyPacketJunkSize = textField.text - // } - // } - // } - - // AwgTextField { - // id: transportPacketJunkSizeTextField - // headerText: qsTr("S4 - Transport packet junk size") - // textField.text: serverTransportPacketJunkSize - - // textField.onEditingFinished: { - // if (textField.text !== serverTransportPacketJunkSize) { - // serverTransportPacketJunkSize = 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 { - id: responsePacketMagicHeaderTextField - headerText: qsTr("H2 - Response packet magic header") - textField.text: serverResponsePacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverResponsePacketMagicHeader) { - serverResponsePacketMagicHeader = textField.text - } - } - } - - AwgTextField { - id: underloadPacketMagicHeaderTextField - headerText: qsTr("H3 - Underload packet magic header") - textField.text: serverUnderloadPacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverUnderloadPacketMagicHeader) { - serverUnderloadPacketMagicHeader = textField.text - } - } - } - - AwgTextField { - id: transportPacketMagicHeaderTextField - headerText: qsTr("H4 - Transport packet magic header") - textField.text: serverTransportPacketMagicHeader - - textField.onEditingFinished: { - if (textField.text !== serverTransportPacketMagicHeader) { - serverTransportPacketMagicHeader = textField.text - } - } - } - - - BasicButtonType { - id: saveRestartButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - enabled: underloadPacketMagicHeaderTextField.errorText === "" && - transportPacketMagicHeaderTextField.errorText === "" && - responsePacketMagicHeaderTextField.errorText === "" && - initPacketMagicHeaderTextField.errorText === "" && - responsePacketJunkSizeTextField.errorText === "" && - // cookieReplyHeaderJunkTextField.errorText === "" && - // transportHeaderJunkTextField.errorText === "" && - initPacketJunkSizeTextField.errorText === "" && - junkPacketMaxSizeTextField.errorText === "" && - junkPacketMinSizeTextField.errorText === "" && - junkPacketCountTextField.errorText === "" && - portTextField.errorText === "" && - vpnAddressSubnetTextField.errorText === "" - - text: qsTr("Save") - - onActiveFocusChanged: { - if(activeFocus) { - listview.positionViewAtEnd() + 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 + // } } - 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") - 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 - } - // 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 yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return } - 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(AwgConfigModel.getConfig()) - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - saveRestartButton.forceActiveFocus() - } - } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(AwgConfigModel.getConfig()) } + + var noButtonFunction = function() {} + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } } diff --git a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml index 8e5129b0..51d4c9e2 100644 --- a/client/ui/qml/Pages2/PageProtocolCloakSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolCloakSettings.qml @@ -16,212 +16,192 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.left: parent.left + anchors.right: parent.right - Column { - id: content + property int selectedIndex: 0 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + enabled: ServersModel.isProcessedServerHasWriteAccess() - enabled: ServersModel.isProcessedServerHasWriteAccess() + header: ColumnLayout { + width: listView.width - ListView { - id: listview + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - property int selectedIndex: 0 + headerText: qsTr("Cloak settings") + } + } - width: parent.width - height: listview.contentItem.height + model: CloakConfigModel - clip: true - reuseItems: true + delegate: ColumnLayout { + width: listView.width - model: CloakConfigModel + property alias trafficFromField: trafficFromField - delegate: Item { - id: delegateItem + spacing: 0 - property alias trafficFromField: trafficFromField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() + TextFieldWithHeaderType { + id: trafficFromField - implicitWidth: listview.width - implicitHeight: col.implicitHeight + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - ColumnLayout { - id: col + headerText: qsTr("Disguised as traffic from") + textField.text: site - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + textField.onEditingFinished: { + if (textField.text !== site) { + var tmpText = textField.text + tmpText = tmpText.toLocaleLowerCase() - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - spacing: 0 - - BaseHeaderType { - Layout.fillWidth: true - headerText: qsTr("Cloak settings") + var indexHttps = tmpText.indexOf("https://") + if (indexHttps === 0) { + tmpText = textField.text.substring(8) + } else { + site = textField.text } + } + } - TextFieldWithHeaderType { - id: trafficFromField + checkEmptyText: true + } - Layout.fillWidth: true - Layout.topMargin: 32 + TextFieldWithHeaderType { + id: portTextField - enabled: delegateItem.isEnabled + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - headerText: qsTr("Disguised as traffic from") - textField.text: site + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } - textField.onEditingFinished: { - if (textField.text !== site) { - var tmpText = textField.text - tmpText = tmpText.toLocaleLowerCase() + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text + } + } - var indexHttps = tmpText.indexOf("https://") - if (indexHttps === 0) { - tmpText = textField.text.substring(8) - } else { - site = textField.text - } - } + checkEmptyText: true + } + + 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 } - - 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() } } } } + + BasicButtonType { + id: saveButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + 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() + } } } } diff --git a/client/ui/qml/Pages2/PageProtocolRaw.qml b/client/ui/qml/Pages2/PageProtocolRaw.qml index bba3eafe..b90af6f6 100644 --- a/client/ui/qml/Pages2/PageProtocolRaw.qml +++ b/client/ui/qml/Pages2/PageProtocolRaw.qml @@ -19,164 +19,154 @@ import "../Components" PageType { id: root - ColumnLayout { - id: header + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton - } - - BaseHeaderType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: header.bottom - anchors.left: parent.left + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom anchors.right: parent.right - contentHeight: content.height + anchors.left: parent.left - Column { - id: content + header: ColumnLayout { + width: listView.width - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 32 + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - ListView { - id: listView - width: parent.width - height: contentItem.height - clip: true - interactive: false - model: ProtocolsModel + headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") + } + } - activeFocusOnTab: true - focus: true + model: ProtocolsModel - delegate: Item { - implicitWidth: parent.width - implicitHeight: delegateContent.implicitHeight + delegate: ColumnLayout { + width: listView.width - property alias focusItem: button + LabelWithButtonType { + id: button - ColumnLayout { - id: delegateContent + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - anchors.fill: parent + text: qsTr("Show connection options") - LabelWithButtonType { - id: button + clickedFunction: function() { + configContentDrawer.openTriggered() + } - Layout.fillWidth: true + MouseArea { + anchors.fill: button + cursorShape: Qt.PointingHandCursor + enabled: false + } + } - text: qsTr("Show connection options") + DividerType {} - clickedFunction: function() { - configContentDrawer.openTriggered() - } + DrawerType2 { + id: configContentDrawer - MouseArea { - anchors.fill: button - cursorShape: Qt.PointingHandCursor - enabled: false + expandedHeight: root.height * 0.9 + + parent: root + 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 { - id: configContentDrawer + delegate: ColumnLayout { + width: drawerListView.width - expandedHeight: root.height * 0.9 + TextArea { + id: configText - parent: root - anchors.fill: parent + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - expandedStateContent: Item { - implicitHeight: configContentDrawer.expandedHeight + padding: 0 + height: 24 - BackButtonType { - id: backButton1 + color: AmneziaStyle.color.paleGray + selectionColor: AmneziaStyle.color.richBrown + selectedTextColor: AmneziaStyle.color.paleGray - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 + font.pixelSize: 16 + font.weight: Font.Medium + font.family: "PT Root UI VF" - backButtonFunction: function() { - configContentDrawer.closeTriggered() - } - } + text: rawConfig - FlickableType { - 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 + wrapMode: Text.Wrap - ColumnLayout { - id: configContent - - 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 - } - } - } + background: Rectangle { + color: AmneziaStyle.color.transparent } } } } } } + } + + footer: ColumnLayout { + width: listView.width LabelWithButtonType { id: removeButton @@ -198,11 +188,7 @@ PageType { PageController.goToPage(PageEnum.PageDeinstalling) InstallController.removeProcessedContainer() } - var noButtonFunction = function() { - if (!GC.isMobile()) { - focusItem.forceActiveFocus() - } - } + var noButtonFunction = function() {} showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } diff --git a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml index 92df3ec7..4d587539 100644 --- a/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolShadowSocksSettings.qml @@ -16,179 +16,158 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + enabled: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: ShadowSocksConfigModel - enabled: ServersModel.isProcessedServerHasWriteAccess() + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + spacing: 0 - width: parent.width - height: listview.contentItem.height + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - clip: true - interactive: false + headerText: qsTr("Shadowsocks settings") + } - model: ShadowSocksConfigModel + TextFieldWithHeaderType { + id: portTextField - delegate: Item { - id: delegateItem + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() + enabled: listView.enabled - implicitWidth: listview.width - implicitHeight: col.implicitHeight + headerText: qsTr("Port") + textField.text: port + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } - ColumnLayout { - id: col + textField.onEditingFinished: { + if (textField.text !== port) { + port = textField.text + } + } - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + checkEmptyText: true + } - anchors.leftMargin: 16 - anchors.rightMargin: 16 + DropDownType { + id: cipherDropDown - spacing: 0 + Layout.fillWidth: true + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - BaseHeaderType { - Layout.fillWidth: true - headerText: qsTr("Shadowsocks settings") - } + enabled: listView.enabled - TextFieldWithHeaderType { - id: portTextField + descriptionText: qsTr("Cipher") + headerText: qsTr("Cipher") - Layout.fillWidth: true - Layout.topMargin: 40 + drawerParent: root - enabled: delegateItem.isEnabled + listView: ListViewWithRadioButtonType { - headerText: qsTr("Port") - textField.text: port - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } + id: cipherListView - textField.onEditingFinished: { - if (textField.text !== port) { - port = textField.text - } + 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 } - - 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: saveButton + + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + 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() + } } } } diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml index 96ec1dc6..ef2490c7 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml @@ -16,160 +16,124 @@ import "../Components" PageType { id: root - Item { - id: focusItem - onFocusChanged: { - if (activeFocus) { - fl.ensureVisible(focusItem) - } - } - KeyNavigation.tab: backButton - } - - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton - KeyNavigation.tab: listview.currentItem.mtuTextField.textField + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.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 { - id: content + model: WireGuardConfigModel - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + property alias mtuTextField: mtuTextField + property bool isSaveButtonEnabled: mtuTextField.errorText === "" - width: parent.width - height: listview.contentItem.height + spacing: 0 - clip: true - interactive: false + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - model: WireGuardConfigModel + headerText: qsTr("WG settings") + } - delegate: Item { - id: delegateItem - implicitWidth: listview.width - implicitHeight: col.implicitHeight + TextFieldWithHeaderType { + id: mtuTextField + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - property alias mtuTextField: mtuTextField - property bool isSaveButtonEnabled: mtuTextField.errorText === "" + headerText: qsTr("MTU") + textField.text: clientMtu + textField.validator: IntValidator { bottom: 576; top: 65535 } - ColumnLayout { - id: col - - 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 - } - } + textField.onEditingFinished: { + if (textField.text !== clientMtu) { + clientMtu = textField.text + } } + 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 { - id: saveButton + footer: ColumnLayout { + width: listView.width - anchors.right: root.right - anchors.left: root.left - anchors.bottom: root.bottom + BasicButtonType { + id: saveButton - anchors.topMargin: 24 - anchors.bottomMargin: 24 - anchors.rightMargin: 16 - anchors.leftMargin: 16 + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 24 + Layout.rightMargin: 16 + Layout.leftMargin: 16 - enabled: listview.currentItem.isSaveButtonEnabled + enabled: listView.currentItem.isSaveButtonEnabled - text: qsTr("Save") + text: qsTr("Save") - clickedFunc: function() { - forceActiveFocus() - var headerText = qsTr("Save settings?") - var descriptionText = qsTr("Only the settings for this device will be changed") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") + clickedFunc: function() { + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("Only the settings for this device will be changed") + 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 - } + 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() + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(WireGuardConfigModel.getConfig()) + } + var noButtonFunction = function() {} + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } } diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index 3122267f..d8ea1d95 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -16,153 +16,134 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + enabled: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: WireGuardConfigModel - enabled: ServersModel.isProcessedServerHasWriteAccess() + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - width: parent.width - height: listview.contentItem.height + spacing: 0 - clip: true - interactive: false + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - model: WireGuardConfigModel + headerText: qsTr("WG settings") + } - delegate: Item { - id: delegateItem + TextFieldWithHeaderType { + id: vpnAddressSubnetTextField - property alias focusItemId: vpnAddressSubnetTextField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() + Layout.fillWidth: true + Layout.topMargin: 40 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - implicitWidth: listview.width - implicitHeight: col.implicitHeight + enabled: delegateItem.isEnabled - ColumnLayout { - id: col + headerText: qsTr("VPN address subnet") + textField.text: subnetAddress - 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: 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: this.clicked() - Keys.onReturnPressed: this.clicked() - } + textField.onEditingFinished: { + if (textField.text !== subnetAddress) { + subnetAddress = textField.text } } + + 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()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + Keys.onEnterPressed: saveButton.clicked() + Keys.onReturnPressed: saveButton.clicked() } } } diff --git a/client/ui/qml/Pages2/PageProtocolXraySettings.qml b/client/ui/qml/Pages2/PageProtocolXraySettings.qml index 0bcd14de..8de36035 100644 --- a/client/ui/qml/Pages2/PageProtocolXraySettings.qml +++ b/client/ui/qml/Pages2/PageProtocolXraySettings.qml @@ -17,163 +17,141 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton - } - } - - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom - anchors.bottom: parent.bottom - contentHeight: content.implicitHeight - - Column { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - enabled: ServersModel.isProcessedServerHasWriteAccess() - - ListView { - id: listview - - width: parent.width - height: listview.contentItem.height - - clip: true - interactive: false - - model: XrayConfigModel - - delegate: Item { - id: delegateItem - - property alias focusItemId: textFieldWithHeaderType.textField - property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() - - implicitWidth: listview.width - implicitHeight: col.implicitHeight - - ColumnLayout { - id: col - - 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("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() - } - } - } + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() } } } + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + enabled: ServersModel.isProcessedServerHasWriteAccess() + model: XrayConfigModel + + delegate: ColumnLayout { + width: listView.width + + property alias focusItemId: textFieldWithHeaderType.textField + + spacing: 0 + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + headerText: qsTr("XRay settings") + } + + TextFieldWithHeaderType { + id: textFieldWithHeaderType + + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: listView.enabled + + 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 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + enabled: listView.enabled + + 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 === "" + + 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()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + + Keys.onEnterPressed: saveButton.clicked() + Keys.onReturnPressed: saveButton.clicked() + } + } + } } diff --git a/client/ui/qml/Pages2/PageServiceDnsSettings.qml b/client/ui/qml/Pages2/PageServiceDnsSettings.qml index d534f991..442dc544 100644 --- a/client/ui/qml/Pages2/PageServiceDnsSettings.qml +++ b/client/ui/qml/Pages2/PageServiceDnsSettings.qml @@ -16,50 +16,53 @@ import "../Components" PageType { id: root - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - - BackButtonType { - id: backButton + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + header: ColumnLayout { + width: listView.width BaseHeaderType { - id: header - Layout.fillWidth: true Layout.rightMargin: 16 Layout.leftMargin: 16 + Layout.bottomMargin: 24 headerText: "AmneziaDNS" 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.") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { + width: listView.width LabelWithButtonType { - id: removeButton - - Layout.topMargin: 24 - width: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() textColor: AmneziaStyle.color.vibrantRed @@ -71,19 +74,14 @@ PageType { var yesButtonFunction = function() { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected - && SettingsController.isAmneziaDnsEnabled()) { + && SettingsController.isAmneziaDnsEnabled()) { PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server")) - } else - { + } else { PageController.goToPage(PageEnum.PageDeinstalling) InstallController.removeProcessedContainer() } } - var noButtonFunction = function() { - if (!GC.isMobile()) { - removeButton.rightButton.forceActiveFocus() - } - } + var noButtonFunction = function() {} showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } diff --git a/client/ui/qml/Pages2/PageServiceSftpSettings.qml b/client/ui/qml/Pages2/PageServiceSftpSettings.qml index b58cb2e0..9fe0bac5 100644 --- a/client/ui/qml/Pages2/PageServiceSftpSettings.qml +++ b/client/ui/qml/Pages2/PageServiceSftpSettings.qml @@ -24,258 +24,215 @@ PageType { } } - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - Column { - id: content + enabled: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: SftpConfigModel - enabled: ServersModel.isProcessedServerHasWriteAccess() + delegate: ColumnLayout { + width: listView.width - ListView { - id: listview + spacing: 0 - width: parent.width - height: listview.contentItem.height + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - clip: true - interactive: false + headerText: qsTr("SFTP settings") + } - model: SftpConfigModel + LabelWithButtonType { + id: hostLabel - onFocusChanged: { - if (focus) { - listview.currentItem.listViewFocusItem.forceActiveFocus() - } + Layout.fillWidth: true + Layout.topMargin: 32 + 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: "WinFsp" + readonly property string windowsSecondLink: "SSHFS-Win" + + readonly property string macosFirstLink: "macFUSE" + readonly property string macosSecondLink: "SSHFS" + + 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:
") + if (Qt.platform.os === "windows") { + str += qsTr("
1. Install the latest version of ") + windowsFirstLink + "\n" + str += qsTr("
2. Install the latest version of ") + windowsSecondLink + "\n" + } else if (Qt.platform.os === "osx") { + str += qsTr("
1. Install the latest version of ") + macosFirstLink + "\n" + str += qsTr("
2. Install the latest version of ") + macosSecondLink + "\n" + } else if (Qt.platform.os === "linux") { + return "" + } else return "" + + return str } - delegate: Item { - implicitWidth: listview.width - implicitHeight: col.implicitHeight + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } - property alias listViewFocusItem: hostLabel.rightButton + BasicButtonType { + id: detailedInstructionsButton - ColumnLayout { - id: col + Layout.topMargin: 16 + Layout.bottomMargin: 16 + Layout.leftMargin: 8 + implicitHeight: 32 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot - spacing: 0 + text: qsTr("Detailed instructions") - BaseHeaderType { - Layout.fillWidth: true - 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: "WinFsp" - readonly property string windowsSecondLink: "SSHFS-Win" - - readonly property string macosFirstLink: "macFUSE" - readonly property string macosSecondLink: "SSHFS" - - 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:
") - if (Qt.platform.os === "windows") { - str += qsTr("
1. Install the latest version of ") + windowsFirstLink + "\n" - str += qsTr("
2. Install the latest version of ") + windowsSecondLink + "\n" - } else if (Qt.platform.os === "osx") { - str += qsTr("
1. Install the latest version of ") + macosFirstLink + "\n" - str += qsTr("
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") - } - } - } + clickedFunc: function() { + // Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest") } } } diff --git a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml index b1daa0fb..f96872e0 100644 --- a/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml +++ b/client/ui/qml/Pages2/PageServiceSocksProxySettings.qml @@ -25,327 +25,290 @@ PageType { } } - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - BackButtonType { - id: backButton + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: listview.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ListView { - id: listview + model: Socks5ProxyConfigModel - width: parent.width - height: listview.contentItem.height + delegate: ColumnLayout { + width: listView.width - clip: true - interactive: false + spacing: 0 - model: Socks5ProxyConfigModel + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - onFocusChanged: { - if (focus) { - listview.currentItem.focusItemId.forceActiveFocus() + headerText: qsTr("SOCKS5 settings") + } + + 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 { - implicitWidth: listview.width - implicitHeight: content.implicitHeight + LabelWithButtonType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - property alias focusItemId: hostLabel.rightButton + text: qsTr("Port") + descriptionText: port - ColumnLayout { - id: content + 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("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.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 - Layout.leftMargin: 16 Layout.rightMargin: 16 + Layout.bottomMargin: 16 headerText: qsTr("SOCKS5 settings") } - LabelWithButtonType { - id: hostLabel + TextFieldWithHeaderType { + id: portTextField + 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") - 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() + textField.onEditingFinished: { + textField.text = textField.text.replace(/^\s+|\s+$/g, '') + if (textField.text !== port) { + port = textField.text } } } - LabelWithButtonType { - id: portLabel + TextFieldWithHeaderType { + id: usernameTextField + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - text: qsTr("Port") - descriptionText: port + headerText: qsTr("Username") + textField.placeholderText: "username" + textField.text: username + textField.maximumLength: 32 - 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() + textField.onEditingFinished: { + textField.text = textField.text.replace(/^\s+|\s+$/g, '') + if (textField.text !== username) { + username = textField.text } } } - LabelWithButtonType { - id: usernameLabel + TextFieldWithHeaderType { + id: passwordTextField + + property bool hidePassword: true + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - text: qsTr("User name") - descriptionText: username + headerText: qsTr("Password") + 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 - - 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() - } + clickedFunc: function() { + hidePassword = !hidePassword } - } - 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() - } - } - } - - 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() - } + textField.onFocusChanged: { + textField.text = textField.text.replace(/^\s+|\s+$/g, '') + if (textField.text !== password) { + password = textField.text } } } BasicButtonType { - id: changeSettingsButton + id: saveButton Layout.fillWidth: true Layout.topMargin: 24 Layout.bottomMargin: 24 - Layout.leftMargin: 16 Layout.rightMargin: 16 text: qsTr("Change connection settings") clickedFunc: function() { - forceActiveFocus() - changeSettingsDrawer.openTriggered() + 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 { + 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() + } + } } } } diff --git a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml index 200beeb8..1ea1f814 100644 --- a/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml +++ b/client/ui/qml/Pages2/PageServiceTorWebsiteSettings.qml @@ -25,34 +25,31 @@ PageType { } } - ColumnLayout { - id: backButtonLayout + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - - BackButtonType { - id: backButton + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } } - FlickableType { - id: fl - anchors.top: backButtonLayout.bottom + ListViewType { + id: listView + + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 + header: ColumnLayout { + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -61,11 +58,19 @@ PageType { headerText: qsTr("Tor website settings") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser after migrate to 6.9 + width: listView.width LabelWithButtonType { id: websiteName + Layout.fillWidth: true Layout.topMargin: 32 + Layout.bottomMargin: 24 text: qsTr("Website address") descriptionText: { @@ -83,15 +88,16 @@ PageType { clickedFunction: function() { GC.copyToClipBoard(descriptionText) PageController.showNotificationMessage(qsTr("Copied")) - if (!GC.isMobile()) { - this.rightButton.forceActiveFocus() - } } } + } + + footer: ColumnLayout { + width: listView.width ParagraphTextType { Layout.fillWidth: true - Layout.topMargin: 40 + Layout.topMargin: 16 Layout.leftMargin: 16 Layout.rightMargin: 16 diff --git a/client/ui/qml/Pages2/PageSettings.qml b/client/ui/qml/Pages2/PageSettings.qml index bb83ec92..f331f912 100644 --- a/client/ui/qml/Pages2/PageSettings.qml +++ b/client/ui/qml/Pages2/PageSettings.qml @@ -1,156 +1,167 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" - -PageType { - id: root - - FlickableType { - id: fl - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 - - BaseHeaderType { - id: header - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - - headerText: qsTr("Settings") - } - - LabelWithButtonType { - id: account - Layout.fillWidth: true - Layout.topMargin: 16 - - text: qsTr("Servers") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/server.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsServersList) - } - } - - DividerType {} - - LabelWithButtonType { - id: connection - Layout.fillWidth: true - - text: qsTr("Connection") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/radio.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsConnection) - } - } - - DividerType {} - - LabelWithButtonType { - id: application - Layout.fillWidth: true - - text: qsTr("Application") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/app.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsApplication) - } - } - - DividerType {} - - LabelWithButtonType { - id: backup - Layout.fillWidth: true - - text: qsTr("Backup") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/save.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsBackup) - } - } - - DividerType {} - - LabelWithButtonType { - id: about - Layout.fillWidth: true - - text: qsTr("About AmneziaVPN") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/amnezia.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageSettingsAbout) - } - } - - DividerType {} - - LabelWithButtonType { - id: devConsole - visible: SettingsController.isDevModeEnabled - Layout.fillWidth: true - - text: qsTr("Dev console") - rightImageSource: "qrc:/images/controls/chevron-right.svg" - leftImageSource: "qrc:/images/controls/bug.svg" - - clickedFunction: function() { - PageController.goToPage(PageEnum.PageDevMenu) - } - } - - DividerType { - visible: SettingsController.isDevModeEnabled - } - - LabelWithButtonType { - id: close - visible: GC.isDesktop() - Layout.fillWidth: true - Layout.preferredHeight: about.height - - text: qsTr("Close application") - leftImageSource: "qrc:/images/controls/x-circle.svg" - isLeftImageHoverEnabled: false - - clickedFunction: function() { - PageController.closeApplication() - } - } - - DividerType { - visible: GC.isDesktop() - } - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" + +PageType { + id: root + + ListViewType { + id: listView + + anchors.fill: parent + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + id: header + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Settings") + } + } + + model: settingsEntries + + delegate: ColumnLayout { + width: listView.width + + spacing: 0 + + LabelWithButtonType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: isVisible + + text: title + rightImageSource: "qrc:/images/controls/chevron-right.svg" + leftImageSource: leftImagePath + + clickedFunction: clickedHandler + } + + DividerType { + visible: isVisible + } + } + + footer: ColumnLayout { + width: listView.width + + LabelWithButtonType { + id: close + + visible: GC.isDesktop() + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Close application") + leftImageSource: "qrc:/images/controls/x-circle.svg" + isLeftImageHoverEnabled: false + + clickedFunction: function() { + PageController.closeApplication() + } + } + + DividerType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: GC.isDesktop() + } + } + } + + property list settingsEntries: [ + servers, + connection, + application, + backup, + about, + devConsole + ] + + QtObject { + id: servers + + property string title: qsTr("Servers") + readonly property string leftImagePath: "qrc:/images/controls/server.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsServersList) + } + } + + QtObject { + id: connection + + property string title: qsTr("Connection") + readonly property string leftImagePath: "qrc:/images/controls/radio.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsConnection) + } + } + + QtObject { + id: application + + property string title: qsTr("Application") + readonly property string leftImagePath: "qrc:/images/controls/app.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsApplication) + } + } + + QtObject { + id: backup + + property string title: qsTr("Backup") + readonly property string leftImagePath: "qrc:/images/controls/save.svg" + property bool isVisible: true + readonly property var clickedHandler: function() { + PageController.goToPage(PageEnum.PageSettingsBackup) + } + } + + QtObject { + id: about + + property string title: qsTr("About AmneziaVPN") + readonly property string leftImagePath: "qrc:/images/controls/amnezia.svg" + property bool isVisible: true + 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) + } + } +} diff --git a/client/ui/qml/Pages2/PageSettingsAbout.qml b/client/ui/qml/Pages2/PageSettingsAbout.qml index 6342ce66..a3c2b884 100644 --- a/client/ui/qml/Pages2/PageSettingsAbout.qml +++ b/client/ui/qml/Pages2/PageSettingsAbout.qml @@ -29,58 +29,7 @@ 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 contacts: [ - telegramGroup, - mail, - github, - website - ] - - ListView { + ListViewType { id: listView anchors.top: backButton.bottom @@ -88,38 +37,6 @@ PageType { anchors.right: parent.right 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 { width: listView.width @@ -170,11 +87,12 @@ PageType { } } + model: contacts + delegate: ColumnLayout { width: listView.width LabelWithButtonType { - id: telegramButton Layout.fillWidth: true Layout.topMargin: 6 @@ -257,4 +175,55 @@ PageType { } } } + + property list contacts: [ + telegramGroup, + mail, + github, + website + ] + + 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()) + } + } } diff --git a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml index 8fa85a33..39e2e626 100644 --- a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml +++ b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml @@ -1,221 +1,243 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import QtCore - -import SortFilterProxyModel 0.2 - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" -import "../Components" - -PageType { - id: root - - property string configExtension: ".conf" - property string configCaption: qsTr("Save AmneziaVPN config") - - ListViewType { - id: listView - - anchors.fill: parent - anchors.topMargin: 20 - anchors.bottomMargin: 24 - - model: ApiCountryModel - - header: ColumnLayout { - width: listView.width - - BackButtonType { - id: backButton - } - - BaseHeaderType { - id: header - - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - - headerText: qsTr("Configuration Files") - descriptionText: qsTr("For router setup or the AmneziaWG app") - } - } - - delegate: ColumnLayout { - width: listView.width - - LabelWithButtonType { - Layout.fillWidth: true - Layout.topMargin: 6 - - text: countryName - descriptionText: isWorkerExpired ? qsTr("Download the update") : "" - hideDescription: false - descriptionColor: AmneziaStyle.color.mutedGray - - leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg" - rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg" - - clickedFunction: function() { - if (isIssued) { - moreOptionsDrawer.countryName = countryName - moreOptionsDrawer.countryCode = countryCode - moreOptionsDrawer.openTriggered() - } else { - issueConfig(countryCode) - } - } - } - - DividerType {} - } - } - - DrawerType2 { - id: moreOptionsDrawer - - property string countryName - property string countryCode - - anchors.fill: parent - expandedHeight: parent.height * 0.4375 - - expandedStateContent: Item { - implicitHeight: moreOptionsDrawer.expandedHeight - - BackButtonType { - id: moreOptionsDrawerBackButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 - - backButtonFunction: function() { - moreOptionsDrawer.closeTriggered() - } - } - - FlickableType { - anchors.top: moreOptionsDrawerBackButton.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - - contentHeight: moreOptionsDrawerContent.height - - ColumnLayout { - id: moreOptionsDrawerContent - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - Header2Type { - Layout.fillWidth: true - Layout.margins: 16 - - headerText: moreOptionsDrawer.countryName + qsTr(" configuration file") - } - - LabelWithButtonType { - Layout.fillWidth: true - - text: qsTr("Generate a new configuration file") - descriptionText: qsTr("The previously created one will stop working") - - clickedFunction: function() { - showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) - } - } - - DividerType {} - - LabelWithButtonType { - Layout.fillWidth: true - text: qsTr("Revoke the current configuration file") - - clickedFunction: function() { - showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) - } - } - - DividerType {} - } - } - } - } - - function issueConfig(countryCode) { - var fileName = "" - if (GC.isMobile()) { - fileName = countryCode + configExtension - } else { - fileName = SystemController.getFileName(configCaption, - qsTr("Config files (*" + configExtension + ")"), - StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode, - true, - configExtension) - } - if (fileName !== "") { - PageController.showBusyIndicator(true) - let result = ApiConfigsController.exportNativeConfig(countryCode, fileName) - if (result) { - ApiSettingsController.getAccountInfo(true) - } - - PageController.showBusyIndicator(false) - if (result) { - PageController.showNotificationMessage(qsTr("Config file saved")) - } - } - } - - function revokeConfig(countryCode) { - PageController.showBusyIndicator(true) - let result = ApiConfigsController.revokeNativeConfig(countryCode) - if (result) { - ApiSettingsController.getAccountInfo(true) - } - PageController.showBusyIndicator(false) - - if (result) { - PageController.showNotificationMessage(qsTr("The config has been revoked")) - } - } - - function showQuestion(isConfigIssue, countryCode, countryName) { - var headerText - if (isConfigIssue) { - headerText = qsTr("Generate a new %1 configuration file?").arg(countryName) - } else { - headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName) - } - - var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it") - var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - if (isConfigIssue) { - issueConfig(countryCode) - } else { - revokeConfig(countryCode) - } - moreOptionsDrawer.closeTriggered() - } - var noButtonFunction = function() { - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import QtCore + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + property string configExtension: ".conf" + property string configCaption: qsTr("Save AmneziaVPN config") + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + model: ApiCountryModel + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + id: header + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Configuration Files") + descriptionText: qsTr("For router setup or the AmneziaWG app") + } + } + + delegate: ColumnLayout { + width: listView.width + + LabelWithButtonType { + Layout.fillWidth: true + Layout.topMargin: 6 + + text: countryName + descriptionText: isWorkerExpired ? qsTr("The configuration needs to be reissued") : "" + hideDescription: isWorkerExpired : true : false + descriptionColor: AmneziaStyle.color.vibrantRed + + leftImageSource: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg" + rightImageSource: isIssued ? "qrc:/images/controls/more-vertical.svg" : "qrc:/images/controls/download.svg" + + clickedFunction: function() { + if (isIssued) { + moreOptionsDrawer.countryName = countryName + moreOptionsDrawer.countryCode = countryCode + moreOptionsDrawer.openTriggered() + } else { + issueConfig(countryCode) + } + } + } + + DividerType {} + } + } + + DrawerType2 { + id: moreOptionsDrawer + + property string countryName + property string countryCode + + anchors.fill: parent + expandedHeight: parent.height * 0.4375 + + expandedStateContent: Item { + implicitHeight: moreOptionsDrawer.expandedHeight + + BackButtonType { + id: moreOptionsDrawerBackButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 + + backButtonFunction: function() { + moreOptionsDrawer.closeTriggered() + } + } + + ListViewType { + id: drawerListView + + anchors.top: moreOptionsDrawerBackButton.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + header: ColumnLayout { + width: drawerListView.width + + Header2Type { + Layout.fillWidth: true + Layout.margins: 16 + + headerText: moreOptionsDrawer.countryName + qsTr(" configuration file") + } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { + width: drawerListView.width + + LabelWithButtonType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Generate a new configuration file") + descriptionText: qsTr("The previously created one will stop working") + + clickedFunction: function() { + showQuestion(true, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) + } + } + + DividerType {} + } + + footer: ColumnLayout { + width: drawerListView.width + + LabelWithButtonType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Revoke the current configuration file") + + clickedFunction: function() { + showQuestion(false, moreOptionsDrawer.countryCode, moreOptionsDrawer.countryName) + } + } + + DividerType {} + } + } + } + } + + function issueConfig(countryCode) { + var fileName = "" + if (GC.isMobile()) { + fileName = countryCode + configExtension + } else { + fileName = SystemController.getFileName(configCaption, + qsTr("Config files (*" + configExtension + ")"), + StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + countryCode, + true, + configExtension) + } + if (fileName !== "") { + PageController.showBusyIndicator(true) + let result = ApiConfigsController.exportNativeConfig(countryCode, fileName) + if (result) { + ApiSettingsController.getAccountInfo(true) + } + + PageController.showBusyIndicator(false) + if (result) { + PageController.showNotificationMessage(qsTr("Config file saved")) + } + } + } + + function revokeConfig(countryCode) { + PageController.showBusyIndicator(true) + let result = ApiConfigsController.revokeNativeConfig(countryCode) + if (result) { + ApiSettingsController.getAccountInfo(true) + } + PageController.showBusyIndicator(false) + + if (result) { + PageController.showNotificationMessage(qsTr("The config has been revoked")) + } + } + + function showQuestion(isConfigIssue, countryCode, countryName) { + var headerText + if (isConfigIssue) { + headerText = qsTr("Generate a new %1 configuration file?").arg(countryName) + } else { + headerText = qsTr("Revoke the current %1 configuration file?").arg(countryName) + } + + var descriptionText = qsTr("Your previous configuration file will no longer work, and it will not be possible to connect using it") + var yesButtonText = isConfigIssue ? qsTr("Download") : qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (isConfigIssue) { + issueConfig(countryCode) + } else { + revokeConfig(countryCode) + } + moreOptionsDrawer.closeTriggered() + } + var noButtonFunction = function() {} + + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } +} diff --git a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml index e31c92db..60b59f45 100644 --- a/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsAppSplitTunneling.qml @@ -50,6 +50,7 @@ PageType { readonly property string name: qsTr("Only the apps from the list should have access via VPN") readonly property int type: routeMode.onlyForwardApps } + QtObject { id: allExceptApps @@ -111,7 +112,7 @@ PageType { headerText: qsTr("Mode") - enabled: Qt.platform.os === "android" && root.pageEnabled + enabled: (Qt.platform.os === "android") && root.pageEnabled listView: ListViewWithRadioButtonType { rootWidth: root.width @@ -146,77 +147,56 @@ PageType { } } - FlickableType { + ListViewType { + id: listView + anchors.top: header.bottom - anchors.topMargin: 16 - contentHeight: col.implicitHeight + addAppButton.implicitHeight + addAppButton.anchors.bottomMargin + addAppButton.anchors.topMargin + anchors.bottom: addAppButton.top + 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 { - id: col - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + delegate: ColumnLayout { + width: listView.width - ListView { - id: apps - width: parent.width - height: apps.contentItem.height + LabelWithButtonType { + Layout.fillWidth: true - model: SortFilterProxyModel { - id: proxyAppSplitTunnelingModel - sourceModel: AppSplitTunnelingModel - filters: RegExpFilter { - roleName: "appPath" - pattern: ".*" + searchField.textField.text + ".*" - caseSensitivity: Qt.CaseInsensitive + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + 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)) } - sorters: [ - 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 {} + var noButtonFunction = function() { } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } } + + DividerType {} } } diff --git a/client/ui/qml/Pages2/PageSettingsApplication.qml b/client/ui/qml/Pages2/PageSettingsApplication.qml index 5f4ada82..981bbecb 100644 --- a/client/ui/qml/Pages2/PageSettingsApplication.qml +++ b/client/ui/qml/Pages2/PageSettingsApplication.qml @@ -21,22 +21,24 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 + header: ColumnLayout { + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -45,9 +47,17 @@ PageType { headerText: qsTr("Application") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser when have migrated to 6.9 + + width: listView.width SwitcherType { - id: switcher + id: switcherAllowScreenshots + visible: GC.isMobile() Layout.fillWidth: true @@ -61,10 +71,6 @@ PageType { SettingsController.toggleScreenshotsEnabled(checked) } } - - // KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ? - // labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton - parentFlickable: fl } DividerType { @@ -73,15 +79,15 @@ PageType { LabelWithButtonType { id: labelWithButtonNotification + visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted + Layout.fillWidth: true text: qsTr("Enable notifications") descriptionText: qsTr("Enable notifications to show the VPN state in the status bar") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { SettingsController.requestNotificationPermission() } @@ -93,6 +99,7 @@ PageType { SwitcherType { id: switcherAutoStart + visible: !GC.isMobile() Layout.fillWidth: true @@ -101,8 +108,6 @@ PageType { text: qsTr("Auto start") descriptionText: qsTr("Launch the application every time the device is starts") - parentFlickable: fl - checked: SettingsController.isAutoStartEnabled() onCheckedChanged: { if (checked !== SettingsController.isAutoStartEnabled()) { @@ -117,6 +122,7 @@ PageType { SwitcherType { id: switcherAutoConnect + visible: !GC.isMobile() Layout.fillWidth: true @@ -125,8 +131,6 @@ PageType { text: qsTr("Auto connect") descriptionText: qsTr("Connect to VPN on app start") - parentFlickable: fl - checked: SettingsController.isAutoConnectEnabled() onCheckedChanged: { if (checked !== SettingsController.isAutoConnectEnabled()) { @@ -141,6 +145,7 @@ PageType { SwitcherType { id: switcherStartMinimized + visible: !GC.isMobile() Layout.fillWidth: true @@ -152,8 +157,6 @@ PageType { enabled: switcherAutoStart.checked opacity: enabled ? 1.0 : 0.5 - parentFlickable: fl - checked: SettingsController.isStartMinimizedEnabled() onCheckedChanged: { if (checked !== SettingsController.isStartMinimizedEnabled()) { @@ -165,17 +168,21 @@ PageType { DividerType { visible: !GC.isMobile() } + } + + footer: ColumnLayout { + + width: listView.width LabelWithButtonType { id: labelWithButtonLanguage + Layout.fillWidth: true text: qsTr("Language") descriptionText: LanguageModel.currentLanguageName rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { selectLanguageDrawer.openTriggered() } @@ -185,14 +192,13 @@ PageType { LabelWithButtonType { id: labelWithButtonLogging + Layout.fillWidth: true text: qsTr("Logging") descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsLogging) } @@ -202,14 +208,13 @@ PageType { LabelWithButtonType { id: labelWithButtonReset + Layout.fillWidth: true text: qsTr("Reset settings and remove all data from the application") rightImageSource: "qrc:/images/controls/chevron-right.svg" textColor: AmneziaStyle.color.vibrantRed - parentFlickable: fl - clickedFunction: function() { 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.") diff --git a/client/ui/qml/Pages2/PageSettingsBackup.qml b/client/ui/qml/Pages2/PageSettingsBackup.qml index 83e0f567..a8ea9da7 100644 --- a/client/ui/qml/Pages2/PageSettingsBackup.qml +++ b/client/ui/qml/Pages2/PageSettingsBackup.qml @@ -41,51 +41,68 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right - ColumnLayout { - id: content + header: ColumnLayout { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 + width: listView.width spacing: 16 BaseHeaderType { Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 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.") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser when have migrated to 6.9 + + width: listView.width + + spacing: 16 WarningType { - Layout.topMargin: 16 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 " + - "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" } BasicButtonType { id: makeBackupButton + Layout.fillWidth: true Layout.topMargin: 14 + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: qsTr("Make a backup") - parentFlickable: fl - clickedFunc: function() { var fileName = "" if (GC.isMobile()) { @@ -108,8 +125,11 @@ PageType { BasicButtonType { id: restoreBackupButton + Layout.fillWidth: true Layout.topMargin: -8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 defaultColor: AmneziaStyle.color.transparent hoveredColor: AmneziaStyle.color.translucentWhite @@ -120,8 +140,6 @@ PageType { text: qsTr("Restore from backup") - parentFlickable: fl - clickedFunc: function() { var filePath = SystemController.getFileName(qsTr("Open backup file"), qsTr("Backup files (*.backup)")) diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index 84b98230..60323629 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -21,20 +21,25 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right - ColumnLayout { - id: content + header: ColumnLayout { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -43,9 +48,17 @@ PageType { headerText: qsTr("Connection") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser when have migrated to 6.9 + + width: listView.width SwitcherType { id: amneziaDnsSwitch + Layout.fillWidth: true Layout.margins: 16 @@ -64,14 +77,13 @@ PageType { LabelWithButtonType { id: dnsServersButton + Layout.fillWidth: true text: qsTr("DNS servers") descriptionText: qsTr("When AmneziaDNS is not used or installed") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsDns) } @@ -81,14 +93,13 @@ PageType { LabelWithButtonType { id: splitTunnelingButton + Layout.fillWidth: true text: qsTr("Site-based split tunneling") descriptionText: qsTr("Allows you to select which sites you want to access through the VPN") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsSplitTunneling) } @@ -96,8 +107,15 @@ PageType { DividerType {} + } + + footer: ColumnLayout { // TODO(CyAn84): move to delegate,add DelegateChooser when have migrated to 6.9 + + width: listView.width + LabelWithButtonType { id: splitTunnelingButton2 + visible: root.isAppSplitTinnelingEnabled Layout.fillWidth: true @@ -106,8 +124,6 @@ PageType { descriptionText: qsTr("Allows you to use the VPN only for certain Apps") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) } @@ -127,8 +143,6 @@ PageType { descriptionText: qsTr("Blocks network connections without VPN") rightImageSource: "qrc:/images/controls/chevron-right.svg" - parentFlickable: fl - clickedFunction: function() { PageController.goToPage(PageEnum.PageSettingsKillSwitch) } diff --git a/client/ui/qml/Pages2/PageSettingsDns.qml b/client/ui/qml/Pages2/PageSettingsDns.qml index d5e2c52b..a510f928 100644 --- a/client/ui/qml/Pages2/PageSettingsDns.qml +++ b/client/ui/qml/Pages2/PageSettingsDns.qml @@ -1,140 +1,167 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Config" -import "../Controls2/TextTypes" -import "../Components" - -PageType { - id: root - - BackButtonType { - id: backButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 20 - } - - FlickableType { - id: fl - anchors.top: backButton.bottom - anchors.bottom: parent.bottom - contentHeight: content.height - - property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) - - enabled: !isServerFromApi - - Component.onCompleted: { - if (isServerFromApi) { - PageController.showNotificationMessage(qsTr("Default server does not support custom DNS")) - } - } - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - spacing: 16 - - BaseHeaderType { - Layout.fillWidth: true - - headerText: qsTr("DNS servers") - } - - ParagraphTextType { - Layout.fillWidth: true - text: qsTr("If AmneziaDNS is not used or installed") - } - - TextFieldWithHeaderType { - id: primaryDns - - Layout.fillWidth: true - headerText: qsTr("Primary DNS") - - textField.text: SettingsController.primaryDns - textField.validator: RegularExpressionValidator { - regularExpression: InstallController.ipAddressRegExp() - } - } - - TextFieldWithHeaderType { - id: secondaryDns - - Layout.fillWidth: true - headerText: qsTr("Secondary DNS") - - textField.text: SettingsController.secondaryDns - textField.validator: RegularExpressionValidator { - regularExpression: InstallController.ipAddressRegExp() - } - } - - BasicButtonType { - id: restoreDefaultButton - Layout.fillWidth: true - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - text: qsTr("Restore default") - - clickedFunc: function() { - var headerText = qsTr("Restore default DNS settings?") - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - SettingsController.primaryDns = "1.1.1.1" - primaryDns.textField.text = SettingsController.primaryDns - SettingsController.secondaryDns = "1.0.0.1" - secondaryDns.textField.text = SettingsController.secondaryDns - PageController.showNotificationMessage(qsTr("Settings have been reset")) - } - var noButtonFunction = function() { - } - - showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) - } - } - - BasicButtonType { - id: saveButton - - Layout.fillWidth: true - - text: qsTr("Save") - - clickedFunc: function() { - if (primaryDns.textField.text !== SettingsController.primaryDns) { - SettingsController.primaryDns = primaryDns.textField.text - } - if (secondaryDns.textField.text !== SettingsController.secondaryDns) { - SettingsController.secondaryDns = secondaryDns.textField.text - } - PageController.showNotificationMessage(qsTr("Settings saved")) - } - } - } - } - -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Config" +import "../Controls2/TextTypes" +import "../Components" + +PageType { + id: root + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) + + enabled: !isServerFromApi + + Component.onCompleted: { + if (isServerFromApi) { + PageController.showNotificationMessage(qsTr("Default server does not support custom DNS")) + } + } + + header: ColumnLayout { + width: listView.width + spacing: 16 + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("DNS servers") + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("If AmneziaDNS is not used or installed") + } + + TextFieldWithHeaderType { + id: primaryDns + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Primary DNS") + + textField.text: SettingsController.primaryDns + textField.validator: RegularExpressionValidator { + regularExpression: InstallController.ipAddressRegExp() + } + } + + TextFieldWithHeaderType { + id: secondaryDns + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + headerText: qsTr("Secondary DNS") + + textField.text: SettingsController.secondaryDns + textField.validator: RegularExpressionValidator { + regularExpression: InstallController.ipAddressRegExp() + } + } + } + + model: 1 // fake model to force the ListView to be created without a model + spacing: 16 + + delegate: ColumnLayout { + width: listView.width + + BasicButtonType { + id: restoreDefaultButton + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: qsTr("Restore default") + + clickedFunc: function() { + var headerText = qsTr("Restore default DNS settings?") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + SettingsController.primaryDns = "1.1.1.1" + primaryDns.textField.text = SettingsController.primaryDns + SettingsController.secondaryDns = "1.0.0.1" + secondaryDns.textField.text = SettingsController.secondaryDns + PageController.showNotificationMessage(qsTr("Settings have been reset")) + } + var noButtonFunction = function() { + } + + showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } + } + + 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")) + } + } + } + } +} diff --git a/client/ui/qml/Pages2/PageSettingsLogging.qml b/client/ui/qml/Pages2/PageSettingsLogging.qml index 5b20936c..fda58175 100644 --- a/client/ui/qml/Pages2/PageSettingsLogging.qml +++ b/client/ui/qml/Pages2/PageSettingsLogging.qml @@ -23,9 +23,15 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } } - ListView { + ListViewType { id: listView anchors.top: backButton.bottom @@ -33,10 +39,6 @@ PageType { anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - header: ColumnLayout { width: listView.width @@ -101,8 +103,7 @@ PageType { } model: logTypes - clip: true - reuseItems: true + snapMode: ListView.SnapOneItem delegate: ColumnLayout { diff --git a/client/ui/qml/Pages2/PageSettingsServerData.qml b/client/ui/qml/Pages2/PageSettingsServerData.qml index 82552958..1a496b5b 100644 --- a/client/ui/qml/Pages2/PageSettingsServerData.qml +++ b/client/ui/qml/Pages2/PageSettingsServerData.qml @@ -18,10 +18,6 @@ PageType { signal lastItemTabClickedSignal() - onFocusChanged: content.isServerWithWriteAccess ? - labelWithButton.forceActiveFocus() : - labelWithButton3.forceActiveFocus() - Connections { target: InstallController @@ -63,218 +59,194 @@ PageType { target: ServersModel function onProcessedServerIndexChanged() { - content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() + listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() } } - FlickableType { - id: fl - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height + ListViewType { + id: listView - ColumnLayout { - id: content + property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + anchors.fill: parent - property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() + model: serverActions + + delegate: ColumnLayout { + width: listView.width LabelWithButtonType { - id: labelWithButton - visible: content.isServerWithWriteAccess Layout.fillWidth: true - text: qsTr("Check the server for previously installed Amnezia services") - descriptionText: qsTr("Add them to the application if they were not displayed") + visible: isVisible + + text: title + descriptionText: description + textColor: tColor clickedFunction: function() { + clickedHandler() + } + } + + DividerType { + visible: isVisible + } + } + } + + property list 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) - InstallController.scanServerForInstalledContainers() + InstallController.rebootProcessedServer() PageController.showBusyIndicator(false) } } + var noButtonFunction = function() { - DividerType { - visible: content.isServerWithWriteAccess } - LabelWithButtonType { - id: labelWithButton2 - visible: content.isServerWithWriteAccess - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Reboot server") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: remove - clickedFunction: 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") + property bool isVisible: true + readonly property string title: qsTr("Remove server from application") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + 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() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection")) - } else { - PageController.showBusyIndicator(true) - InstallController.rebootProcessedServer() - PageController.showBusyIndicator(false) - } - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - labelWithButton2.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot remove server during active connection")) + } else { + PageController.showBusyIndicator(true) + InstallController.removeProcessedServer() + PageController.showBusyIndicator(false) } } + var noButtonFunction = function() { - DividerType { - visible: content.isServerWithWriteAccess } - LabelWithButtonType { - id: labelWithButton3 - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Remove server from application") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: clear - clickedFunction: 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") + property bool isVisible: true + readonly property string title: qsTr("Clear server from Amnezia software") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + 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() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot remove server during active connection")) - } else { - PageController.showBusyIndicator(true) - InstallController.removeProcessedServer() - PageController.showBusyIndicator(false) - } - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - labelWithButton3.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + var yesButtonFunction = function() { + if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { + PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection")) + } else { + PageController.goToPage(PageEnum.PageDeinstalling) + InstallController.removeAllContainers() } } + var noButtonFunction = function() { - DividerType {} + } - LabelWithButtonType { - id: labelWithButton4 - visible: content.isServerWithWriteAccess - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Clear server from Amnezia software") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: reset - clickedFunction: 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") + property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") + readonly property string title: qsTr("Reset API config") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + 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() { - if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { - PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection")) - } else { - PageController.goToPage(PageEnum.PageDeinstalling) - InstallController.removeAllContainers() - } - if (!GC.isMobile()) { - labelWithButton5.forceActiveFocus() - } - } - var noButtonFunction = function() { - if (!GC.isMobile()) { - labelWithButton4.forceActiveFocus() - } - } - - showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + var yesButtonFunction = function() { + 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) } } + var noButtonFunction = function() { - DividerType { - visible: content.isServerWithWriteAccess } - LabelWithButtonType { - id: labelWithButton5 - visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") - Layout.fillWidth: true + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } - text: qsTr("Reset API config") - textColor: AmneziaStyle.color.vibrantRed + QtObject { + id: switch_to_premium - clickedFunction: function() { - var headerText = qsTr("Do you want to reset API config?") - var descriptionText = "" - var yesButtonText = qsTr("Continue") - var noButtonText = qsTr("Cancel") - - var yesButtonFunction = function() { - 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 - } + property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") + readonly property string title: qsTr("Switch to the new Amnezia Premium subscription") + readonly property string description: "" + readonly property var tColor: AmneziaStyle.color.vibrantRed + readonly property var clickedHandler: function() { + PageController.goToPageHome() + ApiPremV1MigrationController.showMigrationDrawer() } } } diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml index fce9b2a3..a17149c9 100644 --- a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml +++ b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml @@ -21,249 +21,211 @@ PageType { property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex()) - ColumnLayout { - id: header + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: 20 - - BackButtonType { - id: backButton + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } } + } - BaseHeaderType { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - Layout.bottomMargin: 32 + ListViewType { + id: listView - headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") - } + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left - ListView { - id: protocols - Layout.fillWidth: true - height: protocols.contentItem.height - clip: true - interactive: true + header: ColumnLayout { + width: listView.width - property bool isFocusable: true + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 32 - 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() - } + headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") } } + 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() + } + } } } - diff --git a/client/ui/qml/Pages2/PageSettingsServersList.qml b/client/ui/qml/Pages2/PageSettingsServersList.qml index 57e39ae8..f7222236 100644 --- a/client/ui/qml/Pages2/PageSettingsServersList.qml +++ b/client/ui/qml/Pages2/PageSettingsServersList.qml @@ -40,25 +40,20 @@ PageType { } } - ListView { + ListViewType { id: servers objectName: "servers" width: parent.width anchors.top: header.bottom anchors.topMargin: 16 + anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - height: 500 - - property bool isFocusable: true model: ServersModel - clip: true - reuseItems: true - delegate: Item { implicitWidth: servers.width implicitHeight: delegateContent.implicitHeight diff --git a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml index 0cbed7c8..7d0ba599 100644 --- a/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml +++ b/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml @@ -161,7 +161,7 @@ PageType { } } - ListView { + ListViewType { id: listView anchors.top: header.bottom @@ -172,8 +172,6 @@ PageType { enabled: root.pageEnabled - property bool isFocusable: true - model: SortFilterProxyModel { id: proxySitesModel sourceModel: SitesModel @@ -193,13 +191,7 @@ PageType { ] } - clip: true - - reuseItems: true - delegate: ColumnLayout { - id: delegateContent - width: listView.width LabelWithButtonType { @@ -236,7 +228,6 @@ PageType { } } - Rectangle { anchors.fill: addSiteButton anchors.bottomMargin: -24 @@ -286,8 +277,8 @@ PageType { moreActionsDrawer.openTriggered() } - Keys.onReturnPressed: this.clicked() - Keys.onEnterPressed: this.clicked() + Keys.onReturnPressed: addSiteButtonImage.clicked() + Keys.onEnterPressed: addSiteButtonImage.clicked() } } @@ -351,7 +342,7 @@ PageType { } DividerType {} - + LabelWithButtonType { id: clearSitesButton Layout.fillWidth: true @@ -402,22 +393,24 @@ PageType { backButtonFunction: function() { importSitesDrawer.closeTriggered() } + + onFocusChanged: { + if (this.activeFocus) { + importSitesDrawerListView.positionViewAtBeginning() + } + } } - FlickableType { + ListViewType { + id: importSitesDrawerListView + anchors.top: importSitesDrawerBackButton.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom - contentHeight: importSitesDrawerContent.height - - ColumnLayout { - id: importSitesDrawerContent - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + header: ColumnLayout { + width: importSitesDrawerListView.width Header2Type { Layout.fillWidth: true @@ -425,49 +418,67 @@ PageType { headerText: qsTr("Import a list of sites") } + } + + model: importOptions + + delegate: ColumnLayout { + width: importSitesDrawerListView.width LabelWithButtonType { - id: importSitesButton2 Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - text: qsTr("Replace site list") + text: title clickedFunction: function() { - var fileName = SystemController.getFileName(qsTr("Open sites file"), - qsTr("Sites files (*.json)")) - if (fileName !== "") { - importSitesDrawerContent.importSites(fileName, true) - } + clickedHandler() } } DividerType {} - - LabelWithButtonType { - id: importSitesButton3 - Layout.fillWidth: true - text: qsTr("Add imported sites to existing ones") - - clickedFunction: function() { - var fileName = SystemController.getFileName(qsTr("Open sites file"), - qsTr("Sites files (*.json)")) - if (fileName !== "") { - importSitesDrawerContent.importSites(fileName, false) - } - } - } - - function importSites(fileName, replaceExistingSites) { - PageController.showBusyIndicator(true) - SitesController.importSites(fileName, replaceExistingSites) - PageController.showBusyIndicator(false) - importSitesDrawer.closeTriggered() - moreActionsDrawer.closeTriggered() - } - - DividerType {} } } } } + + property list importOptions: [ + replaceOption, + addOption, + ] + + QtObject { + id: replaceOption + + readonly property string title: qsTr("Replace site list") + readonly property var clickedHandler: function() { + var fileName = SystemController.getFileName(qsTr("Open sites file"), + qsTr("Sites files (*.json)")) + if (fileName !== "") { + root.importSites(fileName, true) + } + } + } + + QtObject { + id: addOption + + readonly property string title: qsTr("Add imported sites to existing ones") + readonly property var clickedHandler: function() { + var fileName = SystemController.getFileName(qsTr("Open sites file"), + qsTr("Sites files (*.json)")) + if (fileName !== "") { + root.importSites(fileName, false) + } + } + } + + function importSites(fileName, replaceExistingSites) { + PageController.showBusyIndicator(true) + SitesController.importSites(fileName, replaceExistingSites) + PageController.showBusyIndicator(false) + importSitesDrawer.closeTriggered() + moreActionsDrawer.closeTriggered() + } } diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml index cfc07fd1..1f76c97d 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml @@ -1,146 +1,177 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import PageEnum 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" -import "../Components" - -PageType { - id: root - - FlickableType { - id: fl - anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 0 - - BackButtonType { - id: backButton - Layout.topMargin: 20 - } - - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 8 - Layout.rightMargin: 16 - Layout.leftMargin: 16 - Layout.bottomMargin: 32 - - headerText: ApiServicesModel.getSelectedServiceData("name") - descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/map-pin.svg" - leftText: qsTr("For the region") - rightText: ApiServicesModel.getSelectedServiceData("region") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/tag.svg" - leftText: qsTr("Price") - rightText: ApiServicesModel.getSelectedServiceData("price") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/history.svg" - leftText: qsTr("Work period") - rightText: ApiServicesModel.getSelectedServiceData("timeLimit") - - visible: rightText !== "" - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/gauge.svg" - leftText: qsTr("Speed") - rightText: ApiServicesModel.getSelectedServiceData("speed") - } - - LabelWithImageType { - Layout.fillWidth: true - Layout.margins: 16 - - imageSource: "qrc:/images/controls/info.svg" - leftText: qsTr("Features") - rightText: "" - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.rightMargin: 16 - Layout.leftMargin: 16 - - onLinkActivated: function(link) { - Qt.openUrlExternally(link) - } - textFormat: Text.RichText - text: { - var text = ApiServicesModel.getSelectedServiceData("features") - return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")) - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } - } - } - - BasicButtonType { - id: continueButton - - anchors.right: parent.right - anchors.left: parent.left - anchors.bottom: parent.bottom - - anchors.topMargin: 32 - anchors.rightMargin: 16 - anchors.leftMargin: 16 - anchors.bottomMargin: 32 - - text: qsTr("Connect") - - clickedFunc: function() { - var endpoint = ApiServicesModel.getStoreEndpoint() - if (endpoint !== undefined && endpoint !== "") { - Qt.openUrlExternally(endpoint) - PageController.closePage() - PageController.closePage() - } else { - PageController.showBusyIndicator(true) - ApiConfigsController.importServiceFromGateway() - PageController.showBusyIndicator(false) - } - } - } -} +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import PageEnum 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 32 + + headerText: ApiServicesModel.getSelectedServiceData("name") + descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") + } + } + + model: inputFields + spacing: 0 + + delegate: ColumnLayout { + width: listView.width + + LabelWithImageType { + Layout.fillWidth: true + Layout.margins: 16 + + imageSource: imagePath + leftText: lText + rightText: rText + } + } + + footer: ColumnLayout { + width: listView.width + + spacing: 0 + + ParagraphTextType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + onLinkActivated: function(link) { + Qt.openUrlExternally(link) + } + textFormat: Text.RichText + text: { + var text = ApiServicesModel.getSelectedServiceData("features") + return text.replace("%1", LanguageModel.getCurrentSiteUrl("free")) + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + } + + BasicButtonType { + id: continueButton + + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.bottomMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Connect") + + clickedFunc: function() { + var endpoint = ApiServicesModel.getStoreEndpoint() + if (endpoint !== undefined && endpoint !== "") { + Qt.openUrlExternally(endpoint) + PageController.closePage() + PageController.closePage() + } else { + PageController.showBusyIndicator(true) + ApiConfigsController.importServiceFromGateway() + PageController.showBusyIndicator(false) + } + } + } + } + } + + property list inputFields: [ + region, + price, + timeLimit, + speed, + features + ] + + QtObject { + id: region + + readonly property string imagePath: "qrc:/images/controls/map-pin.svg" + readonly property string lText: qsTr("For the region") + readonly property string rText: ApiServicesModel.getSelectedServiceData("region") + property bool isVisible: true + } + + QtObject { + id: price + + readonly property string imagePath: "qrc:/images/controls/tag.svg" + readonly property string lText: qsTr("Price") + readonly property string rText: ApiServicesModel.getSelectedServiceData("price") + property bool isVisible: true + } + + QtObject { + id: timeLimit + + readonly property string imagePath: "qrc:/images/controls/history.svg" + readonly property string lText: qsTr("Work period") + readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit") + property bool isVisible: rText !== "" + } + + QtObject { + id: speed + + readonly property string imagePath: "qrc:/images/controls/gauge.svg" + readonly property string lText: qsTr("Speed") + readonly property string rText: ApiServicesModel.getSelectedServiceData("speed") + property bool isVisible: true + } + + QtObject { + id: features + + readonly property string imagePath: "qrc:/images/controls/info.svg" + readonly property string lText: qsTr("Features") + readonly property string rText: "" + property bool isVisible: true + } +} diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml index 207c305e..51fdee36 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml @@ -14,86 +14,77 @@ import "../Config" PageType { id: root - ColumnLayout { - id: header + BackButtonType { + id: backButton anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right + Layout.topMargin: 20 - spacing: 0 - - BackButtonType { - id: backButton - Layout.topMargin: 20 - } - - BaseHeaderType { - 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.") + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } } } - ListView { - id: servicesListView + ListViewType { + id: listView - anchors.top: header.bottom + anchors.top: backButton.bottom anchors.right: parent.right anchors.left: parent.left anchors.bottom: parent.bottom anchors.topMargin: 16 - spacing: 0 - property bool isFocusable: true - - clip: true - reuseItems: true + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 24 + + headerText: qsTr("VPN by Amnezia") + descriptionText: qsTr("Choose a VPN service that suits your needs.") + } + } + + spacing: 0 model: ApiServicesModel - ScrollBar.vertical: ScrollBarType {} + delegate: ColumnLayout { - delegate: Item { - implicitWidth: servicesListView.width - implicitHeight: delegateContent.implicitHeight + width: listView.width enabled: isServiceAvailable - ColumnLayout { - id: delegateContent + CardWithIconsType { + id: card - anchors.fill: parent + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 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 - - rightImageSource: "qrc:/images/controls/chevron-right.svg" - - onClicked: { - if (isServiceAvailable) { - ApiServicesModel.setServiceIndex(index) - PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) - } + onClicked: { + if (isServiceAvailable) { + ApiServicesModel.setServiceIndex(index) + PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) } - - Keys.onEnterPressed: this.clicked() - Keys.onReturnPressed: this.clicked() } + + Keys.onEnterPressed: clicked() + Keys.onReturnPressed: clicked() } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 520dc5d3..f88745d4 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -27,21 +27,11 @@ PageType { } } - ListView { + ListViewType { id: listView anchors.fill: parent - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - - model: variants - - clip: true - - reuseItems: true - header: ColumnLayout { width: listView.width @@ -216,6 +206,8 @@ PageType { } } + model: variants + delegate: ColumnLayout { width: listView.width diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index fd9404e0..6a30dbb7 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -28,41 +28,14 @@ PageType { } } - ListView { + ListViewType { id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.right: parent.right 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 { width: listView.width @@ -78,8 +51,6 @@ PageType { model: inputFields spacing: 16 - clip: true - reuseItems: true delegate: ColumnLayout { width: listView.width diff --git a/client/ui/qml/Pages2/PageSetupWizardEasy.qml b/client/ui/qml/Pages2/PageSetupWizardEasy.qml index 599464cf..9bc5cf3f 100644 --- a/client/ui/qml/Pages2/PageSetupWizardEasy.qml +++ b/client/ui/qml/Pages2/PageSetupWizardEasy.qml @@ -20,6 +20,7 @@ PageType { SortFilterProxyModel { id: proxyContainersModel + sourceModel: ContainersModel filters: [ ValueFilter { @@ -40,107 +41,98 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - FlickableType { - id: fl + ButtonGroup { + id: buttonGroup + } + + ListViewType { + id: listView + + property int dockerContainer + property int containerDefaultPort + property int containerDefaultTransportProto + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + setupLaterButton.anchors.bottomMargin + anchors.left: parent.left + anchors.right: parent.right - Column { - id: content + spacing: 16 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + header: ColumnLayout { + width: listView.width spacing: 16 BaseHeaderType { id: header - implicitWidth: parent.width + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 + headerTextMaximumLineCount: 10 headerText: qsTr("Choose Installation Type") } + } - ButtonGroup { - id: buttonGroup - } + model: proxyContainersModel + currentIndex: 0 - ListView { - id: containers - width: parent.width - height: containers.contentItem.height - spacing: 16 + delegate: ColumnLayout { + width: listView.width - currentIndex: 0 - clip: true - interactive: false - model: proxyContainersModel + CardType { + id: card - property int dockerContainer - property int containerDefaultPort - property int containerDefaultTransportProto + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.bottomMargin: 16 - property bool isFocusable: true + headerText: easySetupHeader + bodyText: easySetupDescription - delegate: Item { - implicitWidth: containers.width - implicitHeight: delegateContent.implicitHeight + ButtonGroup.group: buttonGroup - ColumnLayout { - id: delegateContent + onClicked: function() { + isEasySetup = true + var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - CardType { - id: card - - 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) - } - - Keys.onEnterPressed: this.clicked() - Keys.onReturnPressed: this.clicked() - } - } + listView.dockerContainer = dockerContainer + listView.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto) + listView.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto) } - Component.onCompleted: { - var item = containers.itemAtIndex(containers.currentIndex) - if (item !== null) { - var button = item.children[0].children[0] - button.checked = true - button.clicked() - } - } + Keys.onReturnPressed: this.clicked() + Keys.onEnterPressed: this.clicked() } + } + + footer: ColumnLayout { + width: listView.width + spacing: 16 DividerType { - implicitWidth: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 } CardType { - implicitWidth: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 headerText: qsTr("Manual") bodyText: qsTr("Choose a VPN protocol") @@ -149,6 +141,7 @@ PageType { onClicked: function() { isEasySetup = false + checked = true } Keys.onEnterPressed: this.clicked() @@ -158,19 +151,19 @@ PageType { BasicButtonType { id: continueButton - implicitWidth: parent.width + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: qsTr("Continue") - - parentFlickable: fl clickedFunc: function() { if (root.isEasySetup) { - ContainersModel.setProcessedContainerIndex(containers.dockerContainer) + ContainersModel.setProcessedContainerIndex(listView.dockerContainer) PageController.goToPage(PageEnum.PageSetupWizardInstalling) - InstallController.install(containers.dockerContainer, - containers.containerDefaultPort, - containers.containerDefaultTransportProto) + InstallController.install(listView.dockerContainer, + listView.containerDefaultPort, + listView.containerDefaultTransportProto) } else { PageController.goToPage(PageEnum.PageSetupWizardProtocols) } @@ -180,9 +173,11 @@ PageType { BasicButtonType { id: setupLaterButton - implicitWidth: parent.width - anchors.topMargin: 8 - anchors.bottomMargin: 24 + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.bottomMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 defaultColor: AmneziaStyle.color.transparent hoveredColor: AmneziaStyle.color.translucentWhite @@ -191,9 +186,6 @@ PageType { textColor: AmneziaStyle.color.paleGray borderWidth: 1 - Keys.onTabPressed: lastItemTabClicked(focusItem) - parentFlickable: fl - visible: { if (PageController.isTriggeredByConnectButton()) { PageController.setTriggeredByConnectButton(false) @@ -211,5 +203,15 @@ PageType { } } } + + Component.onCompleted: { + var item = listView.itemAtIndex(listView.currentIndex) + if (item !== null) { + var button = item.children[0] + button.checked = true + button.clicked() + } + } } } + diff --git a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml index 822931b8..efabeb9f 100644 --- a/client/ui/qml/Pages2/PageSetupWizardInstalling.qml +++ b/client/ui/qml/Pages2/PageSetupWizardInstalling.qml @@ -85,92 +85,76 @@ PageType { ] } - FlickableType { + ListViewType { + id: listView + anchors.fill: parent - contentHeight: content.height - Column { - id: content + currentIndex: -1 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + model: proxyContainersModel - spacing: 16 + delegate: ColumnLayout { + width: listView.width - ListView { - id: container - width: parent.width - height: container.contentItem.height - currentIndex: -1 - clip: true - interactive: false - model: proxyContainersModel + BaseHeaderType { + Layout.fillWidth: true + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - delegate: Item { - implicitWidth: container.width - implicitHeight: delegateContent.implicitHeight + headerText: qsTr("Installing") + descriptionText: name + } - ColumnLayout { - id: delegateContent + ProgressBarType { + id: progressBar - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 20 + Timer { + id: timer - headerText: qsTr("Installing") - descriptionText: name - } - - ProgressBarType { - 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) - } - } + interval: 300 + repeat: true + running: root.isTimerRunning + onTriggered: { + progressBar.value += 0.003 } } } + + 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) + } + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml index ac7fc4b2..4d914a1d 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocolSettings.qml @@ -29,256 +29,239 @@ PageType { ] } - FlickableType { - anchors.fill: parent - contentHeight: content.height + BackButtonType { + id: backButton - Column { - id: content + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } - ListView { - id: processedContainerListView - width: parent.width - height: contentItem.height - currentIndex: -1 - clip: true - interactive: false - model: proxyContainersModel + ListViewType { + id: listView - property bool isFocusable: true + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left - Keys.onTabPressed: { - FocusController.nextKeyTabItem() + currentIndex: -1 + + model: proxyContainersModel + + delegate: ColumnLayout { + width: listView.width + + BaseHeaderType { + id: header + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Installing %1").arg(name) + descriptionText: description + } + + BasicButtonType { + id: showDetailsButton + + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + implicitHeight: 32 + + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.goldenApricot + + text: qsTr("More detailed") + + clickedFunc: function() { + showDetailsDrawer.openTriggered() } + } - Keys.onBacktabPressed: { - FocusController.previousKeyTabItem() - } + DrawerType2 { + id: showDetailsDrawer + parent: root - Keys.onUpPressed: { - FocusController.nextKeyUpItem() - } + anchors.fill: parent + expandedHeight: parent.height * 0.9 + expandedStateContent: Item { + implicitHeight: showDetailsDrawer.expandedHeight - Keys.onDownPressed: { - FocusController.nextKeyDownItem() - } + BackButtonType { + id: showDetailsBackButton - Keys.onLeftPressed: { - FocusController.nextKeyLeftItem() - } + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 - Keys.onRightPressed: { - FocusController.nextKeyRightItem() - } - - delegate: Item { - implicitWidth: processedContainerListView.width - implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height - - property alias port:port - - ColumnLayout { - id: delegateContent - - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 - - BackButtonType { - id: backButton - - Layout.topMargin: 20 - Layout.rightMargin: -16 - Layout.leftMargin: -16 + backButtonFunction: function() { + showDetailsDrawer.closeTriggered() } + } - BaseHeaderType { - id: header + ListViewType { + id: showDetailsListView - Layout.fillWidth: true + anchors.top: showDetailsBackButton.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom - headerText: qsTr("Installing %1").arg(name) - descriptionText: description - } + header: ColumnLayout { + width: showDetailsListView.width - BasicButtonType { - id: showDetailsButton + Header2Type { + id: showDetailsDrawerHeader - Layout.topMargin: 16 - Layout.leftMargin: -8 + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 - implicitHeight: 32 - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.goldenApricot - - text: qsTr("More detailed") - KeyNavigation.tab: transportProtoSelector - - clickedFunc: function() { - showDetailsDrawer.openTriggered() + headerText: name } } - DrawerType2 { - id: showDetailsDrawer - parent: root + model: 1 // fake model to force the ListView to be created without a model - anchors.fill: parent - expandedHeight: parent.height * 0.9 - expandedStateContent: Item { - implicitHeight: showDetailsDrawer.expandedHeight + delegate: ColumnLayout { + width: showDetailsListView.width - BackButtonType { - id: showDetailsBackButton + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.bottomMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 + text: detailedDescription + textFormat: Text.MarkdownText + } - backButtonFunction: function() { - showDetailsDrawer.closeTriggered() - } - } + Rectangle { + Layout.fillHeight: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - FlickableType { - id: fl - anchors.top: showDetailsBackButton.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - contentHeight: { - var emptySpaceHeight = parent.height - showDetailsBackButton.implicitHeight - showDetailsBackButton.anchors.topMargin - return (showDetailsDrawerContent.height > emptySpaceHeight) ? - showDetailsDrawerContent.height : emptySpaceHeight - } + color: AmneziaStyle.color.transparent + } + } - ColumnLayout { - id: showDetailsDrawerContent + footer: ColumnLayout { + width: showDetailsListView.width - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + BasicButtonType { + id: showDetailsCloseButton + Layout.fillWidth: true + Layout.bottomMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 - Header2Type { - id: showDetailsDrawerHeader - Layout.fillWidth: true - Layout.topMargin: 16 + text: qsTr("Close") - headerText: name - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 16 - Layout.bottomMargin: 16 - - text: detailedDescription - textFormat: Text.MarkdownText - } - - Rectangle { - Layout.fillHeight: true - color: AmneziaStyle.color.transparent - } - - BasicButtonType { - id: showDetailsCloseButton - Layout.fillWidth: true - Layout.bottomMargin: 32 - parentFlickable: fl - - text: qsTr("Close") - - clickedFunc: function() { - showDetailsDrawer.closeTriggered() - } - } - } + clickedFunc: function() { + showDetailsDrawer.closeTriggered() } } } - - ParagraphTextType { - id: transportProtoHeader - - Layout.topMargin: 16 - - text: qsTr("Network protocol") - } - - TransportProtoSelector { - id: transportProtoSelector - - Layout.fillWidth: true - rootWidth: root.width - } - - TextFieldWithHeaderType { - id: port - - Layout.fillWidth: true - Layout.topMargin: 16 - - headerText: qsTr("Port") - textField.maximumLength: 5 - textField.validator: IntValidator { bottom: 1; top: 65535 } - } - - Rectangle { - Layout.fillHeight: true - color: AmneziaStyle.color.transparent - } - - BasicButtonType { - id: installButton - - Layout.fillWidth: true - Layout.bottomMargin: 32 - - text: qsTr("Install") - - clickedFunc: function() { - if (!port.textField.acceptableInput && - ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" && - ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") { - port.errorText = qsTr("The port must be in the range of 1 to 65535") - return - } - - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.install(dockerContainer, port.textField.text, transportProtoSelector.currentIndex) - } - } - - Component.onCompleted: { - var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) - - if (ProtocolProps.defaultPort(defaultContainerProto) < 0) { - port.visible = false - } else { - port.textField.text = ProtocolProps.getPortForInstall(defaultContainerProto) - } - transportProtoSelector.currentIndex = ProtocolProps.defaultTransportProto(defaultContainerProto) - - port.enabled = ProtocolProps.defaultPortChangeable(defaultContainerProto) - var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto) - transportProtoSelector.visible = protocolSelectorVisible - transportProtoHeader.visible = protocolSelectorVisible - } } } } + + ParagraphTextType { + id: transportProtoHeader + + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + text: qsTr("Network protocol") + } + + TransportProtoSelector { + id: transportProtoSelector + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + rootWidth: root.width + } + + TextFieldWithHeaderType { + id: port + + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + headerText: qsTr("Port") + textField.maximumLength: 5 + textField.validator: IntValidator { bottom: 1; top: 65535 } + } + + Rectangle { + Layout.fillHeight: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + color: AmneziaStyle.color.transparent + } + + BasicButtonType { + id: installButton + + Layout.fillWidth: true + Layout.bottomMargin: 32 + Layout.rightMargin: 16 + Layout.leftMargin: 16 + + text: qsTr("Install") + + clickedFunc: function() { + if (!port.textField.acceptableInput && + ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" && + ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") { + port.errorText = qsTr("The port must be in the range of 1 to 65535") + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.install(dockerContainer, port.textField.text, transportProtoSelector.currentIndex) + } + } + + Component.onCompleted: { + var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer) + + if (ProtocolProps.defaultPort(defaultContainerProto) < 0) { + port.visible = false + } else { + port.textField.text = ProtocolProps.getPortForInstall(defaultContainerProto) + } + transportProtoSelector.currentIndex = ProtocolProps.defaultTransportProto(defaultContainerProto) + + port.enabled = ProtocolProps.defaultPortChangeable(defaultContainerProto) + var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto) + transportProtoSelector.visible = protocolSelectorVisible + transportProtoHeader.visible = protocolSelectorVisible + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml index 7afab630..da1edee6 100644 --- a/client/ui/qml/Pages2/PageSetupWizardProtocols.qml +++ b/client/ui/qml/Pages2/PageSetupWizardProtocols.qml @@ -42,19 +42,21 @@ PageType { anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } - ListView { + ListViewType { id: listView anchors.top: backButton.bottom anchors.bottom: parent.bottom anchors.right: parent.right anchors.left: parent.left - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - header: ColumnLayout { width: listView.width @@ -72,9 +74,8 @@ PageType { } model: proxyContainersModel - clip: true + spacing: 0 - reuseItems: true snapMode: ListView.SnapToItem delegate: ColumnLayout { @@ -87,9 +88,9 @@ PageType { descriptionText: description rightImageSource: "qrc:/images/controls/chevron-right.svg" - clickedFunction: function() { - ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index)) - PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) + clickedFunction: function () { + ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index)); + PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings); } } diff --git a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml index 930efb57..3a0f7832 100644 --- a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml +++ b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml @@ -13,25 +13,31 @@ import "../Config" PageType { id: root - FlickableType { - id: fl + BackButtonType { + id: backButton + anchors.top: parent.top - anchors.bottom: parent.bottom - contentHeight: content.height + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - spacing: 16 - - BackButtonType { - id: backButton - Layout.topMargin: 20 + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + header: ColumnLayout { + width: listView.width BaseHeaderType { Layout.fillWidth: true @@ -41,6 +47,13 @@ PageType { headerText: qsTr("Connection key") descriptionText: qsTr("A line that starts with vpn://...") } + } + + spacing: 16 + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { + width: listView.width TextFieldWithHeaderType { id: textKey @@ -60,23 +73,26 @@ PageType { } } } - } - BasicButtonType { - id: continueButton + footer: ColumnLayout { + width: listView.width - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 - anchors.bottomMargin: 32 + BasicButtonType { + id: continueButton - text: qsTr("Continue") + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + Layout.bottomMargin: 32 - clickedFunc: function() { - if (ImportController.extractConfigFromData(textKey.textField.text)) { - PageController.goToPage(PageEnum.PageSetupWizardViewConfig) + text: qsTr("Continue") + + clickedFunc: function() { + if (ImportController.extractConfigFromData(textKey.textField.text)) { + PageController.goToPage(PageEnum.PageSetupWizardViewConfig) + } + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml index cfa9c90f..bffa66a2 100644 --- a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml +++ b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml @@ -23,6 +23,12 @@ PageType { anchors.left: parent.left anchors.right: parent.right anchors.topMargin: 20 + + onActiveFocusChanged: { + if(backButton.enabled && backButton.activeFocus) { + listView.positionViewAtBeginning() + } + } } Connections { @@ -46,27 +52,29 @@ PageType { } } - FlickableType { - id: fl + ListViewType { + id: listView + anchors.top: backButton.bottom anchors.bottom: parent.bottom - contentHeight: content.implicitHeight + connectButton.implicitHeight + anchors.right: parent.right + anchors.left: parent.left - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + header: ColumnLayout { + width: listView.width BaseHeaderType { + Layout.leftMargin: 16 + Layout.rightMargin: 16 + headerText: qsTr("New connection") } RowLayout { Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + spacing: 8 visible: fileName.text !== "" @@ -88,7 +96,9 @@ PageType { BasicButtonType { id: showContentButton Layout.topMargin: 16 - Layout.leftMargin: -8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + implicitHeight: 32 defaultColor: AmneziaStyle.color.transparent @@ -99,8 +109,6 @@ PageType { text: showContent ? qsTr("Collapse content") : qsTr("Show content") - parentFlickable: fl - clickedFunc: function() { showContent = !showContent } @@ -108,16 +116,28 @@ PageType { CheckBoxType { id: cloakingCheckBox + objectName: "cloakingCheckBox" visible: ImportController.isNativeWireGuardConfig() Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + text: qsTr("Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider.") } + } + + model: 1 // fake model to force the ListView to be created without a model + + delegate: ColumnLayout { // TODO(CyAn84): add DelegateChooser after have migrated to 6.9 + width: listView.width WarningType { - Layout.topMargin: 16 Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 textString: ImportController.getMaliciousWarningText() textFormat: Qt.RichText @@ -130,8 +150,10 @@ PageType { } WarningType { - Layout.topMargin: 16 Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 textString: qsTr("Use connection codes only from sources you trust. Codes from public sources may have been created to intercept your data.") @@ -140,7 +162,10 @@ PageType { Rectangle { Layout.fillWidth: true + Layout.topMargin: 16 Layout.bottomMargin: 48 + Layout.rightMargin: 16 + Layout.leftMargin: 16 implicitHeight: configContent.implicitHeight @@ -161,34 +186,38 @@ PageType { } } } - } - Rectangle { - anchors.fill: columnContent - anchors.bottomMargin: -24 - color: AmneziaStyle.color.midnightBlack - opacity: 0.8 - } + footer: ColumnLayout { + width: listView.width - ColumnLayout { - id: columnContent - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 16 - anchors.leftMargin: 16 + BasicButtonType { + id: connectButton - BasicButtonType { - id: connectButton - Layout.fillWidth: true - Layout.bottomMargin: 32 + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.bottomMargin: 32 + Layout.rightMargin: 16 + Layout.leftMargin: 16 - text: qsTr("Connect") - clickedFunc: function() { - if (cloakingCheckBox.checked) { - ImportController.processNativeWireGuardConfig() + text: qsTr("Connect") + clickedFunc: function() { + const headerItem = listView.headerItem; + if (!headerItem) { + console.error("Header item not found in ListView") + return + } + + const cloakingCheckBoxItem = listView.findChildWithObjectName(headerItem.children, "cloakingCheckBox"); + if (!cloakingCheckBoxItem) { + console.error("cloakingCheckBox not found") + return + } + + if (cloakingCheckBoxItem.checked) { + ImportController.processNativeWireGuardConfig() + } + ImportController.importConfig() } - ImportController.importConfig() } } } diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 327b59b6..d0d2a4de 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -510,9 +510,6 @@ PageType { text: qsTr("Share") leftImageSource: "qrc:/images/controls/share-2.svg" - - parentFlickable: a - clickedFunc: function(){ if (clientNameTextField.textField.text !== "") { ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type) diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 062d0d1b..8a6b7a28 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -1,150 +1,170 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import SortFilterProxyModel 0.2 - -import PageEnum 1.0 -import ContainerProps 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Components" -import "../Config" - - -PageType { - id: root - - BackButtonType { - id: backButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 20 - } - - FlickableType { - anchors.top: backButton.bottom - anchors.bottom: parent.bottom - contentHeight: content.height - - ColumnLayout { - id: content - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - - anchors.rightMargin: 16 - anchors.leftMargin: 16 - - spacing: 0 - - BaseHeaderType { - Layout.fillWidth: true - Layout.topMargin: 24 - - headerText: qsTr("Full access to the server and VPN") - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 24 - - text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") + - qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ") - color: AmneziaStyle.color.mutedGray - } - - DropDownType { - id: serverSelector - - signal severSelectorIndexChanged - property int currentIndex: 0 - - Layout.fillWidth: true - Layout.topMargin: 16 - - drawerHeight: 0.4375 - drawerParent: root - - descriptionText: qsTr("Server") - headerText: qsTr("Server") - - listView: ListViewWithRadioButtonType { - id: serverSelectorListView - - rootWidth: root.width - imageSource: "qrc:/images/controls/check.svg" - - model: SortFilterProxyModel { - id: proxyServersModel - sourceModel: ServersModel - filters: [ - ValueFilter { - roleName: "hasWriteAccess" - value: true - } - ] - } - - clickedFunction: function() { - handler() - - if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) { - serverSelector.currentIndex = serverSelectorListView.currentIndex - } - - shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text - shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text - serverSelector.closeTriggered() - } - - Component.onCompleted: { - serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ? - proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0 - serverSelectorListView.triggerCurrentItem() - } - - function handler() { - serverSelector.text = selectedText - ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex) - } - } - } - - BasicButtonType { - id: shareButton - Layout.fillWidth: true - Layout.topMargin: 40 - - text: qsTr("Share") - leftImageSource: "qrc:/images/controls/share-2.svg" - - clickedFunc: function() { - PageController.showBusyIndicator(true) - - if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) { - PageController.showBusyIndicator(false) - ExportController.exportErrorOccurred(qsTr("Access error!")) - return - } else { - ExportController.generateFullAccessConfig() - } - - PageController.showBusyIndicator(false) - - PageController.goToPage(PageEnum.PageShareConnection) - } - } - } - } - -} - +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import ContainerProps 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Components" +import "../Config" + + +PageType { + id: root + + BackButtonType { + id: backButton + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + + onFocusChanged: { + if (this.activeFocus) { + listView.positionViewAtBeginning() + } + } + } + + ListViewType { + id: listView + + anchors.top: backButton.bottom + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + header: ColumnLayout { + width: listView.width + + BaseHeaderType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 24 + + headerText: qsTr("Full access to the server and VPN") + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 24 + Layout.bottomMargin: 24 + + text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") + + qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ") + color: AmneziaStyle.color.mutedGray + } + + DropDownType { + id: serverSelector + objectName: "serverSelector" + + signal severSelectorIndexChanged + property int currentIndex: 0 + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 16 + + drawerHeight: 0.4375 + drawerParent: root + + descriptionText: qsTr("Server") + headerText: qsTr("Server") + + listView: ListViewWithRadioButtonType { + id: serverSelectorListView + + rootWidth: root.width + imageSource: "qrc:/images/controls/check.svg" + + model: SortFilterProxyModel { + id: proxyServersModel + sourceModel: ServersModel + filters: [ + ValueFilter { + roleName: "hasWriteAccess" + value: true + } + ] + } + + clickedFunction: function() { + handler() + + if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) { + serverSelector.currentIndex = serverSelectorListView.currentIndex + } + + shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text + shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text + serverSelector.closeTriggered() + } + + Component.onCompleted: { + serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ? + proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0 + serverSelectorListView.triggerCurrentItem() + } + + function handler() { + serverSelector.text = selectedText + ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex) + } + } + } + } + + model: 1 // fake model to force the ListView to be created without a model + spacing: 0 + + delegate: ColumnLayout { + width: listView.width + + BasicButtonType { + id: shareButton + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + text: qsTr("Share") + leftImageSource: "qrc:/images/controls/share-2.svg" + + clickedFunc: function() { + PageController.showBusyIndicator(true) + + if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) { + PageController.showBusyIndicator(false) + ExportController.exportErrorOccurred(qsTr("Access error!")) + return + } else { + ExportController.generateFullAccessConfig() + } + + PageController.showBusyIndicator(false) + + PageController.goToPage(PageEnum.PageShareConnection) + } + } + } + } + + ShareConnectionDrawer { + id: shareConnectionDrawer + + anchors.fill: parent + } +}