feat(onboarding): Remove color and username steps (#21715)

* Remove password disclaimer, update copy and simplify implementation

* Remove non-existing wallet event

* Skip profile configuration for the "create profile" onboarding flow

* Include flow for new profiles when another profile already exists

* Add explanation about temp username

* Point 20 to a constant

* Simplify create profile password screen

* Fix password creation screen jump on mount

* e2e: updated tests

* Completely remove the "create profile" onboarding screen

* e2e: updated tests with recovering user

---------

Co-authored-by: Yevheniia Berdnyk <ie.berdnyk@gmail.com>
This commit is contained in:
Ulises Manuel 2024-12-09 13:55:47 -06:00 committed by GitHub
parent c26d298573
commit e85bc539d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 306 additions and 567 deletions

View File

@ -61,14 +61,17 @@
(defn view (defn view
[{:keys [header footer customization-color footer-container-padding header-container-style [{:keys [header footer customization-color footer-container-padding header-container-style
content-container-style gradient-cover? keyboard-should-persist-taps shell-overlay? content-container-style gradient-cover? keyboard-should-persist-taps shell-overlay?
blur-options content-avoid-keyboard? automatically-adjust-keyboard-insets] blur-options content-avoid-keyboard? automatically-adjust-keyboard-insets
;; Note: Provide `initial-header-height` to avoid a jump due to the on-layout 1-frame
;; delay. Revisit this on RN 0.76 since the on-layout delay has been fixed.
initial-header-height]
:or {footer-container-padding (safe-area/get-top)}} :or {footer-container-padding (safe-area/get-top)}}
& children] & children]
(reagent/with-let [scroll-view-ref (atom nil) (reagent/with-let [scroll-view-ref (atom nil)
set-scroll-ref #(reset! scroll-view-ref %) set-scroll-ref #(reset! scroll-view-ref %)
window-height (:height (rn/get-window)) window-height (:height (rn/get-window))
footer-container-height (reagent/atom 0) footer-container-height (reagent/atom 0)
header-height (reagent/atom 0) header-height (reagent/atom nil)
content-container-height (reagent/atom 0) content-container-height (reagent/atom 0)
content-scroll-y (reagent/atom 0) content-scroll-y (reagent/atom 0)
keyboard-height (reagent/atom 0) keyboard-height (reagent/atom 0)
@ -112,7 +115,7 @@
{:style {:style
(if content-avoid-keyboard? (if content-avoid-keyboard?
(style/content-keyboard-avoiding-view (style/content-keyboard-avoiding-view
{:top @header-height {:top (or @header-height initial-header-height)
:bottom (if keyboard-shown? :bottom (if keyboard-shown?
@footer-container-height @footer-container-height
(+ bottom-safe-area @footer-container-height))}) (+ bottom-safe-area @footer-container-height))})

View File

@ -28,9 +28,10 @@
:long-enough? :long-enough?
:short-enough?))))) :short-enough?)))))
(def password-tip? (set constants/password-tips))
(defn strength (defn strength
[validations] [validations]
(->> (select-keys validations constants/password-tips) (->> validations
(vals) (filter #(and (password-tip? (key %)) (val %)))
(filter true?) (count)))
count))

View File

@ -52,8 +52,8 @@
{:eventName "navigation" {:eventName "navigation"
:platform platform-os :platform platform-os
:appVersion app-version :appVersion app-version
:eventValue {:viewId "onboarding.create-profile-info"}}}] :eventValue {:viewId "onboarding.create-profile-password"}}}]
(tracking/track-view-id-event :screen/onboarding.create-profile))) (tracking/track-view-id-event :screen/onboarding.create-profile-password)))
(is (= [] (tracking/track-view-id-event :unknown-stack))))) (is (= [] (tracking/track-view-id-event :unknown-stack)))))
(deftest tracked-event-test (deftest tracked-event-test

View File

@ -1,6 +1,7 @@
(ns status-im.contexts.onboarding.create-password.style (ns status-im.contexts.onboarding.create-password.style
(:require (:require
[quo.foundations.colors :as colors])) [quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(def heading {:margin-bottom 20}) (def heading {:margin-bottom 20})
(def heading-subtitle {:color colors/white}) (def heading-subtitle {:color colors/white})
@ -21,6 +22,18 @@
:padding-top 12 :padding-top 12
:padding-horizontal 20}) :padding-horizontal 20})
(def disclaimer-container {:padding-horizontal 20})
(def footer-container {:padding-bottom 12}) (def footer-container {:padding-bottom 12})
(def footer-button-container {:margin-top 20 :padding-horizontal 20}) (def footer-button-container {:margin-top 20 :padding-horizontal 20})
(def blur-options
{:blur-amount 34
:blur-radius 20
:blur-type :transparent
:overlay-color :transparent
:background-color (if platform/android?
colors/neutral-100
colors/neutral-80-opa-1-blur)
:padding-vertical 0
:padding-horizontal 0})
(def page-nav-height 56)

View File

@ -1,9 +1,7 @@
(ns status-im.contexts.onboarding.create-password.view (ns status-im.contexts.onboarding.create-password.view
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[status-im.common.floating-button-page.view :as floating-button] [status-im.common.floating-button-page.view :as floating-button]
[status-im.common.password-with-hint.view :as password-with-hint] [status-im.common.password-with-hint.view :as password-with-hint]
@ -29,22 +27,37 @@
(i18n/label :t/password-creation-subtitle)]]) (i18n/label :t/password-creation-subtitle)]])
(defn password-inputs (defn password-inputs
[{:keys [passwords-match? on-change-password on-change-repeat-password on-input-focus [{:keys [set-password set-repeat-password same-password-length? same-passwords?
password-long-enough? password-short-enough? empty-password? show-password-validation? password-long-enough? password-short-enough? non-empty-password?]}]
on-blur-repeat-password]}] (let [[show-validation?
(let [hint-1-status (if password-long-enough? :success :default) set-show-validation?] (rn/use-state false)
hint-2-status (if passwords-match? :success :error) on-change-password (rn/use-callback
hint-2-text (if passwords-match? (fn [new-value]
(i18n/label :t/password-creation-match) (set-password new-value)
(i18n/label :t/password-creation-dont-match)) (when same-password-length?
error? (and show-password-validation? (set-show-validation? true)))
(not passwords-match?) [same-password-length?])
(not empty-password?))] on-change-repeat-password (rn/use-callback
(fn [new-value]
(set-repeat-password new-value)
(when same-password-length?
(set-show-validation? true)))
[same-password-length?])
on-blur-repeat-password (rn/use-callback
#(set-show-validation? non-empty-password?)
[non-empty-password?])
hint-1-status (if password-long-enough? :success :default)
hint-2-status (if same-passwords? :success :error)
hint-2-text (if same-passwords?
(i18n/label :t/password-creation-match)
(i18n/label :t/password-creation-dont-match))
error? (and show-validation?
(not same-passwords?)
non-empty-password?)]
[:<> [:<>
[password-with-hint/view [password-with-hint/view
{:hint (if (not password-short-enough?) {:hint (if (not password-short-enough?)
{:text (i18n/label {:text (i18n/label :t/password-creation-max-length-hint)
:t/password-creation-max-length-hint)
:status :error :status :error
:shown? true} :shown? true}
{:text (i18n/label :t/password-creation-hint) {:text (i18n/label :t/password-creation-hint)
@ -52,55 +65,50 @@
:shown? true}) :shown? true})
:placeholder (i18n/label :t/password-creation-placeholder-1) :placeholder (i18n/label :t/password-creation-placeholder-1)
:on-change-text on-change-password :on-change-text on-change-password
:on-focus on-input-focus
:auto-focus true}] :auto-focus true}]
[rn/view {:style style/space-between-inputs}] [rn/view {:style style/space-between-inputs}]
[password-with-hint/view [password-with-hint/view
{:hint {:text hint-2-text {:hint {:text hint-2-text
:status hint-2-status :status hint-2-status
:shown? (and (not empty-password?) :shown? (and non-empty-password? show-validation?)}
show-password-validation?)}
:error? error? :error? error?
:placeholder (i18n/label :t/password-creation-placeholder-2) :placeholder (i18n/label :t/password-creation-placeholder-2)
:on-change-text on-change-repeat-password :on-change-text on-change-repeat-password
:on-focus on-input-focus
:on-blur on-blur-repeat-password}]])) :on-blur on-blur-repeat-password}]]))
(defn help (defn help
[{{:keys [lower-case? upper-case? numbers? symbols?]} :validations [{:keys [lower-case? upper-case? numbers? symbols?] :as validations}]
password-strength :password-strength}] (let [password-strength (constants/strength-status (password/strength validations) :info)]
[rn/view [rn/view
[quo/strength-divider {:type (constants/strength-status password-strength :info)} [quo/strength-divider {:type password-strength}
(i18n/label :t/password-creation-tips-title)] (i18n/label :t/password-creation-tips-title)]
[rn/view {:style style/password-tips} [rn/view {:style style/password-tips}
[quo/tips {:completed? lower-case?} [quo/tips {:completed? lower-case?}
(i18n/label :t/password-creation-tips-1)] (i18n/label :t/password-creation-tips-1)]
[quo/tips {:completed? upper-case?} [quo/tips {:completed? upper-case?}
(i18n/label :t/password-creation-tips-2)] (i18n/label :t/password-creation-tips-2)]
[quo/tips {:completed? numbers?} [quo/tips {:completed? numbers?}
(i18n/label :t/password-creation-tips-3)] (i18n/label :t/password-creation-tips-3)]
[quo/tips {:completed? symbols?} [quo/tips {:completed? symbols?}
(i18n/label :t/password-creation-tips-4)]]]) (i18n/label :t/password-creation-tips-4)]]]))
(defn- use-password-checks (defn- use-password-checks
[password] [password]
(rn/use-memo (rn/use-memo
(fn [] (fn []
(let [{:keys [long-enough? short-enough?] (-> password
:as validations} (password/validate password)] (password/validate)
{:password-long-enough? long-enough? (assoc :non-empty? (seq password))))
:password-short-enough? short-enough?
:password-validations validations
:password-strength (password/strength validations)
:empty-password? (empty? password)}))
[password])) [password]))
(defn- use-repeat-password-checks (defn- use-repeat-password-checks
[password repeat-password] [password repeat-password]
(rn/use-memo (rn/use-memo
(fn [] (fn []
{:same-password-length? (and (seq password) (= (count password) (count repeat-password))) {:same-password-length? (and (seq password)
:same-passwords? (and (seq password) (= password repeat-password))}) (= (count password) (count repeat-password)))
:same-passwords? (and (seq password)
(= password repeat-password))})
[password repeat-password])) [password repeat-password]))
(defn create-password-doc (defn create-password-doc
@ -119,102 +127,70 @@
{:content create-password-doc {:content create-password-doc
:shell? true}])) :shell? true}]))
(defn- navigate-back (defn- navigate-back [] (rf/dispatch [:navigate-back]))
[]
(rf/dispatch [:navigate-back]))
(defn- page-nav (defn- page-nav
[] [top]
(let [{:keys [top]} (safe-area/get-insets)] [quo/page-nav
[quo/page-nav {:margin-top top
{:margin-top top :background :blur
:background :blur :icon-name :i/arrow-left
:icon-name :i/arrow-left :on-press navigate-back
:on-press navigate-back :right-side [{:icon-name :i/info
:right-side [{:icon-name :i/info :on-press on-press-info}]}])
:on-press on-press-info}]}]))
(defn- help-and-confirm-button
[{:keys [password-validations same-passwords? on-submit]}]
(let [{customization-color :color} (rf/sub [:onboarding/profile])
all-requirements-met? (and (:non-empty? password-validations)
(:long-enough? password-validations)
(:short-enough? password-validations)
same-passwords?)]
[rn/view {:style style/footer-container}
[help password-validations]
[quo/button
{:container-style style/footer-button-container
:disabled? (not all-requirements-met?)
:customization-color customization-color
:on-press on-submit}
(i18n/label :t/password-creation-confirm)]]))
(defn- on-confirm-password
[password]
(rf/dispatch [:onboarding/password-set (security/mask-data password)]))
(defn create-password (defn create-password
[] []
(let [[password set-password] (rn/use-state "") (let [[password set-password] (rn/use-state "")
[repeat-password set-repeat-password] (rn/use-state "") [repeat-password
[accepts-disclaimer? set-accepts-disclaimer?] (rn/use-state false) set-repeat-password] (rn/use-state "")
[focused-input set-focused-input] (rn/use-state nil) {:keys [long-enough? short-enough? non-empty?]
[show-password-validation? :as password-validations} (use-password-checks password)
set-show-password-validation?] (rn/use-state false) {:keys [same-password-length?
{user-color :color} (rf/sub [:onboarding/profile]) same-passwords?]} (use-repeat-password-checks password repeat-password)
on-submit (rn/use-callback
#(on-confirm-password password)
{:keys [password-long-enough? [password])
password-short-enough? top (safe-area/get-top)]
password-validations password-strength
empty-password?]} (use-password-checks password)
{:keys [same-password-length? same-passwords?]} (use-repeat-password-checks password
repeat-password)
meet-requirements? (and (not empty-password?)
password-long-enough?
password-short-enough?
same-passwords?
accepts-disclaimer?)]
[floating-button/view [floating-button/view
{:header [page-nav] {:header [page-nav top]
:keyboard-should-persist-taps :handled :initial-header-height (+ style/page-nav-height top)
:content-avoid-keyboard? true :keyboard-should-persist-taps :handled
:content-avoid-keyboard? true
:automatically-adjust-keyboard-insets true :automatically-adjust-keyboard-insets true
:blur-options :blur-options style/blur-options
{:blur-amount 34 :footer-container-padding 0
:blur-radius 20 :footer [help-and-confirm-button
:blur-type :transparent {:password-validations password-validations
:overlay-color :transparent :same-passwords? same-passwords?
:background-color (if platform/android? colors/neutral-100 colors/neutral-80-opa-1-blur) :on-submit on-submit}]}
:padding-vertical 0
:padding-horizontal 0}
:footer-container-padding 0
:footer
[rn/view
{:style style/footer-container}
(when same-passwords?
[rn/view {:style style/disclaimer-container}
[quo/disclaimer
{:blur? true
:on-change (partial set-accepts-disclaimer? not)
:checked? accepts-disclaimer?
:customization-color user-color}
(i18n/label :t/password-creation-disclaimer)]])
(when (and (= focused-input :password) (not same-passwords?))
[help
{:validations password-validations
:password-strength password-strength}])
[quo/button
{:container-style style/footer-button-container
:disabled? (not meet-requirements?)
:customization-color user-color
:on-press #(rf/dispatch
[:onboarding/password-set
(security/mask-data password)])}
(i18n/label :t/password-creation-confirm)]]}
[rn/view {:style style/form-container} [rn/view {:style style/form-container}
[header] [header]
[password-inputs [password-inputs
{:password-long-enough? password-long-enough? {:password-long-enough? long-enough?
:password-short-enough? password-short-enough? :password-short-enough? short-enough?
:passwords-match? same-passwords? :non-empty-password? non-empty?
:empty-password? empty-password? :same-passwords? same-passwords?
:show-password-validation? show-password-validation? :same-password-length? same-password-length?
:on-input-focus #(set-focused-input :password) :set-password set-password
:on-change-password (fn [new-value] :set-repeat-password set-repeat-password}]]]))
(set-password new-value)
(when same-password-length?
(set-show-password-validation? true)))
:on-change-repeat-password (fn [new-value]
(set-repeat-password new-value)
(when same-password-length?
(set-show-password-validation? true)))
:on-blur-repeat-password #(if empty-password?
(set-show-password-validation? false)
(set-show-password-validation? true))}]]]))

View File

@ -1,60 +0,0 @@
(ns status-im.contexts.onboarding.create-profile.style
(:require
[quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(def continue-button
{:width "100%"
:margin-left :auto
:margin-top (if platform/android? :auto 0)
:margin-right :auto})
(def button-container
{:width "100%"
:padding-left 20
:padding-right 20
:padding-top 12
:align-self :flex-end
:height 64})
(defn view-button-container
[keyboard-shown?]
(merge button-container
(if platform/ios?
{:margin-bottom (if keyboard-shown? 0 34)}
{:margin-bottom (if keyboard-shown? 12 34)})))
(def blur-button-container
(merge button-container
(when platform/android? {:padding-bottom 12})))
(def page-container
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:z-index 100})
(def info-message
{:margin-top 8})
(def title
{:color colors/white
:margin-top 12
:margin-bottom 18})
(def color-title
{:color colors/white-70-blur
:margin-top 20
:margin-bottom 16})
(def content-container
{:padding-horizontal 20})
(def input-container
{:align-items :flex-start})
(def profile-input-container
{:flex-direction :row
:justify-content :center})

View File

@ -1,210 +0,0 @@
(ns status-im.contexts.onboarding.create-profile.view
(:require
[clojure.string :as string]
[oops.core :as oops]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.avatar-picture-picker.view :as profile-picture-picker]
[status-im.common.validation.profile :as profile-validator]
[status-im.constants :as c]
[status-im.contexts.onboarding.create-profile.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.responsiveness :as responsiveness]))
(def scroll-view-height (reagent/atom 0))
(def content-container-height (reagent/atom 0))
(defn show-button-background
[keyboard-height keyboard-shown content-scroll-y]
(let [button-container-height 64
keyboard-view-height (+ keyboard-height button-container-height)]
(when keyboard-shown
(cond
platform/android?
(< (- @scroll-view-height button-container-height) @content-container-height)
platform/ios?
(< (- @scroll-view-height keyboard-view-height) (- @content-container-height content-scroll-y))
:else
false))))
(defn button-container
[show-keyboard? keyboard-shown show-background? keyboard-height children]
(let [height (reagent/atom 0)]
(reset! height (if show-keyboard? (if keyboard-shown keyboard-height 0) 0))
[rn/view {:style {:margin-top :auto}}
(cond
(and (> @height 0) show-background?)
[quo/blur
(when keyboard-shown
{:blur-amount 34
:blur-type :transparent
:overlay-color :transparent
:background-color (if platform/android? colors/neutral-100 colors/neutral-80-opa-1-blur)
:style style/blur-button-container})
children]
(and (> @height 0) (not show-background?))
[rn/view {:style (style/view-button-container true)}
children]
(not show-keyboard?)
[rn/view {:style (style/view-button-container false)}
children])]))
(defn- page
[{:keys [onboarding-profile-data navigation-bar-top]}]
(reagent/with-let [show-keyboard? (reagent/atom false)
content-scroll-y (reagent/atom 0)
show-listener (oops/ocall rn/keyboard
"addListener"
(if platform/android?
"keyboardDidShow"
"keyboardWillShow")
#(reset! show-keyboard? true))
hide-listener (oops/ocall rn/keyboard
"addListener"
(if platform/android?
"keyboardDidHide"
"keyboardWillHide")
#(reset! show-keyboard? false))
{:keys [image-path display-name color]} onboarding-profile-data
full-name (reagent/atom display-name)
validation-msg (reagent/atom
(profile-validator/validation-name
@full-name))
on-change-text (fn [s]
(reset! validation-msg
(profile-validator/validation-name
s))
(reset! full-name (string/trim s)))
custom-color (reagent/atom (or color
c/profile-default-color))
profile-pic (reagent/atom image-path)
on-change-profile-pic #(reset! profile-pic %)
on-change #(reset! custom-color %)]
(let [name-too-short? (profile-validator/name-too-short? @full-name)
valid-name? (and (not @validation-msg) (not name-too-short?))
info-message (if @validation-msg
@validation-msg
(i18n/label :t/minimum-characters
{:min-chars
profile-validator/min-length}))
info-type (cond @validation-msg :error
name-too-short? :default
:else :success)
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
show-background? (show-button-background keyboard-height
keyboard-shown
@content-scroll-y)
{window-width :width} (rn/get-window)]
[rn/view {:style style/page-container}
[quo/page-nav
{:margin-top navigation-bar-top
:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]
[rn/scroll-view
{:on-layout (fn [event]
(let [height (oops/oget event "nativeEvent.layout.height")]
(reset! scroll-view-height height)
(reset! content-scroll-y 0)))
:on-scroll (fn [event]
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
(reset! content-scroll-y y)))
:scroll-event-throttle 64
:content-container-style {:flexGrow 1}}
[rn/view
{:on-layout (fn [event]
(let [height (oops/oget event "nativeEvent.layout.height")]
(reset! content-container-height height)))}
[rn/view
{:style style/content-container}
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/title} (i18n/label :t/create-profile)]
[rn/view
{:style style/input-container}
[rn/view
{:style style/profile-input-container}
[quo/profile-input
{:customization-color @custom-color
:placeholder (i18n/label :t/your-name)
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch
[:show-bottom-sheet
{:content (fn []
[profile-picture-picker/view
{:on-result on-change-profile-pic
:has-picture? false}])
:shell? true}]))
:image-picker-props {:profile-picture @profile-pic
:full-name (if (seq @full-name)
@full-name
(i18n/label :t/your-name))
:customization-color @custom-color}
:title-input-props {:default-value display-name
:auto-focus true
:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
[quo/info-message
{:status info-type
:size :default
:icon (if valid-name? :i/positive-state :i/info)
:color (when (= :default info-type) colors/white-70-blur)
:container-style style/info-message}
info-message]
[quo/text
{:size :paragraph-2
:weight :medium
:style style/color-title}
(i18n/label :t/accent-colour)]]]
[quo/color-picker
{:blur? true
:default-selected :blue
:on-change on-change
:window-width window-width
:container-style {:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
window-width)}}]]]
[rn/keyboard-avoiding-view
{:style {:position :absolute
:top 0
:bottom 0
:left 0
:right 0}
:pointer-events :box-none}
[button-container @show-keyboard? keyboard-shown show-background? keyboard-height
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:customization-color @custom-color
:on-press (fn []
(rf/dispatch [:onboarding/profile-data-set
{:image-path @profile-pic
:display-name @full-name
:color @custom-color}]))
:container-style style/continue-button
:disabled? (or (not valid-name?) (not (seq @full-name)))}
(i18n/label :t/continue)]]]])
(finally
(oops/ocall show-listener "remove")
(oops/ocall hide-listener "remove"))))
(defn create-profile
[]
(let [{:keys [top]} (safe-area/get-insets)
onboarding-profile-data (rf/sub [:onboarding/profile])]
[page
{:navigation-bar-top top
:onboarding-profile-data onboarding-profile-data}]))

View File

@ -1,5 +1,6 @@
(ns status-im.contexts.onboarding.events (ns status-im.contexts.onboarding.events
(:require (:require
[quo.foundations.colors :as colors]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
status-im.common.biometric.events status-im.common.biometric.events
[status-im.constants :as constants] [status-im.constants :as constants]
@ -111,63 +112,57 @@
(rf/reg-event-fx (rf/reg-event-fx
:onboarding/password-set :onboarding/password-set
(fn [{:keys [db]} [masked-password]] (fn [{:keys [db]} [masked-password]]
(let [biometric-supported-type (get-in db [:biometrics :supported-type])] (let [biometric-supported-type (get-in db [:biometrics :supported-type])
from-screen (get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]
{:db (-> db {:db (-> db
(assoc-in [:onboarding/profile :password] masked-password) (assoc-in [:onboarding/profile :password] masked-password)
(assoc-in [:onboarding/profile :auth-method] constants/auth-method-password)) (assoc-in [:onboarding/profile :auth-method] constants/auth-method-password))
:fx [[:dispatch :fx [[:dispatch
(if biometric-supported-type (if biometric-supported-type
[:navigate-to-within-stack [:navigate-to-within-stack [:screen/onboarding.enable-biometrics from-screen]]
[:screen/onboarding.enable-biometrics
(get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]]
[:onboarding/create-account-and-login])]]}))) [:onboarding/create-account-and-login])]]})))
(rf/defn navigate-to-enable-biometrics (rf/reg-event-fx
{:events [:onboarding/navigate-to-enable-biometrics]} :onboarding/navigate-to-enable-biometrics
[{:keys [db]}] (fn [{:keys [db]}]
(let [supported-type (get-in db [:biometrics :supported-type])] (let [supported-type (get-in db [:biometrics :supported-type])]
{:dispatch (if supported-type {:dispatch (if supported-type
[:open-modal :screen/onboarding.enable-biometrics] [:open-modal :screen/onboarding.enable-biometrics]
[:open-modal :screen/onboarding.enable-notifications])})) [:open-modal :screen/onboarding.enable-notifications])})))
(rf/defn seed-phrase-validated (rf/reg-event-fx
{:events [:onboarding/seed-phrase-validated]} :onboarding/seed-phrase-validated
[{:keys [db]} seed-phrase key-uid] (fn [{:keys [db]} [seed-phrase key-uid]]
(let [syncing-account-recovered? (and (seq (:syncing/key-uid db)) (let [next-screen :screen/onboarding.create-profile-password
(= (:syncing/key-uid db) key-uid)) from-screen (get db
next-screen (if syncing-account-recovered? :onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.create-profile-password :screen/onboarding.new-to-status)]
:screen/onboarding.create-profile)] (if (contains? (:profile/profiles-overview db) key-uid)
(if (contains? (:profile/profiles-overview db) key-uid) {:fx [[:effects.utils/show-confirmation
{:effects.utils/show-confirmation {:title (i18n/label :t/multiaccount-exists-title)
{:title (i18n/label :t/multiaccount-exists-title) :content (i18n/label :t/multiaccount-exists-content)
:content (i18n/label :t/multiaccount-exists-content) :confirm-button-text (i18n/label :t/unlock)
:confirm-button-text (i18n/label :t/unlock) :on-accept (fn []
:on-accept (fn [] (re-frame/dispatch [:pop-to-root :screen/profile.profiles])
(re-frame/dispatch [:pop-to-root :screen/profile.profiles]) (re-frame/dispatch [:profile/profile-selected key-uid]))
(re-frame/dispatch :on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}]]}
[:profile/profile-selected key-uid])) {:db (-> db
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}} (assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
{:db (-> db (assoc-in [:onboarding/profile :key-uid] key-uid)
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase) (assoc-in [:onboarding/profile :color] constants/profile-default-color))
(assoc-in [:onboarding/profile :key-uid] key-uid) :fx [[:dispatch [:navigate-to-within-stack [next-screen from-screen]]]]}))))
(assoc-in [:onboarding/profile :color] constants/profile-default-color))
:fx [[:dispatch
[:navigate-to-within-stack
[next-screen
(get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]]]]})))
(rf/defn navigate-to-create-profile (rf/reg-event-fx
{:events [:onboarding/navigate-to-create-profile]} :onboarding/navigate-to-create-profile
[{:keys [db]}] (fn [{:keys [db]}]
;; Restart the flow {:db (-> db
{:db (dissoc db :onboarding/profile) (assoc-in [:onboarding/profile :color] (rand-nth colors/account-colors))
:dispatch [:navigate-to-within-stack (update :onboarding/profile dissoc :image-path))
[:screen/onboarding.create-profile :screen/onboarding.new-to-status]]}) :fx [[:dispatch
[:navigate-to-within-stack
[:screen/onboarding.create-profile-password :screen/onboarding.new-to-status]]]]}))
(rf/reg-event-fx :onboarding/navigate-to-sign-in-by-syncing (rf/reg-event-fx :onboarding/navigate-to-sign-in-by-syncing
(fn [{:keys [db]}] (fn [{:keys [db]}]
@ -180,26 +175,43 @@
(fn [{:keys [db]} [auth-method]] (fn [{:keys [db]} [auth-method]]
{:db (assoc db :auth-method auth-method)})) {:db (assoc db :auth-method auth-method)}))
(rf/defn onboarding-new-account-finalize-setup (def ^:const temp-display-name
{:events [:onboarding/finalize-setup]} "While creating a profile, we cannot use an empty string; this value works as a
[{:keys [db]}] placeholder that will be updated later once the compressed key exists. See
(let [masked-password (get-in db [:onboarding/profile :password]) `status-im.contexts.profile.edit.name.events/get-default-display-name` for more details."
key-uid (get-in db [:profile/profile :key-uid]) "temporal username")
syncing? (get-in db [:onboarding/profile :syncing?])
auth-method (get-in db [:onboarding/profile :auth-method]) (rf/reg-event-fx
biometric-enabled? (= auth-method constants/auth-method-biometric)] :onboarding/use-temporary-display-name
(cond-> {:db (assoc db :onboarding/generated-keys? true)} (fn [{:keys [db]} [temporary-display-name?]]
biometric-enabled? {:db (assoc db
(assoc :keychain/save-password-and-auth-method :onboarding/profile
{:key-uid key-uid {:temporary-display-name? temporary-display-name?
:masked-password (if syncing? :display-name (if temporary-display-name?
masked-password temp-display-name
(security/hash-masked-password masked-password)) "")})}))
:on-success (fn []
(rf/dispatch [:onboarding/set-auth-method auth-method]) (rf/reg-event-fx
(when syncing? :onboarding/finalize-setup
(rf/dispatch (fn [{db :db}]
[:onboarding/navigate-to-enable-notifications-from-syncing]))) (let [{:keys [password syncing? auth-method
:on-error #(log/error "failed to save biometrics" temporary-display-name?]} (:onboarding/profile db)
{:key-uid key-uid {:keys [key-uid] :as profile} (:profile/profile db)
:error %})})))) biometric-enabled? (= auth-method constants/auth-method-biometric)]
{:db (assoc db :onboarding/generated-keys? true)
:fx [(when temporary-display-name?
[:dispatch [:profile/set-default-profile-name profile]])
(when biometric-enabled?
[:keychain/save-password-and-auth-method
{:key-uid key-uid
:masked-password (if syncing?
password
(security/hash-masked-password password))
:on-success (fn []
(rf/dispatch [:onboarding/set-auth-method auth-method])
(when syncing?
(rf/dispatch
[:onboarding/navigate-to-enable-notifications-from-syncing])))
:on-error #(log/error "failed to save biometrics"
{:key-uid key-uid
:error %})}])]})))

View File

@ -52,6 +52,7 @@
[] []
(when-let [blur-show-fn @overlay/blur-show-fn-atom] (when-let [blur-show-fn @overlay/blur-show-fn-atom]
(blur-show-fn)) (blur-show-fn))
(rf/dispatch [:onboarding/use-temporary-display-name false])
(rf/dispatch [:open-modal (rf/dispatch [:open-modal
:screen/onboarding.share-usage :screen/onboarding.share-usage
{:next-screen :screen/onboarding.sync-or-recover-profile}])) {:next-screen :screen/onboarding.sync-or-recover-profile}]))
@ -60,6 +61,7 @@
[] []
(when-let [blur-show-fn @overlay/blur-show-fn-atom] (when-let [blur-show-fn @overlay/blur-show-fn-atom]
(blur-show-fn)) (blur-show-fn))
(rf/dispatch [:onboarding/use-temporary-display-name true])
(rf/dispatch [:open-modal :screen/onboarding.share-usage (rf/dispatch [:open-modal :screen/onboarding.share-usage
{:next-screen :screen/onboarding.new-to-status}])) {:next-screen :screen/onboarding.new-to-status}]))

View File

@ -1,5 +1,7 @@
(ns status-im.contexts.profile.edit.name.events (ns status-im.contexts.profile.edit.name.events
(:require [utils.i18n :as i18n] (:require [clojure.string :as string]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(rf/reg-event-fx :profile/edit-profile-name-success (rf/reg-event-fx :profile/edit-profile-name-success
@ -20,3 +22,16 @@
:on-success [:profile/edit-profile-name-success]}]]]}) :on-success [:profile/edit-profile-name-success]}]]]})
(rf/reg-event-fx :profile/edit-name edit-profile-name) (rf/reg-event-fx :profile/edit-name edit-profile-name)
(defn display-name-from-compressed-key
[profile]
(-> profile :compressed-key (string/split #"zQ3") second (subs 0 constants/profile-name-max-length)))
(rf/reg-event-fx
:profile/set-default-profile-name
(fn [{db :db} [profile]]
(let [default-display-name (display-name-from-compressed-key profile)]
{:db (assoc-in db [:profile/profile :display-name] default-display-name)
:fx [[:json-rpc/call
[{:method "wakuext_setDisplayName"
:params [default-display-name]}]]]})))

View File

@ -152,15 +152,12 @@
(rf/reg-event-fx (rf/reg-event-fx
:profile.login/login-node-signal :profile.login/login-node-signal
(fn [{{:onboarding/keys [recovered-account? new-account?] :as db} :db} (fn [{db :db} [{:keys [settings account ensUsernames error]}]]
[{:keys [settings account ensUsernames error]}]]
(log/debug "[signals] node.login" "error" error) (log/debug "[signals] node.login" "error" error)
(if error (if error
{:db (update db :profile/login #(-> % (dissoc :processing) (assoc :error error)))} {:db (update db :profile/login #(-> % (dissoc :processing) (assoc :error error)))}
{:db (dissoc db :profile/login) {:db (dissoc db :profile/login)
:fx [(when (and new-account? (not recovered-account?)) :fx [[:dispatch-later [{:ms 2000 :dispatch [:ens/update-usernames ensUsernames]}]]
[:dispatch-later [{:ms 1000 :dispatch [:wallet-legacy/set-initial-blocks-range]}]])
[:dispatch-later [{:ms 2000 :dispatch [:ens/update-usernames ensUsernames]}]]
[:dispatch [:profile.login/login-existing-profile settings account]]]}))) [:dispatch [:profile.login/login-existing-profile settings account]]]})))
(rf/reg-event-fx (rf/reg-event-fx

View File

@ -47,6 +47,7 @@
[] []
(when @push-animation-fn-atom (when @push-animation-fn-atom
(@push-animation-fn-atom)) (@push-animation-fn-atom))
(rf/dispatch [:onboarding/use-temporary-display-name true])
(debounce/throttle-and-dispatch (debounce/throttle-and-dispatch
[:open-modal :screen/onboarding.new-to-status] [:open-modal :screen/onboarding.new-to-status]
1000)) 1000))
@ -55,6 +56,7 @@
[] []
(when @push-animation-fn-atom (when @push-animation-fn-atom
(@push-animation-fn-atom)) (@push-animation-fn-atom))
(rf/dispatch [:onboarding/use-temporary-display-name false])
(debounce/throttle-and-dispatch (debounce/throttle-and-dispatch
[:open-modal :screen/onboarding.sync-or-recover-profile] [:open-modal :screen/onboarding.sync-or-recover-profile]
1000)) 1000))

View File

@ -43,7 +43,6 @@
[status-im.contexts.keycard.pin.enter.view :as keycard.pin.enter] [status-im.contexts.keycard.pin.enter.view :as keycard.pin.enter]
[status-im.contexts.onboarding.create-or-sync-profile.view :as create-or-sync-profile] [status-im.contexts.onboarding.create-or-sync-profile.view :as create-or-sync-profile]
[status-im.contexts.onboarding.create-password.view :as create-password] [status-im.contexts.onboarding.create-password.view :as create-password]
[status-im.contexts.onboarding.create-profile.view :as create-profile]
[status-im.contexts.onboarding.enable-biometrics.view :as enable-biometrics] [status-im.contexts.onboarding.enable-biometrics.view :as enable-biometrics]
[status-im.contexts.onboarding.enable-notifications.view :as enable-notifications] [status-im.contexts.onboarding.enable-notifications.view :as enable-notifications]
[status-im.contexts.onboarding.identifiers.view :as identifiers] [status-im.contexts.onboarding.identifiers.view :as identifiers]
@ -728,16 +727,6 @@
:modalPresentationStyle :overCurrentContext} :modalPresentationStyle :overCurrentContext}
:component create-or-sync-profile/sync-or-recover-profile}) :component create-or-sync-profile/sync-or-recover-profile})
(def onboarding-create-profile
{:name :screen/onboarding.create-profile
:metrics {:track? true
:alias-id :onboarding.create-profile-info}
:options {:theme :dark
:layout options/onboarding-transparent-layout
:animations transitions/push-animations-for-transparent-background
:popGesture false}
:component create-profile/create-profile})
(def onboarding-create-profile-password (def onboarding-create-profile-password
{:name :screen/onboarding.create-profile-password {:name :screen/onboarding.create-profile-password
:metrics {:track? true :metrics {:track? true
@ -872,7 +861,6 @@
[onboarding-intro [onboarding-intro
onboarding-new-to-status onboarding-new-to-status
onboarding-sync-or-recover-profile onboarding-sync-or-recover-profile
onboarding-create-profile
onboarding-create-profile-password onboarding-create-profile-password
onboarding-enable-biometrics onboarding-enable-biometrics
onboarding-preparing-status onboarding-preparing-status

View File

@ -17,11 +17,10 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
def prepare_devices(self): def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2) self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1]) self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = 'sender', 'receiver' self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True, (self.device_2.create_user,))))
'username': self.username_1}),
(self.device_2.create_user, {'username': self.username_2}))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view() self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view() self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
self.public_key_1 = self.home_1.get_public_key() self.public_key_1 = self.home_1.get_public_key()
self.profile_link_2 = self.home_2.get_link_to_profile() self.profile_link_2 = self.home_2.get_link_to_profile()
@ -98,8 +97,8 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
def test_activity_center_contact_request_accept_swipe_mark_all_as_read(self): def test_activity_center_contact_request_accept_swipe_mark_all_as_read(self):
self.device_2.just_fyi('Creating a new user on Device2') self.device_2.just_fyi('Creating a new user on Device2')
self.home_2.reopen_app(sign_in=False) self.home_2.reopen_app(sign_in=False)
new_username = "new user" self.device_2.create_user(first_user=False)
self.device_2.create_user(username=new_username, first_user=False) new_username = self.home_2.get_username()
self.device_2.just_fyi('Device2 sends a contact request to Device1 via Paste button and check user details') self.device_2.just_fyi('Device2 sends a contact request to Device1 via Paste button and check user details')
self.home_2.chats_tab.click() self.home_2.chats_tab.click()
@ -159,20 +158,19 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
self.username_2, self.profile_link_2, decoded_username)) self.username_2, self.profile_link_2, decoded_username))
public_key_2 = self.profile_link_2.split("#")[-1] public_key_2 = self.profile_link_2.split("#")[-1]
new_username_1 = "test user 123"
def _device_1_creates_user(): def _device_1_creates_user():
self.home_1.just_fyi("Device 1 creates a new user") self.home_1.just_fyi("Device 1 creates a new user")
self.home_1.reopen_app(sign_in=False) self.home_1.reopen_app(sign_in=False)
self.device_1.create_user(username=new_username_1, first_user=False) self.device_1.create_user(first_user=False)
return self.home_1.get_username()
def _device_2_sign_in(): def _device_2_sign_in():
self.home_2.just_fyi("Device 2 sign in, user name is " + self.username_2) self.home_2.just_fyi("Device 2 sign in, user name is " + self.username_2)
self.home_2.reopen_app(sign_in=False) self.home_2.reopen_app(sign_in=False)
self.device_2.sign_in(user_name=self.username_2) self.device_2.sign_in(user_name=self.username_2)
self.loop.run_until_complete(run_in_parallel(((_device_1_creates_user, {}), new_username_1, _ = self.loop.run_until_complete(run_in_parallel(((_device_1_creates_user, {}),
(_device_2_sign_in, {})))) (_device_2_sign_in, {}))))
self.device_1.just_fyi('Device1 sends a contact request to Device2 using his profile link') self.device_1.just_fyi('Device1 sends a contact request to Device2 using his profile link')
self.home_1.chats_tab.click() self.home_1.chats_tab.click()
@ -242,11 +240,11 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
def prepare_devices(self): def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2) self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1]) self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = 'user1', 'user2'
self.loop.run_until_complete( self.loop.run_until_complete(
run_in_parallel(((self.device_1.create_user, {'username': self.username_1}), run_in_parallel(((self.device_1.create_user,),
(self.device_2.create_user, {'username': self.username_2})))) (self.device_2.create_user,))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view() self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view() self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
self.public_key_2 = self.home_2.get_public_key() self.public_key_2 = self.home_2.get_public_key()
self.home_2.navigate_back_to_home_view() self.home_2.navigate_back_to_home_view()
@ -382,11 +380,11 @@ class TestActivityMultipleDevicePRTwo(MultipleSharedDeviceTestCase):
def prepare_devices(self): def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2) self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1]) self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = 'user1', 'user2'
self.loop.run_until_complete( self.loop.run_until_complete(
run_in_parallel(((self.device_1.create_user, {'username': self.username_1}), run_in_parallel(((self.device_1.create_user,),
(self.device_2.create_user, {'username': self.username_2})))) (self.device_2.create_user,))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view() self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view() self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
self.public_key_2 = self.home_2.get_public_key() self.public_key_2 = self.home_2.get_public_key()
self.home_2.navigate_back_to_home_view() self.home_2.navigate_back_to_home_view()

View File

@ -20,13 +20,11 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
self.drivers, self.loop = create_shared_drivers(2) self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1]) self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = 'sender', 'receiver' self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True, (self.device_2.create_user, {'enable_notifications': True}))))
'username': self.username_1}),
(self.device_2.create_user, {'enable_notifications': True,
'username': self.username_2}))))
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view() self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.homes = (self.home_1, self.home_2) self.homes = (self.home_1, self.home_2)
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
self.profile_1, self.profile_2 = (home.get_profile_view() for home in self.homes) self.profile_1, self.profile_2 = (home.get_profile_view() for home in self.homes)
self.public_key_2 = self.home_2.get_public_key() self.public_key_2 = self.home_2.get_public_key()
@ -543,13 +541,11 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
self.drivers, self.loop = create_shared_drivers(2) self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1]) self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = 'sender', 'receiver' self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True, (self.device_2.create_user, {'enable_notifications': True}))))
'username': self.username_1}),
(self.device_2.create_user, {'enable_notifications': True,
'username': self.username_2}))))
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view() self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.homes = (self.home_1, self.home_2) self.homes = (self.home_1, self.home_2)
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
self.profile_1, self.profile_2 = (home.get_profile_view() for home in self.homes) self.profile_1, self.profile_2 = (home.get_profile_view() for home in self.homes)
self.public_key_2 = self.home_2.get_public_key() self.public_key_2 = self.home_2.get_public_key()

View File

@ -21,17 +21,25 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
self.message_to_admin = 'Hey, admin!' self.message_to_admin = 'Hey, admin!'
self.public_keys, self.usernames, self.chats = {}, {}, {} self.public_keys, self.usernames, self.chats = {}, {}, {}
self.sign_in_views = [SignInView(self.drivers[key]) for key in self.drivers] self.sign_in_views = [SignInView(self.drivers[key]) for key in self.drivers]
self.usernames = ('user admin', 'member_1', 'member_2')
self.loop.run_until_complete( self.loop.run_until_complete(
run_in_parallel( run_in_parallel(
( (
(self.sign_in_views[0].create_user, {'enable_notifications': True, 'username': self.usernames[0]}), (self.sign_in_views[0].create_user, {'enable_notifications': True}),
(self.sign_in_views[1].create_user, {'enable_notifications': True, 'username': self.usernames[1]}), (self.sign_in_views[1].create_user, {'enable_notifications': True}),
(self.sign_in_views[2].create_user, {'enable_notifications': True, 'username': self.usernames[2]}) (self.sign_in_views[2].create_user, {'enable_notifications': True})
) )
) )
) )
self.homes = [sign_in.get_home_view() for sign_in in self.sign_in_views] self.homes = [sign_in.get_home_view() for sign_in in self.sign_in_views]
self.usernames = self.loop.run_until_complete(
run_in_parallel(
(
(self.homes[0].get_username,),
(self.homes[1].get_username,),
(self.homes[2].get_username,)
)
)
)
self.public_keys = self.loop.run_until_complete( self.public_keys = self.loop.run_until_complete(
run_in_parallel( run_in_parallel(
( (

View File

@ -21,9 +21,9 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
def prepare_devices(self): def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(1) self.drivers, self.loop = create_shared_drivers(1)
self.sign_in = SignInView(self.drivers[0]) self.sign_in = SignInView(self.drivers[0])
self.username = 'first user'
self.home = self.sign_in.create_user(username=self.username) self.home = self.sign_in.create_user()
self.username = self.home.get_username()
self.home.communities_tab.click_until_presence_of_element(self.home.plus_community_button) self.home.communities_tab.click_until_presence_of_element(self.home.plus_community_button)
self.community_name = "closed community" self.community_name = "closed community"
self.channel_name = "cats" self.channel_name = "cats"
@ -158,8 +158,8 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
def test_restore_multiaccount_with_waku_backup_remove_profile_switch(self): def test_restore_multiaccount_with_waku_backup_remove_profile_switch(self):
self.home.reopen_app(sign_in=False) self.home.reopen_app(sign_in=False)
self.home.just_fyi("Restore user with predefined communities and contacts") self.home.just_fyi("Restore user with predefined communities and contacts")
recover_user_name = 'Recover user' self.sign_in.recover_access(passphrase=waku_user.seed, second_user=True)
self.sign_in.recover_access(passphrase=waku_user.seed, second_user=True, username=recover_user_name) recover_user_name = self.home.get_username()
self.home.just_fyi("Check contacts/blocked users") self.home.just_fyi("Check contacts/blocked users")
self.home.chats_tab.click() self.home.chats_tab.click()
@ -306,11 +306,10 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
def prepare_devices(self): def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2) self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1]) self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = "user_1", "user_2" self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True, (self.device_2.create_user,))))
'username': self.username_1}),
(self.device_2.create_user, {'username': self.username_2}))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view() self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
self.public_key_2 = self.home_2.get_public_key() self.public_key_2 = self.home_2.get_public_key()
self.profile_1 = self.home_1.get_profile_view() self.profile_1 = self.home_1.get_profile_view()
[home.navigate_back_to_home_view() for home in self.homes] [home.navigate_back_to_home_view() for home in self.homes]
@ -836,12 +835,10 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
def prepare_devices(self): def prepare_devices(self):
self.drivers, self.loop = create_shared_drivers(2) self.drivers, self.loop = create_shared_drivers(2)
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1]) self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.username_1, self.username_2 = "user_1", "user_2" self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True, (self.device_2.create_user, {'enable_notifications': True}))))
'username': self.username_1}),
(self.device_2.create_user, {'enable_notifications': True,
'username': self.username_2}))))
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view() self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
self.public_key_2 = self.home_2.get_public_key() self.public_key_2 = self.home_2.get_public_key()
self.profile_1 = self.home_1.get_profile_view() self.profile_1 = self.home_1.get_profile_view()
[home.navigate_back_to_home_view() for home in self.homes] [home.navigate_back_to_home_view() for home in self.homes]

View File

@ -13,9 +13,9 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
self.drivers, self.loop = create_shared_drivers(1) self.drivers, self.loop = create_shared_drivers(1)
self.driver = self.drivers[0] self.driver = self.drivers[0]
self.sign_in = SignInView(self.driver) self.sign_in = SignInView(self.driver)
self.username = 'test user'
self.home = self.sign_in.create_user(username=self.username) self.home = self.sign_in.create_user()
self.username = self.home.get_username()
self.home.communities_tab.click_until_presence_of_element(self.home.plus_community_button) self.home.communities_tab.click_until_presence_of_element(self.home.plus_community_button)
self.open_community_name = "open community" self.open_community_name = "open community"
self.channel_name = "general" self.channel_name = "general"

View File

@ -20,10 +20,10 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
self.sign_in_3.get_home_view() self.sign_in_3.get_home_view()
self.sign_in_1.just_fyi("Device 1: create a new user") self.sign_in_1.just_fyi("Device 1: create a new user")
self.sign_in_3.just_fyi("Device 3: create a new user") self.sign_in_3.just_fyi("Device 3: create a new user")
self.user_name_1, self.user_name_3 = 'first user', 'third user'
self.loop.run_until_complete( self.loop.run_until_complete(
run_in_parallel(((self.sign_in_1.create_user, {'username': self.user_name_1}), run_in_parallel(((self.sign_in_1.create_user,),
(self.sign_in_3.create_user, {'username': self.user_name_3})))) (self.sign_in_3.create_user,))))
self.user_name_1, self.user_name_3 = self.home_1.get_username(), self.home_3.get_username()
self.profile_1 = self.home_1.profile_button.click() self.profile_1 = self.home_1.profile_button.click()
self.profile_2 = self.home_2.get_profile_view() self.profile_2 = self.home_2.get_profile_view()
self.sign_in_3.just_fyi("Device 3: get public key") self.sign_in_3.just_fyi("Device 3: get public key")

View File

@ -24,13 +24,11 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
self.sender, self.receiver = transaction_senders['ETH_1'], transaction_senders['ETH_2'] self.sender, self.receiver = transaction_senders['ETH_1'], transaction_senders['ETH_2']
self.sender['wallet_address'] = '0x' + self.sender['address'] self.sender['wallet_address'] = '0x' + self.sender['address']
self.receiver['wallet_address'] = '0x' + self.receiver['address'] self.receiver['wallet_address'] = '0x' + self.receiver['address']
self.sender_username, self.receiver_username = 'sender', 'receiver'
self.loop.run_until_complete( self.loop.run_until_complete(
run_in_parallel(((self.sign_in_1.recover_access, {'passphrase': self.sender['passphrase'], run_in_parallel(((self.sign_in_1.recover_access, {'passphrase': self.sender['passphrase']}),
'username': self.sender_username}), (self.sign_in_2.recover_access, {'passphrase': self.receiver['passphrase']}))))
(self.sign_in_2.recover_access, {'passphrase': self.receiver['passphrase'],
'username': self.receiver_username}))))
self.home_1, self.home_2 = self.sign_in_1.get_home_view(), self.sign_in_2.get_home_view() self.home_1, self.home_2 = self.sign_in_1.get_home_view(), self.sign_in_2.get_home_view()
self.sender_username, self.receiver_username = self.home_1.get_username(), self.home_2.get_username()
self.wallet_1, self.wallet_2 = self.sign_in_1.get_wallet_view(), self.sign_in_2.get_wallet_view() self.wallet_1, self.wallet_2 = self.sign_in_1.get_wallet_view(), self.sign_in_2.get_wallet_view()
self.wallet_1.wallet_tab.click() self.wallet_1.wallet_tab.click()
self.wallet_2.wallet_tab.click() self.wallet_2.wallet_tab.click()
@ -206,10 +204,10 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
self.arb_balance = {'Ether': 0.0001, 'USDCoin': 0.0, 'Status': 0.0, 'Uniswap': 0.5, 'Dai Stablecoin': 0.0} self.arb_balance = {'Ether': 0.0001, 'USDCoin': 0.0, 'Status': 0.0, 'Uniswap': 0.5, 'Dai Stablecoin': 0.0}
self.sender['wallet_address'] = '0x' + self.sender['address'] self.sender['wallet_address'] = '0x' + self.sender['address']
self.receiver['wallet_address'] = '0x' + self.receiver['address'] self.receiver['wallet_address'] = '0x' + self.receiver['address']
self.sender_username, self.receiver_username = 'sender', 'receiver' self.sign_in_view.recover_access(passphrase=self.sender['passphrase'])
self.sign_in_view.recover_access(passphrase=self.sender['passphrase'], username=self.sender_username)
self.home_view = self.sign_in_view.get_home_view() self.home_view = self.sign_in_view.get_home_view()
self.sender_username = self.home_view.get_username()
self.wallet_view = self.home_view.wallet_tab.click() self.wallet_view = self.home_view.wallet_tab.click()
@marks.testrail_id(740490) @marks.testrail_id(740490)

View File

@ -624,3 +624,11 @@ class HomeView(BaseView):
element = Text(self.driver, accessibility_id='new-device-installation-id') element = Text(self.driver, accessibility_id='new-device-installation-id')
element.wait_for_visibility_of_element() element.wait_for_visibility_of_element()
return element.text return element.text
def get_username(self):
profile_view = self.get_profile_view()
profile_view = self.profile_button.click_until_presence_of_element(profile_view.default_username_text)
profile_view.default_username_text.wait_for_element(3)
username = profile_view.default_username_text.text
profile_view.click_system_back_button()
return username

View File

@ -179,7 +179,7 @@ class ProfileView(BaseView):
# Header # Header
self.public_key_text = Text(self.driver, accessibility_id="chat-key") self.public_key_text = Text(self.driver, accessibility_id="chat-key")
self.default_username_text = Text(self.driver, accessibility_id="default-username") self.default_username_text = Text(self.driver, accessibility_id="username")
self.contact_name_text = Text(self.driver, accessibility_id="contact-name") self.contact_name_text = Text(self.driver, accessibility_id="contact-name")
self.share_my_profile_button = Button(self.driver, accessibility_id="share-header-button") self.share_my_profile_button = Button(self.driver, accessibility_id="share-header-button")
self.profile_picture = ProfilePictureElement(self.driver) self.profile_picture = ProfilePictureElement(self.driver)

View File

@ -211,7 +211,7 @@ class SignInView(BaseView):
self.profile_continue_button = Button(self.driver, accessibility_id="submit-create-profile-button") self.profile_continue_button = Button(self.driver, accessibility_id="submit-create-profile-button")
self.profile_password_edit_box = EditBox(self.driver, translation_id="password-creation-placeholder-1") self.profile_password_edit_box = EditBox(self.driver, translation_id="password-creation-placeholder-1")
self.profile_repeat_password_edit_box = EditBox(self.driver, translation_id="password-creation-placeholder-2") self.profile_repeat_password_edit_box = EditBox(self.driver, translation_id="password-creation-placeholder-2")
self.profile_confirm_password_button = Button(self.driver, translation_id="password-creation-confirm") self.profile_confirm_password_button = Button(self.driver, accessibility_id="Confirm password")
self.enable_biometric_maybe_later_button = Button(self.driver, translation_id="maybe-later") self.enable_biometric_maybe_later_button = Button(self.driver, translation_id="maybe-later")
self.identifiers_button = Button(self.driver, accessibility_id="skip-identifiers") self.identifiers_button = Button(self.driver, accessibility_id="skip-identifiers")
self.start_button = Button(self.driver, accessibility_id="welcome-button") self.start_button = Button(self.driver, accessibility_id="welcome-button")
@ -228,8 +228,6 @@ class SignInView(BaseView):
input_elements[0].send_keys(password) input_elements[0].send_keys(password)
input_elements[1].click() input_elements[1].click()
input_elements[1].send_keys(password) input_elements[1].send_keys(password)
self.checkbox_button.scroll_to_element()
self.checkbox_button.click()
self.profile_confirm_password_button.click() self.profile_confirm_password_button.click()
def set_profile(self, username: str, set_image=False): def set_profile(self, username: str, set_image=False):
@ -238,7 +236,7 @@ class SignInView(BaseView):
if set_image: if set_image:
pass pass
def create_user(self, password=common_password, username="test user", first_user=True, enable_notifications=False): def create_user(self, password=common_password, first_user=True, enable_notifications=False):
self.driver.info("## Creating new multiaccount with password:'%s'" % password, device=False) self.driver.info("## Creating new multiaccount with password:'%s'" % password, device=False)
if first_user: if first_user:
self.create_profile_button.click_until_presence_of_element(self.start_fresh_lets_go_button) self.create_profile_button.click_until_presence_of_element(self.start_fresh_lets_go_button)
@ -249,7 +247,6 @@ class SignInView(BaseView):
self.plus_profiles_button.click() self.plus_profiles_button.click()
self.create_new_profile_button.click() self.create_new_profile_button.click()
self.start_fresh_lets_go_button.click_until_presence_of_element(self.profile_title_input) self.start_fresh_lets_go_button.click_until_presence_of_element(self.profile_title_input)
self.set_profile(username)
self.set_password(password) self.set_password(password)
self.chats_tab.wait_for_visibility_of_element(30) self.chats_tab.wait_for_visibility_of_element(30)
self.driver.info("## New multiaccount is created successfully!", device=False) self.driver.info("## New multiaccount is created successfully!", device=False)
@ -261,7 +258,7 @@ class SignInView(BaseView):
return home_view return home_view
def recover_access(self, passphrase: str, password: str = common_password, enable_notifications=False, def recover_access(self, passphrase: str, password: str = common_password, enable_notifications=False,
second_user=False, username='Restore user', set_image=False, after_sync_code=False): second_user=False, after_sync_code=False):
self.driver.info("## Recover access (password:%s)" % password, device=False) self.driver.info("## Recover access (password:%s)" % password, device=False)
if not after_sync_code: if not after_sync_code:
@ -274,8 +271,6 @@ class SignInView(BaseView):
self.use_recovery_phrase_button.click() self.use_recovery_phrase_button.click()
self.passphrase_edit_box.send_keys(passphrase) self.passphrase_edit_box.send_keys(passphrase)
self.continue_button.click_until_presence_of_element(self.profile_title_input) self.continue_button.click_until_presence_of_element(self.profile_title_input)
if not after_sync_code:
self.set_profile(username, set_image)
self.set_password(password) self.set_password(password)
self.chats_tab.wait_for_visibility_of_element(30) self.chats_tab.wait_for_visibility_of_element(30)
self.driver.info("## Multiaccount is recovered successfully!", device=False) self.driver.info("## Multiaccount is recovered successfully!", device=False)

View File

@ -1930,7 +1930,7 @@
"password-creation-max-length-hint": "Maximum 100 characters", "password-creation-max-length-hint": "Maximum 100 characters",
"password-creation-placeholder-1": "Type password", "password-creation-placeholder-1": "Type password",
"password-creation-placeholder-2": "Repeat password", "password-creation-placeholder-2": "Repeat password",
"password-creation-subtitle": "To log in to Status and sign transactions", "password-creation-subtitle": "This password can't be recovered",
"password-creation-tips-1": "Lower case", "password-creation-tips-1": "Lower case",
"password-creation-tips-2": "Upper case", "password-creation-tips-2": "Upper case",
"password-creation-tips-3": "Numbers", "password-creation-tips-3": "Numbers",