Files
amnezia-client/client/ui/qml/Pages2/PageSetupWizardApiQrPairingReceive.qml
T

193 lines
5.6 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
readonly property int qrRefreshIntervalMs: Math.max(5000, PairingUiController.tvPairingWaitWindowSeconds * 1000)
function scrollPairingToBottom() {
receiveScroll.contentY = Math.max(0, receiveScroll.contentHeight - receiveScroll.height)
}
function beginReceiveFlow() {
PairingUiController.startTvQrSession()
qrRotationTimer.restart()
}
Timer {
id: scrollToBottomRetryTimer
interval: 48
repeat: true
property int retries: 0
onTriggered: {
root.scrollPairingToBottom()
retries++
if (retries >= 12) {
stop()
}
}
onRunningChanged: {
if (!running) {
retries = 0
}
}
}
Timer {
id: qrRotationTimer
interval: root.qrRefreshIntervalMs
repeat: true
running: root.visible
onTriggered: {
PairingUiController.rotateTvQrSession()
}
}
Connections {
target: root
function onVisibleChanged() {
if (!root.visible) {
PairingUiController.cancelAllPairingActivity()
scrollToBottomRetryTimer.stop()
qrRotationTimer.stop()
} else {
Qt.callLater(root.beginReceiveFlow)
}
}
}
Component.onCompleted: {
if (root.visible) {
Qt.callLater(root.beginReceiveFlow)
}
}
FlickableType {
id: receiveScroll
anchors.fill: parent
contentHeight: layout.implicitHeight
Behavior on contentY {
NumberAnimation {
duration: 320
easing.type: Easing.OutCubic
}
}
onContentHeightChanged: {
if (PairingUiController.tvQrCodesCount > 0) {
Qt.callLater(root.scrollPairingToBottom)
}
}
ColumnLayout {
id: layout
width: root.width
spacing: 12
BackButtonType {
Layout.topMargin: 20 + PageController.safeAreaTopMargin
}
Label {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 8
horizontalAlignment: Text.AlignHCenter
text: qsTr("Scan this QR code with a phone that has an active Amnezia Premium subscription")
font.pixelSize: 17
font.bold: false
color: AmneziaStyle.color.paleGray
wrapMode: Text.Wrap
}
Item {
id: qrBox
Layout.fillWidth: true
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.topMargin: 16
// Avoid width*0.92 before first layout (width can be 0 → zero height → no QR).
Layout.preferredHeight: PairingUiController.tvQrCodesCount > 0 ? Math.max(200, layout.width - 48) : 0
visible: PairingUiController.tvQrCodesCount > 0
Rectangle {
anchors.fill: parent
radius: 20
color: "#FFFFFF"
Image {
id: qrImage
anchors.fill: parent
anchors.margins: 20
fillMode: Image.PreserveAspectFit
sourceSize: Qt.size(2048, 2048)
source: PairingUiController.tvQrCodesCount > 0 ? PairingUiController.tvQrCodes[0] : ""
}
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 24
horizontalAlignment: Text.AlignHCenter
color: AmneziaStyle.color.mutedGray
font.pixelSize: 13
text: qsTr("AmneziaVPN → Amnezia Premium →\nPersonal Dashboard → Active Devices →\nAdd Device via QR Code")
wrapMode: Text.Wrap
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: 24 + PageController.safeAreaBottomMargin
}
}
}
Connections {
target: PairingUiController
function onTvQrCodesChanged() {
if (PairingUiController.tvQrCodesCount > 0) {
scrollToBottomRetryTimer.retries = 0
scrollToBottomRetryTimer.start()
Qt.callLater(function() {
root.scrollPairingToBottom()
})
Qt.callLater(function() {
Qt.callLater(function() {
root.scrollPairingToBottom()
})
})
}
}
function onTvPairingConfigReceived() {
scrollToBottomRetryTimer.stop()
qrRotationTimer.stop()
qrImage.source = ""
PageController.showNotificationMessage(qsTr("Configuration received from gateway"))
Qt.callLater(function() {
PageController.closePage()
})
}
function onTvPairingConfigAlreadyAdded() {
scrollToBottomRetryTimer.stop()
qrRotationTimer.restart()
}
}
}