From e505b500d99c83d37683e27c81fc631ef1bbee5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Tinkl?= Date: Mon, 6 Jan 2025 18:11:49 +0100 Subject: [PATCH] feat(LoginWithKeycardFlow): implement "Unlock with recovery phrase" - instead of the factory reset when the keycard is locked --- .../Onboarding2/LoginWithKeycardFlow.qml | 32 +++++++++++++++++++ .../AppLayouts/Onboarding2/OnboardingFlow.qml | 6 ++++ .../pages/KeycardCreatePinPage.qml | 3 +- .../Onboarding2/pages/KeycardEnterPinPage.qml | 19 ++++++++--- .../Onboarding2/pages/KeycardIntroPage.qml | 18 +++++++++-- .../Onboarding2/pages/SeedphrasePage.qml | 2 ++ 6 files changed, 73 insertions(+), 7 deletions(-) diff --git a/ui/app/AppLayouts/Onboarding2/LoginWithKeycardFlow.qml b/ui/app/AppLayouts/Onboarding2/LoginWithKeycardFlow.qml index 16dbc82c4d4..94c71c3ea97 100644 --- a/ui/app/AppLayouts/Onboarding2/LoginWithKeycardFlow.qml +++ b/ui/app/AppLayouts/Onboarding2/LoginWithKeycardFlow.qml @@ -14,10 +14,13 @@ SQUtils.QObject { required property int keycardState required property var tryToSetPinFunction required property int remainingAttempts + required property var isSeedPhraseValid property bool displayKeycardPromoBanner signal keycardPinEntered(string pin) + signal keycardPinCreated(string pin) + signal seedphraseSubmitted(string seedphrase) signal reloadKeycardRequested signal keycardFactoryResetRequested signal createProfileWithEmptyKeycardRequested @@ -53,9 +56,11 @@ SQUtils.QObject { KeycardIntroPage { keycardState: root.keycardState displayPromoBanner: root.displayKeycardPromoBanner + unlockUsingSeedphrase: true onReloadKeycardRequested: d.reload() onKeycardFactoryResetRequested: root.keycardFactoryResetRequested() + onUnlockWithSeedphraseRequested: root.stackView.push(seedphrasePage) onEmptyKeycardDetected: root.stackView.replace(keycardEmptyPage) onNotEmptyKeycardDetected: root.stackView.replace(keycardEnterPinPage) } @@ -78,6 +83,7 @@ SQUtils.QObject { KeycardEnterPinPage { tryToSetPinFunction: root.tryToSetPinFunction remainingAttempts: root.remainingAttempts + unlockUsingSeedphrase: true onKeycardPinEntered: { root.keycardPinEntered(pin) @@ -86,6 +92,32 @@ SQUtils.QObject { onReloadKeycardRequested: d.reload() onKeycardFactoryResetRequested: root.keycardFactoryResetRequested() + onUnlockWithSeedphraseRequested: root.stackView.push(seedphrasePage) + } + } + + Component { + id: seedphrasePage + + SeedphrasePage { + title: qsTr("Unlock Keycard using the recovery phrase") + btnContinueText: qsTr("Unlock") + isSeedPhraseValid: root.isSeedPhraseValid + onSeedphraseSubmitted: (seedphrase) => { + root.seedphraseSubmitted(seedphrase) + root.stackView.push(keycardCreatePinPage) + } + } + } + + Component { + id: keycardCreatePinPage + + KeycardCreatePinPage { + onKeycardPinCreated: { + root.keycardPinCreated(pin) + root.finished() + } } } } diff --git a/ui/app/AppLayouts/Onboarding2/OnboardingFlow.qml b/ui/app/AppLayouts/Onboarding2/OnboardingFlow.qml index 8115310a793..c850432cac9 100644 --- a/ui/app/AppLayouts/Onboarding2/OnboardingFlow.qml +++ b/ui/app/AppLayouts/Onboarding2/OnboardingFlow.qml @@ -37,6 +37,7 @@ SQUtils.QObject { signal seedphraseSubmitted(string seedphrase) signal setPasswordRequested(string password) signal reloadKeycardRequested + signal keycardFactoryResetRequested signal finished(int flow) @@ -162,6 +163,7 @@ SQUtils.QObject { splashScreenDurationMs: root.splashScreenDurationMs onReloadKeycardRequested: root.reloadKeycardRequested() + onKeycardFactoryResetRequested: root.keycardFactoryResetRequested() onKeycardPinCreated: (pin) => root.keycardPinCreated(pin) onLoginWithKeycardRequested: loginWithKeycardFlow.init() @@ -214,10 +216,14 @@ SQUtils.QObject { remainingAttempts: root.remainingAttempts displayKeycardPromoBanner: root.displayKeycardPromoBanner tryToSetPinFunction: root.tryToSetPinFunction + isSeedPhraseValid: root.isSeedPhraseValid onKeycardPinEntered: (pin) => root.keycardPinEntered(pin) + onKeycardPinCreated: (pin) => root.keycardPinCreated(pin) + onSeedphraseSubmitted: (seedphrase) => root.seedphraseSubmitted(seedphrase) onReloadKeycardRequested: root.reloadKeycardRequested() onCreateProfileWithEmptyKeycardRequested: keycardCreateProfileFlow.init() + onKeycardFactoryResetRequested: root.keycardFactoryResetRequested() onFinished: { d.flow = Onboarding.SecondaryFlow.LoginWithKeycard diff --git a/ui/app/AppLayouts/Onboarding2/pages/KeycardCreatePinPage.qml b/ui/app/AppLayouts/Onboarding2/pages/KeycardCreatePinPage.qml index acc9b5f670a..d3c96c749de 100644 --- a/ui/app/AppLayouts/Onboarding2/pages/KeycardCreatePinPage.qml +++ b/ui/app/AppLayouts/Onboarding2/pages/KeycardCreatePinPage.qml @@ -7,6 +7,7 @@ import StatusQ.Components 0.1 import StatusQ.Controls 0.1 import StatusQ.Controls.Validators 0.1 import StatusQ.Core.Theme 0.1 +import StatusQ.Core.Backpressure 0.1 import AppLayouts.Onboarding2.controls 1.0 @@ -103,7 +104,7 @@ KeycardBasePage { StateChangeScript { script: { pinInput.setPin(d.pin) - root.keycardPinCreated(d.pin) + Backpressure.debounce(root, 2000, () => root.keycardPinCreated(d.pin))() } } }, diff --git a/ui/app/AppLayouts/Onboarding2/pages/KeycardEnterPinPage.qml b/ui/app/AppLayouts/Onboarding2/pages/KeycardEnterPinPage.qml index 3004a1cdc2f..21b02a328d9 100644 --- a/ui/app/AppLayouts/Onboarding2/pages/KeycardEnterPinPage.qml +++ b/ui/app/AppLayouts/Onboarding2/pages/KeycardEnterPinPage.qml @@ -17,9 +17,11 @@ KeycardBasePage { property var tryToSetPinFunction: (pin) => { console.error("tryToSetPinFunction: IMPLEMENT ME"); return false } required property int remainingAttempts + property bool unlockUsingSeedphrase signal keycardPinEntered(string pin) signal reloadKeycardRequested() + signal unlockWithSeedphraseRequested() signal keycardFactoryResetRequested() pageClassName: "KeycardEnterPinPage" @@ -63,6 +65,13 @@ KeycardBasePage { text: qsTr("Factory reset Keycard") onClicked: root.keycardFactoryResetRequested() }, + StatusButton { + id: btnUnlockWithSeedphrase + visible: false + text: qsTr("Unlock with recovery phrase") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: root.unlockWithSeedphraseRequested() + }, StatusButton { id: btnReload width: 320 @@ -96,7 +105,11 @@ KeycardBasePage { } PropertyChanges { target: btnFactoryReset - visible: true + visible: !root.unlockUsingSeedphrase + } + PropertyChanges { + target: btnUnlockWithSeedphrase + visible: root.unlockUsingSeedphrase } PropertyChanges { target: btnReload @@ -135,9 +148,7 @@ KeycardBasePage { } StateChangeScript { script: { - Backpressure.debounce(root, 2000, function() { - root.keycardPinEntered(pinInput.pinInput) - })() + Backpressure.debounce(root, 2000, () => root.keycardPinEntered(pinInput.pinInput))() } } }, diff --git a/ui/app/AppLayouts/Onboarding2/pages/KeycardIntroPage.qml b/ui/app/AppLayouts/Onboarding2/pages/KeycardIntroPage.qml index e61866a718d..3c88cda3848 100644 --- a/ui/app/AppLayouts/Onboarding2/pages/KeycardIntroPage.qml +++ b/ui/app/AppLayouts/Onboarding2/pages/KeycardIntroPage.qml @@ -17,8 +17,10 @@ KeycardBasePage { required property int keycardState // cf Onboarding.KeycardState property bool displayPromoBanner + property bool unlockUsingSeedphrase signal keycardFactoryResetRequested() + signal unlockWithSeedphraseRequested() signal reloadKeycardRequested() signal emptyKeycardDetected() signal notEmptyKeycardDetected() @@ -87,6 +89,13 @@ KeycardBasePage { anchors.horizontalCenter: parent.horizontalCenter onClicked: root.keycardFactoryResetRequested() }, + MaybeOutlineButton { + id: btnUnlockWithSeedphrase + visible: false + text: qsTr("Unlock with recovery phrase") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: root.unlockWithSeedphraseRequested() + }, MaybeOutlineButton { id: btnReload visible: false @@ -190,12 +199,17 @@ KeycardBasePage { PropertyChanges { target: root title: "".arg(Theme.palette.dangerColor1) + qsTr("Keycard locked") + "" - subtitle: qsTr("The Keycard you have inserted is locked, you will need to factory reset it or insert a different one") + subtitle: root.unlockUsingSeedphrase ? qsTr("The Keycard you have inserted is locked, you will need to unlock it using the recovery phrase or insert a different one") + : qsTr("The Keycard you have inserted is locked, you will need to factory reset it or insert a different one") image.source: Theme.png("onboarding/keycard/error") } PropertyChanges { target: btnFactoryReset - visible: true + visible: !root.unlockUsingSeedphrase + } + PropertyChanges { + target: btnUnlockWithSeedphrase + visible: root.unlockUsingSeedphrase } PropertyChanges { target: btnReload diff --git a/ui/app/AppLayouts/Onboarding2/pages/SeedphrasePage.qml b/ui/app/AppLayouts/Onboarding2/pages/SeedphrasePage.qml index b79e842bcfa..b410da57e23 100644 --- a/ui/app/AppLayouts/Onboarding2/pages/SeedphrasePage.qml +++ b/ui/app/AppLayouts/Onboarding2/pages/SeedphrasePage.qml @@ -14,6 +14,7 @@ OnboardingPage { title: qsTr("Create profile using a recovery phrase") property string subtitle: qsTr("Enter your 12, 18 or 24 word recovery phrase") + property alias btnContinueText: btnContinue.text property var isSeedPhraseValid: (mnemonic) => { console.error("isSeedPhraseValid IMPLEMENT ME"); return false } @@ -53,6 +54,7 @@ OnboardingPage { } StatusButton { + id: btnContinue objectName: "btnContinue" Layout.alignment: Qt.AlignHCenter Layout.topMargin: -Theme.halfPadding