Skip to content

Commit

Permalink
feat(Onboarding): Create Profile
Browse files Browse the repository at this point in the history
- implement the basic Onboarding UI skeleton and the Create Profile
flows
- adjust the PasswordView and EnterSeedPhrase views to the latest design
- add the main OnboardingLayout and StatusPinInput pages to Storybook

Fixes #16719
  • Loading branch information
caybro committed Nov 14, 2024
1 parent 331f234 commit 35e9ad5
Show file tree
Hide file tree
Showing 59 changed files with 2,292 additions and 120 deletions.
2 changes: 1 addition & 1 deletion libs/StatusQ/qml/Status/Core/StatusBaseText.qml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Status.Core.Theme
width: 240
text: qsTr("Hello World!")
font.pixelSize: 24
color: Theme.pallete.directColor1
color: Theme.palette.directColor1
}
\endqml
Expand Down
4 changes: 4 additions & 0 deletions storybook/pages/ColorsPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ SplitView {
enabled: searchField.searchText !== ""
onClicked: searchField.clear()
}
Label {
text: "INFO: Reload the page after selecting 'Dark mode'"
font.weight: Font.Medium
}
}

ColorFlow {
Expand Down
173 changes: 173 additions & 0 deletions storybook/pages/OnboardingLayoutPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15

import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1

import Models 1.0
import Storybook 1.0

import utils 1.0

import AppLayouts.Onboarding2 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: [
// initial
//Constants.startupState.keycardNoPCSCService,
Constants.startupState.keycardPluginReader,
Constants.startupState.keycardInsertKeycard,
Constants.startupState.keycardInsertedKeycard, Constants.startupState.keycardReadingKeycard,
// initial errors
Constants.startupState.keycardWrongKeycard, Constants.startupState.keycardNotKeycard,
Constants.startupState.keycardMaxPairingSlotsReached,
Constants.startupState.keycardLocked,
Constants.startupState.keycardNotEmpty,
// create keycard profile
Constants.startupState.keycardEmpty
]
}

OnboardingLayout {
id: onboarding
SplitView.fillWidth: true
SplitView.fillHeight: true
startupStore: OOBS.StartupStore {
property var currentStartupState: QtObject {
property string stateType: keycardMock.stateType
}

function getPasswordStrengthScore(password) {
return Math.min(password.length-1, 4)
}
function validMnemonic(mnemonic) {
return true
}
function getPin() {
return "" // FIXME make configurable
}
}
metricsStore: SharedStores.MetricsStore {
readonly property var d: QtObject {
id: d
property bool isCentralizedMetricsEnabled
}

function toggleCentralizedMetrics(enabled) {
d.isCentralizedMetricsEnabled = enabled
}

function addCentralizedMetricIfEnabled(eventName, eventValue = null) {}

readonly property bool isCentralizedMetricsEnabled : d.isCentralizedMetricsEnabled
}
splashScreenDurationMs: 3000

QtObject {
id: localAppSettings
property bool metricsPopupSeen
}

onFinished: (success, primaryPath, secondaryPath) => {
console.warn("!!! ONBOARDING FINISHED; success:", success, "; primary path:", primaryPath, "; secondary:", secondaryPath)
logs.logEvent("onFinished", ["success", "primaryPath", "secondaryPath"], arguments)

console.warn("!!! RESTARTING FLOW")
restartFlow()
ctrlKeycardState.currentIndex = 0
}
onKeycardFactoryResetRequested: {
logs.logEvent("onKeycardFactoryResetRequested")
console.warn("!!! FACTORY RESET; RESTARTING FLOW")
restartFlow()
ctrlKeycardState.currentIndex = 0
}
onKeycardReloaded: {
logs.logEvent("onKeycardReloaded")
ctrlKeycardState.currentIndex = 0
}
}

Connections {
target: Global
function onOpenLink(link: string) {
console.debug("Opening link in an external web browser:", link)
Qt.openUrlExternally(link)
}
function onOpenLinkWithConfirmation(link: string, domain: string) {
console.debug("Opening link in an external web browser:", link, domain)
Qt.openUrlExternally(link)
}
}

LogsAndControlsPanel {
id: logsAndControlsPanel

SplitView.minimumHeight: 150
SplitView.preferredHeight: 150

logsView.logText: logs.logText

RowLayout {
anchors.fill: parent
ColumnLayout {
Layout.fillWidth: true
Label {
text: "Current page: %1".arg(onboarding.stack.currentItem ? onboarding.stack.currentItem.title : "")
}
Label {
text: `Current path: ${onboarding.primaryPath} -> ${onboarding.secondaryPath}`
}
Label {
text: "Stack depth: %1".arg(onboarding.stack.depth)
}
}
Item { Layout.fillWidth: true }
Button {
text: "Restart"
focusPolicy: Qt.NoFocus
onClicked: onboarding.restartFlow()
}
Button {
text: "Copy password"
focusPolicy: Qt.NoFocus
onClicked: ClipboardUtils.setText("0123456789")
}
Button {
text: "Copy seedphrase"
focusPolicy: Qt.NoFocus
onClicked: ClipboardUtils.setText("dog dog dog dog dog dog dog dog dog dog dog dog")
}
ComboBox {
Layout.preferredWidth: 250
id: ctrlKeycardState
focusPolicy: Qt.NoFocus
model: keycardMock.keycardStates
}
}
}
}

// category: Onboarding
// status: good
// https://www.figma.com/design/Lw4nPYQcZOPOwTgETiiIYo/Desktop-Onboarding-Redesign?node-id=1-25&node-type=canvas&m=dev
41 changes: 41 additions & 0 deletions storybook/pages/StatusPinInputPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
import StatusQ.Core.Theme 0.1

Item {
id: root

ColumnLayout {
anchors.centerIn: parent
spacing: 16
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "ENTER NUMERIC PIN, EXPECTED LENGTH: %1".arg(pinInput.pinLen)
}
StatusPinInput {
Layout.alignment: Qt.AlignHCenter
id: pinInput
validator: StatusIntValidator { bottom: 0; top: 999999 }
Component.onCompleted: {
statesInitialization()
forceFocus()
}
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "ENTERED PIN: %1".arg(pinInput.pinInput || "[empty]")
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "VALID: %1".arg(pinInput.valid ? "true" : "false")
}
}
}

// category: Controls
// status: good
2 changes: 1 addition & 1 deletion storybook/stubs/shared/stores/BIP39_en.qml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ListModel {

Component.onCompleted: {
var englishWords = [
"apple", "banana", "cat", "cow", "catalog", "catch", "category", "cattle", "dog", "elephant", "fish", "grape", "horse", "ice cream", "jellyfish",
"age", "agent", "apple", "banana", "cat", "cow", "catalog", "catch", "category", "cattle", "dog", "elephant", "fish", "grape", "horse", "ice cream", "jellyfish",
"kiwi", "lemon", "mango", "nut", "orange", "pear", "quail", "rabbit", "strawberry", "turtle",
"umbrella", "violet", "watermelon", "xylophone", "yogurt", "zebra"
// Add more English words here...
Expand Down
3 changes: 3 additions & 0 deletions storybook/stubs/shared/stores/MetricsStore.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import QtQml 2.15

QtObject {}
1 change: 1 addition & 0 deletions storybook/stubs/shared/stores/qmldir
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ PermissionsStore 1.0 PermissionsStore.qml
ProfileStore 1.0 ProfileStore.qml
RootStore 1.0 RootStore.qml
UtilsStore 1.0 UtilsStore.qml
MetricsStore 1.0 MetricsStore.qml
3 changes: 1 addition & 2 deletions ui/StatusQ/src/StatusQ/Components/StatusImage.qml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import QtQuick 2.13
import QtQuick.Window 2.15
import QtQuick 2.15

/*!
\qmltype StatusImage
Expand Down
1 change: 1 addition & 0 deletions ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Loader {
objectName: "statusRoundImage"
width: parent.width
height: parent.height
radius: asset.bgRadius
image.source: root.asset.isImage ? root.asset.name : ""
showLoadingIndicator: true
border.width: root.asset.imgIsIdenticon ? 1 : 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ StatusProgressBar {
Default value: "So-so"
*/
property string labelSoso: qsTr("So-so")
property string labelSoso: qsTr("Okay")
/*!
\qmlproperty string StatusPasswordStrengthIndicator::labelGood
This property holds the text shown when the strength is StatusPasswordStrengthIndicator.Strength.Good.
Expand All @@ -88,7 +88,7 @@ StatusProgressBar {
Default value: "Great"
*/
property string labelGreat: qsTr("Great")
property string labelGreat: qsTr("Very strong")

enum Strength {
None, // 0
Expand Down
26 changes: 25 additions & 1 deletion ui/StatusQ/src/StatusQ/Controls/StatusPinInput.qml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Item {
property alias pinInput: inputText.text

/*!
\qmlproperty Validator StatusPinInput::validator
\qmlproperty StatusValidator StatusPinInput::validator
This property allows you to set a validator on the StatusPinInput. When a validator is set the StatusPinInput will only accept
input which leaves the pinInput property in an acceptable state.
Expand All @@ -59,6 +59,13 @@ Item {
*/
property alias validator: d.statusValidator

/*!
\qmlproperty bool StatusPinInput::pinInput
This property holds whether the entered PIN is valid; PIN is considered valid when it passes the internal validator
and its length matches that of @p pinLen
*/
readonly property bool valid: inputText.acceptableInput && inputText.length === pinLen

/*!
\qmlproperty int StatusPinInput::pinLen
This property allows you to set a specific pin input length. The default value is 6.
Expand Down Expand Up @@ -169,6 +176,23 @@ Item {
}
}

/*
\qmlmethod StatusPinInput::clearPin()
Sets the pin input to an empty string, setting state of each digit to "EMPTY", and stops the blinking animation
Doesn't change the current `pinLen`.
*/
function clearPin() {
inputText.text = ""
d.currentPinIndex = 0
d.deactivateBlink()
for (var i = 0; i < root.pinLen; i++) {
const currItem = repeater.itemAt(i)
currItem.innerState = "EMPTY"
}
}

implicitWidth: childrenRect.width
implicitHeight: childrenRect.height

Expand Down
7 changes: 4 additions & 3 deletions ui/StatusQ/src/StatusQ/Controls/StatusSeedPhraseInput.qml
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,10 @@ Item {
Component {
id: seedInputLeftComponent
StatusBaseText {
leftPadding: 4
rightPadding: 6
leftPadding: text.length == 1 ? 10 : 6
rightPadding: 4
text: root.leftComponentText
font.family: Theme.monoFont.name
color: seedWordInput.input.edit.activeFocus ?
Theme.palette.primaryColor1 : Theme.palette.baseColor1
}
Expand Down Expand Up @@ -197,7 +198,7 @@ Item {
id: suggListContainer
contentWidth: seedSuggestionsList.width
contentHeight: ((seedSuggestionsList.count <= 5) ? seedSuggestionsList.count : 5) *34
x: 16
x: 0
y: seedWordInput.height + 4
topPadding: 8
bottomPadding: 8
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import QtQuick 2.14
import QtQuick 2.15

import StatusQ.Controls 0.1

Expand Down
3 changes: 3 additions & 0 deletions ui/StatusQ/src/StatusQ/Core/Theme/StatusColors.qml
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,8 @@ QtObject {

'lightDesktopBlue10': '#ECEFFB',
'darkDesktopBlue10': '#273251',

// new/mobile colors
'neutral-95': '#0D1625'
}
}
24 changes: 24 additions & 0 deletions ui/StatusQ/src/StatusQ/Popups/StatusSimpleTextPopup.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import QtQuick 2.15
import QtQuick.Controls 2.15

import StatusQ.Core 0.1
import StatusQ.Popups.Dialog 0.1

StatusDialog {
width: 600
padding: 0
standardButtons: Dialog.Ok

property alias content: contentText

StatusScrollView {
id: scrollView
anchors.fill: parent
contentWidth: availableWidth
StatusBaseText {
id: contentText
width: scrollView.availableWidth
wrapMode: Text.Wrap
}
}
}
Loading

0 comments on commit 35e9ad5

Please sign in to comment.