chore: onboarding profile adjustments (#16291)

* remove b&w color as an option

* change system message for minimum display name length to match designs

* update display name validation to match desktop
This commit is contained in:
Jamie Caprani 2023-06-22 16:00:06 +01:00 committed by GitHub
parent 7260c23e8e
commit 9ec4f91c9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 197 additions and 165 deletions

View File

@ -3,11 +3,13 @@
[reagent.core :as reagent] [reagent.core :as reagent]
[test-helpers.component :as h])) [test-helpers.component :as h]))
(def color-list [:blue :yellow :turquoise :copper :sky :camel :orange :army :pink :purple :magenta])
(h/describe "color-picker" (h/describe "color-picker"
(h/test "color picker rendered" (h/test "color picker rendered"
(h/render [color-picker/view]) (h/render [color-picker/view])
(-> (h/expect (h/get-all-by-label-text :color-picker-item)) (-> (h/expect (h/get-all-by-label-text :color-picker-item))
(.toHaveLength 12))) (.toHaveLength 11)))
(h/test "clicks on a color item" (h/test "clicks on a color item"
(let [event (h/mock-fn)] (let [event (h/mock-fn)]
(h/render [color-picker/view {:on-change #(event)}]) (h/render [color-picker/view {:on-change #(event)}])
@ -19,5 +21,11 @@
(h/render [color-picker/view {:on-change #(reset! selected %)}]) (h/render [color-picker/view {:on-change #(reset! selected %)}])
(h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0)) (h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0))
(-> (h/expect @selected) (-> (h/expect @selected)
(.toStrictEqual :blue))))) (.toStrictEqual :blue))))
(h/test "all of the values of colors-list are rendered"
(h/render [color-picker/view])
(js/Promise.all (map (fn [color]
(h/is-truthy (h/get-all-by-label-text color)))
color-list))))

View File

@ -2,7 +2,7 @@
(:require [quo2.foundations.colors :as colors])) (:require [quo2.foundations.colors :as colors]))
(def color-picker-container (def color-picker-container
{:max-width 338 {:flex 1
:flex-direction :row :flex-direction :row
:flex-wrap :wrap :flex-wrap :wrap
:justify-content :space-between}) :justify-content :space-between})
@ -11,14 +11,17 @@
{:flex-basis "100%" {:flex-basis "100%"
:height 10}) :height 10})
(def color-button-common
{:width 48
:height 48
:border-width 4
:border-radius 24
:transform [{:rotate "45deg"}]
:border-color :transparent})
(defn color-button (defn color-button
[color selected?] [color selected?]
(merge {:width 48 (merge color-button-common
:height 48
:border-width 4
:border-radius 24
:transform [{:rotate "45deg"}]
:border-color :transparent}
(when selected? (when selected?
{:border-top-color (colors/alpha color 0.4) {:border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4) :border-end-color (colors/alpha color 0.4)

View File

@ -5,25 +5,27 @@
[reagent.core :as reagent] [reagent.core :as reagent]
[quo2.components.colors.color-picker.style :as style])) [quo2.components.colors.color-picker.style :as style]))
(def color-list [:blue :yellow :turquoise :copper :sky :camel :orange :army :pink :purple :magenta]) ;; TODO: using :no-color this to keep alignment of colors correct while b & w is being developed.
;; https://github.com/status-im/status-mobile/issues/15442
(def color-list
[:blue :yellow :turquoise :copper :sky :camel :orange :army :pink :purple :magenta :no-color])
(defn picker-colors (defn picker-colors
[blur?] [blur?]
(concat (map (fn [color] (map (fn [color]
{:name color {:name color
:color (colors/custom-color-by-theme color (if blur? 60 50) 60)}) :color (colors/custom-color-by-theme color (if blur? 60 50) 60)})
color-list) color-list))
[{:name :yinyang
:color (colors/theme-colors (colors/custom-color :yin 50)
(colors/custom-color :yang 50))
:secondary-color (colors/theme-colors (colors/custom-color :yang 50)
(colors/custom-color :yin 50))}]))
(defn- on-change-handler (defn- on-change-handler
[selected color-name on-change] [selected color-name on-change]
(reset! selected color-name) (reset! selected color-name)
(when on-change (on-change color-name))) (when on-change (on-change color-name)))
(defn empty-color-item
[]
[rn/view {:style style/color-button-common}])
(defn- color-item (defn- color-item
[{:keys [name [{:keys [name
color color
@ -32,20 +34,24 @@
on-press on-press
blur?]}] blur?]}]
(let [border? (and (not blur?) (and secondary-color (not selected?)))] (let [border? (and (not blur?) (and secondary-color (not selected?)))]
[rn/touchable-opacity (if (= :no-color name)
{:style (style/color-button color selected?) [empty-color-item]
:accessibility-label :color-picker-item [rn/touchable-opacity
:on-press #(on-press name)} {:style (style/color-button color selected?)
[rn/view :accessibility-label :color-picker-item
{:style (style/color-circle color border?)} :on-press #(on-press name)}
(when (and secondary-color (not selected?)) [rn/view
[rn/view {:accessibile true
{:style (style/secondary-overlay secondary-color border?)}]) :accessibility-label name
(when selected? :style (style/color-circle color border?)}
[icon/icon :i/check (when (and secondary-color (not selected?))
{:size 20 [rn/view
:color (or secondary-color {:style (style/secondary-overlay secondary-color border?)}])
colors/white)}])]])) (when selected?
[icon/icon :i/check
{:size 20
:color (or secondary-color
colors/white)}])]])))
(defn view (defn view
"Options "Options

View File

@ -182,51 +182,48 @@
(def danger-50-opa-30 (alpha danger-50 0.3)) (def danger-50-opa-30 (alpha danger-50 0.3))
(def danger-50-opa-40 (alpha danger-50 0.4)) (def danger-50-opa-40 (alpha danger-50 0.4))
;;;; Customization
;; Colors for customizing profiles and communities themes ;; Colors for customizing users account
(def customization (def customization
{:primary {50 primary-50 ;; User can also use primary color as customisation color {:blue {50 "#2A4AF5"
60 primary-60}
:purple {50 "#7140FD"
60 "#5A33CA"}
:indigo {50 "#496289"
60 "#3D5273"}
:turquoise {50 "#2A799B"
60 "#22617C"}
:blue {50 "#2A4AF5"
60 "#223BC4"} 60 "#223BC4"}
:green {50 "#5BCC95"
60 "#4CAB7D"}
:yellow {50 "#F6B03C" :yellow {50 "#F6B03C"
60 "#C58D30"} 60 "#C58D30"}
:orange {50 "#FF7D46" :turquoise {50 "#2A799B"
60 "#CC6438"} 60 "#22617C"}
:red {50 "#F46666"
60 "#CD5656"}
:pink {50 "#F66F8F"
60 "#C55972"}
:brown {50 "#99604D"
60 "#805141"}
:sky {50 "#1992D7"
60 "#1475AC"}
:army {50 "#216266"
60 "#1A4E52"}
:magenta {50 "#EC266C"
60 "#BD1E56"}
:copper {50 "#CB6256" :copper {50 "#CB6256"
60 "#A24E45"} 60 "#A24E45"}
:sky {50 "#1992D7"
60 "#1475AC"}
:camel {50 "#C78F67" :camel {50 "#C78F67"
60 "#9F7252"} 60 "#9F7252"}
:yin {50 "#09101C" :orange {50 "#FF7D46"
60 "#1D232E"} 60 "#CC6438"}
:yang {50 "#FFFFFF" :army {50 "#216266"
60 "#EBEBEB"} 60 "#1A4E52"}
:beige {50 "#CAAE93" :pink {50 "#F66F8F"
60 "#AA927C"}}) 60 "#C55972"}
:purple {50 "#7140FD"
60 "#5A33CA"}
:magenta {50 "#EC266C"
60 "#BD1E56"}})
(def colors-map (def colors-map
(merge {:danger {50 danger-50 (merge {:primary {50 primary-50 ;; User can also use primary color as customisation color
60 primary-60}
:beige {50 "#CAAE93"
60 "#AA927C"}
:green {50 "#5BCC95"
60 "#4CAB7D"}
:brown {50 "#99604D"
60 "#805141"}
:red {50 "#F46666"
60 "#CD5656"}
:magenta {50 "#EC266C"
60 "#BD1E56"}
:indigo {50 "#496289"
60 "#3D5273"}
:danger {50 danger-50
60 danger-60} 60 danger-60}
:success {50 success-50 :success {50 success-50
60 success-60}} 60 success-60}}
@ -244,9 +241,7 @@
([color suffix opacity] ([color suffix opacity]
(let [color-keyword (keyword color) (let [color-keyword (keyword color)
base-color (get-in colors-map base-color (get-in colors-map
[(if (= color-keyword :yinyang) [color-keyword suffix])]
(if (theme/dark?) :yang :yin)
(keyword color)) suffix])]
(if opacity (alpha base-color (/ opacity 100)) base-color)))))) (if opacity (alpha base-color (/ opacity 100)) base-color))))))
(defn custom-color-by-theme (defn custom-color-by-theme

View File

@ -12,16 +12,15 @@
{:width "100%" {:width "100%"
:padding-left 20 :padding-left 20
:padding-right 20 :padding-right 20
:padding-top (if platform/android? 0 12) :padding-top 12
:align-self :flex-end :align-self :flex-end
:height 64}) :height 64})
(def blur-button-container
(merge button-container
{:background-color colors/neutral-80-opa-1-blur}))
(def view-button-container (def view-button-container
(merge button-container {:margin-bottom 24})) (merge button-container {:margin-bottom 34}))
(def blur-button-container
(merge button-container (when platform/android? {:padding-bottom 12})))
(def page-container (def page-container
{:position :absolute {:position :absolute
@ -37,7 +36,7 @@
(def title (def title
{:color colors/white {:color colors/white
:margin-top 12 :margin-top 12
:margin-bottom 20}) :margin-bottom 18})
(def color-title (def color-title
{:color colors/white-70-blur {:color colors/white-70-blur

View File

@ -13,8 +13,12 @@
[utils.re-frame :as rf] [utils.re-frame :as rf]
[oops.core :as oops] [oops.core :as oops]
[react-native.blur :as blur] [react-native.blur :as blur]
[status-im2.constants :as c])) [status-im2.constants :as c]
[react-native.platform :as platform]))
;; NOTE - validation should match with Desktop
;; https://github.com/status-im/status-desktop/blob/2ba96803168461088346bf5030df750cb226df4c/ui/imports/utils/Constants.qml#L468
;;
(def emoji-regex (def emoji-regex
(new (new
js/RegExp js/RegExp
@ -23,12 +27,10 @@
(defn has-emojis [s] (re-find emoji-regex s)) (defn has-emojis [s] (re-find emoji-regex s))
(def common-names ["Ethereum" "Bitcoin"]) (def common-names ["Ethereum" "Bitcoin"])
(defn has-common-names [s] (pos? (count (filter #(string/includes? s %) common-names)))) (defn has-common-names [s] (pos? (count (filter #(string/includes? s %) common-names))))
(def special-characters-regex (new js/RegExp #"[^a-zA-Z\d\s-._]" "i")) (def status-regex (new js/RegExp #"^[a-zA-Z0-9\-_ ]+$"))
(defn has-special-characters [s] (re-find special-characters-regex s)) (defn has-special-characters [s] (not (re-find status-regex s)))
(def min-length 5) (def min-length 5)
(defn length-not-valid [s] (< (count (string/trim s)) min-length)) (defn length-not-valid [s] (< (count (string/trim (str s))) min-length))
(def valid-regex (new js/RegExp #"^[\w-\s]{5,24}$" "i"))
(defn valid-name [s] (re-find valid-regex s))
(defn validation-message (defn validation-message
[s] [s]
@ -39,18 +41,22 @@
(string/ends-with? s "-eth") (i18n/label :t/ending-not-allowed {:ending "-eth"}) (string/ends-with? s "-eth") (i18n/label :t/ending-not-allowed {:ending "-eth"})
(string/ends-with? s "_eth") (i18n/label :t/ending-not-allowed {:ending "_eth"}) (string/ends-with? s "_eth") (i18n/label :t/ending-not-allowed {:ending "_eth"})
(string/ends-with? s ".eth") (i18n/label :t/ending-not-allowed {:ending ".eth"}) (string/ends-with? s ".eth") (i18n/label :t/ending-not-allowed {:ending ".eth"})
(string/starts-with? s " ") (i18n/label :t/start-with-space)
(string/ends-with? s " ") (i18n/label :t/ends-with-space)
(has-common-names s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/common-names)}) (has-common-names s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/common-names)})
(has-emojis s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/emojis)}) (has-emojis s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/emojis)})
(length-not-valid s) (i18n/label :t/name-must-have-at-least-characters
{:min-chars min-length})
(not (valid-name s)) (i18n/label :t/name-is-not-valid)
:else nil)) :else nil))
(defn button-container (defn button-container
[keyboard-shown? children] [keyboard-shown? children]
[rn/view {:style {:margin-top :auto}} [rn/view {:style {:margin-top :auto}}
(if keyboard-shown? (if keyboard-shown?
[blur/ios-view {:style style/blur-button-container} [blur/ios-view
{: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] children]
[rn/view {:style style/view-button-container} [rn/view {:style style/view-button-container}
children])]) children])])
@ -58,13 +64,17 @@
(defn- f-page (defn- f-page
[{:keys [onboarding-profile-data navigation-bar-top]}] [{:keys [onboarding-profile-data navigation-bar-top]}]
(reagent/with-let [keyboard-shown? (reagent/atom false) (reagent/with-let [keyboard-shown? (reagent/atom false)
will-show-listener (oops/ocall rn/keyboard show-listener (oops/ocall rn/keyboard
"addListener" "addListener"
"keyboardWillShow" (if platform/android?
"keyboardDidShow"
"keyboardWillShow")
#(reset! keyboard-shown? true)) #(reset! keyboard-shown? true))
will-hide-listener (oops/ocall rn/keyboard hide-listener (oops/ocall rn/keyboard
"addListener" "addListener"
"keyboardWillHide" (if platform/android?
"keyboardDidHide"
"keyboardWillHide")
#(reset! keyboard-shown? false)) #(reset! keyboard-shown? false))
{:keys [image-path display-name color]} onboarding-profile-data {:keys [image-path display-name color]} onboarding-profile-data
full-name (reagent/atom display-name) full-name (reagent/atom display-name)
@ -79,82 +89,92 @@
profile-pic (reagent/atom image-path) profile-pic (reagent/atom image-path)
on-change-profile-pic #(reset! profile-pic %) on-change-profile-pic #(reset! profile-pic %)
on-change #(reset! custom-color %)] on-change #(reset! custom-color %)]
[rn/view {:style style/page-container} (let [name-too-short? (length-not-valid @full-name)
[navigation-bar/navigation-bar {:top navigation-bar-top}] valid-name? (and (not @validation-msg) (not name-too-short?))
[rn/scroll-view info-message (if @validation-msg
{:keyboard-should-persist-taps :always @validation-msg
:content-container-style {:flex-grow 1}} (i18n/label :t/minimum-characters
{:min-chars min-length}))
info-type (cond @validation-msg :error
name-too-short? :default
:else :success)]
[rn/view {:style style/page-container} [rn/view {:style style/page-container}
[rn/view [navigation-bar/navigation-bar {:top navigation-bar-top}]
{:style style/content-container} [rn/scroll-view
[quo/text {:content-container-style {:flexGrow 1}}
{:size :heading-1 [rn/view {:style style/page-container}
:weight :semi-bold
:style style/title} (i18n/label :t/create-profile)]
[rn/view
{:style style/input-container}
[rn/view [rn/view
{:style style/profile-input-container} {:style style/content-container}
[quo/profile-input [quo/text
{:customization-color @custom-color {:size :heading-1
:placeholder (i18n/label :t/your-name) :weight :semi-bold
:on-press (fn [] :style style/title} (i18n/label :t/create-profile)]
(rf/dispatch [:dismiss-keyboard]) [rn/view
(rf/dispatch {:style style/input-container}
[:show-bottom-sheet [rn/view
{:override-theme :dark {:style style/profile-input-container}
:content [quo/profile-input
(fn [] {:customization-color @custom-color
[method-menu/view on-change-profile-pic])}])) :placeholder (i18n/label :t/your-name)
:image-picker-props {:profile-picture (when @profile-pic {:uri @profile-pic}) :on-press (fn []
:full-name (if (seq @full-name) (rf/dispatch [:dismiss-keyboard])
@full-name (rf/dispatch
(i18n/label :t/your-name)) [:show-bottom-sheet
:customization-color @custom-color} {:override-theme :dark
:title-input-props {:default-value @full-name :content
:auto-focus true (fn []
:max-length c/profile-name-max-length [method-menu/view on-change-profile-pic])}]))
:on-change-text on-change-text}}]] :image-picker-props {:profile-picture (when @profile-pic {:uri @profile-pic})
(when @validation-msg :full-name (if (seq @full-name)
@full-name
(i18n/label :t/your-name))
:customization-color @custom-color}
:title-input-props {:default-value @full-name
:auto-focus true
:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
[quo/info-message [quo/info-message
{:type :error {:type info-type
:size :default :size :default
:icon :i/info :icon (if valid-name? :i/positive-state :i/info)
:style style/info-message} :text-color (when (= :default info-type) colors/white-70-blur)
@validation-msg]) :icon-color (when (= :default info-type) colors/white-70-blur)
[quo/text :style style/info-message}
{:size :paragraph-2 info-message]
:weight :medium [quo/text
:style style/color-title} {:size :paragraph-2
(i18n/label :t/accent-colour)] :weight :medium
[quo/color-picker :style style/color-title}
{:blur? true (i18n/label :t/accent-colour)]
:default-selected? :blue [quo/color-picker
:selected @custom-color {:blur? true
:on-change on-change}]]]]] :default-selected? :blue
[rn/keyboard-avoiding-view :selected @custom-color
{:style {:position :absolute :on-change on-change}]]]]]
:top 0 [rn/keyboard-avoiding-view
:bottom 0 {:style {:position :absolute
:left 0 :top 0
:right 0} :bottom 0
:pointer-events :box-none} :left 0
[button-container @keyboard-shown? :right 0}
[quo/button :pointer-events :box-none}
{:accessibility-label :submit-create-profile-button [button-container @keyboard-shown?
:type :primary [quo/button
:override-background-color (colors/custom-color @custom-color 60) {:accessibility-label :submit-create-profile-button
:on-press (fn [] :type :primary
(rf/dispatch [:onboarding-2/profile-data-set :override-background-color (colors/custom-color @custom-color 60)
{:image-path @profile-pic :on-press (fn []
:display-name @full-name (rf/dispatch [:onboarding-2/profile-data-set
:color @custom-color}])) {:image-path @profile-pic
:style style/continue-button :display-name @full-name
:disabled (or (not (seq @full-name)) @validation-msg)} :color @custom-color}]))
(i18n/label :t/continue)]]]] :style style/continue-button
:disabled (or (not valid-name?) (not (seq @full-name)))}
(i18n/label :t/continue)]]]])
(finally (finally
(oops/ocall will-show-listener "remove") (oops/ocall show-listener "remove")
(oops/ocall will-hide-listener "remove")))) (oops/ocall hide-listener "remove"))))
(defn create-profile (defn create-profile
[] []

View File

@ -493,6 +493,7 @@
"enable-notifications-sub-title": "Receive notifications when somebody sends you a message or crypto to your wallet", "enable-notifications-sub-title": "Receive notifications when somebody sends you a message or crypto to your wallet",
"encrypt-with-password": "Encrypt with password", "encrypt-with-password": "Encrypt with password",
"ending-not-allowed": "{{ending}} ending is not allowed", "ending-not-allowed": "{{ending}} ending is not allowed",
"ends-with-space": "Cannot end with space",
"ens-10-SNT": "10 SNT", "ens-10-SNT": "10 SNT",
"ens-add-username": "Add username", "ens-add-username": "Add username",
"ens-agree-to": "Agree to ", "ens-agree-to": "Agree to ",
@ -1296,6 +1297,7 @@
"start-group-chat": "Start group chat", "start-group-chat": "Start group chat",
"start-new-chat": "Start new chat", "start-new-chat": "Start new chat",
"start-using-status": "Start using Status", "start-using-status": "Start using Status",
"start-with-space": "Cannot start with space",
"status": "Status", "status": "Status",
"status-confirmed": "Confirmed", "status-confirmed": "Confirmed",
"status-hardwallet": "Status hardwallet", "status-hardwallet": "Status hardwallet",
@ -2110,8 +2112,7 @@
"camera-permission-denied": "Permission denied", "camera-permission-denied": "Permission denied",
"enable-biometrics": "Enable biometrics", "enable-biometrics": "Enable biometrics",
"use-biometrics": "Use biometrics to fill in your password", "use-biometrics": "Use biometrics to fill in your password",
"name-must-have-at-least-characters": "Name must have at least {{min-chars}} characters", "minimum-characters": "Minimum {{min-chars}} characters",
"name-is-not-valid": "Name is not valid",
"no-communities": "No communities", "no-communities": "No communities",
"no-communities-description-strikethrough": "Never", "no-communities-description-strikethrough": "Never",
"no-communities-description": "go full nyan, find your community", "no-communities-description": "go full nyan, find your community",