refactor: transferController

This commit is contained in:
Mitternacht822
2026-01-16 02:31:21 +04:00
parent 43b51db132
commit 832fea3d50
6 changed files with 239 additions and 207 deletions

View File

@@ -4,6 +4,9 @@
#include <QJsonParseError>
#include <QDebug>
#include <qeventloop.h>
#include <QNetworkProxyFactory>
#include <QNetworkProxyQuery>
#include <QUrl>
#include "core/api/apiUtils.h"
#include "amnezia_application.h"
@@ -13,11 +16,27 @@
#include "ui/controllers/importController.h"
#include "core/api/apiDefs.h"
#include "core/controllers/gatewayController.h"
#include "core/errorstrings.h"
static ErrorCode postPlainJson(const QString& url,
const QJsonObject& payload,
int timeoutMs,
QByteArray& responseBody);
namespace {
void logSystemProxiesForUrl(const QString &urlStr)
{
const QUrl url(urlStr);
const QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(url));
QStringList proxyDesc;
proxyDesc.reserve(proxies.size());
for (const auto &p : proxies) {
proxyDesc << QStringLiteral("%1 %2:%3")
.arg(p.type() == QNetworkProxy::NoProxy ? QStringLiteral("NoProxy")
: p.type() == QNetworkProxy::HttpProxy ? QStringLiteral("HttpProxy")
: p.type() == QNetworkProxy::Socks5Proxy ? QStringLiteral("Socks5Proxy")
: QStringLiteral("Proxy"))
.arg(p.hostName())
.arg(p.port());
}
qDebug() << "TransferController: system proxies for" << urlStr << ":" << proxyDesc;
}
}
TransferController::TransferController(const std::shared_ptr<Settings> &settings,
const QSharedPointer<ServersModel> &serversModel,
@@ -37,21 +56,20 @@ void TransferController::handleImportControllerDestroyed()
TransferController::~TransferController() {
}
QString TransferController::buildQrPayloadJson(const QString &gatewayUrl, const QString &uuid, int version) const
QString TransferController::buildQrPayloadJson(const QString &gatewayUrl, const QString &uuid) const
{
QJsonObject obj;
obj["gw"] = gatewayUrl;
obj["u"] = uuid;
obj["v"] = version;
obj["uuid"] = uuid;
qDebug() << "built QrPayload with GW = " << gatewayUrl
<< " uuid = " << uuid
<< " version = " << version;
<< " uuid = " << uuid;
return QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact));
}
void TransferController::generateNewQrCode()
{
qDebug() << "TransferController::generateNewQrCode: generating QR code";
// Debug mode: keep UUID/payload generation, but disable actual QR rendering (temporary).
qDebug() << "TransferController::generateNewQrCode: generating transfer payload (QR rendering disabled)";
QString gw = m_settings->getGatewayEndpoint();
if (!gw.endsWith('/')) {
@@ -61,13 +79,20 @@ void TransferController::generateNewQrCode()
m_currentUuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
qDebug() << "uuid:" << m_currentUuid;
const QString payload = buildQrPayloadJson(gw, m_currentUuid, 1);
m_currentPayload = buildQrPayloadJson(gw, m_currentUuid);
auto qr = qrCodeUtils::generateQrCode(payload.toUtf8());
const QString svg = QString::fromStdString(toSvgString(qr, 1));
m_qrCodeUrl = qrCodeUtils::svgToBase64(svg);
// QR generation disabled for debugging/CLI-style copy-paste flow.
// If/when QR is re-enabled, restore this block:
//
// auto qr = qrCodeUtils::generateQrCode(m_currentPayload.toUtf8());
// const QString svg = QString::fromStdString(toSvgString(qr, 1));
// m_qrCodeUrl = qrCodeUtils::svgToBase64(svg);
// emit qrCodeUpdated();
m_qrCodeUrl.clear();
emit qrCodeUpdated();
emit currentUuidChanged();
emit currentPayloadChanged();
}
void TransferController::stopScanner()
@@ -76,14 +101,7 @@ void TransferController::stopScanner()
emit scannerShouldStop();
}
QString TransferController::getPremiumConfigToSend() const
{
qDebug() << "TransferController:getPremiumConfigToSend() called with apiKey " << apiDefs::key::apiKey;
//Q_UNUSED(apiDefs::key::apiKey)
return m_exportController ? m_exportController->getConfig() : QString();
}
QString TransferController::getCurrentApiKey() const
QString TransferController::getCurrentApiKey(QString *vpnKeyOut) const
{
const int idx = m_serversModel ? m_serversModel->getProcessedServerIndex() : -1;
if (idx < 0 || !m_serversModel) {
@@ -95,23 +113,25 @@ QString TransferController::getCurrentApiKey() const
qDebug() << "server:" << server;
const QJsonObject apiConfig = server.value(apiDefs::key::apiConfig).toObject();
QJsonObject authData = server.value(QStringLiteral("auth_data")).toObject();
//QString key = authData.value(apiDefs::key::apiKey).toString();
QString key = authData.value(QStringLiteral("api_key")).toString();
const QJsonObject authData = server.value(QStringLiteral("auth_data")).toObject();
/*if (key.isEmpty()) {
const QJsonObject nestedAuth = apiConfig.value(QStringLiteral("auth_data")).toObject();
if (!nestedAuth.isEmpty()) {
key = nestedAuth.value(apiDefs::key::apiKey).toString();
const QString apiKey = authData.value(QStringLiteral("api_key")).toString();
if (vpnKeyOut) {
QString vpnKey = apiConfig.value(apiDefs::key::vpnKey).toString();
if (vpnKey.isEmpty()) {
// Fallback for older Premium V1 configs where vpn_key may be derived.
vpnKey = apiUtils::getPremiumV1VpnKey(server);
}
}*/
*vpnKeyOut = vpnKey;
}
return key;
return apiKey;
}
void TransferController::onTransferQrScanned(const QString &code)
{
qDebug() << "TransferController has scanned the Qr";
qDebug() << "TransferController has scanned the Qr";
QJsonParseError err;
const QJsonDocument doc = QJsonDocument::fromJson(code.toUtf8(), &err);
@@ -123,7 +143,7 @@ void TransferController::onTransferQrScanned(const QString &code)
const QJsonObject obj = doc.object();
QString gw = obj.value("gw").toString();
const QString uuid = obj.value("u").toString();
const QString uuid = obj.value("uuid").toString();
if (gw.isEmpty() || uuid.isEmpty()) {
qWarning() << "TransferController::onTransferQrScanned: QR missing gw or uuid";
@@ -134,17 +154,15 @@ void TransferController::onTransferQrScanned(const QString &code)
gw.append('/');
}
const QString apiKey = getCurrentApiKey();
QString vpnKey;
const QString apiKey = getCurrentApiKey(&vpnKey);
qDebug() << "scanned apiKey:" << apiKey;
const QString config = getPremiumConfigToSend();
qDebug() << "config:" << config;
if (apiKey.isEmpty() || config.isEmpty()) {
if (apiKey.isEmpty()) {
qWarning() << "TransferController::onTransferQrScanned: no subscription key or config to send";
emit postFailed(QStringLiteral("No subscription key or config to send"));
return;
}
// Allow only premium (subscription) configs
bool isPremium = m_serversModel && m_serversModel->processedServerIsPremium();
qDebug() << "isPremium: " << isPremium;
bool isFromGatewayApi = m_serversModel && m_serversModel->getProcessedServerData("isServerFromGatewayApi").toBool();
@@ -157,85 +175,52 @@ void TransferController::onTransferQrScanned(const QString &code)
emit postStarted();
qDebug() << "entered POST section";
qDebug() << "gw:" << gw;
qDebug() << "uuid:" << uuid;
qDebug() << "apiKey:" << apiKey;
qDebug() << "config:" << config;
if (vpnKey.isEmpty()) {
qWarning() << "TransferController::onTransferQrScanned: missing vpn_key";
emit postFailed(QStringLiteral("Missing vpn_key to send"));
return;
}
/*GatewayController gatewayController(gw, //m_settings->getGatewayEndpoint(),
// sendConfig can take longer on slower networks / debug setups, so use a bigger timeout than generic API calls.
const int sendTimeoutMs = 120000;
GatewayController gatewayController(gw,
m_settings->isDevGatewayEnv(),
apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());*/
QByteArray responseBody;
sendTimeoutMs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject payload;
payload.insert(QStringLiteral("config"), config);
payload.insert(QStringLiteral("uuid"), uuid);
payload.insert(QStringLiteral("api_key"), apiKey);
payload.insert(QStringLiteral("config"), vpnKey);
const QString url = gw + "sendConfig";
qDebug() << "TransferController::onTransferQrScanned: sending POST to" << url
<< "with payload:" << QJsonDocument(payload).toJson(QJsonDocument::Compact);
const QString endpoint = QStringLiteral("%1v1/sendConfig");
QByteArray responseBody;
const QString fullUrl = endpoint.arg(gw);
qDebug() << "TransferController::onTransferQrScanned: POST" << fullUrl
<< "uuid:" << uuid;
logSystemProxiesForUrl(fullUrl);
const auto errorCode = gatewayController.post(endpoint, payload, responseBody);
qDebug() << "TransferController::onTransferQrScanned: sendConfig finished with code"
<< static_cast<int>(errorCode)
<< "response size:" << responseBody.size();
auto ec = postPlainJson(url, payload, apiDefs::requestTimeoutMsecs, responseBody);
qDebug() << "TransferController::onTransferQrScanned: POST finished with code"
<< static_cast<int>(ec);
if (ec != ErrorCode::NoError) {
qWarning() << "TransferController::onTransferQrScanned: network error during POST"
<< "body:" << responseBody;
emit postFailed(QStringLiteral("Network error"));
if (errorCode != ErrorCode::NoError) {
qWarning() << "TransferController::onTransferQrScanned: sendConfig failed with code" << static_cast<int>(errorCode);
emit postFailed(QStringLiteral("sendConfig failed: %1").arg(errorString(errorCode)));
return;
}
// Parse response and handle success/failure
{
QJsonParseError parseErr;
const QJsonDocument respDoc = QJsonDocument::fromJson(responseBody, &parseErr);
if (parseErr.error == QJsonParseError::NoError && respDoc.isObject()) {
const QJsonObject respObj = respDoc.object();
const QString status = respObj.value(QStringLiteral("status")).toString();
if (status == QStringLiteral("success")) {
qDebug() << "TransferController::onTransferQrScanned: gateway returned success";
emit postSucceeded();
stopScanner();
return;
}
}
qWarning() << "TransferController::onTransferQrScanned: gateway response error" << responseBody;
emit postFailed(QStringLiteral("Gateway response error"));
QJsonParseError parseErr;
const QJsonDocument respDoc = QJsonDocument::fromJson(responseBody, &parseErr);
if (parseErr.error == QJsonParseError::NoError && respDoc.isObject()
&& respDoc.object().value(QStringLiteral("status")).toString() == QStringLiteral("success")) {
emit postSucceeded();
stopScanner();
return;
}
//const QString endpoint = QStringLiteral("%1sendConfig").arg(gw);
//const QString endpoint = QStringLiteral("sendConfig");
/*qDebug() << "TransferController::onTransferQrScanned: sending POST to " << endpoint
<< "with payload: " << QJsonDocument(payload).toJson(QJsonDocument::Compact);
auto errorCode = gatewayController.post(endpoint, payload, responseBody);
qDebug() << "TransferController::onTransferQrScanned: POST finished with code"
<< static_cast<int>(errorCode);
if (errorCode == ErrorCode::NoError) {
QJsonParseError err;
const QJsonDocument doc = QJsonDocument::fromJson(responseBody, &err);
if (err.error == QJsonParseError::NoError && doc.isObject()) {
const QJsonObject obj = doc.object();
if (obj.value(QStringLiteral("status")).toString() == QStringLiteral("success")) {
qDebug() << "TransferController::onTransferQrScanned: gateway returned success";
emit postSucceeded();
stopScanner();
return;
}
}
qWarning() << "TransferController::onTransferQrScanned: gateway response error";
emit postFailed(QStringLiteral("Gateway response error"));
} else {
qWarning() << "TransferController::onTransferQrScanned: network error during POST";
emit postFailed(QStringLiteral("Network error"));
}*/
qWarning() << "TransferController::onTransferQrScanned: unexpected gateway response:" << responseBody;
emit postFailed(QStringLiteral("Gateway response error"));
}
QString TransferController::qrCodeUrl() const
@@ -261,58 +246,33 @@ void TransferController::startWaitForConfig(ImportController *importController)
m_importController = importController;
if (m_importController) {
connect(m_importController, &QObject::destroyed,
connect(m_importController, &ImportController::destroyed,
this,
&TransferController::handleImportControllerDestroyed,
Qt::UniqueConnection);
}
// Blocking request to /waitConfig with a timeout.
const int waitTimeoutMs = 30000;
/*GatewayController gatewayController(gw, //m_settings->getGatewayEndpoint(),
m_settings->isDevGatewayEnv(),
waitTimeoutMs,
m_settings->isStrictKillSwitchEnabled());
const QString endpoint = QStringLiteral("%1waitConfig");
//const QString endpoint = QStringLiteral("waitConfig");
qDebug() << "waitConfig endpoint:" << QString(endpoint).arg(gw);*/
const int waitTimeoutMs = 300000;
QJsonObject payload;
payload.insert(QStringLiteral("uuid"), uuid);
GatewayController gatewayController(gw,
m_settings->isDevGatewayEnv(),
waitTimeoutMs,
m_settings->isStrictKillSwitchEnabled());
const QString endpoint = QStringLiteral("%1v1/waitConfig");
QByteArray responseBody;
const QString fullUrl = endpoint.arg(gw);
qDebug() << "TransferController::startWaitForConfig: POST" << fullUrl
<< "uuid:" << uuid;
logSystemProxiesForUrl(fullUrl);
const auto errorCode = gatewayController.post(endpoint, payload, responseBody);
const QString url = gw + "waitConfig";
qDebug() << "waitConfig endpoint: " << url;
auto ec = postPlainJson(url, payload, waitTimeoutMs, responseBody);
if (ec != ErrorCode::NoError) {
qWarning() << "waitConfig failed, code:" << (int)ec << "body:" << responseBody;
emit waitError(QStringLiteral("Network error"));
return;
}
/*auto errorCode = gatewayController.post(endpoint, payload, responseBody);
if (errorCode != ErrorCode::NoError) {
qWarning() << "TransferController::startWaitForConfig: network error during waitConfig";
emit waitError(QStringLiteral("Network error"));
return;
}*/
QJsonParseError err;
const QJsonDocument doc = QJsonDocument::fromJson(responseBody, &err);
if (err.error != QJsonParseError::NoError ||!doc.isObject()) {
qWarning() << "TransferController::startWaitForConfig: invalid gateway JSON";
emit waitError(QStringLiteral("Gateway Response Error"));
return;
}
const QJsonObject obj = doc.object();
QString cfg = obj.value(QStringLiteral("config")).toString();
if (cfg.isEmpty() || cfg == QStringLiteral("timeout")) {
qWarning() << "TransferController::startWaitForConfig: timeout or empty config";
emit waitError(QStringLiteral("Gateway response error (timeout)"));
qWarning() << "TransferController::startWaitForConfig: waitConfig failed with code" << static_cast<int>(errorCode);
emit waitError(QStringLiteral("waitConfig failed (%1)").arg(static_cast<int>(errorCode)));
return;
}
@@ -322,40 +282,41 @@ void TransferController::startWaitForConfig(ImportController *importController)
return;
}
if (!m_importController->extractConfigFromData(cfg)) {
qWarning() << "TransferController::startWaitForConfig: invalid config received from gateway";
emit waitError(QStringLiteral("Invalid config received from gateway"));
QJsonParseError parseErr;
const QJsonDocument respDoc = QJsonDocument::fromJson(responseBody, &parseErr);
if (parseErr.error != QJsonParseError::NoError || !respDoc.isObject()) {
qWarning() << "TransferController::startWaitForConfig: invalid JSON response:" << responseBody;
emit waitError(QStringLiteral("Invalid gateway response"));
return;
}
const QJsonObject respObj = respDoc.object();
const QString status = respObj.value(QStringLiteral("status")).toString();
const QString configStr = respObj.value(QStringLiteral("config")).toString();
if (status != QStringLiteral("success")) {
qWarning() << "TransferController::startWaitForConfig: gateway status not success:" << status;
emit waitError(QStringLiteral("Gateway error"));
return;
}
if (configStr.isEmpty()) {
emit waitError(QStringLiteral("Empty config"));
return;
}
if (configStr == QStringLiteral("timeout")) {
emit waitError(QStringLiteral("Timeout"));
return;
}
if (!m_importController->extractConfigFromData(configStr)) {
qWarning() << "TransferController::startWaitForConfig: failed to parse config string";
emit waitError(QStringLiteral("Invalid config payload"));
return;
}
m_importController->importConfig();
emit configApplied();
}
void TransferController::stopWaitForConfig()
{
qDebug() << "TransferController::stopWaitForConfig: stop flag set";
}
static ErrorCode postPlainJson(const QString& url, const QJsonObject& payload, int timeoutMs, QByteArray& responseBody)
{
QNetworkRequest request;
request.setTransferTimeout(timeoutMs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setUrl(QUrl(url));
QNetworkReply* reply = amnApp->networkManager()->post(request, QJsonDocument(payload).toJson(QJsonDocument::Compact));
QEventLoop wait;
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
QList<QSslError> sslErrors;
QObject::connect(reply, &QNetworkReply::sslErrors, [&sslErrors](const QList<QSslError>& errors){ sslErrors = errors; });
wait.exec();
responseBody = reply->readAll();
auto ec = apiUtils::checkNetworkReplyErrors(sslErrors, reply);
reply->deleteLater();
return ec;
}

View File

@@ -7,8 +7,6 @@
#include <QJsonDocument>
#include <QUuid>
#include "core/qrCodeUtils.h"
class Settings;
class ServersModel;
class ExportController;
@@ -20,6 +18,9 @@ class TransferController : public QObject
Q_PROPERTY(QString qrCodeUrl READ qrCodeUrl NOTIFY qrCodeUpdated)
Q_PROPERTY(QString pendingQrCode READ pendingQrCode WRITE setPendingQrCode NOTIFY pendingQrCodeChanged)
// Debug / manual transfer support (temporary): expose UUID and payload JSON used to generate the QR code.
Q_PROPERTY(QString currentUuid READ currentUuid NOTIFY currentUuidChanged)
Q_PROPERTY(QString currentPayload READ currentPayload NOTIFY currentPayloadChanged)
public:
explicit TransferController(const std::shared_ptr<Settings> &settings,
@@ -41,11 +42,15 @@ public:
Q_INVOKABLE void stopWaitForConfig();
QString qrCodeUrl() const;
QString currentUuid() const { return m_currentUuid; }
QString currentPayload() const { return m_currentPayload; }
signals:
void qrCodeUpdated();
void scannerShouldStop();
void pendingQrCodeChanged();
void currentUuidChanged();
void currentPayloadChanged();
void waitError(const QString &message);
void configApplied();
@@ -58,10 +63,10 @@ private slots:
void handleImportControllerDestroyed();
private:
QString buildQrPayloadJson(const QString &gatewayUrl, const QString &uuid, int version) const;
QString getPremiumConfigToSend() const;
QString buildQrPayloadJson(const QString &gatewayUrl, const QString &uuid) const;
//QString getPremiumConfigToSend() const;
QString m_pendingQrCode;
QString getCurrentApiKey() const;
QString getCurrentApiKey(QString *vpnKeyOut = nullptr) const;
std::shared_ptr<Settings> m_settings;
QSharedPointer<ServersModel> m_serversModel;
ExportController *m_exportController { nullptr };
@@ -69,6 +74,7 @@ private:
QString m_qrCodeUrl;
QString m_currentUuid;
QString m_currentPayload;
};
#endif // TRANSFERCONTROLLER_H

View File

@@ -14,6 +14,9 @@ import "../Config"
PageType {
id: root
// Debug-friendly: don't auto-close on send; keep the page responsive and show status.
property bool isSending: false
function getAvailableCount() {
var max = ApiAccountInfoModel.data("maxDeviceCount")
var active = ApiAccountInfoModel.data("activeDeviceCount")
@@ -32,7 +35,16 @@ PageType {
header: ColumnLayout {
width: listView.width
BackButtonType {}
BackButtonType {
backButtonFunction: function() {
if (root.isSending) {
// We cannot truly abort GatewayController::post() without changing it,
// but we can at least stop waiting on the other side and let the user navigate.
TransferController.stopWaitForConfig()
}
PageController.closePage()
}
}
BaseHeaderType {
Layout.fillWidth: true
@@ -50,13 +62,13 @@ PageType {
Layout.topMargin: 16
text: qsTr("Yes, share")
enabled: root.getAvailableCount() > 0 && TransferController.pendingQrCode !== ""
enabled: !root.isSending && root.getAvailableCount() > 0 && TransferController.pendingQrCode !== ""
clickedFunc: function() {
if (TransferController.pendingQrCode !== "") {
root.isSending = true
TransferController.onTransferQrScanned(TransferController.pendingQrCode)
}
PageController.closePage()
}
}
@@ -74,6 +86,7 @@ PageType {
borderWidth: 1
text: qsTr("Cancel")
enabled: !root.isSending
clickedFunc: function() {
PageController.closePage()
@@ -86,14 +99,17 @@ PageType {
target: TransferController
function onPostStarted() {
PageController.showInfoMessage(qsTr("Sending configuration..."))
PageController.showNotificationMessage(qsTr("Sending configuration..."))
}
function onPostSucceeded() {
PageController.showInfoMessage(qsTr("Configuration sent successfully"))
root.isSending = false
PageController.showNotificationMessage(qsTr("Configuration sent successfully"))
PageController.closePage()
}
function onPostFailed(message) {
root.isSending = false
PageController.showErrorMessage(message)
}
}

View File

@@ -4,7 +4,6 @@ import QtQuick.Layouts
import QtQuick.Dialogs
import PageEnum 1.0
import QRCodeReader 1.0
import Style 1.0
import "./"
@@ -35,7 +34,7 @@ PageType {
anchors.leftMargin: 16
anchors.rightMargin: 16
text: qsTr("Point the camera at the QR code and hold it for a couple of seconds. ") + progressString
text: qsTr("Debug mode: paste payload JSON from the other device (or enter UUID). ") + progressString
}
ProgressBarType {
@@ -49,7 +48,7 @@ PageType {
anchors.rightMargin: 16
}
// Manual UUID input (temporary instead of camera scanning)
// Debug: manual payload/UUID input (temporary instead of camera scanning)
ColumnLayout {
id: manualInput
anchors.left: parent.left
@@ -63,6 +62,14 @@ PageType {
anchors.bottomMargin: 24
spacing: 12
TextFieldWithHeaderType {
id: payloadField
Layout.fillWidth: true
headerText: qsTr("Payload JSON")
textField.placeholderText: qsTr("Paste JSON like {\"gw\":\"...\",\"uuid\":\"...\"}")
}
TextFieldWithHeaderType {
id: uuidField
Layout.fillWidth: true
@@ -72,9 +79,28 @@ PageType {
}
BasicButtonType {
id: sendButton
id: usePayloadButton
Layout.fillWidth: true
text: qsTr("Send")
text: qsTr("Next (use payload)")
enabled: payloadField.textField.text.length > 0
clickedFunc: function() {
TransferController.setPendingQrCode(payloadField.textField.text)
PageController.goToPage(PageEnum.PageSettingsApiAddDeviceConfirm)
}
}
BasicButtonType {
id: buildFromUuidButton
Layout.fillWidth: true
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.paleGray
borderColor: AmneziaStyle.color.paleGray
borderWidth: 1
text: qsTr("Next (build from UUID)")
enabled: uuidField.textField.text.length > 0
clickedFunc: function() {
@@ -94,7 +120,7 @@ PageType {
gw = gw + "/"
}
var payload = JSON.stringify({ gw: gw, u: uuidField.textField.text, v: 1 })
var payload = JSON.stringify({ gw: gw, uuid: uuidField.textField.text })
TransferController.setPendingQrCode(payload)
PageController.goToPage(PageEnum.PageSettingsApiAddDeviceConfirm)
}

View File

@@ -60,7 +60,7 @@ PageType {
Layout.rightMargin: 16
Layout.topMargin: 16
visible: GC.isMobile()
//visible: GC.isMobile()
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite

View File

@@ -7,7 +7,6 @@ import PageEnum 1.0
import Style 1.0
import "../Controls2"
import "../Components"
import QRCodeReader 1.0
import "../Controls2/TextTypes"
PageType {
@@ -58,31 +57,56 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
text: qsTr("Scan the QR code with the phone where Amnezia Premium is active")
text: qsTr("Debug mode: copy the payload to the other device and send it there")
}
Rectangle {
id: qrContainer
ColumnLayout {
id: debugPayload
anchors.left: parent.left
anchors.right: parent.right
anchors.top: qrHeader.bottom
anchors.topMargin: 8
// anchors.horizontalCenter: parent.horizontalCenter // УБРАТЬ
anchors.topMargin: 12
anchors.bottom: bottomHint.top
anchors.bottomMargin: 8
anchors.bottomMargin: 12
spacing: 8
color: AmneziaStyle.color.transparent
border.color: AmneziaStyle.color.paleGray
border.width: 1
TextArea {
id: payloadArea
Layout.fillWidth: true
Layout.fillHeight: true
readOnly: true
wrapMode: TextArea.WrapAnywhere
selectByMouse: true
text: TransferController.currentPayload
placeholderText: qsTr("Payload will appear here after generating")
}
Image {
id: qrImage
anchors.centerIn: parent
width: Math.min(parent.width, parent.height)
height: width
source: TransferController.qrCodeUrl
fillMode: Image.Stretch
smooth: false
RowLayout {
Layout.fillWidth: true
spacing: 8
BasicButtonType {
Layout.fillWidth: true
text: qsTr("Regenerate")
clickedFunc: function() {
TransferController.generateNewQrCode()
TransferController.startWaitForConfig(ImportController)
}
}
BasicButtonType {
Layout.fillWidth: true
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.paleGray
borderColor: AmneziaStyle.color.paleGray
borderWidth: 1
text: qsTr("Restart wait")
clickedFunc: function() {
TransferController.startWaitForConfig(ImportController)
}
}
}
}
@@ -92,7 +116,7 @@ PageType {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
text: qsTr("In the Amnezia app on your phone, tap «+» at the bottom → «QR code»")
text: qsTr("Copy the JSON payload above, paste it on the other device, and confirm sending there")
horizontalAlignment: Text.AlignHCenter
}
}
@@ -100,7 +124,6 @@ PageType {
Connections {
target: TransferController
function onQrCodeUpdated() { qrImage.source = TransferController.qrCodeUrl }
function onConfigApplied() {
PageController.showNotificationMessage(qsTr("Configuration received and applied"))
}