diff --git a/client/resources.qrc b/client/resources.qrc index 30c191cf..f25efc8e 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -135,5 +135,6 @@ ui/qml/Controls/TextAreaType.qml ui/qml/Controls/ContextMenu.qml ui/qml/Pages/Share/PageShareProtoAmnezia.qml + ui/qml/Controls/ShareConnectionButtonCopyType.qml diff --git a/client/ui/pages_logic/PageLogicBase.h b/client/ui/pages_logic/PageLogicBase.h index 2e7e8d52..26858ee0 100644 --- a/client/ui/pages_logic/PageLogicBase.h +++ b/client/ui/pages_logic/PageLogicBase.h @@ -14,8 +14,6 @@ class PageLogicBase : public QObject { Q_OBJECT AUTO_PROPERTY(bool, pageEnabled) -// AUTO_PROPERTY(int, serverIndex) -// AUTO_PROPERTY(DockerContainer, dockerContainer) public: explicit PageLogicBase(UiLogic *uiLogic, QObject *parent = nullptr); diff --git a/client/ui/pages_logic/ServerSettingsLogic.cpp b/client/ui/pages_logic/ServerSettingsLogic.cpp index 30a8871d..86283351 100644 --- a/client/ui/pages_logic/ServerSettingsLogic.cpp +++ b/client/ui/pages_logic/ServerSettingsLogic.cpp @@ -127,5 +127,5 @@ void ServerSettingsLogic::onLineEditDescriptionEditingFinished() void ServerSettingsLogic::onPushButtonShareFullClicked() { uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), DockerContainer::None); - emit uiLogic()->goToPage(Page::ShareConnection); + emit uiLogic()->goToShareProtocolPage(Protocol::Any); } diff --git a/client/ui/pages_logic/ShareConnectionLogic.cpp b/client/ui/pages_logic/ShareConnectionLogic.cpp index 3d339451..228590a0 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.cpp +++ b/client/ui/pages_logic/ShareConnectionLogic.cpp @@ -23,161 +23,76 @@ ShareConnectionLogic::ShareConnectionLogic(UiLogic *logic, QObject *parent): PageLogicBase(logic, parent), m_textEditShareOpenVpnCodeText{}, - m_pushButtonShareOpenVpnCopyEnabled{false}, - m_pushButtonShareOpenVpnSaveEnabled{false}, m_lineEditShareShadowSocksStringText{}, - m_labelShareShadowSocksQrCodeText{}, + m_shareShadowSocksQrCodeText{}, m_labelShareShadowSocksServerText{}, m_labelShareShadowSocksPortText{}, m_labelShareShadowSocksMethodText{}, m_labelShareShadowSocksPasswordText{}, - m_plainTextEditShareCloakText{}, - m_textEditShareFullCodeText{}, + m_textEditShareCloakText{}, m_textEditShareAmneziaCodeText{}, - m_pushButtonShareFullCopyText{tr("Copy")}, - m_pushButtonShareAmneziaCopyText{tr("Copy")}, - m_pushButtonShareOpenVpnCopyText{tr("Copy")}, - m_pushButtonShareShadowSocksCopyText{tr("Copy")}, - m_pushButtonShareCloakCopyText{tr("Copy")}, - m_pushButtonShareAmneziaGenerateEnabled{true}, - m_pushButtonShareAmneziaCopyEnabled{true}, - m_pushButtonShareAmneziaGenerateText{tr("Generate config")}, - m_pushButtonShareOpenVpnGenerateEnabled{true}, m_pushButtonShareOpenVpnGenerateText{tr("Generate config")} { // TODO consider move to Component.onCompleted //updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer); } - -void ShareConnectionLogic::onPushButtonShareFullCopyClicked() +void ShareConnectionLogic::onUpdatePage() { - QGuiApplication::clipboard()->setText(textEditShareFullCodeText()); - set_pushButtonShareFullCopyText(tr("Copied")); - - QTimer::singleShot(3000, this, [this]() { - set_pushButtonShareFullCopyText(tr("Copy")); - }); -} - -void ShareConnectionLogic::onPushButtonShareFullSaveClicked() -{ - if (textEditShareFullCodeText().isEmpty()) return; - - QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save AmneziaVPN config"), - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.amnezia"); - QSaveFile save(fileName); - save.open(QIODevice::WriteOnly); - save.write(textEditShareFullCodeText().toUtf8()); - save.commit(); -} - -void ShareConnectionLogic::onPushButtonShareAmneziaCopyClicked() -{ - if (textEditShareAmneziaCodeText().isEmpty()) return; - - QGuiApplication::clipboard()->setText(textEditShareAmneziaCodeText()); - set_pushButtonShareAmneziaCopyText(tr("Copied")); - - QTimer::singleShot(3000, this, [this]() { - set_pushButtonShareAmneziaCopyText(tr("Copy")); - }); -} - -void ShareConnectionLogic::onPushButtonShareAmneziaSaveClicked() -{ - if (textEditShareAmneziaCodeText().isEmpty()) return; - - QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save AmneziaVPN config"), - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.amnezia"); - QSaveFile save(fileName); - save.open(QIODevice::WriteOnly); - save.write(textEditShareAmneziaCodeText().toUtf8()); - save.commit(); -} - -void ShareConnectionLogic::onPushButtonShareOpenVpnCopyClicked() -{ - QGuiApplication::clipboard()->setText(textEditShareOpenVpnCodeText()); - set_pushButtonShareOpenVpnCopyText(tr("Copied")); - - QTimer::singleShot(3000, this, [this]() { - set_pushButtonShareOpenVpnCopyText(tr("Copy")); - }); -} - -void ShareConnectionLogic::onPushButtonShareShadowSocksCopyClicked() -{ - QGuiApplication::clipboard()->setText(lineEditShareShadowSocksStringText()); - set_pushButtonShareShadowSocksCopyText(tr("Copied")); - - QTimer::singleShot(3000, this, [this]() { - set_pushButtonShareShadowSocksCopyText(tr("Copy")); - }); -} - -void ShareConnectionLogic::onPushButtonShareCloakCopyClicked() -{ - QGuiApplication::clipboard()->setText(plainTextEditShareCloakText()); - set_pushButtonShareCloakCopyText(tr("Copied")); - - QTimer::singleShot(3000, this, [this]() { - set_pushButtonShareCloakCopyText(tr("Copy")); - }); } void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked() { - set_pushButtonShareAmneziaGenerateEnabled(false); - set_pushButtonShareAmneziaCopyEnabled(false); - set_pushButtonShareAmneziaGenerateText(tr("Generating...")); - qApp->processEvents(); - - ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex); - QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); - containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer)); - - ErrorCode e = ErrorCode::NoError; - for (Protocol p: ContainerProps::protocolsForContainer(uiLogic()->selectedDockerContainer)) { - QJsonObject protoConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p); - - QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, p, &e); - if (e) { - cfg = "Error generating config"; - break; - } - protoConfig.insert(config_key::last_config, cfg); - - containerConfig.insert(ProtocolProps::protoToString(p), protoConfig); - } - - QByteArray ba; - if (!e) { - QJsonObject serverConfig = m_settings.server(uiLogic()->selectedServerIndex); - serverConfig.remove(config_key::userName); - serverConfig.remove(config_key::password); - serverConfig.remove(config_key::port); - serverConfig.insert(config_key::containers, QJsonArray {containerConfig}); - serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(uiLogic()->selectedDockerContainer)); - - - ba = QJsonDocument(serverConfig).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - set_textEditShareAmneziaCodeText(QString("vpn://%1").arg(QString(ba))); + set_textEditShareAmneziaCodeText(""); + QJsonObject serverConfig; + // Full access + if (shareFullAccess()) { + serverConfig = m_settings.server(uiLogic()->selectedServerIndex); } + // Container share else { - set_textEditShareAmneziaCodeText(tr("Error while generating connection profile")); + ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex); + QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); + containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer)); + + ErrorCode e = ErrorCode::NoError; + for (Protocol p: ContainerProps::protocolsForContainer(uiLogic()->selectedDockerContainer)) { + QJsonObject protoConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p); + + QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, p, &e); + if (e) { + cfg = "Error generating config"; + break; + } + protoConfig.insert(config_key::last_config, cfg); + containerConfig.insert(ProtocolProps::protoToString(p), protoConfig); + } + + QByteArray ba; + if (!e) { + serverConfig = m_settings.server(uiLogic()->selectedServerIndex); + serverConfig.remove(config_key::userName); + serverConfig.remove(config_key::password); + serverConfig.remove(config_key::port); + serverConfig.insert(config_key::containers, QJsonArray {containerConfig}); + serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(uiLogic()->selectedDockerContainer)); + } + else { + set_textEditShareAmneziaCodeText(tr("Error while generating connection profile")); + return; + } } - set_pushButtonShareAmneziaGenerateEnabled(true); - set_pushButtonShareAmneziaCopyEnabled(true); - set_pushButtonShareAmneziaGenerateText(tr("Generate config")); + QByteArray ba = QJsonDocument(serverConfig).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + QString code = QString("vpn://%1").arg(QString(ba)); + set_textEditShareAmneziaCodeText(code); + + QImage qr = updateQRCodeImage(code); + set_shareAmneziaQrCodeText(imageToBase64(qr)); } void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked() { - set_pushButtonShareOpenVpnGenerateEnabled(false); - set_pushButtonShareOpenVpnCopyEnabled(false); - set_pushButtonShareOpenVpnSaveEnabled(false); set_pushButtonShareOpenVpnGenerateText(tr("Generating...")); ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex); @@ -189,49 +104,19 @@ void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked() set_textEditShareOpenVpnCodeText(QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString()); - set_pushButtonShareOpenVpnGenerateEnabled(true); - set_pushButtonShareOpenVpnCopyEnabled(true); - set_pushButtonShareOpenVpnSaveEnabled(true); set_pushButtonShareOpenVpnGenerateText(tr("Generate config")); } -void ShareConnectionLogic::onPushButtonShareOpenVpnSaveClicked() -{ - QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save OpenVPN config"), - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.ovpn"); - - QSaveFile save(fileName); - save.open(QIODevice::WriteOnly); - save.write(textEditShareOpenVpnCodeText().toUtf8()); - save.commit(); -} - - void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCredentials &credentials, DockerContainer container) { uiLogic()->selectedDockerContainer = container; uiLogic()->selectedServerIndex = serverIndex; + set_shareFullAccess(container == DockerContainer::None); - - // Full access - if (container == DockerContainer::None) { - - const QJsonObject &server = m_settings.server(uiLogic()->selectedServerIndex); - - QByteArray ba = QJsonDocument(server).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - - set_textEditShareFullCodeText(QString("vpn://%1").arg(QString(ba))); - } - else { + if (! shareFullAccess()) { for (Protocol p : ContainerProps::protocolsForContainer(container)) { - if (p == Protocol::OpenVpn) { - QString cfg = tr("Press Generate config"); - set_textEditShareOpenVpnCodeText(cfg); - set_pushButtonShareOpenVpnCopyEnabled(false); - set_pushButtonShareOpenVpnSaveEnabled(false); - } - else if (p == Protocol::ShadowSocks) { + if (p == Protocol::ShadowSocks) { QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::ShadowSocks); QString cfg = protoConfig.value(config_key::last_config).toString(); @@ -254,7 +139,7 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCreden set_lineEditShareShadowSocksStringText(ssString); QImage qr = updateQRCodeImage(ssString); - set_labelShareShadowSocksQrCodeText(imageToBase64(qr)); + set_shareShadowSocksQrCodeText(imageToBase64(qr)); set_labelShareShadowSocksServerText(ssConfig.value("server").toString()); set_labelShareShadowSocksPortText(ssConfig.value("server_port").toString()); @@ -263,7 +148,7 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCreden } else if (p == Protocol::Cloak) { - set_plainTextEditShareCloakText(QString("")); + set_textEditShareCloakText(QString("")); QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::Cloak); QString cfg = protoConfig.value(config_key::last_config).toString(); @@ -281,29 +166,15 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCreden cloakConfig.remove(config_key::transport_proto); cloakConfig.insert("ProxyMethod", "shadowsocks"); - set_plainTextEditShareCloakText(QJsonDocument(cloakConfig).toJson()); + set_textEditShareCloakText(QJsonDocument(cloakConfig).toJson()); } } } - //ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); - - // Amnezia sharing - // QJsonObject exportContainer; - // for (Protocol p: protocolsForContainer(container)) { - // QJsonObject protocolConfig = containerConfig.value(ProtocolProps::protoToString(p)).toObject(); - // protocolConfig.remove(config_key::last_config); - // exportContainer.insert(ProtocolProps::protoToString(p), protocolConfig); - // } - // exportContainer.insert(config_key::container, containerToString(container)); - - // ui->textEdit_share_amnezia_code->setPlainText(QJsonDocument(exportContainer).toJson()); - set_textEditShareAmneziaCodeText(tr("")); } - QImage ShareConnectionLogic::updateQRCodeImage(const QString &text) { int levelIndex = 1; diff --git a/client/ui/pages_logic/ShareConnectionLogic.h b/client/ui/pages_logic/ShareConnectionLogic.h index 2f1acafa..2008dacb 100644 --- a/client/ui/pages_logic/ShareConnectionLogic.h +++ b/client/ui/pages_logic/ShareConnectionLogic.h @@ -11,40 +11,28 @@ class ShareConnectionLogic: public PageLogicBase Q_OBJECT public: + AUTO_PROPERTY(bool, shareFullAccess) + + AUTO_PROPERTY(QString, textEditShareAmneziaCodeText) + AUTO_PROPERTY(QString, shareAmneziaQrCodeText) + AUTO_PROPERTY(QString, textEditShareOpenVpnCodeText) - AUTO_PROPERTY(bool, pushButtonShareOpenVpnCopyEnabled) - AUTO_PROPERTY(bool, pushButtonShareOpenVpnSaveEnabled) + AUTO_PROPERTY(QString, pushButtonShareOpenVpnGenerateText) + AUTO_PROPERTY(QString, lineEditShareShadowSocksStringText) - AUTO_PROPERTY(QString, labelShareShadowSocksQrCodeText) + AUTO_PROPERTY(QString, shareShadowSocksQrCodeText) AUTO_PROPERTY(QString, labelShareShadowSocksServerText) AUTO_PROPERTY(QString, labelShareShadowSocksPortText) AUTO_PROPERTY(QString, labelShareShadowSocksMethodText) AUTO_PROPERTY(QString, labelShareShadowSocksPasswordText) - AUTO_PROPERTY(QString, plainTextEditShareCloakText) - AUTO_PROPERTY(QString, textEditShareFullCodeText) - AUTO_PROPERTY(QString, textEditShareAmneziaCodeText) - AUTO_PROPERTY(QString, pushButtonShareFullCopyText) - AUTO_PROPERTY(QString, pushButtonShareAmneziaCopyText) - AUTO_PROPERTY(QString, pushButtonShareOpenVpnCopyText) - AUTO_PROPERTY(QString, pushButtonShareShadowSocksCopyText) - AUTO_PROPERTY(QString, pushButtonShareCloakCopyText) - AUTO_PROPERTY(bool, pushButtonShareAmneziaGenerateEnabled) - AUTO_PROPERTY(bool, pushButtonShareAmneziaCopyEnabled) - AUTO_PROPERTY(QString, pushButtonShareAmneziaGenerateText) - AUTO_PROPERTY(bool, pushButtonShareOpenVpnGenerateEnabled) - AUTO_PROPERTY(QString, pushButtonShareOpenVpnGenerateText) + + AUTO_PROPERTY(QString, textEditShareCloakText) public: - Q_INVOKABLE void onPushButtonShareFullCopyClicked(); - Q_INVOKABLE void onPushButtonShareFullSaveClicked(); - Q_INVOKABLE void onPushButtonShareAmneziaCopyClicked(); - Q_INVOKABLE void onPushButtonShareAmneziaSaveClicked(); - Q_INVOKABLE void onPushButtonShareOpenVpnCopyClicked(); - Q_INVOKABLE void onPushButtonShareShadowSocksCopyClicked(); - Q_INVOKABLE void onPushButtonShareCloakCopyClicked(); Q_INVOKABLE void onPushButtonShareAmneziaGenerateClicked(); Q_INVOKABLE void onPushButtonShareOpenVpnGenerateClicked(); - Q_INVOKABLE void onPushButtonShareOpenVpnSaveClicked(); + + Q_INVOKABLE virtual void onUpdatePage() override; public: explicit ShareConnectionLogic(UiLogic *uiLogic, QObject *parent = nullptr); diff --git a/client/ui/qml/Controls/ShareConnectionButtonCopyType.qml b/client/ui/qml/Controls/ShareConnectionButtonCopyType.qml new file mode 100644 index 00000000..49df118d --- /dev/null +++ b/client/ui/qml/Controls/ShareConnectionButtonCopyType.qml @@ -0,0 +1,20 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +ShareConnectionButtonType { + readonly property string start_text: qsTr("Copy") + readonly property string end_text: qsTr("Copied") + + Timer { + id: timer + interval: 1000; running: false; repeat: false + onTriggered: text = start_text + } + + text: start_text + + onClicked: { + text = end_text + timer.running = true + } +} diff --git a/client/ui/qml/Controls/ShareConnectionButtonType.qml b/client/ui/qml/Controls/ShareConnectionButtonType.qml index 9a13a07e..5609a29d 100644 --- a/client/ui/qml/Controls/ShareConnectionButtonType.qml +++ b/client/ui/qml/Controls/ShareConnectionButtonType.qml @@ -8,7 +8,9 @@ BasicButtonType { background: Rectangle { anchors.fill: parent radius: 4 - color: root.containsMouse ? "#282932" : "#181922" + color: root.enabled + ? (root.containsMouse ? "#282932" : "#181922") + : "#484952" } font.pixelSize: 16 contentItem: Text { diff --git a/client/ui/qml/Controls/TextAreaType.qml b/client/ui/qml/Controls/TextAreaType.qml index 3bd9ac1d..b3e5772b 100644 --- a/client/ui/qml/Controls/TextAreaType.qml +++ b/client/ui/qml/Controls/TextAreaType.qml @@ -14,12 +14,10 @@ Flickable id: root property bool error: false - width: parent.width - 80 height: 40 anchors.topMargin: 5 selectByMouse: false - selectionColor: "darkgray" font.pixelSize: 16 color: "#333333" diff --git a/client/ui/qml/Pages/PageShareConnection.qml b/client/ui/qml/Pages/PageShareConnection.qml index 791f8226..1e4f7cba 100644 --- a/client/ui/qml/Pages/PageShareConnection.qml +++ b/client/ui/qml/Pages/PageShareConnection.qml @@ -44,13 +44,6 @@ PageBase { topPadding: 20 spacing: 10 -// Caption { -// id: cap1 -// text: qsTr("Installed Protocols and Services") -// font.pixelSize: 20 - -// } - SortFilterProxyModel { id: proxyProtocolsModel sourceModel: UiLogic.protocolsModel @@ -92,323 +85,8 @@ PageBase { onClicked: UiLogic.onGotoShareProtocolPage(proxyProtocolsModel.mapToSource(index)) } - -// Rectangle { -// id: c_item -// x: 0 -// y: 0 -// width: parent.width -// height: 40 -// color: "transparent" -// clip: true -// radius: 2 -// LinearGradient { -// anchors.fill: parent -// start: Qt.point(0, 0) -// end: Qt.point(0, height) -// gradient: Gradient { -// GradientStop { position: 0.0; color: "#E1E1E1" } -// GradientStop { position: 0.4; color: "#DDDDDD" } -// GradientStop { position: 0.5; color: "#D8D8D8" } -// GradientStop { position: 1.0; color: "#D3D3D3" } -// } -// } -// Image { -// anchors.verticalCenter: parent.verticalCenter -// anchors.left: parent.left -// anchors.leftMargin: 10 -// source: "qrc:/images/share.png" -// } -// Rectangle { -// anchors.left: parent.left -// anchors.right: parent.right -// anchors.bottom: parent.bottom -// height: 2 -// color: "#148CD2" -// visible: ms.containsMouse ? true : false -// } -// Text { -// x: 40 -// anchors.verticalCenter: parent.verticalCenter -// font.family: "Lato" -// font.styleName: "normal" -// font.pixelSize: 18 -// color: "#100A44" -// font.bold: true -// text: name_role -// horizontalAlignment: Text.AlignLeft -// verticalAlignment: Text.AlignVCenter -// wrapMode: Text.Wrap -// } -// MouseArea { -// id: ms -// anchors.fill: parent -// hoverEnabled: true -// onClicked: UiLogic.onGotoShareProtocolPage(proxyProtocolsModel.mapToSource(index)) -// } -// } - - - - - - - - - - - - -// Item { -// id: c_item -// width: parent.width -// height: row_container.height -// anchors.left: parent.left -// Rectangle { -// anchors.top: parent.top -// width: parent.width -// height: 1 -// color: "lightgray" -// visible: index !== tb_c.currentIndex -// } -// Rectangle { -// anchors.top: row_container.top -// anchors.bottom: row_container.bottom -// anchors.left: parent.left -// anchors.right: parent.right - -// color: "#63B4FB" -// visible: index === tb_c.currentIndex -// } - -// RowLayout { -// id: row_container -// //width: parent.width -// anchors.left: parent.left -// anchors.right: parent.right - -//// anchors.top: lb_container_name.top -//// anchors.bottom: lb_container_name.bottom - -// Text { -// id: lb_container_name -// text: name_role -// font.pixelSize: 17 -// //font.bold: true -// color: "#100A44" -// topPadding: 5 -// bottomPadding: 5 -// leftPadding: 10 -// verticalAlignment: Text.AlignVCenter -// wrapMode: Text.WordWrap -// Layout.fillWidth: true - -// MouseArea { -// enabled: col.visible -// anchors.top: lb_container_name.top -// anchors.bottom: lb_container_name.bottom -// anchors.left: parent.left -// anchors.right: parent.right -// propagateComposedEvents: true -// onClicked: { -// if (tb_c.currentIndex === index) tb_c.currentIndex = -1 -// else tb_c.currentIndex = index - -// UiLogic.protocolsModel.setSelectedDockerContainer(proxyContainersModel.mapToSource(index)) -// } -// } -// } -// } - -// } } } } } - - - - - - - - - - - - - - - - -// ScrollView { -// x: 10 -// y: 40 -// width: 360 -// height: 580 -// Item { -// id: ct -// width: parent.width -// height: childrenRect.height + 10 -// property var contentList: [ -// full_access, -// share_amezia, -// share_openvpn, -// share_shadowshock, -// share_cloak -// ] -// property int currentIndex: ShareConnectionLogic.toolBoxShareConnectionCurrentIndex -// onCurrentIndexChanged: { -// ShareConnectionLogic.toolBoxShareConnectionCurrentIndex = currentIndex -// for (let i = 0; i < contentList.length; ++i) { -// if (i == currentIndex) { -// contentList[i].active = true -// } else { -// contentList[i].active = false -// } -// } -// } - -// function clearActive() { -// for (let i = 0; i < contentList.length; ++i) { -// contentList[i].active = false -// } -// currentIndex = -1; -// } -// Column { -// spacing: 5 -// ShareConnectionContent { -// id: full_access -// x: 0 -// text: qsTr("Full access") -// visible: ShareConnectionLogic.pageShareFullAccessVisible -// content: Component { -// Item { -// width: 360 -// height: 380 -// Text { -// x: 10 -// y: 250 -// width: 341 -// height: 111 -// font.family: "Lato" -// font.styleName: "normal" -// font.pixelSize: 16 -// color: "#181922" -// horizontalAlignment: Text.AlignLeft -// verticalAlignment: Text.AlignVCenter -// wrapMode: Text.Wrap -// text: qsTr("Anyone who logs in with this code will have the same permissions to use VPN and your server as you. \nThis code includes your server credentials!\nProvide this code only to TRUSTED users.") -// } -// ShareConnectionButtonType { -// x: 10 -// y: 130 -// width: 341 -// height: 40 -// text: ShareConnectionLogic.pushButtonShareFullCopyText -// onClicked: { -// ShareConnectionLogic.onPushButtonShareFullCopyClicked() -// } -// } -// ShareConnectionButtonType { -// x: 10 -// y: 180 -// width: 341 -// height: 40 -// text: qsTr("Save file") -// onClicked: { -// ShareConnectionLogic.onPushButtonShareFullSaveClicked() -// } -// } -// TextFieldType { -// x: 10 -// y: 10 -// width: 341 -// height: 100 -// verticalAlignment: Text.AlignTop -// text: ShareConnectionLogic.textEditShareFullCodeText -// onEditingFinished: { -// ShareConnectionLogic.textEditShareFullCodeText = text -// } -// } -// } -// } -// onClicked: { -// if (active) { -// ct.currentIndex = -1 -// } else { -// ct.clearActive() -// ct.currentIndex = 0 -// } -// } -// } -// ShareConnectionContent { -// id: share_amezia -// x: 0 -// text: qsTr("Share for Amnezia client") -// visible: ShareConnectionLogic.pageShareAmneziaVisible -// content: Component { -// Item { -// width: 360 -// height: 380 -// } -// } -// onClicked: { -// if (active) { -// ct.currentIndex = -1 -// } else { -// ct.clearActive() -// ct.currentIndex = 1 -// } -// } -// } - -// ShareConnectionContent { -// id: share_shadowshock -// x: 0 -// text: qsTr("Share for ShadowSocks client") -// visible: ShareConnectionLogic.pageShareShadowSocksVisible -// content: Component { -// Item { -// width: 360 -// height: 380 - -// } -// } -// onClicked: { -// if (active) { -// ct.currentIndex = -1 -// } else { -// ct.clearActive() -// ct.currentIndex = 3 -// } -// } -// } -// ShareConnectionContent { -// id: share_cloak -// x: 0 -// text: qsTr("Share for Cloak client") -// visible: ShareConnectionLogic.pageShareCloakVisible -// content: Component { -// Item { -// width: 360 -// height: 380 - -// } -// } -// onClicked: { -// if (active) { -// ct.currentIndex = -1 -// } else { -// ct.clearActive() -// ct.currentIndex = 4 -// } -// } -// } -// } -// } -// } - - - } diff --git a/client/ui/qml/Pages/Share/PageShareProtoAmnezia.qml b/client/ui/qml/Pages/Share/PageShareProtoAmnezia.qml index ba84b541..30a4c9e4 100644 --- a/client/ui/qml/Pages/Share/PageShareProtoAmnezia.qml +++ b/client/ui/qml/Pages/Share/PageShareProtoAmnezia.qml @@ -11,6 +11,11 @@ PageShareProtocolBase { protocol: ProtocolEnum.Any logic: ShareConnectionLogic + readonly property string generateConfigText: qsTr("Generate config") + readonly property string generatingConfigText: qsTr("Generating config...") + readonly property string showConfigText: qsTr("Show config") + property bool genConfigProcess: false + BackButton { id: back } @@ -19,72 +24,113 @@ PageShareProtocolBase { text: qsTr("Share for Amnezia") } - Text { - id: lb_desc + Flickable { + id: fl + width: root.width anchors.top: caption.bottom anchors.topMargin: 20 - width: parent.width - 60 - anchors.horizontalCenter: root.horizontalCenter - - font.family: "Lato" - font.styleName: "normal" - font.pixelSize: 16 - color: "#181922" - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - wrapMode: Text.Wrap - text: qsTr("Anyone who logs in with this code will be able to connect to this VPN server. \nThis code does not include server credentials.") - } - - TextAreaType { - anchors.top: lb_desc.bottom - anchors.topMargin: 20 - anchors.bottom: pb_gen.top - anchors.bottomMargin: 20 - - anchors.horizontalCenter: root.horizontalCenter - width: parent.width - 60 - - textArea.readOnly: true - textArea.wrapMode: TextEdit.WrapAnywhere - textArea.verticalAlignment: Text.AlignTop - textArea.text: ShareConnectionLogic.textEditShareAmneziaCodeText - } - - - ShareConnectionButtonType { - id: pb_gen - anchors.bottom: pb_copy.top - anchors.bottomMargin: 10 - anchors.horizontalCenter: root.horizontalCenter - width: parent.width - 60 - text: ShareConnectionLogic.pushButtonShareAmneziaGenerateText - enabled: ShareConnectionLogic.pushButtonShareAmneziaGenerateEnabled - onClicked: { - ShareConnectionLogic.onPushButtonShareAmneziaGenerateClicked() - } - } - ShareConnectionButtonType { - id: pb_copy - anchors.bottom: pb_save.top - anchors.bottomMargin: 10 - anchors.horizontalCenter: root.horizontalCenter - width: parent.width - 60 - text: ShareConnectionLogic.pushButtonShareAmneziaCopyText - onClicked: { - ShareConnectionLogic.onPushButtonShareAmneziaCopyClicked() - } - enabled: ShareConnectionLogic.pushButtonShareAmneziaCopyEnabled - } - ShareConnectionButtonType { - id: pb_save anchors.bottom: root.bottom - anchors.bottomMargin: 10 - anchors.horizontalCenter: root.horizontalCenter - width: parent.width - 60 - text: qsTr("Save file") - onClicked: { - ShareConnectionLogic.onPushButtonShareAmneziaSaveClicked() + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + 20 + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + Text { + id: lb_desc + Layout.fillWidth: true + font.family: "Lato" + font.styleName: "normal" + font.pixelSize: 16 + color: "#181922" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + text: ShareConnectionLogic.shareFullAccess + ? qsTr("Anyone who logs in with this code will have the same permissions to use VPN and YOUR SERVER as you. \n +This code includes your server credentials!\n +Provide this code only to TRUSTED users.") + : qsTr("Anyone who logs in with this code will be able to connect to this VPN server. \n +This code does not include server credentials.") + + } + + ShareConnectionButtonType { + id: pb_gen + Layout.topMargin: 20 + Layout.fillWidth: true + Layout.preferredHeight: 40 + + text: ShareConnectionLogic.shareFullAccess + ? showConfigText + : (genConfigProcess ? generatingConfigText : generateConfigText) + onClicked: { + enabled = false + genConfigProcess = true + ShareConnectionLogic.onPushButtonShareAmneziaGenerateClicked() + enabled = true + genConfigProcess = false + } + } + + TextAreaType { + id: tfShareCode + + Layout.topMargin: 20 + Layout.bottomMargin: 20 + Layout.preferredHeight: 200 + + Layout.fillWidth: true + + textArea.readOnly: true + textArea.wrapMode: TextEdit.WrapAnywhere + textArea.verticalAlignment: Text.AlignTop + textArea.text: ShareConnectionLogic.textEditShareAmneziaCodeText + + visible: tfShareCode.textArea.length > 0 + } + + + ShareConnectionButtonCopyType { + id: pb_copy + Layout.bottomMargin: 10 + Layout.fillWidth: true + Layout.preferredHeight: 40 + enabled: tfShareCode.textArea.length > 0 + visible: tfShareCode.textArea.length > 0 + } + ShareConnectionButtonType { + id: pb_save + Layout.bottomMargin: 10 + Layout.fillWidth: true + Layout.preferredHeight: 40 + text: qsTr("Save to file") + enabled: tfShareCode.textArea.length > 0 + visible: tfShareCode.textArea.length > 0 + + onClicked: { + UiLogic.saveTextFile(qsTr("Save AmneziaVPN config"), "*.vpn", tfShareCode.textArea.text) + } + } + + Image { + id: label_share_code + Layout.topMargin: 20 + Layout.fillWidth: true + Layout.preferredHeight: width + smooth: false + source: ShareConnectionLogic.shareAmneziaQrCodeText + } } } } diff --git a/client/ui/qml/Pages/Share/PageShareProtoCloak.qml b/client/ui/qml/Pages/Share/PageShareProtoCloak.qml index 82edae85..7e8db7d2 100644 --- a/client/ui/qml/Pages/Share/PageShareProtoCloak.qml +++ b/client/ui/qml/Pages/Share/PageShareProtoCloak.qml @@ -29,22 +29,15 @@ PageShareProtocolBase { width: parent.width - 60 textArea.readOnly: true - - textArea.text: ShareConnectionLogic.plainTextEditShareCloakText + textArea.text: ShareConnectionLogic.textEditShareCloakText } - ShareConnectionButtonType { + ShareConnectionButtonCopyType { id: pb_save anchors.bottom: root.bottom anchors.bottomMargin: 10 anchors.horizontalCenter: root.horizontalCenter width: parent.width - 60 - text: ShareConnectionLogic.pushButtonShareCloakCopyText //enabled: ShareConnectionLogic.pushButtonShareCloakCopyEnabled - onClicked: { - ShareConnectionLogic.onPushButtonShareCloakCopyClicked() - } } - - } diff --git a/client/ui/qml/Pages/Share/PageShareProtoOpenVPN.qml b/client/ui/qml/Pages/Share/PageShareProtoOpenVPN.qml index 007ca6b5..1ca97c36 100644 --- a/client/ui/qml/Pages/Share/PageShareProtoOpenVPN.qml +++ b/client/ui/qml/Pages/Share/PageShareProtoOpenVPN.qml @@ -20,6 +20,7 @@ PageShareProtocolBase { } TextAreaType { + id: tfShareCode anchors.top: caption.bottom anchors.topMargin: 20 anchors.bottom: pb_gen.top @@ -44,22 +45,19 @@ PageShareProtocolBase { text: ShareConnectionLogic.pushButtonShareOpenVpnGenerateText onClicked: { + enabled = false ShareConnectionLogic.onPushButtonShareOpenVpnGenerateClicked() + enabled = true } - enabled: ShareConnectionLogic.pushButtonShareOpenVpnGenerateEnabled } - ShareConnectionButtonType { + ShareConnectionButtonCopyType { id: pb_copy anchors.bottom: pb_save.top anchors.bottomMargin: 10 anchors.horizontalCenter: root.horizontalCenter width: parent.width - 60 - text: ShareConnectionLogic.pushButtonShareOpenVpnCopyText - enabled: ShareConnectionLogic.pushButtonShareOpenVpnCopyEnabled - onClicked: { - ShareConnectionLogic.onPushButtonShareOpenVpnCopyClicked() - } + enabled: tfShareCode.textArea.length > 0 } ShareConnectionButtonType { id: pb_save @@ -68,10 +66,11 @@ PageShareProtocolBase { anchors.horizontalCenter: root.horizontalCenter width: parent.width - 60 - text: qsTr("Save file") - enabled: ShareConnectionLogic.pushButtonShareOpenVpnSaveEnabled + text: qsTr("Save to file") + enabled: tfShareCode.textArea.length > 0 + onClicked: { - ShareConnectionLogic.onPushButtonShareOpenVpnSaveClicked() + UiLogic.saveTextFile(qsTr("Save OpenVPN config"), "*.ovpn", tfShareCode.textArea.text) } } } diff --git a/client/ui/qml/Pages/Share/PageShareProtoShadowSocks.qml b/client/ui/qml/Pages/Share/PageShareProtoShadowSocks.qml index ca6ad8d5..cb5ab01f 100644 --- a/client/ui/qml/Pages/Share/PageShareProtoShadowSocks.qml +++ b/client/ui/qml/Pages/Share/PageShareProtoShadowSocks.qml @@ -24,7 +24,7 @@ PageShareProtocolBase { width: root.width anchors.top: caption.bottom anchors.topMargin: 20 - anchors.bottom: parent.bottom + anchors.bottom: root.bottom anchors.bottomMargin: 20 anchors.left: root.left anchors.leftMargin: 30 @@ -108,14 +108,10 @@ PageShareProtocolBase { text: ShareConnectionLogic.lineEditShareShadowSocksStringText readOnly: true } - ShareConnectionButtonType { - height: 40 + ShareConnectionButtonCopyType { + Layout.preferredHeight: 40 Layout.fillWidth: true - text: ShareConnectionLogic.pushButtonShareShadowSocksCopyText enabled: tfConnString.length > 0 - onClicked: { - ShareConnectionLogic.onPushButtonShareShadowSocksCopyClicked() - } } Image { @@ -124,7 +120,7 @@ PageShareProtocolBase { Layout.fillWidth: true Layout.preferredHeight: width smooth: false - source: ShareConnectionLogic.labelShareShadowSocksQrCodeText + source: ShareConnectionLogic.shareShadowSocksQrCodeText } } } diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index fa1ca9e8..c036718d 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -697,4 +697,13 @@ void UiLogic::setTrayState(VpnProtocol::ConnectionState state) } +bool UiLogic::saveTextFile(const QString& desc, const QString& ext, const QString& data) +{ + QString fileName = QFileDialog::getSaveFileName(nullptr, desc, + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext); + QSaveFile save(fileName); + save.open(QIODevice::WriteOnly); + save.write(data.toUtf8()); + return save.commit(); +} diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index e7ba4c6d..f02b5f8e 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -98,6 +98,7 @@ public: Q_INVOKABLE void keyPressEvent(Qt::Key key); + Q_INVOKABLE bool saveTextFile(const QString& desc, const QString& ext, const QString& data); QString getTrayIconUrl() const; void setTrayIconUrl(const QString &trayIconUrl);