diff --git a/storybook/pages/OnboardingLayoutPage.qml b/storybook/pages/OnboardingLayoutPage.qml
new file mode 100644
index 00000000000..11bc2b40506
--- /dev/null
+++ b/storybook/pages/OnboardingLayoutPage.qml
@@ -0,0 +1,94 @@
+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 mainui 1.0
+import shared.stores 1.0 as SharedStores
+import AppLayouts.stores 1.0 as AppLayoutStores
+
+// compat
+import AppLayouts.Onboarding.stores 1.0 as OOBS
+
+SplitView {
+ id: root
+ orientation: Qt.Vertical
+
+ Logs { id: logs }
+
+ Popups {
+ popupParent: root
+ sharedRootStore: SharedStores.RootStore {}
+ rootStore: AppLayoutStores.RootStore {}
+ communityTokensStore: SharedStores.CommunityTokensStore {}
+ }
+
+ OnboardingLayout {
+ id: onboarding
+ SplitView.fillWidth: true
+ SplitView.fillHeight: true
+ startupStore: OOBS.StartupStore {
+ function getPasswordStrengthScore(password) {
+ return Math.min(password.length, 4)
+ }
+ }
+ 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
+ }
+
+ QtObject {
+ id: localAppSettings
+ property bool metricsPopupSeen
+ }
+ }
+
+ LogsAndControlsPanel {
+ id: logsAndControlsPanel
+
+ SplitView.minimumHeight: 100
+ SplitView.preferredHeight: 150
+
+ logsView.logText: logs.logText
+
+ ColumnLayout {
+ Label {
+ text: "Current page: %1".arg(onboarding.stack.currentItem ? onboarding.stack.currentItem.title : "")
+ }
+ Label {
+ text: "Current path: %1 -> %2".arg(onboarding.primaryPath).arg(onboarding.secondaryPath)
+ }
+ Label {
+ text: "Stack depth: %1".arg(onboarding.stack.depth)
+ }
+ }
+ }
+}
+
+// category: Onboarding
+// status: good
+// https://www.figma.com/design/Lw4nPYQcZOPOwTgETiiIYo/Desktop-Onboarding-Redesign?node-id=1-25&node-type=canvas&m=dev
diff --git a/storybook/stubs/shared/stores/MetricsStore.qml b/storybook/stubs/shared/stores/MetricsStore.qml
new file mode 100644
index 00000000000..2587cd419c7
--- /dev/null
+++ b/storybook/stubs/shared/stores/MetricsStore.qml
@@ -0,0 +1,3 @@
+import QtQml 2.15
+
+QtObject {}
diff --git a/storybook/stubs/shared/stores/qmldir b/storybook/stubs/shared/stores/qmldir
index d7a633428cd..b907b1108bc 100644
--- a/storybook/stubs/shared/stores/qmldir
+++ b/storybook/stubs/shared/stores/qmldir
@@ -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
diff --git a/ui/StatusQ/src/StatusQ/Components/StatusImage.qml b/ui/StatusQ/src/StatusQ/Components/StatusImage.qml
index 608414d4ab1..c2b1915c426 100644
--- a/ui/StatusQ/src/StatusQ/Components/StatusImage.qml
+++ b/ui/StatusQ/src/StatusQ/Components/StatusImage.qml
@@ -1,5 +1,4 @@
-import QtQuick 2.13
-import QtQuick.Window 2.15
+import QtQuick 2.15
/*!
\qmltype StatusImage
diff --git a/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml b/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml
index 90180869cad..1644ff7b13f 100644
--- a/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml
+++ b/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml
@@ -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
diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusPasswordStrengthIndicator.qml b/ui/StatusQ/src/StatusQ/Controls/StatusPasswordStrengthIndicator.qml
index d8c58f95e65..013de9caf7d 100644
--- a/ui/StatusQ/src/StatusQ/Controls/StatusPasswordStrengthIndicator.qml
+++ b/ui/StatusQ/src/StatusQ/Controls/StatusPasswordStrengthIndicator.qml
@@ -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.
@@ -88,7 +88,7 @@ StatusProgressBar {
Default value: "Great"
*/
- property string labelGreat: qsTr("Great")
+ property string labelGreat: qsTr("Very strong")
enum Strength {
None, // 0
diff --git a/ui/StatusQ/src/assets.qrc b/ui/StatusQ/src/assets.qrc
index 8f7d43516fa..31f192b249c 100644
--- a/ui/StatusQ/src/assets.qrc
+++ b/ui/StatusQ/src/assets.qrc
@@ -8339,6 +8339,11 @@
assets/png/onboarding/profile_fetching_in_progress.png
assets/png/onboarding/seed-phrase.png
assets/png/onboarding/welcome.png
+ assets/png/onboarding/status_totebag_artwork_1.png
+ assets/png/onboarding/status_generate_keys.png
+ assets/png/onboarding/create_profile_seed.png
+ assets/png/onboarding/create_profile_keycard.png
+ assets/png/onboarding/enable_biometrics.png
assets/png/onRampProviders/latamex.png
assets/png/onRampProviders/mercuryo.png
assets/png/onRampProviders/moonPay.png
diff --git a/ui/StatusQ/src/assets/png/onboarding/create_profile_keycard.png b/ui/StatusQ/src/assets/png/onboarding/create_profile_keycard.png
new file mode 100644
index 00000000000..673ecd60586
Binary files /dev/null and b/ui/StatusQ/src/assets/png/onboarding/create_profile_keycard.png differ
diff --git a/ui/StatusQ/src/assets/png/onboarding/create_profile_seed.png b/ui/StatusQ/src/assets/png/onboarding/create_profile_seed.png
new file mode 100644
index 00000000000..4756cd71092
Binary files /dev/null and b/ui/StatusQ/src/assets/png/onboarding/create_profile_seed.png differ
diff --git a/ui/StatusQ/src/assets/png/onboarding/enable_biometrics.png b/ui/StatusQ/src/assets/png/onboarding/enable_biometrics.png
new file mode 100644
index 00000000000..83538879b0f
Binary files /dev/null and b/ui/StatusQ/src/assets/png/onboarding/enable_biometrics.png differ
diff --git a/ui/StatusQ/src/assets/png/onboarding/status_generate_keys.png b/ui/StatusQ/src/assets/png/onboarding/status_generate_keys.png
new file mode 100644
index 00000000000..4c348579336
Binary files /dev/null and b/ui/StatusQ/src/assets/png/onboarding/status_generate_keys.png differ
diff --git a/ui/StatusQ/src/assets/png/onboarding/status_totebag_artwork_1.png b/ui/StatusQ/src/assets/png/onboarding/status_totebag_artwork_1.png
new file mode 100644
index 00000000000..ce8f1dd1d35
Binary files /dev/null and b/ui/StatusQ/src/assets/png/onboarding/status_totebag_artwork_1.png differ
diff --git a/ui/app/AppLayouts/Onboarding2/OnboardingLayout.qml b/ui/app/AppLayouts/Onboarding2/OnboardingLayout.qml
new file mode 100644
index 00000000000..1e880c523ec
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/OnboardingLayout.qml
@@ -0,0 +1,207 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+import StatusQ.Controls 0.1
+import StatusQ.Core.Theme 0.1
+
+import AppLayouts.Onboarding2.pages 1.0
+
+import shared.stores 1.0 as SharedStores
+import utils 1.0
+
+// compat
+import AppLayouts.Onboarding.stores 1.0 as OOBS
+
+Page {
+ id: root
+
+ property OOBS.StartupStore startupStore: OOBS.StartupStore {}
+ required property SharedStores.MetricsStore metricsStore
+
+ readonly property alias stack: stack
+ readonly property alias primaryPath: d.primaryPath
+ readonly property alias secondaryPath: d.secondaryPath
+
+ signal finished(bool success, int primaryPath, int secondaryPath)
+
+ QtObject {
+ id: d
+ // logic
+ property int primaryPath: OnboardingLayout.PrimaryPath.Unknown
+ property int secondaryPath: OnboardingLayout.SecondaryPath.Unknown
+
+ // UI
+ readonly property int opacityDuration: 50
+ readonly property int swipeDuration: 400
+
+ // state
+ property string password
+ property bool enableBiometrics
+ }
+
+ enum PrimaryPath {
+ Unknown,
+ CreateProfile,
+ Login
+ }
+
+ enum SecondaryPath {
+ Unknown,
+ CreateProfileWithPassword,
+ CreateProfileWithSeedphrase,
+ CreateProfileWithKeycard
+ // TODO secondary Login paths
+ }
+
+ // page stack
+ StackView {
+ id: stack
+ anchors.fill: parent
+ initialItem: welcomePage
+
+ pushEnter: Transition {
+ ParallelAnimation {
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 50; easing.type: Easing.InQuint }
+ NumberAnimation { property: "x"; from: (stack.mirrored ? -0.3 : 0.3) * stack.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+ }
+ pushExit: Transition {
+ NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 50; easing.type: Easing.OutQuint }
+ }
+ popEnter: Transition {
+ ParallelAnimation {
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 50; easing.type: Easing.InQuint }
+ NumberAnimation { property: "x"; from: (stack.mirrored ? -0.3 : 0.3) * -stack.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+ }
+ popExit: pushExit
+ replaceEnter: pushEnter
+ replaceExit: pushExit
+ }
+
+ // back button
+ StatusButton {
+ objectName: "onboardingBackButton"
+ isRoundIcon: true
+ width: 44
+ height: 44
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.padding
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: Theme.padding
+ icon.name: "arrow-left"
+ visible: stack.depth > 1 && !stack.busy
+ onClicked: stack.pop()
+ }
+
+ // main signal handler
+ Connections {
+ target: stack.currentItem
+ ignoreUnknownSignals: true
+
+ // welcome page
+ function onCreateProfileRequested() {
+ console.warn("!!! CREATE PROFILE")
+ d.primaryPath = OnboardingLayout.PrimaryPath.CreateProfile
+ stack.push(helpUsImproveStatusPage)
+ }
+ function onLoginRequested() {
+ console.warn("!!! LOG IN")
+ d.primaryPath = OnboardingLayout.PrimaryPath.Login
+ }
+
+ // help us improve page
+ function onShareUsageDataRequested() {
+ console.warn("!!! SHARE USAGE DATA")
+ metricsStore.toggleCentralizedMetrics(true)
+ Global.addCentralizedMetricIfEnabled("usage_data_shared", {placement: Constants.metricsEnablePlacement.onboarding})
+ localAppSettings.metricsPopupSeen = true
+
+ if (d.primaryPath === OnboardingLayout.PrimaryPath.CreateProfile)
+ stack.push(createProfilePage)
+ else if (d.primaryPath === OnboardingLayout.PrimaryPath.Login)
+ ; // TODO Login
+ }
+ function onDontShareUsageDataRequested() {
+ console.warn("!!! DONT SHARE USAGE DATA")
+ metricsStore.toggleCentralizedMetrics(false)
+ localAppSettings.metricsPopupSeen = true
+
+ if (d.primaryPath === OnboardingLayout.PrimaryPath.CreateProfile)
+ stack.push(createProfilePage)
+ else if (d.primaryPath === OnboardingLayout.PrimaryPath.Login)
+ ; // TODO Login
+ }
+
+ // create profile page
+ function onCreateProfileWithPasswordRequested() {
+ console.warn("!!! CREATE PROFILE WITH PASSWORD")
+ d.secondaryPath = OnboardingLayout.SecondaryPath.CreateProfileWithPassword
+ stack.push(createPasswordPage)
+ }
+ function onCreateProfileWithSeedphraseRequested() {
+ console.warn("!!! CREATE PROFILE WITH SEEDPHRASE")
+ d.secondaryPath = OnboardingLayout.SecondaryPath.CreateProfileWithSeedphrase
+ }
+ function onCreateProfileWithEmptyKeycardRequested() {
+ console.warn("!!! CREATE PROFILE WITH KEYCARD")
+ d.secondaryPath = OnboardingLayout.SecondaryPath.CreateProfileWithKeycard
+ }
+
+ // create password page
+ function onPasswordSetRequested(password: string) {
+ console.warn("!!! SET PASSWORD REQUESTED")
+ //root.startupStore.setPassword(password)
+ d.password = password
+
+ stack.push(enableBiometricsPage, {subtitle: qsTr("Use biometrics to fill in your password?")})
+ }
+
+ // enable biometrics page
+ function onEnableBiometricsRequested(enabled: bool) {
+ console.warn("!!! ENABLE BIOMETRICS:", enabled)
+ d.enableBiometrics = enabled
+ // TODO push final splash screen
+ }
+ }
+
+ Component {
+ id: welcomePage
+ WelcomePage {
+ StackView.onActivated: {
+ d.primaryPath = OnboardingLayout.PrimaryPath.Unknown
+ d.secondaryPath = OnboardingLayout.SecondaryPath.Unknown
+ d.password = ""
+ d.enableBiometrics = false
+ }
+ }
+ }
+
+ Component {
+ id: helpUsImproveStatusPage
+ HelpUsImproveStatusPage {}
+ }
+
+ Component {
+ id: createProfilePage
+ CreateProfilePage {}
+ }
+
+ Component {
+ id: createPasswordPage
+ CreatePasswordPage {
+ passwordStrengthScoreFunction: root.startupStore.getPasswordStrengthScore
+ StackView.onRemoved: {
+ d.secondaryPath = OnboardingLayout.SecondaryPath.Unknown
+ d.password = ""
+ }
+ }
+ }
+
+ Component {
+ id: enableBiometricsPage
+ EnableBiometricsPage {
+ StackView.onRemoved: d.enableBiometrics = false
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Onboarding2/pages/CreatePasswordPage.qml b/ui/app/AppLayouts/Onboarding2/pages/CreatePasswordPage.qml
new file mode 100644
index 00000000000..11984612c09
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/pages/CreatePasswordPage.qml
@@ -0,0 +1,98 @@
+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.Core.Theme 0.1
+import StatusQ.Popups.Dialog 0.1
+
+import utils 1.0
+import shared.views 1.0
+
+OnboardingPage {
+ id: root
+
+ property var passwordStrengthScoreFunction: (password) => { console.error("passwordStrengthScoreFunction: IMPLEMENT ME") }
+
+ signal passwordSetRequested(string password)
+
+ title: qsTr("Create profile password")
+
+ QtObject {
+ id: d
+
+ function submit() {
+ if (!passView.ready)
+ return
+ root.passwordSetRequested(passView.newPswText)
+ }
+ }
+
+ Component.onCompleted: passView.forceNewPswInputFocus()
+
+ contentItem: Item {
+ ColumnLayout {
+ spacing: Theme.padding
+ anchors.centerIn: parent
+ width: Math.min(400, root.availableWidth)
+
+ PasswordView {
+ id: passView
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignHCenter
+ highSizeIntro: true
+ title: root.title
+ introText: qsTr("This password can’t be recovered")
+ recoverText: ""
+ passwordStrengthScoreFunction: root.passwordStrengthScoreFunction
+ onReturnPressed: d.submit()
+ }
+ StatusButton {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Confirm password")
+ enabled: passView.ready
+ onClicked: d.submit()
+ }
+ }
+ }
+
+ StatusButton {
+ width: 32
+ height: 32
+ icon.width: 20
+ icon.height: 20
+ icon.color: Theme.palette.directColor1
+ normalColor: Theme.palette.baseColor2
+ padding: 0
+ anchors.right: parent.right
+ anchors.top: parent.top
+ icon.name: "info"
+ onClicked: passwordDetailsPopup.createObject(root).open()
+ }
+
+ Component {
+ id: passwordDetailsPopup
+ StatusDialog {
+ title: qsTr("Create profile password")
+ width: 480
+ padding: 0
+ standardButtons: Dialog.Ok
+ destroyOnClose: true
+ StatusScrollView {
+ id: detailsScrollView
+ anchors.fill: parent
+ contentWidth: availableWidth
+ StatusBaseText {
+ width: detailsScrollView.availableWidth
+ wrapMode: Text.Wrap
+ text: qsTr("Your Status keys are the foundation of your self-sovereign identity in Web3. You have complete control over these keys, which you can use to sign transactions, access your data, and interact with Web3 services.
+
+Your keys are always securely stored on your device and protected by your Status profile password. Status doesn't know your password and can't reset it for you. If you forget your password, you may lose access to your Status profile and wallet funds.
+
+Remember your password and don't share it with anyone.")
+ }
+ }
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Onboarding2/pages/CreateProfilePage.qml b/ui/app/AppLayouts/Onboarding2/pages/CreateProfilePage.qml
new file mode 100644
index 00000000000..defeff1347b
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/pages/CreateProfilePage.qml
@@ -0,0 +1,145 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+import StatusQ.Core 0.1
+import StatusQ.Components 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Popups 0.1
+
+import utils 1.0
+
+OnboardingPage {
+ id: root
+
+ title: qsTr("Create your profile")
+
+ signal createProfileWithPasswordRequested()
+ signal createProfileWithSeedphraseRequested()
+ signal createProfileWithEmptyKeycardRequested()
+
+ contentItem: Item {
+ ColumnLayout {
+ anchors.centerIn: parent
+ width: Math.min(380, root.availableWidth)
+ spacing: 20
+
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: root.title
+ font.pixelSize: 22
+ font.bold: true
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.topMargin: -12
+ text: qsTr("How would you like to start using Status?")
+ color: Theme.palette.baseColor1
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ Frame {
+ Layout.fillWidth: true
+ padding: Theme.bigPadding
+ background: Rectangle {
+ border.width: 1
+ border.color: Theme.palette.baseColor2
+ radius: 20
+ color: "transparent"
+ }
+ contentItem: ColumnLayout {
+ spacing: 20
+ StatusImage {
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: Math.min(268, parent.width)
+ Layout.preferredHeight: Math.min(164, height)
+ source: Theme.png("onboarding/status_generate_keys")
+ mipmap: true
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: qsTr("Start fresh")
+ font.pixelSize: Theme.secondaryAdditionalTextSize
+ font.bold: true
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.topMargin: -Theme.padding
+ text: qsTr("Create a new profile from scratch")
+ font.pixelSize: Theme.additionalTextSize
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ color: Theme.palette.baseColor1
+ }
+ StatusButton {
+ Layout.fillWidth: true
+ text: qsTr("Let’s go!")
+ font.pixelSize: Theme.additionalTextSize
+ onClicked: root.createProfileWithPasswordRequested()
+ }
+ }
+ }
+
+ Frame {
+ id: buttonFrame
+ Layout.fillWidth: true
+ padding: 1
+ background: Rectangle {
+ border.width: 1
+ border.color: Theme.palette.baseColor2
+ radius: 20
+ color: "transparent"
+ }
+ contentItem: ColumnLayout {
+ spacing: 0
+ ListItemButton {
+ title: qsTr("Create profile with a seed phrase")
+ subTitle: qsTr("If you already have an Ethereum wallet")
+ asset.name: Theme.png("onboarding/create_profile_seed")
+ onClicked: root.createProfileWithSeedphraseRequested()
+ }
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.leftMargin: -buttonFrame.padding
+ Layout.rightMargin: -buttonFrame.padding
+ Layout.preferredHeight: 1
+ color: Theme.palette.statusMenu.separatorColor
+ }
+ ListItemButton {
+ title: qsTr("Create profile with an empty Keycard")
+ subTitle: qsTr("Store your new profile keys on Keycard")
+ asset.name: Theme.png("onboarding/create_profile_keycard")
+ onClicked: root.createProfileWithEmptyKeycardRequested()
+ }
+ }
+ }
+ }
+ }
+
+ component ListItemButton: StatusListItem {
+ Layout.fillWidth: true
+ radius: 20
+ asset.width: 32
+ asset.height: 32
+ asset.bgRadius: 0
+ asset.bgColor: "transparent"
+ asset.isImage: true
+ statusListItemTitle.font.pixelSize: Theme.additionalTextSize
+ statusListItemTitle.font.weight: Font.Medium
+ statusListItemSubTitle.font.pixelSize: Theme.additionalTextSize
+ components: [
+ StatusIcon {
+ icon: "next"
+ width: 16
+ height: 16
+ color: Theme.palette.baseColor1
+ }
+ ]
+ }
+}
diff --git a/ui/app/AppLayouts/Onboarding2/pages/EnableBiometricsPage.qml b/ui/app/AppLayouts/Onboarding2/pages/EnableBiometricsPage.qml
new file mode 100644
index 00000000000..bc31e62e16d
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/pages/EnableBiometricsPage.qml
@@ -0,0 +1,65 @@
+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.Components 0.1
+import StatusQ.Core.Theme 0.1
+
+OnboardingPage {
+ id: root
+
+ title: qsTr("Enable biometrics")
+
+ property string subtitle
+
+ signal enableBiometricsRequested(bool enable)
+
+ contentItem: Item {
+ ColumnLayout {
+ anchors.centerIn: parent
+ spacing: 20
+ width: Math.min(400, root.availableWidth)
+
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: root.title
+ font.pixelSize: 22
+ font.bold: true
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.topMargin: -12
+ text: qsTr("Use biometrics to fill in your password?")
+ color: Theme.palette.baseColor1
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StatusImage {
+ Layout.preferredWidth: 260
+ Layout.preferredHeight: 260
+ Layout.topMargin: 20
+ Layout.bottomMargin: 20
+ Layout.alignment: Qt.AlignHCenter
+ mipmap: true
+ source: Theme.png("onboarding/enable_biometrics")
+ }
+
+ StatusButton {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Yes, use biometrics")
+ onClicked: root.enableBiometricsRequested(true)
+ }
+
+ StatusFlatButton {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Maybe later")
+ onClicked: root.enableBiometricsRequested(false)
+ }
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Onboarding2/pages/HelpUsImproveStatusPage.qml b/ui/app/AppLayouts/Onboarding2/pages/HelpUsImproveStatusPage.qml
new file mode 100644
index 00000000000..4279b33f99e
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/pages/HelpUsImproveStatusPage.qml
@@ -0,0 +1,158 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+import StatusQ.Core 0.1
+import StatusQ.Components 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Popups.Dialog 0.1
+
+import utils 1.0
+
+OnboardingPage {
+ id: root
+
+ title: qsTr("Help us improve Status")
+
+ signal shareUsageDataRequested()
+ signal dontShareUsageDataRequested()
+
+ contentItem: Item {
+ ColumnLayout {
+ anchors.centerIn: parent
+ width: Math.min(320, root.availableWidth)
+ spacing: root.padding
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: root.title
+ font.pixelSize: 22
+ font.bold: true
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: qsTr("Your usage data helps us make Status better")
+ color: Theme.palette.baseColor1
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StatusImage {
+ Layout.preferredWidth: 300
+ Layout.preferredHeight: 300
+ Layout.topMargin: 36
+ Layout.bottomMargin: 36
+ Layout.alignment: Qt.AlignHCenter
+ mipmap: true
+ source: Theme.png("onboarding/status_totebag_artwork_1")
+ }
+
+ StatusButton {
+ Layout.fillWidth: true
+ text: qsTr("Share usage data")
+ onClicked: root.shareUsageDataRequested()
+ }
+ StatusButton {
+ Layout.fillWidth: true
+ text: qsTr("Not now")
+ normalColor: "transparent"
+ borderWidth: 1
+ borderColor: Theme.palette.baseColor2
+ onClicked: root.dontShareUsageDataRequested()
+ }
+ StatusFlatButton {
+ Layout.fillWidth: true
+ text: qsTr("Learn more")
+ font.pixelSize: Theme.additionalTextSize
+ onClicked: helpUsImproveDetails.createObject(root).open()
+ }
+ }
+ }
+
+ Component {
+ id: helpUsImproveDetails
+ StatusDialog {
+ title: qsTr("Help us improve Status")
+ width: 480
+ standardButtons: Dialog.Ok
+ padding: 20
+ destroyOnClose: true
+ contentItem: ColumnLayout {
+ spacing: 20
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: qsTr("We’ll collect anonymous analytics and diagnostics from your app to enhance Status’s quality and performance.")
+ wrapMode: Text.WordWrap
+ }
+ Frame {
+ Layout.fillWidth: true
+ background: Rectangle {
+ border.width: 1
+ border.color: Theme.palette.baseColor2
+ radius: Theme.radius
+ color: "transparent"
+ }
+ ColumnLayout {
+ spacing: 12
+ BulletPoint {
+ text: qsTr("Gather basic usage data, like clicks and page views")
+ check: true
+ }
+ BulletPoint {
+ text: qsTr("Gather core diagnostics, like bandwidth usage")
+ check: true
+ }
+ BulletPoint {
+ text: qsTr("Never collect your profile information or wallet address")
+ }
+ BulletPoint {
+ text: qsTr("Never collect information you input or send")
+ }
+ BulletPoint {
+ text: qsTr("Never sell your usage analytics data")
+ }
+ }
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: qsTr("For more details and other cases where we handle your data, refer to our %1.")
+ .arg(Utils.getStyledLink(qsTr("Privacy Policy"), "#privacy", hoveredLink, Theme.palette.primaryColor1, Theme.palette.primaryColor1, false))
+ color: Theme.palette.baseColor1
+ font.pixelSize: Theme.additionalTextSize
+ wrapMode: Text.WordWrap
+ textFormat: Text.RichText
+ onLinkActivated: {
+ if (link == "#privacy") {
+ close()
+ Global.privacyPolicyRequested()
+ }
+ }
+ HoverHandler {
+ // Qt CSS doesn't support custom cursor shape
+ cursorShape: !!parent.hoveredLink ? Qt.PointingHandCursor : undefined
+ }
+ }
+ }
+ }
+ }
+
+ component BulletPoint: RowLayout {
+ property string text
+ property bool check
+
+ spacing: 6
+ StatusIcon {
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ icon: parent.check ? "check-circle" : "close-circle"
+ color: parent.check ? Theme.palette.successColor1 : Theme.palette.dangerColor1
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: parent.text
+ font.pixelSize: Theme.additionalTextSize
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Onboarding2/pages/OnboardingPage.qml b/ui/app/AppLayouts/Onboarding2/pages/OnboardingPage.qml
new file mode 100644
index 00000000000..fcae29c920c
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/pages/OnboardingPage.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+import StatusQ.Core.Theme 0.1
+
+Page {
+ implicitWidth: 1200
+ implicitHeight: 700
+
+ padding: 12
+
+ background: Rectangle {
+ color: Theme.palette.background
+ }
+}
diff --git a/ui/app/AppLayouts/Onboarding2/pages/WelcomePage.qml b/ui/app/AppLayouts/Onboarding2/pages/WelcomePage.qml
new file mode 100644
index 00000000000..bcfaf58747d
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/pages/WelcomePage.qml
@@ -0,0 +1,256 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtGraphicalEffects 1.15
+import QtQuick.Layouts 1.15
+
+import StatusQ.Core 0.1
+import StatusQ.Components 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Core.Theme 0.1
+
+import utils 1.0
+
+OnboardingPage {
+ id: root
+
+ title: qsTr("Welcome to Status")
+
+ signal createProfileRequested()
+ signal loginRequested()
+
+ QtObject {
+ id: d
+ readonly property ListModel newsModel: ListModel {
+ ListElement {
+ primary: qsTr("Own your crypto")
+ secondary: qsTr("Use the leading multi-chain self-custodial wallet")
+ }
+ ListElement {
+ primary: qsTr("Store your assets on Keycard")
+ secondary: qsTr("Your secure card-shaped hardware Wallet")
+ }
+ ListElement {
+ primary: qsTr("Chat privately with friends")
+ secondary: qsTr("With full metadata privacy and e2e encryption")
+ }
+ ListElement {
+ primary: qsTr("Discover web3")
+ secondary: qsTr("Explore and interact with the decentralised web")
+ }
+ }
+ }
+
+ contentItem: RowLayout {
+ spacing: root.padding
+
+ // left part (welcome + buttons)
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.topMargin: -headerText.height
+
+ ColumnLayout {
+ width: Math.min(400, parent.width)
+ spacing: 18
+ anchors.centerIn: parent
+
+ StatusImage {
+ Layout.preferredWidth: 90
+ Layout.preferredHeight: 90
+ Layout.alignment: Qt.AlignHCenter
+ source: Theme.png("status-logo-icon")
+ mipmap: true
+ layer.enabled: true
+ layer.effect: DropShadow {
+ horizontalOffset: 0
+ verticalOffset: 4
+ radius: 12
+ samples: 25
+ spread: 0.2
+ color: Theme.palette.dropShadow
+ }
+ }
+
+ StatusBaseText {
+ id: headerText
+ Layout.fillWidth: true
+ text: root.title
+ font.pixelSize: 40
+ font.bold: true
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: qsTr("The open-source, decentralised wallet and messenger")
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ ColumnLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 48 - root.padding
+ width: Math.min(320, parent.width)
+ spacing: 12
+
+ StatusButton {
+ Layout.fillWidth: true
+ text: qsTr("Create profile")
+ onClicked: root.createProfileRequested()
+ }
+ StatusButton {
+ Layout.fillWidth: true
+ text: qsTr("Log in")
+ onClicked: root.loginRequested()
+ normalColor: "transparent"
+ borderWidth: 1
+ borderColor: Theme.palette.baseColor2
+ }
+ StatusBaseText {
+ Layout.fillWidth: true
+ Layout.topMargin: Theme.halfPadding
+ text: qsTr("By proceeding you accept Status
%1 and %2")
+ .arg(Utils.getStyledLink(qsTr("Terms of Use"), "#terms", hoveredLink, Theme.palette.primaryColor1, Theme.palette.primaryColor1, false))
+ .arg(Utils.getStyledLink(qsTr("Privacy Policy"), "#privacy", hoveredLink, Theme.palette.primaryColor1, Theme.palette.primaryColor1, false))
+ textFormat: Text.RichText
+ font.pixelSize: Theme.tertiaryTextFontSize
+ lineHeightMode: Text.FixedHeight
+ lineHeight: 16
+ wrapMode: Text.WordWrap
+ color: Theme.palette.baseColor1
+ horizontalAlignment: Text.AlignHCenter
+ onLinkActivated: {
+ if (link == "#terms")
+ Global.termsOfUseRequested()
+ else if (link == "#privacy")
+ Global.privacyPolicyRequested()
+ }
+
+ HoverHandler {
+ // Qt CSS doesn't support custom cursor shape
+ cursorShape: !!parent.hoveredLink ? Qt.PointingHandCursor : undefined
+ }
+ }
+ }
+ }
+
+
+ // right part (news carousel)
+ // TODO factor out to a separate component?
+ Control {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ background: Rectangle {
+ color: "#0D1625" // FIXME not in Palette
+ radius: 20
+ }
+
+ contentItem: Item {
+ id: newsPage
+ readonly property string primaryText: d.newsModel.get(pageIndicator.currentIndex).primary
+ readonly property string secondaryText: d.newsModel.get(pageIndicator.currentIndex).secondary
+
+ Rectangle { // FIXME placeholder
+ anchors.centerIn: parent
+ width: parent.width / 3 * 2
+ height: width
+ radius: width/2
+ color: Theme.palette.dangerColor1
+ }
+
+ ColumnLayout {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 48 - root.padding
+ width: Math.min(300, parent.width)
+ spacing: 4
+
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: newsPage.primaryText
+ horizontalAlignment: Text.AlignHCenter
+ font.weight: Font.DemiBold
+ color: Theme.palette.white
+ }
+
+ StatusBaseText {
+ Layout.fillWidth: true
+ text: newsPage.secondaryText
+ horizontalAlignment: Text.AlignHCenter
+ font.pixelSize: Theme.additionalTextSize
+ color: Theme.palette.white
+ wrapMode: Text.WordWrap
+ }
+
+ PageIndicator {
+ Layout.alignment: Qt.AlignHCenter
+ Layout.topMargin: Theme.halfPadding
+ id: pageIndicator
+ interactive: true
+ count: d.newsModel.count
+ currentIndex: -1
+ Component.onCompleted: currentIndex = 0 // start switching pages
+
+ function switchToNextOrFirstPage() {
+ if (currentIndex < count - 1)
+ currentIndex++
+ else
+ currentIndex = 0
+ }
+
+ delegate: Control {
+ id: pageIndicatorDelegate
+ implicitWidth: 44
+ implicitHeight: 8
+
+ readonly property bool isCurrentPage: index === pageIndicator.currentIndex
+ onIsCurrentPageChanged: {
+ if (isCurrentPage)
+ indicatorWidth = pageIndicatorDelegate.availableWidth
+ else
+ indicatorWidth = 0
+ }
+
+ property real indicatorWidth: 0
+ Behavior on indicatorWidth {
+ NumberAnimation { duration: pageTimer.interval }
+ }
+
+ Timer {
+ id: pageTimer
+ running: pageIndicatorDelegate.isCurrentPage
+ repeat: true
+ interval: 2000
+ onTriggered: {
+ pageIndicator.switchToNextOrFirstPage()
+
+ pageIndicatorDelegate.indicatorWidth = 0 // reset width
+ }
+ }
+
+ background: Rectangle {
+ color: Qt.rgba(1, 1, 1, 0.1)
+ radius: 4
+ HoverHandler {
+ cursorShape: hovered ? Qt.PointingHandCursor : undefined
+ }
+ }
+ contentItem: Item {
+ Rectangle {
+ width: pageIndicatorDelegate.indicatorWidth
+ height: parent.height
+ color: pageIndicatorDelegate.isCurrentPage ? Theme.palette.white : "transparent"
+ radius: 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/app/AppLayouts/Onboarding2/pages/qmldir b/ui/app/AppLayouts/Onboarding2/pages/qmldir
new file mode 100644
index 00000000000..b2fe30ff64c
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/pages/qmldir
@@ -0,0 +1,5 @@
+WelcomePage 1.0 WelcomePage.qml
+HelpUsImproveStatusPage 1.0 HelpUsImproveStatusPage.qml
+CreateProfilePage 1.0 CreateProfilePage.qml
+CreatePasswordPage 1.0 CreatePasswordPage.qml
+EnableBiometricsPage 1.0 EnableBiometricsPage.qml
diff --git a/ui/app/AppLayouts/Onboarding2/qmldir b/ui/app/AppLayouts/Onboarding2/qmldir
new file mode 100644
index 00000000000..ac7c41394ab
--- /dev/null
+++ b/ui/app/AppLayouts/Onboarding2/qmldir
@@ -0,0 +1 @@
+OnboardingLayout 1.0 OnboardingLayout.qml
diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml
index d0a2cb14bf9..65f34653bdf 100644
--- a/ui/app/mainui/Popups.qml
+++ b/ui/app/mainui/Popups.qml
@@ -103,6 +103,7 @@ QtObject {
Global.openSwapModalRequested.connect(openSwapModal)
Global.openBuyCryptoModalRequested.connect(openBuyCryptoModal)
Global.privacyPolicyRequested.connect(() => openPopup(privacyPolicyPopupComponent))
+ Global.termsOfUseRequested.connect(() => openPopup(termsOfUsePopupComponent))
}
property var currentPopup
@@ -1240,6 +1241,28 @@ QtObject {
standardButtons: Dialog.Ok
destroyOnClose: true
}
+ },
+ Component {
+ id: termsOfUsePopupComponent
+ StatusDialog {
+ width: 600
+ padding: 0
+ title: qsTr("Status Software Terms of Use")
+ StatusScrollView {
+ id: termsOfUseDialogScrollView
+ anchors.fill: parent
+ contentWidth: availableWidth
+ StatusBaseText {
+ width: termsOfUseDialogScrollView.availableWidth
+ wrapMode: Text.Wrap
+ textFormat: Text.MarkdownText
+ text: SQUtils.StringUtils.readTextFile(":/imports/assets/docs/terms-of-use.mdwn")
+ onLinkActivated: Global.openLinkWithConfirmation(link, SQUtils.StringUtils.extractDomainFromLink(link))
+ }
+ }
+ standardButtons: Dialog.Ok
+ destroyOnClose: true
+ }
}
]
}
diff --git a/ui/imports/shared/views/PasswordView.qml b/ui/imports/shared/views/PasswordView.qml
index ed5fc8b8758..ca50e64fd8f 100644
--- a/ui/imports/shared/views/PasswordView.qml
+++ b/ui/imports/shared/views/PasswordView.qml
@@ -79,11 +79,6 @@ ColumnLayout {
QtObject {
id: d
- property bool containsLower: false
- property bool containsUpper: false
- property bool containsNumbers: false
- property bool containsSymbols: false
-
readonly property var validatorRegexp: /^[!-~]+$/
readonly property string validatorErrMessage: qsTr("Only ASCII letters, numbers, and symbols are allowed")
readonly property string passTooLongErrMessage: qsTr("Maximum %n character(s)", "", Constants.maxPasswordLength)
@@ -244,7 +239,7 @@ ColumnLayout {
Layout.alignment: root.contentAlignment
StatusBaseText {
- text: qsTr("New password")
+ text: qsTr("Choose password")
}
StatusPasswordInput {
@@ -255,7 +250,7 @@ ColumnLayout {
Layout.alignment: root.contentAlignment
Layout.fillWidth: true
- placeholderText: qsTr("Enter new password")
+ placeholderText: qsTr("Type password")
echoMode: showPassword ? TextInput.Normal : TextInput.Password
rightPadding: showHideNewIcon.width + showHideNewIcon.anchors.rightMargin + Theme.padding / 2
@@ -265,11 +260,6 @@ ColumnLayout {
// Update strength indicator:
strengthInditactor.strength = d.convertStrength(root.passwordStrengthScoreFunction(newPswInput.text))
- d.containsLower = d.lowerCaseValidator(text)
- d.containsUpper = d.upperCaseValidator(text)
- d.containsNumbers = d.numbersValidator(text)
- d.containsSymbols = d.symbolsValidator(text)
-
if(!d.validateCharacterSet(text)) return
if (text.length === confirmPswInput.text.length) {
@@ -292,87 +282,11 @@ ColumnLayout {
onClicked: newPswInput.showPassword = !newPswInput.showPassword
}
}
-
- StatusPasswordStrengthIndicator {
- id: strengthInditactor
- Layout.fillWidth: true
- value: Math.min(Constants.minPasswordLength, newPswInput.text.length)
- from: 0
- to: Constants.minPasswordLength
- labelVeryWeak: qsTr("Very weak")
- labelWeak: qsTr("Weak")
- labelSoso: qsTr("So-so")
- labelGood: qsTr("Good")
- labelGreat: qsTr("Great")
- }
- }
-
- Rectangle {
- Layout.fillWidth: true
- Layout.minimumHeight: 80
- border.color: Theme.palette.baseColor2
- border.width: 1
- color: "transparent"
- radius: Theme.radius
- implicitHeight: strengthColumn.implicitHeight
- implicitWidth: strengthColumn.implicitWidth
-
- ColumnLayout {
- id: strengthColumn
- anchors.fill: parent
- anchors.margins: Theme.padding
- anchors.verticalCenter: parent.verticalCenter
- spacing: Theme.padding
-
- StatusBaseText {
- id: strengthenTxt
- Layout.fillHeight: true
- Layout.alignment: Qt.AlignHCenter
- wrapMode: Text.WordWrap
- text: root.strengthenText
- font.pixelSize: 12
- color: Theme.palette.baseColor1
- clip: true
- }
-
- RowLayout {
- spacing: Theme.padding
- Layout.alignment: Qt.AlignHCenter
-
- StatusBaseText {
- id: lowerCaseTxt
- text: "• " + qsTr("Lower case")
- font.pixelSize: 12
- color: d.containsLower ? Theme.palette.successColor1 : Theme.palette.baseColor1
- }
-
- StatusBaseText {
- id: upperCaseTxt
- text: "• " + qsTr("Upper case")
- font.pixelSize: 12
- color: d.containsUpper ? Theme.palette.successColor1 : Theme.palette.baseColor1
- }
-
- StatusBaseText {
- id: numbersTxt
- text: "• " + qsTr("Numbers")
- font.pixelSize: 12
- color: d.containsNumbers ? Theme.palette.successColor1 : Theme.palette.baseColor1
- }
-
- StatusBaseText {
- id: symbolsTxt
- text: "• " + qsTr("Symbols")
- font.pixelSize: 12
- color: d.containsSymbols ? Theme.palette.successColor1 : Theme.palette.baseColor1
- }
- }
- }
}
ColumnLayout {
StatusBaseText {
- text: qsTr("Confirm new password")
+ text: qsTr("Repeat password")
}
StatusPasswordInput {
@@ -384,7 +298,7 @@ ColumnLayout {
z: root.zFront
Layout.fillWidth: true
Layout.alignment: root.contentAlignment
- placeholderText: qsTr("Enter new password")
+ placeholderText: qsTr("Type password")
echoMode: showPassword ? TextInput.Normal : TextInput.Password
rightPadding: showHideConfirmIcon.width + showHideConfirmIcon.anchors.rightMargin + Theme.padding / 2
@@ -427,11 +341,53 @@ ColumnLayout {
}
}
+ StatusPasswordStrengthIndicator {
+ id: strengthInditactor
+ Layout.fillWidth: true
+ value: Math.min(Constants.minPasswordLength, newPswInput.text.length)
+ from: 0
+ to: Constants.minPasswordLength
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Theme.padding
+ Layout.alignment: Qt.AlignHCenter
+
+ PassIncludesIndicator {
+ caption: qsTr("Lower case")
+ checked: d.lowerCaseValidator(newPswInput.text)
+ }
+
+ PassIncludesIndicator {
+ caption: qsTr("Upper case")
+ checked: d.upperCaseValidator(newPswInput.text)
+ }
+
+ PassIncludesIndicator {
+ caption: qsTr("Numbers")
+ checked: d.numbersValidator(newPswInput.text)
+ }
+
+ PassIncludesIndicator {
+ caption: qsTr("Symbols")
+ checked: d.symbolsValidator(newPswInput.text)
+ }
+ }
+
StatusBaseText {
id: errorTxt
Layout.alignment: root.contentAlignment
- Layout.fillHeight: true
- font.pixelSize: 12
+ font.pixelSize: Theme.tertiaryTextFontSize
color: Theme.palette.dangerColor1
}
+
+ component PassIncludesIndicator: StatusBaseText {
+ property bool checked
+ property string caption
+
+ text: "%1 %2".arg(checked ? "✓" : "+").arg(caption)
+ font.pixelSize: Theme.tertiaryTextFontSize
+ color: checked ? Theme.palette.successColor1 : Theme.palette.baseColor1
+ }
}
diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml
index 9f04a462b26..4b22c5ce12f 100644
--- a/ui/imports/utils/Constants.qml
+++ b/ui/imports/utils/Constants.qml
@@ -1346,6 +1346,7 @@ QtObject {
readonly property string welcome: "welcome_view"
readonly property string privacyAndSecurity: "privacy_and_security_view"
readonly property string startApp: "start_app_after_upgrade"
+ readonly property string onboarding: "onboarding"
}
enum MutingVariations {
diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml
index d5111d97b68..dbfc7838ca5 100644
--- a/ui/imports/utils/Global.qml
+++ b/ui/imports/utils/Global.qml
@@ -91,6 +91,7 @@ QtObject {
signal openTestnetPopup()
signal privacyPolicyRequested()
+ signal termsOfUseRequested()
// Swap
signal openSwapModalRequested(var formDataParams)
diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml
index 9609442a8c7..f212a7a14c0 100644
--- a/ui/imports/utils/Utils.qml
+++ b/ui/imports/utils/Utils.qml
@@ -78,11 +78,11 @@ QtObject {
`${link}`
}
- function getStyledLink(linkText, linkUrl, hoveredLink, textColor = Theme.palette.directColor1, linkColor = Theme.palette.primaryColor1) {
+ function getStyledLink(linkText, linkUrl, hoveredLink, textColor = Theme.palette.directColor1, linkColor = Theme.palette.primaryColor1, underlineLink = true) {
return `` +