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]
[test-helpers.component :as h]))
(def color-list [:blue :yellow :turquoise :copper :sky :camel :orange :army :pink :purple :magenta])
(h/describe "color-picker"
(h/test "color picker rendered"
(h/render [color-picker/view])
(-> (h/expect (h/get-all-by-label-text :color-picker-item))
(.toHaveLength 12)))
(.toHaveLength 11)))
(h/test "clicks on a color item"
(let [event (h/mock-fn)]
(h/render [color-picker/view {:on-change #(event)}])
@ -19,5 +21,11 @@
(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/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]))
(def color-picker-container
{:max-width 338
{:flex 1
:flex-direction :row
:flex-wrap :wrap
:justify-content :space-between})
@ -11,14 +11,17 @@
{:flex-basis "100%"
: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
[color selected?]
(merge {:width 48
:height 48
:border-width 4
:border-radius 24
:transform [{:rotate "45deg"}]
:border-color :transparent}
(merge color-button-common
(when selected?
{:border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4)

View File

@ -5,25 +5,27 @@
[reagent.core :as reagent]
[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
[blur?]
(concat (map (fn [color]
{:name color
:color (colors/custom-color-by-theme color (if blur? 60 50) 60)})
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))}]))
(map (fn [color]
{:name color
:color (colors/custom-color-by-theme color (if blur? 60 50) 60)})
color-list))
(defn- on-change-handler
[selected color-name on-change]
(reset! selected color-name)
(when on-change (on-change color-name)))
(defn empty-color-item
[]
[rn/view {:style style/color-button-common}])
(defn- color-item
[{:keys [name
color
@ -32,20 +34,24 @@
on-press
blur?]}]
(let [border? (and (not blur?) (and secondary-color (not selected?)))]
[rn/touchable-opacity
{:style (style/color-button color selected?)
:accessibility-label :color-picker-item
:on-press #(on-press name)}
[rn/view
{:style (style/color-circle color border?)}
(when (and secondary-color (not selected?))
[rn/view
{:style (style/secondary-overlay secondary-color border?)}])
(when selected?
[icon/icon :i/check
{:size 20
:color (or secondary-color
colors/white)}])]]))
(if (= :no-color name)
[empty-color-item]
[rn/touchable-opacity
{:style (style/color-button color selected?)
:accessibility-label :color-picker-item
:on-press #(on-press name)}
[rn/view
{:accessibile true
:accessibility-label name
:style (style/color-circle color border?)}
(when (and secondary-color (not selected?))
[rn/view
{:style (style/secondary-overlay secondary-color border?)}])
(when selected?
[icon/icon :i/check
{:size 20
:color (or secondary-color
colors/white)}])]])))
(defn view
"Options

View File

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

View File

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

View File

@ -13,8 +13,12 @@
[utils.re-frame :as rf]
[oops.core :as oops]
[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
(new
js/RegExp
@ -23,12 +27,10 @@
(defn has-emojis [s] (re-find emoji-regex s))
(def common-names ["Ethereum" "Bitcoin"])
(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"))
(defn has-special-characters [s] (re-find special-characters-regex s))
(def status-regex (new js/RegExp #"^[a-zA-Z0-9\-_ ]+$"))
(defn has-special-characters [s] (not (re-find status-regex s)))
(def min-length 5)
(defn length-not-valid [s] (< (count (string/trim s)) min-length))
(def valid-regex (new js/RegExp #"^[\w-\s]{5,24}$" "i"))
(defn valid-name [s] (re-find valid-regex s))
(defn length-not-valid [s] (< (count (string/trim (str s))) min-length))
(defn validation-message
[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/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-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))
(defn button-container
[keyboard-shown? children]
[rn/view {:style {:margin-top :auto}}
(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]
[rn/view {:style style/view-button-container}
children])])
@ -58,13 +64,17 @@
(defn- f-page
[{:keys [onboarding-profile-data navigation-bar-top]}]
(reagent/with-let [keyboard-shown? (reagent/atom false)
will-show-listener (oops/ocall rn/keyboard
show-listener (oops/ocall rn/keyboard
"addListener"
"keyboardWillShow"
(if platform/android?
"keyboardDidShow"
"keyboardWillShow")
#(reset! keyboard-shown? true))
will-hide-listener (oops/ocall rn/keyboard
hide-listener (oops/ocall rn/keyboard
"addListener"
"keyboardWillHide"
(if platform/android?
"keyboardDidHide"
"keyboardWillHide")
#(reset! keyboard-shown? false))
{:keys [image-path display-name color]} onboarding-profile-data
full-name (reagent/atom display-name)
@ -79,82 +89,92 @@
profile-pic (reagent/atom image-path)
on-change-profile-pic #(reset! profile-pic %)
on-change #(reset! custom-color %)]
[rn/view {:style style/page-container}
[navigation-bar/navigation-bar {:top navigation-bar-top}]
[rn/scroll-view
{:keyboard-should-persist-taps :always
:content-container-style {:flex-grow 1}}
(let [name-too-short? (length-not-valid @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 min-length}))
info-type (cond @validation-msg :error
name-too-short? :default
:else :success)]
[rn/view {:style style/page-container}
[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}
[navigation-bar/navigation-bar {:top navigation-bar-top}]
[rn/scroll-view
{:content-container-style {:flexGrow 1}}
[rn/view {:style style/page-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
{:override-theme :dark
:content
(fn []
[method-menu/view on-change-profile-pic])}]))
:image-picker-props {:profile-picture (when @profile-pic {:uri @profile-pic})
: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}}]]
(when @validation-msg
{: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
{:override-theme :dark
:content
(fn []
[method-menu/view on-change-profile-pic])}]))
:image-picker-props {:profile-picture (when @profile-pic {:uri @profile-pic})
: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
{:type :error
:size :default
:icon :i/info
:style style/info-message}
@validation-msg])
[quo/text
{:size :paragraph-2
:weight :medium
:style style/color-title}
(i18n/label :t/accent-colour)]
[quo/color-picker
{:blur? true
:default-selected? :blue
:selected @custom-color
:on-change on-change}]]]]]
[rn/keyboard-avoiding-view
{:style {:position :absolute
:top 0
:bottom 0
:left 0
:right 0}
:pointer-events :box-none}
[button-container @keyboard-shown?
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:override-background-color (colors/custom-color @custom-color 60)
:on-press (fn []
(rf/dispatch [:onboarding-2/profile-data-set
{:image-path @profile-pic
:display-name @full-name
:color @custom-color}]))
:style style/continue-button
:disabled (or (not (seq @full-name)) @validation-msg)}
(i18n/label :t/continue)]]]]
{:type info-type
:size :default
:icon (if valid-name? :i/positive-state :i/info)
:text-color (when (= :default info-type) colors/white-70-blur)
:icon-color (when (= :default info-type) colors/white-70-blur)
: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
:selected @custom-color
:on-change on-change}]]]]]
[rn/keyboard-avoiding-view
{:style {:position :absolute
:top 0
:bottom 0
:left 0
:right 0}
:pointer-events :box-none}
[button-container @keyboard-shown?
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:override-background-color (colors/custom-color @custom-color 60)
:on-press (fn []
(rf/dispatch [:onboarding-2/profile-data-set
{:image-path @profile-pic
:display-name @full-name
:color @custom-color}]))
:style style/continue-button
:disabled (or (not valid-name?) (not (seq @full-name)))}
(i18n/label :t/continue)]]]])
(finally
(oops/ocall will-show-listener "remove")
(oops/ocall will-hide-listener "remove"))))
(oops/ocall show-listener "remove")
(oops/ocall hide-listener "remove"))))
(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",
"encrypt-with-password": "Encrypt with password",
"ending-not-allowed": "{{ending}} ending is not allowed",
"ends-with-space": "Cannot end with space",
"ens-10-SNT": "10 SNT",
"ens-add-username": "Add username",
"ens-agree-to": "Agree to ",
@ -1296,6 +1297,7 @@
"start-group-chat": "Start group chat",
"start-new-chat": "Start new chat",
"start-using-status": "Start using Status",
"start-with-space": "Cannot start with space",
"status": "Status",
"status-confirmed": "Confirmed",
"status-hardwallet": "Status hardwallet",
@ -2110,8 +2112,7 @@
"camera-permission-denied": "Permission denied",
"enable-biometrics": "Enable biometrics",
"use-biometrics": "Use biometrics to fill in your password",
"name-must-have-at-least-characters": "Name must have at least {{min-chars}} characters",
"name-is-not-valid": "Name is not valid",
"minimum-characters": "Minimum {{min-chars}} characters",
"no-communities": "No communities",
"no-communities-description-strikethrough": "Never",
"no-communities-description": "go full nyan, find your community",