mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
temporary save
This commit is contained in:
@@ -237,6 +237,9 @@
|
||||
<file>ui/qml/Pages2/PageSettingsApiInstructions.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiNativeConfigs.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiDevices.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiDevicesLimit.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiAddDeviceScan.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiAddDeviceConfirm.qml</file>
|
||||
<file>images/controls/monitor.svg</file>
|
||||
<file>images/controls/monitor-with-phone.svg</file>
|
||||
<file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file>
|
||||
|
||||
@@ -38,6 +38,9 @@ namespace PageLoader
|
||||
PageSettingsApiInstructions,
|
||||
PageSettingsApiNativeConfigs,
|
||||
PageSettingsApiDevices,
|
||||
PageSettingsApiDevicesLimit,
|
||||
PageSettingsApiAddDeviceConfirm,
|
||||
PageSettingsApiAddDeviceScan,
|
||||
PageSettingsApiSubscriptionKey,
|
||||
PageSettingsKillSwitchExceptions,
|
||||
|
||||
|
||||
@@ -125,7 +125,10 @@ void TransferController::onTransferQrScanned(const QString &code)
|
||||
QUrlQuery q;
|
||||
q.addQueryItem(QStringLiteral("uuid"), uuid);
|
||||
q.addQueryItem(QStringLiteral("api_key"), apiKey);
|
||||
const QString endpoint = QString("%1sendConfig?%2").arg(gw, q.query(QUrl::FullyEncoded));
|
||||
//const QString endpoint = QString("%1sendConfig?%2").arg(gw, q.query(QUrl::FullyEncoded));
|
||||
const QString endpoint = QStringLiteral("%1waitConfig?%2")
|
||||
.arg(gw)
|
||||
.arg(q.query(QUrl::FullyEncoded));
|
||||
|
||||
auto errorCode = gatewayController.post(endpoint, payload, responseBody);
|
||||
|
||||
@@ -161,8 +164,12 @@ void TransferController::startWaitForConfig(ImportController *importController)
|
||||
m_importController = importController;
|
||||
m_stopWaiting.storeRelease(0);
|
||||
|
||||
qDebug() << "GW endpoint" << m_settings->getGatewayEndpoint();
|
||||
|
||||
QString gw = m_settings->getGatewayEndpoint();
|
||||
if (!gw.endsWith('/')) gw.append('/');
|
||||
if (!gw.endsWith('/')) {
|
||||
gw.append('/');
|
||||
}
|
||||
const QString uuid = m_currentUuid;
|
||||
const QString apiKey = getCurrentApiKey();
|
||||
const int generation = m_waitGeneration.loadAcquire();
|
||||
@@ -185,7 +192,11 @@ void TransferController::startWaitForConfig(ImportController *importController)
|
||||
QUrlQuery q;
|
||||
q.addQueryItem(QStringLiteral("uuid"), uuid);
|
||||
q.addQueryItem(QStringLiteral("api_key"), apiKey);
|
||||
const QString endpoint = QString("%1waitConfig?%2").arg(gw, q.query(QUrl::FullyEncoded));
|
||||
//const QString endpoint = QString("%1waitConfig?%2").arg(gw, q.query(QUrl::FullyEncoded));
|
||||
const QString endpoint = QStringLiteral("%1waitConfig?%2")
|
||||
.arg(gw)
|
||||
.arg(q.query(QUrl::FullyEncoded));
|
||||
|
||||
|
||||
auto errorCode = gatewayController.get(endpoint, responseBody);
|
||||
|
||||
@@ -222,8 +233,6 @@ void TransferController::startWaitForConfig(ImportController *importController)
|
||||
QThread::msleep(static_cast<unsigned long>(backoffMs));
|
||||
backoffMs = qMin(backoffMs * 2, maxBackoffMs);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ class TransferController : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString qrCodeUrl READ qrCodeUrl NOTIFY qrCodeUpdated)
|
||||
Q_PROPERTY(QString pendingQrCode READ pendingQrCode WRITE setPendingQrCode NOTIFY pendingQrCodeChanged)
|
||||
|
||||
public:
|
||||
explicit TransferController(const std::shared_ptr<Settings> &settings,
|
||||
@@ -33,6 +34,9 @@ public:
|
||||
Q_INVOKABLE void stopScanner();
|
||||
Q_INVOKABLE void onTransferQrScanned(const QString &code);
|
||||
|
||||
Q_INVOKABLE void setPendingQrCode(const QString &code) { m_pendingQrCode = code; emit pendingQrCodeChanged(); }
|
||||
QString pendingQrCode() const { return m_pendingQrCode; }
|
||||
|
||||
// Waiting for config on receiver device
|
||||
Q_INVOKABLE void startWaitForConfig(ImportController *importController);
|
||||
Q_INVOKABLE void stopWaitForConfig();
|
||||
@@ -42,6 +46,7 @@ public:
|
||||
signals:
|
||||
void qrCodeUpdated();
|
||||
void scannerShouldStop();
|
||||
void pendingQrCodeChanged();
|
||||
|
||||
void waitError(const QString &message);
|
||||
void configApplied();
|
||||
@@ -53,6 +58,7 @@ signals:
|
||||
private:
|
||||
QString buildQrPayloadJson(const QString &gatewayUrl, const QString &uuid, int version) const;
|
||||
QString getPremiumConfigToSend() const;
|
||||
QString m_pendingQrCode;
|
||||
QString getCurrentApiKey() const;
|
||||
|
||||
private:
|
||||
|
||||
85
client/ui/qml/Pages2/PageSettingsApiAddDeviceConfirm.qml
Normal file
85
client/ui/qml/Pages2/PageSettingsApiAddDeviceConfirm.qml
Normal file
@@ -0,0 +1,85 @@
|
||||
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
|
||||
|
||||
function getAvailableCount() {
|
||||
var max = ApiAccountInfoModel.data("maxDeviceCount")
|
||||
var active = ApiAccountInfoModel.data("activeDeviceCount")
|
||||
if (!max || max <= 0) max = 7
|
||||
if (!active || active < 0) active = 0
|
||||
var remain = max - active
|
||||
return remain > 0 ? remain : 0
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 20
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BackButtonType {}
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Share VPN with a new device?")
|
||||
descriptionText: qsTr("Your Amnezia Premium subscription can connect %1 more devices").arg(getAvailableCount())
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Yes, share")
|
||||
|
||||
clickedFunc: function() {
|
||||
if (TransferController.pendingQrCode !== "") {
|
||||
TransferController.onTransferQrScanned(TransferController.pendingQrCode)
|
||||
}
|
||||
PageController.closePage()
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 8
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Cancel")
|
||||
|
||||
clickedFunc: function() {
|
||||
PageController.closePage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
118
client/ui/qml/Pages2/PageSettingsApiAddDeviceScan.qml
Normal file
118
client/ui/qml/Pages2/PageSettingsApiAddDeviceScan.qml
Normal file
@@ -0,0 +1,118 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import PageEnum 1.0
|
||||
import QRCodeReader 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
// Единая логика при входе на страницу
|
||||
Component.onCompleted: {
|
||||
// Страница имеет смысл только на мобилках
|
||||
if (!GC.isMobile()) {
|
||||
PageController.closePage()
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем наличие камеры
|
||||
if (!SettingsController.isCameraPresent()) {
|
||||
PageController.showErrorMessage(qsTr("Camera is not available on this device"))
|
||||
PageController.closePage()
|
||||
return
|
||||
}
|
||||
|
||||
// Android: запускаем нативный сканер камеры
|
||||
if (Qt.platform.os === "android"
|
||||
&& typeof ImportController !== "undefined"
|
||||
&& ImportController.startDecodingQr) {
|
||||
ImportController.startDecodingQr()
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
visible: GC.isMobile()
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 20
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BackButtonType {}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: qsTr("Point the camera at the QR code and hold for a couple of seconds.")
|
||||
}
|
||||
}
|
||||
|
||||
footer: Item { height: 0 }
|
||||
|
||||
model: 1
|
||||
|
||||
delegate: Item {
|
||||
width: listView.width
|
||||
height: listView.height - 100
|
||||
|
||||
Rectangle {
|
||||
id: cameraArea
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
anchors.bottomMargin: 16
|
||||
anchors.topMargin: 16
|
||||
visible: Qt.platform.os === "ios" // На Android используется нативная камера
|
||||
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: AmneziaStyle.color.paleGray
|
||||
border.width: 1
|
||||
|
||||
// ВАЖНО: ридер виден на всех мобильных платформах
|
||||
QRCodeReader {
|
||||
id: qrReader
|
||||
|
||||
onCodeReaded: function (code) {
|
||||
if (!code || code.length === 0)
|
||||
return
|
||||
|
||||
qrReader.stopReading()
|
||||
TransferController.setPendingQrCode(code)
|
||||
PageController.goToPage(PageEnum.PageSettingsApiAddDeviceConfirm)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
qrReader.setCameraSize(
|
||||
Qt.rect(cameraArea.x,
|
||||
cameraArea.y,
|
||||
cameraArea.width,
|
||||
cameraArea.height))
|
||||
qrReader.startReading()
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
qrReader.stopReading()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: TransferController
|
||||
function onScannerShouldStop() {
|
||||
qrReader.stopReading()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import QtCore
|
||||
import QRCodeReader 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
@@ -19,6 +20,11 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
function isAtDeviceLimit() {
|
||||
var maxDeviceCount = ApiAccountInfoModel.data("maxDeviceCount")
|
||||
return listView.count >= maxDeviceCount
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
@@ -46,6 +52,34 @@ PageType {
|
||||
descriptionText: qsTr("Manage currently connected devices")
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: addDeviceQrButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: GC.isMobile()
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Add device by QR code")
|
||||
|
||||
clickedFunc: function() {
|
||||
if (root.isAtDeviceLimit()) {
|
||||
PageController.goToPage(PageEnum.PageSettingsApiDevicesLimit)
|
||||
} else {
|
||||
PageController.goToPage(PageEnum.PageSettingsApiAddDeviceScan)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WarningType {
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
@@ -93,6 +127,27 @@ PageType {
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: TransferController
|
||||
|
||||
function onPostStarted() {
|
||||
PageController.showBusyIndicator(true)
|
||||
}
|
||||
|
||||
function onPostSucceeded() {
|
||||
PageController.showBusyIndicator(false)
|
||||
ApiSettingsController.getAccountInfo(true)
|
||||
PageController.showNotificationMessage(qsTr("New device added to subscription"))
|
||||
}
|
||||
|
||||
function onPostFailed(message) {
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showErrorMessage(message)
|
||||
}
|
||||
|
||||
function onScannerShouldStop() {}
|
||||
}
|
||||
}
|
||||
|
||||
function deactivateExternalDevice(supportTag, countryCode) {
|
||||
|
||||
53
client/ui/qml/Pages2/PageSettingsApiDevicesLimit.qml
Normal file
53
client/ui/qml/Pages2/PageSettingsApiDevicesLimit.qml
Normal file
@@ -0,0 +1,53 @@
|
||||
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
|
||||
anchors.topMargin: 20
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BackButtonType {}
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Your Amnezia Premium subscription already has the maximum number of devices — ") + ApiAccountInfoModel.data("connectedDevices")
|
||||
descriptionText: qsTr("Remove one of the previously connected devices to add a new one")
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Show all devices")
|
||||
|
||||
clickedFunc: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsApiDevices)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,14 @@ PageType {
|
||||
anchors.right: parent.right
|
||||
anchors.top: qrHeader.bottom
|
||||
anchors.topMargin: 8
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: Math.min(qrContainer.width, parent.height - (qrHeader.height + 8) - (bottomHint.implicitHeight + 8))
|
||||
// anchors.horizontalCenter: parent.horizontalCenter // УБРАТЬ
|
||||
|
||||
// Высота – квадрат по ширине, но ограниченный высотой колонки
|
||||
height: Math.min(width,
|
||||
parent.height
|
||||
- (qrHeader.height + 8)
|
||||
- (bottomHint.implicitHeight + 8))
|
||||
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: AmneziaStyle.color.paleGray
|
||||
border.width: 1
|
||||
|
||||
Reference in New Issue
Block a user