status-desktop/ui/app/AppLayouts/Profile/popups/SetupSyncingPopup.qml
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

254 lines
6.9 KiB
QML

import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQml.Models 2.14
import QtQml.StateMachine 1.14 as DSM
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Utils 0.1
import utils 1.0
import shared.controls 1.0
import shared.views 1.0
import "setupsyncing" as Views
import "../stores"
StatusDialog {
id: root
property string password
property string keyUid
property DevicesStore devicesStore
property ProfileStore profileStore
width: 480
padding: 16
modal: true
title: qsTr("Sync a New Device")
QtObject {
id: d
signal generatingConnectionStringFailed
signal connectionStringGenerated
signal localPairingStarted
signal localPairingFailed
signal localPairingFinished
property string localPairingErrorMessage
property string connectionString
property string errorMessage
function generateConnectionString() {
d.connectionString = ""
d.errorMessage = ""
const result = root.devicesStore.getConnectionStringForBootstrappingAnotherDevice(root.keyUid, root.password)
try {
const json = JSON.parse(result)
d.errorMessage = json.error
} catch (e) {
d.connectionString = result
}
if (d.errorMessage !== "") {
d.generatingConnectionStringFailed()
return
}
displaySyncCodeView.secondsTimeout = 5 * 60 // This timeout should be moved to status-go.
displaySyncCodeView.start()
}
}
Connections {
target: root.devicesStore
function onLocalPairingStateChanged() {
switch (root.devicesStore.localPairingState) {
case Constants.LocalPairingState.WaitingForConnection:
break;
case Constants.LocalPairingState.Transferring:
d.localPairingStarted()
break
case Constants.LocalPairingState.Error:
d.localPairingFailed()
break
case Constants.LocalPairingState.Finished:
d.localPairingFinished()
break
}
}
}
DSM.StateMachine {
id: stateMachine
running: root.visible
initialState: displaySyncCodeState
DSM.State {
id: displaySyncCodeState
onEntered: {
d.generateConnectionString()
}
DSM.SignalTransition {
targetState: errorState
signal: d.generatingConnectionStringFailed
}
DSM.SignalTransition {
targetState: localPairingBaseState
signal: d.localPairingStarted
}
DSM.SignalTransition {
targetState: finalState
signal: nextButton.clicked
}
// Next 2 transitions are here temporarily.
// TODO: Remove when server notifies with ProcessSuccess/ProcessError event.
DSM.SignalTransition {
targetState: localPairingFailedState
signal: d.localPairingFailed
}
DSM.SignalTransition {
targetState: localPairingSuccessState
signal: d.localPairingFinished
}
}
DSM.State {
id: localPairingBaseState
initialState: localPairingInProgressState
DSM.State {
id: localPairingInProgressState
DSM.SignalTransition {
targetState: localPairingFailedState
signal: d.localPairingFailed
}
DSM.SignalTransition {
targetState: localPairingSuccessState
signal: d.localPairingFinished
}
}
DSM.State {
id: localPairingFailedState
DSM.SignalTransition {
targetState: finalState
signal: nextButton.clicked
}
}
DSM.State {
id: localPairingSuccessState
DSM.SignalTransition {
targetState: finalState
signal: nextButton.clicked
}
}
}
DSM.State {
id: errorState
DSM.SignalTransition {
targetState: finalState
signal: nextButton.clicked
}
}
DSM.FinalState {
id: finalState
onEntered: {
root.close()
}
}
}
contentItem: Item {
implicitWidth: Math.max(displaySyncCodeView.implicitWidth,
localPairingView.implicitWidth,
errorView.implicitWidth)
implicitHeight: Math.max(displaySyncCodeView.implicitHeight,
localPairingView.implicitHeight,
errorView.implicitHeight)
Views.DisplaySyncCode {
id: displaySyncCodeView
anchors.fill: parent
visible: displaySyncCodeState.active
connectionString: d.connectionString
secondsTimeout: 5 * 60
onRequestConnectionString: {
d.generateConnectionString()
}
}
DeviceSyncingView {
id: localPairingView
anchors.fill: parent
visible: localPairingBaseState.active
devicesModel: root.devicesStore.devicesModel
userDisplayName: root.profileStore.displayName
userPublicKey: root.profileStore.pubkey
userImage: root.profileStore.icon
localPairingState: root.devicesStore.localPairingState
localPairingError: root.devicesStore.localPairingError
}
Views.ErrorMessage {
id: errorView
anchors.fill: parent
visible: errorState.active
primaryText: qsTr("Failed to generate sync code")
secondaryText: d.errorMessage
}
}
footer: StatusDialogFooter {
rightButtons: ObjectModel {
StatusButton {
id: nextButton
visible: !!text
enabled: !localPairingInProgressState.active
text: {
if (displaySyncCodeState.active
|| localPairingInProgressState.active
|| localPairingSuccessState.active)
return qsTr("Done");
if (localPairingFailedState.active
|| errorState.active)
return qsTr("Close");
return ""
}
}
}
}
}