Igor Sirotin 33d38a4081 fix: Device syncing
- Added local pairing signals
- Remove slash ending from keystorePath
- Implemented localPairingState. Fixed sync new device workflow. 
- Error message view design update 
- Moved local pairing status to devices service
- ConnectionString automatic validation
- Async inputConnectionString
- Added all installation properties to model. Minor renaming.
- Removed emoji and color customization
- Show display name, colorhash and color in device being synced
- Add timeout to pairing server
- Add device type
Fix `DeviceSyncingView` sizing. Fix `inputConnectionString` async task slot.
2023-03-16 00:27:21 +13:00

239 lines
6.7 KiB
QML

import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import shared.controls 1.0
import shared.panels 1.0
import utils 1.0
ColumnLayout {
id: root
property int secondsTimeout: 5 * 60
property string connectionString: ""
signal requestConnectionString()
function start() {
d.qrBlurred = true
d.codeExpired = false
d.secondsLeft = root.secondsTimeout
expireTimer.start()
}
spacing: 0
QtObject {
id: d
property int secondsLeft: root.secondsTimeout
property int secondsRatio: 1 // This property can be used to speed up testing of syncCode expiration
property bool qrBlurred: true
property bool codeExpired: false
onCodeExpiredChanged: {
if (codeExpired)
syncCodeInput.showPassword = false
}
}
Timer {
id: expireTimer
interval: root.secondsTimeout * 1000 / d.secondsRatio
onTriggered: {
d.codeExpired = true
}
}
Timer {
id: timeLeftUpdateTimer
interval: 1000 / d.secondsRatio
repeat: true
running: expireTimer.running
onTriggered: {
d.secondsLeft = Math.max(0, --d.secondsLeft)
}
}
Item {
Layout.alignment: Qt.AlignHCenter
implicitWidth: 254
implicitHeight: 254
Image {
id: qrCode
anchors.fill: parent
visible: false
asynchronous: true
fillMode: Image.PreserveAspectFit
mipmap: true
smooth: false
source: globalUtils.qrCode(root.connectionString)
}
FastBlur {
anchors.fill: qrCode
source: qrCode
radius: d.codeExpired || d.qrBlurred ? 40 : 0
transparentBorder: true
Behavior on radius {
NumberAnimation { duration: 500 }
}
}
StatusButton {
id: revealButton
anchors.centerIn: parent
visible: !d.codeExpired && d.qrBlurred
normalColor: Theme.palette.primaryColor1
hoverColor: Theme.palette.miscColor1;
textColor: Theme.palette.indirectColor1
font.weight: Font.Medium
icon.name: "show"
text: qsTr("Reveal QR")
onClicked: {
d.qrBlurred = !d.qrBlurred
}
}
StatusButton {
id: regenerateButton
anchors.centerIn: parent
visible: d.codeExpired
normalColor: Theme.palette.primaryColor1
hoverColor: Theme.palette.miscColor1;
textColor: Theme.palette.indirectColor1
font.weight: Font.Medium
icon.name: "refresh"
text: qsTr("Regenerate")
onClicked: {
root.requestConnectionString()
}
}
}
Row {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 16
StatusBaseText {
font.pixelSize: 17
text: qsTr("Code valid for: ")
}
StatusBaseText {
id: timeoutText
width: fontMetrics.advanceWidth("10:00")
horizontalAlignment: Text.AlignLeft
font.pixelSize: 17
color: d.secondsLeft < 60 ? Theme.palette.dangerColor1 : Theme.palette.directColor1
text: {
const minutes = Math.floor(d.secondsLeft / 60);
const seconds = d.secondsLeft % 60;
return `${minutes}:${String(seconds).padStart(2,'0')}`;
}
FontMetrics {
id: fontMetrics
font: timeoutText.font
}
}
}
// TODO: Extract this to a component.
// Also used in `PasswordView` and several other files.
// https://github.com/status-im/status-desktop/issues/6136
StyledText {
id: inputLabel
Layout.fillWidth: true
Layout.topMargin: 12
Layout.bottomMargin: 7
text: qsTr("Sync code")
font.weight: Font.Medium
font.pixelSize: 13
color: Theme.palette.directColor1
}
Input {
id: syncCodeInput
property bool showPassword
readonly property bool effectiveShowPassword: showPassword && !d.codeExpired
Layout.fillWidth: true
Layout.bottomMargin: 24
readOnly: true
keepHeight: true
textField.echoMode: effectiveShowPassword ? TextInput.Normal : TextInput.Password
textField.rightPadding: syncCodeButtons.width + Style.current.padding / 2
textField.color: Style.current.textColor
textField.selectByMouse: !d.codeExpired
text: root.connectionString
Row {
id: syncCodeButtons
anchors.verticalCenter: syncCodeInput.verticalCenter
anchors.right: parent.right
spacing: 8
rightPadding: 8
leftPadding: 8
StatusFlatRoundButton {
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
icon.name: syncCodeInput.effectiveShowPassword ? "hide" : "show"
icon.color: Theme.palette.baseColor1
enabled: !d.codeExpired
onClicked: {
syncCodeInput.showPassword = !syncCodeInput.showPassword
}
}
StatusButton {
anchors.verticalCenter: parent.verticalCenter
size: StatusBaseButton.Size.Tiny
enabled: !d.codeExpired
text: qsTr("Copy")
onClicked: {
const showPassword = syncCodeInput.showPassword
syncCodeInput.showPassword = true
syncCodeInput.textField.selectAll()
syncCodeInput.textField.copy()
syncCodeInput.textField.deselect()
syncCodeInput.showPassword = showPassword
}
}
}
}
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
horizontalAlignment: Text.AlignHCenter
visible: !d.codeExpired
font.pixelSize: 15
color: Theme.palette.baseColor1
text: qsTr("On your other device, navigate to the Syncing<br>screen and select Enter Sync Code.")
}
StatusBaseText {
Layout.fillWidth: true
Layout.fillHeight: true
horizontalAlignment: Text.AlignHCenter
visible: d.codeExpired
font.pixelSize: 15
color: Theme.palette.baseColor1
text: qsTr("Your QR and Sync Code has expired.")
}
}