Skip to content

Commit

Permalink
feat(OnboardingStore): introduce a new OnboardingStore
Browse files Browse the repository at this point in the history
- serves as a contract between the QML UI and NIM middleware
- removed the old PrivacyStore and StartupStore usage from the new
onboarding
- actual enumerators done in C++ to reduce code duplication between the
real store and an empty mock one, also should be reusable from NIM and
separate SB pages w/o having to access the full OnboardingStore
- fixup and adjusts the tests and separate SB pages too
- fixes to the collecting of the seedphrase
  • Loading branch information
caybro committed Dec 9, 2024
1 parent f821715 commit fef86b4
Show file tree
Hide file tree
Showing 18 changed files with 377 additions and 298 deletions.
3 changes: 0 additions & 3 deletions storybook/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ file(GLOB_RECURSE STORYBOOK_QML_FILES "stubs/*.qml" "mocks/*.qml" "pages/*.qml"
"src/*.qml" "src/qmldir")

file(GLOB_RECURSE TEST_QML_FILES "qmlTests/*.qml")
if (Qt5Core_VERSION VERSION_LESS_EQUAL 5.15.2)
list(FILTER TEST_QML_FILES EXCLUDE REGEX "tst_OnboardingLayout.qml$")
endif()

set(PROJECT_LIB "${PROJECT_NAME}Lib")

Expand Down
9 changes: 5 additions & 4 deletions storybook/pages/KeycardAddKeyPairPagePage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import QtQuick.Controls 2.15
import StatusQ.Core.Backpressure 0.1

import AppLayouts.Onboarding2.pages 1.0
import AppLayouts.Onboarding.enums 1.0

Item {
id: root

KeycardAddKeyPairPage {
id: progressPage
anchors.fill: parent
addKeyPairState: KeycardAddKeyPairPage.AddKeyPairState.InProgress
addKeyPairState: Onboarding.AddKeyPairState.InProgress
timeoutInterval: 5000
onKeypairAddTryAgainRequested: {
console.warn("!!! onKeypairAddTryAgainRequested")
addKeyPairState = KeycardAddKeyPairPage.AddKeyPairState.InProgress
addKeyPairState = Onboarding.AddKeyPairState.InProgress
Backpressure.debounce(root, 2000, function() {
console.warn("!!! SIMULATION: SUCCESS")
addKeyPairState = KeycardAddKeyPairPage.AddKeyPairState.Success
addKeyPairState = Onboarding.AddKeyPairState.Success
})()
}
onKeypairAddContinueRequested: console.warn("!!! onKeypairAddContinueRequested")
Expand All @@ -31,7 +32,7 @@ Item {
anchors.right: parent.right
anchors.bottom: parent.bottom
width: 350
model: ["KeycardAddKeyPairPage.AddKeyPairState.InProgress", "KeycardAddKeyPairPage.AddKeyPairState.Success", "KeycardAddKeyPairPage.AddKeyPairState.Failed"]
model: ["Onboarding.AddKeyPairState.InProgress", "Onboarding.AddKeyPairState.Success", "Onboarding.AddKeyPairState.Failed"]
onCurrentIndexChanged: progressPage.addKeyPairState = currentIndex
}
}
Expand Down
38 changes: 18 additions & 20 deletions storybook/pages/KeycardIntroPagePage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

import AppLayouts.Onboarding2.pages 1.0

import utils 1.0
import AppLayouts.Onboarding.enums 1.0

Item {
id: root
Expand All @@ -14,8 +13,8 @@ Item {
anchors.fill: parent
sourceComponent: {
switch (ctrlKeycardState.currentValue) {
case Constants.startupState.keycardEmpty: return emptyPage
case Constants.startupState.keycardNotEmpty: return notEmptyPage
case Onboarding.KeycardState.Empty: return emptyPage
case Onboarding.KeycardState.NotEmpty: return notEmptyPage
default: introPage
}
}
Expand All @@ -31,13 +30,15 @@ Item {
onReloadKeycardRequested: console.warn("!!! RELOAD REQUESTED")
onOpenLink: Qt.openUrlExternally(link)
onOpenLinkWithConfirmation: Qt.openUrlExternally(link)
onKeycardFactoryResetRequested: console.warn("!!! FACTORY RESET")
}
}

Component {
id: emptyPage
KeycardEmptyPage {
onCreateProfileWithEmptyKeycardRequested: console.warn("!!! CREATE NEW PROFILE")
onReloadKeycardRequested: console.warn("!!! RELOAD REQUESTED")
}
}

Expand All @@ -58,7 +59,7 @@ Item {
id: ctrlDisplayPromo
text: "Promo banner"
checked: true
visible: ctrlKeycardState.currentValue === Constants.startupState.keycardPluginReader
visible: ctrlKeycardState.currentValue === Onboarding.KeycardState.InsertKeycard
}
ToolButton {
text: "<"
Expand All @@ -69,22 +70,19 @@ Item {

focusPolicy: Qt.NoFocus
Layout.preferredWidth: 250
textRole: "text"
valueRole: "value"
model: [
// initial
Constants.startupState.keycardNoPCSCService,
Constants.startupState.keycardPluginReader,
Constants.startupState.keycardInsertKeycard,
Constants.startupState.keycardInsertedKeycard,
Constants.startupState.keycardReadingKeycard,
Constants.startupState.keycardRecognizedKeycard,
// initial errors
Constants.startupState.keycardWrongKeycard,
Constants.startupState.keycardNotKeycard,
Constants.startupState.keycardMaxPairingSlotsReached,
Constants.startupState.keycardLocked,
// exit states
Constants.startupState.keycardNotEmpty,
Constants.startupState.keycardEmpty
{ value: Onboarding.KeycardState.NoPCSCService, text: "NoPCSCService" },
{ value: Onboarding.KeycardState.PluginReader, text: "PluginReader" },
{ value: Onboarding.KeycardState.InsertKeycard, text: "InsertKeycard" },
{ value: Onboarding.KeycardState.ReadingKeycard, text: "ReadingKeycard" },
{ value: Onboarding.KeycardState.WrongKeycard, text: "WrongKeycard" },
{ value: Onboarding.KeycardState.NotKeycard, text: "NotKeycard" },
{ value: Onboarding.KeycardState.MaxPairingSlotsReached, text: "MaxPairingSlotsReached" },
{ value: Onboarding.KeycardState.Locked, text: "Locked" },
{ value: Onboarding.KeycardState.NotEmpty, text: "NotEmpty" },
{ value: Onboarding.KeycardState.Empty, text: "Empty" }
]
}
ToolButton {
Expand Down
134 changes: 67 additions & 67 deletions storybook/pages/OnboardingLayoutPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -16,83 +16,88 @@ import Storybook 1.0
import utils 1.0

import AppLayouts.Onboarding2 1.0
import AppLayouts.Profile.stores 1.0 as ProfileStores
import AppLayouts.Onboarding2.stores 1.0
import AppLayouts.Onboarding.enums 1.0

import shared.panels 1.0
import shared.stores 1.0 as SharedStores

// compat
import AppLayouts.Onboarding.stores 1.0 as OOBS

SplitView {
id: root
orientation: Qt.Vertical

Logs { id: logs }

QtObject {
id: keycardMock
property string stateType: ctrlKeycardState.currentValue

readonly property var keycardStates: [ // FIXME replace with proper/separate enums for the intro/pin pages
// initial
Constants.startupState.keycardNoPCSCService,
Constants.startupState.keycardPluginReader,
Constants.startupState.keycardInsertKeycard,
Constants.startupState.keycardInsertedKeycard,
Constants.startupState.keycardReadingKeycard,
Constants.startupState.keycardRecognizedKeycard,
// initial errors
Constants.startupState.keycardWrongKeycard,
Constants.startupState.keycardNotKeycard,
Constants.startupState.keycardMaxPairingSlotsReached,
Constants.startupState.keycardLocked,
// exit states
Constants.startupState.keycardNotEmpty,
Constants.startupState.keycardEmpty
]

id: mockDriver
readonly property string mnemonic: "dog dog dog dog dog dog dog dog dog dog dog dog"
readonly property var seedWords: ["apple", "banana", "cat", "cow", "catalog", "catch", "category", "cattle", "dog", "elephant", "fish", "grape"]

// TODO simulation
function restart() {
// add keypair state
// sync state
}
}

OnboardingLayout {
id: onboarding
SplitView.fillWidth: true
SplitView.fillHeight: true
startupStore: OOBS.StartupStore {
readonly property var currentStartupState: QtObject {
property string stateType: keycardMock.stateType // Constants.startupState.keycardXXX
onboardingStore: OnboardingStore {
readonly property int keycardState: ctrlKeycardState.currentValue // enum Onboarding.KeycardState
readonly property int keycardRemainingPinAttempts: 5

// FIXME REMOVE !!!
function getPin() {
logs.logEvent("OnboardingStore.getPin()")
return ctrlPin.text
}

function getPasswordStrengthScore(password) {
logs.logEvent("StartupStore.getPasswordStrengthScore", ["password"], arguments)
function setPin(pin: string) { // -> bool
logs.logEvent("OnboardingStore.setPin", ["pin"], arguments)
return true
}

readonly property int addKeyPairState: Onboarding.AddKeyPairState.InProgress // enum Onboarding.AddKeyPairState
function startKeypairTransfer() { // -> void
logs.logEvent("OnboardingStore.startKeypairTransfer")
}

// password
function getPasswordStrengthScore(password: string) { // -> int
logs.logEvent("OnboardingStore.getPasswordStrengthScore", ["password"], arguments)
return Math.min(password.length-1, 4)
}
function validMnemonic(mnemonic) {
logs.logEvent("StartupStore.validMnemonic", ["mnemonic"], arguments)
return mnemonic === keycardMock.mnemonic

// seedphrase/mnemonic
function validMnemonic(mnemonic: string) { // -> bool
logs.logEvent("OnboardingStore.validMnemonic", ["mnemonic"], arguments)
return mnemonic === mockDriver.mnemonic
}
function getPin() { // FIXME refactor to a hasPin(); there's no way to extract the PIN from the Keycard once written
logs.logEvent("StartupStore.getPin()")
return ctrlPin.text
function getMnemonic() { // -> string
logs.logEvent("OnboardingStore.getMnemonic()")
return mockDriver.seedWords.join(" ")
}
function mnemonicWasShown() { // -> void
console.warn("!!! MNEMONIC SHOWN")
logs.logEvent("OnboardingStore.mnemonicWasShown()")
}
function getSeedPhrase() {
logs.logEvent("StartupStore.getSeedPhrase()")
// FIXME needed? cf getMnemonic()
function removeMnemonic() { // -> void
console.warn("!!! REMOVE MNEMONIC")
logs.logEvent("OnboardingStore.removeMnemonic()")
}

function validateLocalPairingConnectionString(connectionString) {
logs.logEvent("StartupStore.validateLocalPairingConnectionString", ["connectionString"], arguments)
readonly property int syncState: Onboarding.SyncState.InProgress // enum Onboarding.SyncState
function validateLocalPairingConnectionString(connectionString: string) { // -> bool
logs.logEvent("OnboardingStore.validateLocalPairingConnectionString", ["connectionString"], arguments)
return !Number.isNaN(parseInt(connectionString))
}
function setConnectionString(connectionString) {
logs.logEvent("StartupStore.setConnectionString", ["connectionString"], arguments)
}

readonly property var startupModuleInst: QtObject {
property int remainingAttempts: 5
function setConnectionString(connectionString: string) { // -> void
logs.logEvent("OnboardingStore.setConnectionString", ["connectionString"], arguments)
}
}

metricsStore: SharedStores.MetricsStore {
readonly property var d: QtObject {
id: d
Expand All @@ -107,24 +112,6 @@ SplitView {

readonly property bool isCentralizedMetricsEnabled : d.isCentralizedMetricsEnabled
}
privacyStore: ProfileStores.PrivacyStore {
readonly property var words: ["apple", "banana", "cat", "cow", "catalog", "catch", "category", "cattle", "dog", "elephant", "fish", "grape"]

function getMnemonic() {
logs.logEvent("PrivacyStore.getMnemonic()")
return words.join(" ")
}

function mnemonicWasShown() {
console.warn("!!! MNEMONIC SHOWN")
logs.logEvent("PrivacyStore.mnemonicWasShown()")
}

function removeMnemonic() {
console.warn("!!! REMOVE MNEMONIC")
logs.logEvent("PrivacyStore.removeMnemonic()")
}
}

splashScreenDurationMs: 3000
biometricsAvailable: ctrlBiometrics.checked
Expand Down Expand Up @@ -226,7 +213,7 @@ SplitView {
Button {
text: "Copy seedphrase"
focusPolicy: Qt.NoFocus
onClicked: ClipboardUtils.setText(keycardMock.mnemonic)
onClicked: ClipboardUtils.setText(mockDriver.mnemonic)
}
Button {
text: "Copy PIN (\"%1\")".arg(ctrlPin.text)
Expand Down Expand Up @@ -256,7 +243,20 @@ SplitView {
Layout.preferredWidth: 300
id: ctrlKeycardState
focusPolicy: Qt.NoFocus
model: keycardMock.keycardStates
textRole: "text"
valueRole: "value"
model: [
{ value: Onboarding.KeycardState.NoPCSCService, text: "NoPCSCService" },
{ value: Onboarding.KeycardState.PluginReader, text: "PluginReader" },
{ value: Onboarding.KeycardState.InsertKeycard, text: "InsertKeycard" },
{ value: Onboarding.KeycardState.ReadingKeycard, text: "ReadingKeycard" },
{ value: Onboarding.KeycardState.WrongKeycard, text: "WrongKeycard" },
{ value: Onboarding.KeycardState.NotKeycard, text: "NotKeycard" },
{ value: Onboarding.KeycardState.MaxPairingSlotsReached, text: "MaxPairingSlotsReached" },
{ value: Onboarding.KeycardState.Locked, text: "Locked" },
{ value: Onboarding.KeycardState.NotEmpty, text: "NotEmpty" },
{ value: Onboarding.KeycardState.Empty, text: "Empty" }
]
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions storybook/pages/SyncProgressPagePage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import QtQuick.Controls 2.15
import StatusQ.Core.Backpressure 0.1

import AppLayouts.Onboarding2.pages 1.0
import AppLayouts.Onboarding.enums 1.0

Item {
id: root

SyncProgressPage {
id: progressPage
anchors.fill: parent
syncState: SyncProgressPage.SyncState.InProgress
syncState: Onboarding.SyncState.InProgress
timeoutInterval: 5000
onRestartSyncRequested: {
console.warn("!!! RESTART SYNC REQUESTED")
syncState = SyncProgressPage.SyncState.InProgress
syncState = Onboarding.SyncState.InProgress
Backpressure.debounce(root, 2000, function() {
console.warn("!!! SIMULATION: SUCCESS")
syncState = SyncProgressPage.SyncState.Success
syncState = Onboarding.SyncState.Success
})()
}
onLoginToAppRequested: console.warn("!!! LOGIN TO APP REQUESTED")
Expand All @@ -30,7 +31,7 @@ Item {
anchors.right: parent.right
anchors.bottom: parent.bottom
width: 300
model: ["SyncProgressPage.SyncState.InProgress", "SyncProgressPage.SyncState.Success", "SyncProgressPage.SyncState.Failed"]
model: ["Onboarding.SyncState.InProgress", "Onboarding.SyncState.Success", "Onboarding.SyncState.Failed"]
onCurrentIndexChanged: progressPage.syncState = currentIndex
}
}
Expand Down
Loading

0 comments on commit fef86b4

Please sign in to comment.