temporary save

This commit is contained in:
Mitternacht822
2025-11-17 19:20:27 +04:00
parent 9a5e437f7b
commit f821bcb01f
9 changed files with 345 additions and 7 deletions

View File

@@ -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>

View File

@@ -38,6 +38,9 @@ namespace PageLoader
PageSettingsApiInstructions,
PageSettingsApiNativeConfigs,
PageSettingsApiDevices,
PageSettingsApiDevicesLimit,
PageSettingsApiAddDeviceConfirm,
PageSettingsApiAddDeviceScan,
PageSettingsApiSubscriptionKey,
PageSettingsKillSwitchExceptions,

View File

@@ -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);
}
});
}

View File

@@ -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:

View 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()
}
}
}
}
}

View 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()
}
}
}
}
}
}

View File

@@ -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) {

View 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)
}
}
}
}
}

View File

@@ -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