diff --git a/client/resources.qrc b/client/resources.qrc index 54b5846c..4c15c6bb 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -127,7 +127,7 @@ ui/qml/Components/SelectLanguageDrawer.qml ui/qml/Components/ServersListView.qml ui/qml/Components/SettingsContainersListView.qml - ui/qml/Components/ShareConnectionDrawer.qml + ui/qml/Components/TransportProtoSelector.qml ui/qml/Components/AddSitePanel.qml ui/qml/Config/GlobalConfig.qml @@ -228,6 +228,7 @@ ui/qml/Pages2/PageSetupWizardViewConfig.qml ui/qml/Pages2/PageShare.qml ui/qml/Pages2/PageShareFullAccess.qml + ui/qml/Pages2/PageShareConnection.qml ui/qml/Pages2/PageStart.qml ui/qml/Components/RenameServerDrawer.qml ui/qml/Controls2/ListViewType.qml @@ -240,6 +241,7 @@ ui/qml/Components/ApiPremV1SubListDrawer.qml ui/qml/Components/OtpCodeDrawer.qml ui/qml/Components/AwgTextField.qml + ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml images/flagKit/ZW.svg diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h index fc981091..1aee1ed7 100644 --- a/client/ui/controllers/pageController.h +++ b/client/ui/controllers/pageController.h @@ -38,6 +38,7 @@ namespace PageLoader PageSettingsApiInstructions, PageSettingsApiNativeConfigs, PageSettingsApiDevices, + PageSettingsApiSubscriptionKey, PageSettingsKillSwitchExceptions, PageServiceSftpSettings, @@ -71,6 +72,7 @@ namespace PageLoader PageProtocolAwgClientSettings, PageShareFullAccess, + PageShareConnection, PageDevMenu }; diff --git a/client/ui/qml/Components/ShareConnectionDrawer.qml b/client/ui/qml/Components/ShareConnectionDrawer.qml deleted file mode 100644 index dd59180b..00000000 --- a/client/ui/qml/Components/ShareConnectionDrawer.qml +++ /dev/null @@ -1,375 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Dialogs - -import QtCore - -import SortFilterProxyModel 0.2 - -import PageEnum 1.0 -import ContainerProps 1.0 -import Style 1.0 - -import "./" -import "../Controls2" -import "../Controls2/TextTypes" -import "../Config" -import "../Components" - -DrawerType2 { - id: root - - property string headerText - property string configContentHeaderText - property string shareButtonText: qsTr("Share") - property string copyButtonText: qsTr("Copy") - property bool isSelfHostedConfig: true - - property string configExtension: ".vpn" - property string configCaption: qsTr("Save AmneziaVPN config") - property string configFileName: "amnezia_config" - - expandedHeight: parent.height * 0.9 - - onClosed: { - configExtension = ".vpn" - configCaption = qsTr("Save AmneziaVPN config") - configFileName = "amnezia_config" - } - - expandedStateContent: Item { - implicitHeight: root.expandedHeight - - Header2Type { - id: header - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 20 - anchors.leftMargin: 16 - anchors.rightMargin: 16 - - headerText: root.headerText - } - - ListView { - id: listView - - anchors.top: header.bottom - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - - property bool isFocusable: true - - ScrollBar.vertical: ScrollBarType {} - - model: 1 - - clip: true - reuseItems: true - - header: ColumnLayout { - width: listView.width - - BasicButtonType { - id: shareButton - Layout.fillWidth: true - Layout.topMargin: 16 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - text: root.shareButtonText - leftImageSource: "qrc:/images/controls/share-2.svg" - - clickedFunc: function() { - var fileName = "" - if (GC.isMobile()) { - fileName = configFileName + configExtension - } else { - fileName = SystemController.getFileName(configCaption, - qsTr("Config files (*" + configExtension + ")"), - StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + configFileName, - true, - configExtension) - } - if (fileName !== "") { - PageController.showBusyIndicator(true) - ExportController.exportConfig(fileName) - PageController.showBusyIndicator(false) - } - } - } - - BasicButtonType { - id: copyConfigTextButton - Layout.fillWidth: true - Layout.topMargin: 8 - 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: root.copyButtonText - leftImageSource: "qrc:/images/controls/copy.svg" - - Keys.onReturnPressed: { copyConfigTextButton.clicked() } - Keys.onEnterPressed: { copyConfigTextButton.clicked() } - } - - BasicButtonType { - id: copyNativeConfigStringButton - Layout.fillWidth: true - Layout.topMargin: 8 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: false - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - text: qsTr("Copy config string") - leftImageSource: "qrc:/images/controls/copy.svg" - - KeyNavigation.tab: showSettingsButton - } - - BasicButtonType { - id: showSettingsButton - - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: root.isSelfHostedConfig - - defaultColor: AmneziaStyle.color.transparent - hoveredColor: AmneziaStyle.color.translucentWhite - pressedColor: AmneziaStyle.color.sheerWhite - disabledColor: AmneziaStyle.color.mutedGray - textColor: AmneziaStyle.color.paleGray - borderWidth: 1 - - text: qsTr("Show connection settings") - - clickedFunc: function() { - configContentDrawer.openTriggered() - } - } - - DrawerType2 { - id: configContentDrawer - - parent: root.parent - - anchors.fill: parent - expandedHeight: parent.height * 0.9 - - expandedStateContent: Item { - id: configContentContainer - - implicitHeight: configContentDrawer.expandedHeight - - Connections { - target: copyNativeConfigStringButton - function onClicked() { - nativeConfigString.selectAll() - nativeConfigString.copy() - nativeConfigString.select(0, 0) - PageController.showNotificationMessage(qsTr("Copied")) - } - } - - Connections { - target: copyConfigTextButton - function onClicked() { - configText.selectAll() - configText.copy() - configText.select(0, 0) - PageController.showNotificationMessage(qsTr("Copied")) - header.forceActiveFocus() - } - } - - BackButtonType { - id: backButton - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: 16 - - backButtonFunction: function() { configContentDrawer.closeTriggered() } - } - - FlickableType { - anchors.top: backButton.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin - - ColumnLayout { - id: configContent - - anchors.fill: parent - anchors.rightMargin: 16 - anchors.leftMargin: 16 - - Header2Type { - id: configContentHeader - Layout.fillWidth: true - Layout.topMargin: 16 - - headerText: root.configContentHeaderText - } - - TextField { - id: nativeConfigString - visible: false - text: ExportController.nativeConfigString - - onTextChanged: { - copyNativeConfigStringButton.visible = nativeConfigString.text !== "" - } - } - - TextArea { - id: configText - - Layout.fillWidth: true - Layout.topMargin: 16 - Layout.bottomMargin: 16 - - padding: 0 - leftPadding: 0 - height: 24 - - readOnly: true - activeFocusOnTab: false - - 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: ExportController.config - - wrapMode: Text.Wrap - - background: Rectangle { - color: AmneziaStyle.color.transparent - } - } - } - } - } - } - } - - delegate: ColumnLayout { - width: listView.width - - property bool isQrCodeVisible: root.isSelfHostedConfig ? ExportController.qrCodesCount > 0 : ApiConfigsController.qrCodesCount > 0 - - Rectangle { - id: qrCodeContainer - - Layout.fillWidth: true - Layout.preferredHeight: width - Layout.topMargin: 20 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: isQrCodeVisible - - color: "white" - - Image { - anchors.fill: parent - smooth: false - - source: root.isSelfHostedConfig ? (isQrCodeVisible ? ExportController.qrCodes[0] : "") : - (isQrCodeVisible ? ApiConfigsController.qrCodes[0] : "") - - 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() - } - - Timer { - property int index: 0 - interval: 1000 - running: isQrCodeVisible - repeat: true - onTriggered: { - if (isQrCodeVisible) { - index++ - let qrCodesCount = root.isSelfHostedConfig ? ExportController.qrCodesCount : ApiConfigsController.qrCodesCount - if (index >= qrCodesCount) { - index = 0 - } - - parent.source = root.isSelfHostedConfig ? ExportController.qrCodes[index] : ApiConfigsController.qrCodes[index] - } - } - } - - Behavior on source { - PropertyAnimation { duration: 200 } - } - } - } - - ParagraphTextType { - Layout.fillWidth: true - Layout.topMargin: 24 - Layout.bottomMargin: 32 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - visible: isQrCodeVisible - - horizontalAlignment: Text.AlignHCenter - text: qsTr("To read the QR code in the Amnezia app, select \"Add server\" → \"I have data to connect\" → \"QR code, key or settings file\"") - } - } - } - } -} diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index 75832fa6..48fcfa11 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -111,17 +111,6 @@ PageType { serverNameEditDrawer.openTriggered() } } - - RenameServerDrawer { - id: serverNameEditDrawer - - parent: root - - anchors.fill: parent - expandedHeight: root.height * 0.35 - - serverNameText: root.processedServer.name - } } delegate: ColumnLayout { @@ -207,35 +196,30 @@ PageType { Layout.fillWidth: true Layout.topMargin: warning.visible ? 16 : 32 - visible: false //footer.isVisibleForAmneziaFree + visible: footer.isVisibleForAmneziaFree text: qsTr("Subscription Key") rightImageSource: "qrc:/images/controls/chevron-right.svg" clickedFunction: function() { - shareConnectionDrawer.headerText = qsTr("Amnezia Premium subscription key") - - shareConnectionDrawer.openTriggered() - shareConnectionDrawer.isSelfHostedConfig = false; - shareConnectionDrawer.shareButtonText = qsTr("Save VPN key as a file") - shareConnectionDrawer.copyButtonText = qsTr("Copy VPN key") - - + PageController.goToPage(PageEnum.PageSettingsApiSubscriptionKey) PageController.showBusyIndicator(true) ApiConfigsController.prepareVpnKeyExport() PageController.showBusyIndicator(false) + + // Navigate to PageShareConnection page + //PageController.goToPage(PageEnum.PageShareConnection) } } DividerType { - visible: false //footer.isVisibleForAmneziaFree + visible: footer.isVisibleForAmneziaFree } LabelWithButtonType { Layout.fillWidth: true - Layout.topMargin: warning.visible ? 16 : 32 visible: footer.isVisibleForAmneziaFree @@ -420,9 +404,12 @@ PageType { } } - ShareConnectionDrawer { - id: shareConnectionDrawer + RenameServerDrawer { + id: serverNameEditDrawer anchors.fill: parent + expandedHeight: parent.height * 0.35 + + serverNameText: root.processedServer.name } } diff --git a/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml b/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml new file mode 100644 index 00000000..eace92ed --- /dev/null +++ b/client/ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml @@ -0,0 +1,204 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import Qt.labs.platform 1.1 + +import QtCore + +import PageEnum 1.0 +import Style 1.0 + +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: root + + Component.onCompleted: { + PageController.showBusyIndicator(true) + ApiConfigsController.prepareVpnKeyExport() + PageController.showBusyIndicator(false) + } + + FlickableType { + anchors.fill: parent + contentHeight: layout.implicitHeight + + ColumnLayout { + id: layout + width: root.width + + BackButtonType { + Layout.topMargin: 20 + } + + Label { + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.topMargin: 16 + text: qsTr("Amnezia Premium\nsubscription key") + font.pixelSize: 32 + font.bold: true + color: AmneziaStyle.color.paleGray + wrapMode: Text.Wrap + } + + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: AmneziaStyle.color.paleGray + hoveredColor: AmneziaStyle.color.sheerWhite + pressedColor: AmneziaStyle.color.translucentWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.black + leftImageColor: "black" + borderWidth: 1 + + text: qsTr("Copy key") + leftImageSource: "qrc:/images/controls/copy.svg" + + onClicked: { + ApiConfigsController.copyVpnKeyToClipboard() + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 4 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + defaultColor: "transparent" + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: qsTr("Save key as a file") + leftImageSource: "qrc:/images/controls/share-2.svg" + + onClicked: { + var fileName = GC.isMobile() + ? "amnezia_vpn_key.vpn" + : SystemController.getFileName( + qsTr("Save AmneziaVPN config"), + qsTr("Config files (*.vpn)"), + StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_vpn_key", + true, + ".vpn" + ) + + if (fileName !== "") { + PageController.showBusyIndicator(true) + ExportController.exportConfig(fileName) + PageController.showBusyIndicator(false) + } + } + } + + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + defaultColor: "transparent" + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + + text: qsTr("Show key text") + leftImageSource: "qrc:/images/controls/eye.svg" + + onClicked: { + PageController.showBusyIndicator(true) + ApiConfigsController.prepareVpnKeyExport() + PageController.showBusyIndicator(false) + vpnKeyDrawer.openTriggered() + } + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: width + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + visible: ApiConfigsController.qrCodesCount > 0 + color: "white" + radius: 12 + + Image { + anchors.fill: parent + smooth: false + source: ApiConfigsController.qrCodesCount > 0 && ApiConfigsController.qrCodes[0] ? ApiConfigsController.qrCodes[0] : "" + } + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: ApiConfigsController.qrCodesCount > 0 + horizontalAlignment: Text.AlignHCenter + text: qsTr("To read the QR code in the Amnezia app, tap + in the main menu → 'QR code'") + } + } + } + + DrawerType2 { + id: vpnKeyDrawer + + anchors.fill: root + expandedHeight: root.height * 0.9 + + expandedStateContent: Item { + BackButtonType { + anchors.top: parent.top + anchors.left: parent.left + anchors.topMargin: 16 + backButtonFunction: function() { vpnKeyDrawer.closeTriggered() } + } + + ColumnLayout { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 56 + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + Header2Type { + Layout.fillWidth: true + headerText: qsTr("Amnezia Premium Subscription key") + } + + TextArea { + Layout.fillWidth: true + Layout.topMargin: 16 + readOnly: true + 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: ApiConfigsController.vpnKey //|| "" + wrapMode: Text.Wrap + background: Rectangle { color: AmneziaStyle.color.transparent } + } + } + } + } +} diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 21a5771c..327b59b6 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -15,6 +15,7 @@ import "../Controls2/TextTypes" import "../Components" import "../Config" + PageType { id: root @@ -42,10 +43,6 @@ PageType { target: ExportController function onGenerateConfig(type) { - shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text - - shareConnectionDrawer.openTriggered() PageController.showBusyIndicator(true) switch (type) { @@ -55,54 +52,36 @@ PageType { } case PageShare.ConfigType.OpenVpn: { ExportController.generateOpenVpnConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config") - shareConnectionDrawer.configExtension = ".ovpn" - shareConnectionDrawer.configFileName = "amnezia_for_openvpn" break } case PageShare.ConfigType.WireGuard: { ExportController.generateWireGuardConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save WireGuard config") - shareConnectionDrawer.configExtension = ".conf" - shareConnectionDrawer.configFileName = "amnezia_for_wireguard" break } case PageShare.ConfigType.Awg: { ExportController.generateAwgConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save AmneziaWG config") - shareConnectionDrawer.configExtension = ".conf" - shareConnectionDrawer.configFileName = "amnezia_for_awg" break } case PageShare.ConfigType.ShadowSocks: { ExportController.generateShadowSocksConfig() - shareConnectionDrawer.configCaption = qsTr("Save Shadowsocks config") - shareConnectionDrawer.configExtension = ".json" - shareConnectionDrawer.configFileName = "amnezia_for_shadowsocks" break } case PageShare.ConfigType.Cloak: { ExportController.generateCloakConfig() - shareConnectionDrawer.configCaption = qsTr("Save Cloak config") - shareConnectionDrawer.configExtension = ".json" - shareConnectionDrawer.configFileName = "amnezia_for_cloak" break } case PageShare.ConfigType.Xray: { ExportController.generateXrayConfig(clientNameTextField.textField.text) - shareConnectionDrawer.configCaption = qsTr("Save XRay config") - shareConnectionDrawer.configExtension = ".json" - shareConnectionDrawer.configFileName = "amnezia_for_xray" break } } PageController.showBusyIndicator(false) + + PageController.goToPage(PageEnum.PageShareConnection) } function onExportErrorOccurred(error) { - shareConnectionDrawer.closeTriggered() - PageController.showErrorMessage(error) } } @@ -832,9 +811,6 @@ PageType { root.revokeConfig(index) } var noButtonFunction = function() { - if (!GC.isMobile()) { - // focusItem1.forceActiveFocus() - } } showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) @@ -848,9 +824,4 @@ PageType { } } - ShareConnectionDrawer { - id: shareConnectionDrawer - - anchors.fill: parent - } } diff --git a/client/ui/qml/Pages2/PageShareConnection.qml b/client/ui/qml/Pages2/PageShareConnection.qml new file mode 100644 index 00000000..9bc81ca3 --- /dev/null +++ b/client/ui/qml/Pages2/PageShareConnection.qml @@ -0,0 +1,329 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +import QtCore + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 +import ContainerProps 1.0 +import Style 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + +PageType { + id: pageShareConnection + + property string headerText + + Component.onCompleted: { + var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server" + headerText = qsTr("Connection to ") + serverName + configContentHeaderText = qsTr("File with connection settings to ") + serverName + } + property string configContentHeaderText + property string shareButtonText: qsTr("Share") + property string copyButtonText: qsTr("Copy") + property bool isSelfHostedConfig: true + + property string configExtension: ".vpn" + property string configCaption: qsTr("Save AmneziaVPN config") + property string configFileName: "amnezia_config" + + onVisibleChanged: { + configExtension = ".vpn" + configCaption = qsTr("Save AmneziaVPN config") + configFileName = "amnezia_config" + + if (visible) { + var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server" + headerText = qsTr("Connection to ") + serverName + configContentHeaderText = qsTr("File with connection settings to ") + serverName + } + } + + BackButtonType { + id: backButton + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + } + + Text { + id: shareHeader + anchors.top: backButton.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 20 + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + text: pageShareConnection.headerText + color: AmneziaStyle.color.paleGray + font.pixelSize: 32 + font.weight: 700 + font.family: "PT Root UI VF" + wrapMode: Text.WordWrap + } + + ListView { + id: listView + + anchors.top: shareHeader.bottom + anchors.topMargin: 16 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + property bool isFocusable: true + + ScrollBar.vertical: ScrollBarType {} + model: 1 + clip: true + reuseItems: true + + header: ColumnLayout { + width: listView.width + + BasicButtonType { + id: shareButton + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + text: pageShareConnection.shareButtonText + leftImageSource: "qrc:/images/controls/share-2.svg" + clickedFunc: function() { + var fileName = "" + if (GC.isMobile()) { + fileName = configFileName + configExtension + } else { + fileName = SystemController.getFileName(configCaption, + qsTr("Config files (*" + configExtension + ")"), + StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + configFileName, + true, + configExtension) + } + if (fileName !== "") { + PageController.showBusyIndicator(true) + ExportController.exportConfig(fileName) + PageController.showBusyIndicator(false) + } + } + } + + BasicButtonType { + id: copyConfigTextButton + Layout.fillWidth: true + Layout.topMargin: 8 + 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: pageShareConnection.copyButtonText + leftImageSource: "qrc:/images/controls/copy.svg" + + Keys.onReturnPressed: copyConfigTextButton.clicked() + Keys.onEnterPressed: copyConfigTextButton.clicked() + } + + BasicButtonType { + id: copyNativeConfigStringButton + Layout.fillWidth: true + Layout.topMargin: 8 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: false + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + text: qsTr("Copy config string") + leftImageSource: "qrc:/images/controls/copy.svg" + KeyNavigation.tab: showSettingsButton + } + + BasicButtonType { + id: showSettingsButton + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: pageShareConnection.isSelfHostedConfig + defaultColor: AmneziaStyle.color.transparent + hoveredColor: AmneziaStyle.color.translucentWhite + pressedColor: AmneziaStyle.color.sheerWhite + disabledColor: AmneziaStyle.color.mutedGray + textColor: AmneziaStyle.color.paleGray + borderWidth: 1 + text: qsTr("Show connection settings") + clickedFunc: function() { + configContentDrawer.openTriggered() + } + } + + DrawerType2 { + id: configContentDrawer + parent: pageShareConnection.parent + anchors.fill: parent + expandedHeight: parent.height * 0.9 + expandedStateContent: Item { + id: configContentContainer + implicitHeight: configContentDrawer.expandedHeight + + Connections { + target: copyNativeConfigStringButton + function onClicked() { + nativeConfigString.selectAll() + nativeConfigString.copy() + nativeConfigString.select(0, 0) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + + Connections { + target: copyConfigTextButton + function onClicked() { + configText.selectAll() + configText.copy() + configText.select(0, 0) + PageController.showNotificationMessage(qsTr("Copied")) + header.forceActiveFocus() + } + } + + BackButtonType { + id: configBackButton + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 16 + backButtonFunction: function() { configContentDrawer.closeTriggered() } + } + + FlickableType { + anchors.top: configBackButton.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin + + ColumnLayout { + id: configContent + anchors.fill: parent + anchors.rightMargin: 16 + anchors.leftMargin: 16 + + Header2Type { + id: configContentHeader + Layout.fillWidth: true + Layout.topMargin: 16 + headerText: pageShareConnection.configContentHeaderText + } + + TextField { + id: nativeConfigString + visible: false + text: ExportController.nativeConfigString + onTextChanged: copyNativeConfigStringButton.visible = nativeConfigString.text !== "" + } + + TextArea { + id: configText + Layout.fillWidth: true + Layout.topMargin: 16 + Layout.bottomMargin: 16 + padding: 0 + leftPadding: 0 + height: 24 + readOnly: true + activeFocusOnTab: false + 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: ExportController.config + wrapMode: Text.Wrap + background: Rectangle { color: AmneziaStyle.color.transparent } + } + } + } + } + } + } + + delegate: ColumnLayout { + width: listView.width + property bool isQrCodeVisible: pageShareConnection.isSelfHostedConfig ? ExportController.qrCodesCount > 0 : ApiConfigsController.qrCodesCount > 0 + + Rectangle { + id: qrCodeContainer + Layout.fillWidth: true + Layout.preferredHeight: width + Layout.topMargin: 20 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: isQrCodeVisible + color: "white" + + Image { + anchors.fill: parent + smooth: false + source: pageShareConnection.isSelfHostedConfig ? (isQrCodeVisible ? ExportController.qrCodes[0] : "") : (isQrCodeVisible ? ApiConfigsController.qrCodes[0] : "") + 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() + + Timer { + property int index: 0 + interval: 1000 + running: isQrCodeVisible + repeat: true + onTriggered: { + if (isQrCodeVisible) { + index++ + let qrCodesCount = pageShareConnection.isSelfHostedConfig ? ExportController.qrCodesCount : ApiConfigsController.qrCodesCount + if (index >= qrCodesCount) index = 0 + parent.source = pageShareConnection.isSelfHostedConfig ? ExportController.qrCodes[index] : ApiConfigsController.qrCodes[index] + } + } + } + + Behavior on source { PropertyAnimation { duration: 200 } } + } + } + + ParagraphTextType { + Layout.fillWidth: true + Layout.topMargin: 24 + Layout.bottomMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + visible: isQrCodeVisible + horizontalAlignment: Text.AlignHCenter + text: qsTr("To read the QR code in the Amnezia app, select \"Add server\" → \"I have data to connect\" → \"QR code, key or settings file\"") + } + } + } +} diff --git a/client/ui/qml/Pages2/PageShareFullAccess.qml b/client/ui/qml/Pages2/PageShareFullAccess.qml index 82effb57..062d0d1b 100644 --- a/client/ui/qml/Pages2/PageShareFullAccess.qml +++ b/client/ui/qml/Pages2/PageShareFullAccess.qml @@ -15,6 +15,7 @@ import "../Controls2/TextTypes" import "../Components" import "../Config" + PageType { id: root @@ -100,8 +101,8 @@ PageType { serverSelector.currentIndex = serverSelectorListView.currentIndex } - shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text + shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text + shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text serverSelector.closeTriggered() } @@ -137,20 +138,13 @@ PageType { ExportController.generateFullAccessConfig() } - shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text - shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text - - shareConnectionDrawer.openTriggered() - PageController.showBusyIndicator(false) + + PageController.goToPage(PageEnum.PageShareConnection) } } } } - ShareConnectionDrawer { - id: shareConnectionDrawer - - anchors.fill: parent - } } +