Standardized in-app authentication (#16916)
* chore: move password input to connected component --------- Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com> Co-authored-by: frank <lovefree103@gmail.com>
This commit is contained in:
parent
6b9b5fa300
commit
0522120c66
|
@ -70,7 +70,7 @@
|
||||||
[sliding-complete?]
|
[sliding-complete?]
|
||||||
(reset! sliding-complete? true))
|
(reset! sliding-complete? true))
|
||||||
|
|
||||||
(defn- reset-track-position
|
(defn reset-track-position
|
||||||
[x-pos]
|
[x-pos]
|
||||||
(animate-spring x-pos 0))
|
(animate-spring x-pos 0))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
(ns quo2.components.buttons.slide-button.component-spec
|
(ns quo2.components.buttons.slide-button.component-spec
|
||||||
(:require [quo2.components.buttons.slide-button.view :as slide-button]
|
(:require [quo2.components.buttons.slide-button.view :as slide-button]
|
||||||
[quo2.components.buttons.slide-button.constants :as constants]
|
[quo2.components.buttons.slide-button.constants :as constants]
|
||||||
[quo2.components.buttons.slide-button.utils :as utils]
|
|
||||||
["@testing-library/react-native" :as rtl]
|
["@testing-library/react-native" :as rtl]
|
||||||
["react-native-gesture-handler/jest-utils" :as gestures-jest]
|
["react-native-gesture-handler/jest-utils" :as gestures-jest]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
|
@ -82,17 +81,11 @@
|
||||||
(h/has-style track-mock {:opacity constants/disable-opacity})))
|
(h/has-style track-mock {:opacity constants/disable-opacity})))
|
||||||
|
|
||||||
(h/test "render the small button"
|
(h/test "render the small button"
|
||||||
(h/render [slide-button/view (assoc default-props :size :small)])
|
(h/render [slide-button/view (assoc default-props :size :size/s-40)])
|
||||||
(let [mock (h/get-by-test-id :slide-button-track)
|
(let [mock (h/get-by-test-id :slide-button-track)
|
||||||
small-height (:track-height constants/small-dimensions)]
|
small-height (:track-height constants/small-dimensions)]
|
||||||
(h/has-style mock {:height small-height})))
|
(h/has-style mock {:height small-height})))
|
||||||
|
|
||||||
(h/test "render with the correct customization-color"
|
|
||||||
(h/render [slide-button/view (assoc default-props :customization-color :purple)])
|
|
||||||
(let [track-mock (h/get-by-test-id :slide-button-track)
|
|
||||||
purple-color (utils/slider-color :track :purple)]
|
|
||||||
(h/has-style track-mock {:backgroundColor purple-color})))
|
|
||||||
|
|
||||||
(h/test
|
(h/test
|
||||||
"calls on-complete when dragged"
|
"calls on-complete when dragged"
|
||||||
(let [props (merge default-props {:on-complete (h/mock-fn)})
|
(let [props (merge default-props {:on-complete (h/mock-fn)})
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
:right 0})
|
:right 0})
|
||||||
|
|
||||||
(defn thumb-container
|
(defn thumb-container
|
||||||
[interpolate-track thumb-size customization-color]
|
[{:keys [interpolate-track thumb-size customization-color theme]}]
|
||||||
(reanimated/apply-animations-to-style
|
(reanimated/apply-animations-to-style
|
||||||
{:transform [{:translate-x (interpolate-track :track-clamp)}]}
|
{:transform [{:translate-x (interpolate-track :track-clamp)}]}
|
||||||
{:background-color (utils/slider-color :main customization-color)
|
{:background-color (utils/slider-color :main customization-color theme)
|
||||||
:border-radius 12
|
:border-radius 12
|
||||||
:height thumb-size
|
:height thumb-size
|
||||||
:width thumb-size
|
:width thumb-size
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
:justify-content :space-around}))
|
:justify-content :space-around}))
|
||||||
|
|
||||||
(defn track
|
(defn track
|
||||||
[disabled? customization-color height]
|
[{:keys [disabled? customization-color height theme]}]
|
||||||
{:align-items :flex-start
|
{:align-items :flex-start
|
||||||
:justify-content :center
|
:justify-content :center
|
||||||
:border-radius 14
|
:border-radius 14
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
:align-self :stretch
|
:align-self :stretch
|
||||||
:padding constants/track-padding
|
:padding constants/track-padding
|
||||||
:opacity (if disabled? 0.3 1)
|
:opacity (if disabled? 0.3 1)
|
||||||
:background-color (utils/slider-color :track customization-color)})
|
:background-color (utils/slider-color :track customization-color theme)})
|
||||||
|
|
||||||
(defn track-cover
|
(defn track-cover
|
||||||
[interpolate-track]
|
[interpolate-track]
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
:width track-width})
|
:width track-width})
|
||||||
|
|
||||||
(defn track-text
|
(defn track-text
|
||||||
[customization-color]
|
[customization-color theme]
|
||||||
(-> typography/paragraph-1
|
(-> typography/paragraph-1
|
||||||
(merge typography/font-medium)
|
(merge typography/font-medium)
|
||||||
(assoc :color (utils/slider-color :main customization-color))))
|
(assoc :color (utils/slider-color :main customization-color theme))))
|
||||||
|
|
|
@ -6,9 +6,15 @@
|
||||||
(defn slider-color
|
(defn slider-color
|
||||||
"- `color-key` `:main`/`:track`
|
"- `color-key` `:main`/`:track`
|
||||||
- `customization-color` Customization color"
|
- `customization-color` Customization color"
|
||||||
[color-key customization-color]
|
[color-key customization-color theme]
|
||||||
(let [colors-by-key {:main (colors/custom-color-by-theme customization-color 50 60)
|
(let [colors-by-key {:main (colors/theme-colors
|
||||||
:track (colors/custom-color-by-theme customization-color 50 60 10 10)}]
|
(colors/custom-color customization-color 50)
|
||||||
|
(colors/custom-color customization-color 60)
|
||||||
|
theme)
|
||||||
|
:track (colors/theme-colors
|
||||||
|
(colors/custom-color customization-color 50 10)
|
||||||
|
(colors/custom-color customization-color 60 10)
|
||||||
|
theme)}]
|
||||||
(color-key colors-by-key)))
|
(color-key colors-by-key)))
|
||||||
|
|
||||||
(defn clamp-value
|
(defn clamp-value
|
||||||
|
@ -28,8 +34,8 @@
|
||||||
(defn get-dimensions
|
(defn get-dimensions
|
||||||
[track-width size dimension-key]
|
[track-width size dimension-key]
|
||||||
(let [default-dimensions (case size
|
(let [default-dimensions (case size
|
||||||
:small constants/small-dimensions
|
:size/s-40 constants/small-dimensions
|
||||||
:large constants/large-dimensions
|
:size/s-48 constants/large-dimensions
|
||||||
constants/large-dimensions)]
|
constants/large-dimensions)]
|
||||||
(-> default-dimensions
|
(-> default-dimensions
|
||||||
(merge {:usable-track (calc-usable-track
|
(merge {:usable-track (calc-usable-track
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[oops.core :as oops]
|
[oops.core :as oops]
|
||||||
[react-native.reanimated :as reanimated]
|
[react-native.reanimated :as reanimated]
|
||||||
[quo2.components.buttons.slide-button.constants :as constants]))
|
[quo2.components.buttons.slide-button.constants :as constants]
|
||||||
|
[quo2.theme :as quo.theme]))
|
||||||
|
|
||||||
(defn- f-slider
|
(defn- f-slider
|
||||||
[{:keys [disabled?]}]
|
[{:keys [disabled?]}]
|
||||||
|
@ -20,14 +21,15 @@
|
||||||
on-track-layout (fn [evt]
|
on-track-layout (fn [evt]
|
||||||
(let [width (oops/oget evt "nativeEvent.layout.width")]
|
(let [width (oops/oget evt "nativeEvent.layout.width")]
|
||||||
(reset! track-width width)))]
|
(reset! track-width width)))]
|
||||||
|
(fn [{:keys [on-reset
|
||||||
(fn [{:keys [on-complete
|
on-complete
|
||||||
track-text
|
track-text
|
||||||
track-icon
|
track-icon
|
||||||
disabled?
|
disabled?
|
||||||
customization-color
|
customization-color
|
||||||
size
|
size
|
||||||
container-style]}]
|
container-style
|
||||||
|
theme]}]
|
||||||
(let [x-pos (reanimated/use-shared-value 0)
|
(let [x-pos (reanimated/use-shared-value 0)
|
||||||
dimensions (partial utils/get-dimensions
|
dimensions (partial utils/get-dimensions
|
||||||
(or @track-width constants/default-width)
|
(or @track-width constants/default-width)
|
||||||
|
@ -36,12 +38,19 @@
|
||||||
x-pos
|
x-pos
|
||||||
(dimensions :usable-track)
|
(dimensions :usable-track)
|
||||||
(dimensions :thumb))]
|
(dimensions :thumb))]
|
||||||
|
|
||||||
(rn/use-effect (fn []
|
(rn/use-effect (fn []
|
||||||
(when @sliding-complete?
|
(when @sliding-complete?
|
||||||
(on-complete)))
|
(on-complete)))
|
||||||
[@sliding-complete?])
|
[@sliding-complete?])
|
||||||
|
|
||||||
|
(rn/use-effect (fn []
|
||||||
|
(when on-reset
|
||||||
|
(reset! sliding-complete? false)
|
||||||
|
(reset! gestures-disabled? false)
|
||||||
|
(animations/reset-track-position x-pos)
|
||||||
|
(on-reset)))
|
||||||
|
[on-reset])
|
||||||
|
|
||||||
[gesture/gesture-detector
|
[gesture/gesture-detector
|
||||||
{:gesture (animations/drag-gesture x-pos
|
{:gesture (animations/drag-gesture x-pos
|
||||||
gestures-disabled?
|
gestures-disabled?
|
||||||
|
@ -50,21 +59,25 @@
|
||||||
sliding-complete?)}
|
sliding-complete?)}
|
||||||
[reanimated/view
|
[reanimated/view
|
||||||
{:test-ID :slide-button-track
|
{:test-ID :slide-button-track
|
||||||
:style (merge (style/track disabled? customization-color (dimensions :track-height))
|
:style (merge (style/track {:disabled? disabled?
|
||||||
|
:customization-color customization-color
|
||||||
|
:height (dimensions :track-height)
|
||||||
|
:theme theme})
|
||||||
container-style)
|
container-style)
|
||||||
:on-layout (when-not (some? @track-width)
|
:on-layout (when-not (some? @track-width)
|
||||||
on-track-layout)}
|
on-track-layout)}
|
||||||
[reanimated/view {:style (style/track-cover interpolate-track)}
|
[reanimated/view {:style (style/track-cover interpolate-track)}
|
||||||
[rn/view {:style (style/track-cover-text-container @track-width)}
|
[rn/view {:style (style/track-cover-text-container @track-width)}
|
||||||
[icon/icon track-icon
|
[icon/icon track-icon
|
||||||
{:color (utils/slider-color :main customization-color)
|
{:color (utils/slider-color :main customization-color theme)
|
||||||
:size 20}]
|
:size 20}]
|
||||||
[rn/view {:width 4}]
|
[rn/view {:width 4}]
|
||||||
[rn/text {:style (style/track-text customization-color)} track-text]]]
|
[rn/text {:style (style/track-text customization-color theme)} track-text]]]
|
||||||
[reanimated/view
|
[reanimated/view
|
||||||
{:style (style/thumb-container interpolate-track
|
{:style (style/thumb-container {:interpolate-track interpolate-track
|
||||||
(dimensions :thumb)
|
:thumb-size (dimensions :thumb)
|
||||||
customization-color)}
|
:customization-color customization-color
|
||||||
|
:theme theme})}
|
||||||
[reanimated/view {:style (style/arrow-icon-container interpolate-track)}
|
[reanimated/view {:style (style/arrow-icon-container interpolate-track)}
|
||||||
[icon/icon :arrow-right
|
[icon/icon :arrow-right
|
||||||
{:color colors/white
|
{:color colors/white
|
||||||
|
@ -76,16 +89,19 @@
|
||||||
{:color colors/white
|
{:color colors/white
|
||||||
:size 20}]]]]]))))
|
:size 20}]]]]]))))
|
||||||
|
|
||||||
(defn view
|
(defn- view-internal
|
||||||
"Options
|
"Options
|
||||||
- `on-complete` Callback called when the sliding is complete
|
- `on-complete` Callback called when the sliding is complete
|
||||||
- `disabled?` Boolean that disables the button
|
- `disabled?` Boolean that disables the button
|
||||||
(_and gestures_)
|
(_and gestures_)
|
||||||
- `size` `:small`/`:large`
|
- `size` :size/s-40`/`:size/s-48`
|
||||||
- `track-text` Text that is shown on the track
|
- `track-text` Text that is shown on the track
|
||||||
- `track-icon` Key of the icon shown on the track
|
- `track-icon` Key of the icon shown on the track
|
||||||
(e.g. `:face-id`)
|
(e.g. `:face-id`)
|
||||||
- `customization-color` Customization color
|
- `customization-color` Customization color
|
||||||
|
- `on-reset` A callback which can be used to reset the component and run required functionality
|
||||||
"
|
"
|
||||||
[props]
|
[props]
|
||||||
[:f> f-slider props])
|
[:f> f-slider props])
|
||||||
|
|
||||||
|
(def view (quo.theme/with-theme view-internal))
|
||||||
|
|
|
@ -15,5 +15,5 @@
|
||||||
(defn authenticate
|
(defn authenticate
|
||||||
[{:keys [on-success on-fail reason options]}]
|
[{:keys [on-success on-fail reason options]}]
|
||||||
(-> (.authenticate ^js touchid reason (clj->js options))
|
(-> (.authenticate ^js touchid reason (clj->js options))
|
||||||
(.then #(when on-success (on-success)))
|
(.then #(when on-success (on-success %)))
|
||||||
(.catch #(when on-fail (on-fail (aget % "code"))))))
|
(.catch #(when on-fail (on-fail (aget % "code"))))))
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
(defn hide
|
(defn hide
|
||||||
[translate-y bg-opacity window-height on-close]
|
[translate-y bg-opacity window-height on-close]
|
||||||
|
(rf/dispatch [:dismiss-keyboard])
|
||||||
(when (fn? on-close)
|
(when (fn? on-close)
|
||||||
(on-close))
|
(on-close))
|
||||||
;; it will be better to use animation callback, but it doesn't work
|
;; it will be better to use animation callback, but it doesn't work
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
(ns status-im2.common.standard-authentication.enter-password.style)
|
||||||
|
|
||||||
|
(def enter-password-container
|
||||||
|
{:margin-horizontal 20
|
||||||
|
:border-top-left-radius 12
|
||||||
|
:border-top-right-radius 12})
|
||||||
|
|
||||||
|
(def error-message
|
||||||
|
{:margin-top 8
|
||||||
|
:flex-direction :row
|
||||||
|
:align-items :center})
|
||||||
|
|
||||||
|
(def enter-password-button
|
||||||
|
{:margin-top 45
|
||||||
|
:margin-bottom 12})
|
||||||
|
|
||||||
|
(def context-tag
|
||||||
|
{:flex-direction :row
|
||||||
|
:margin-bottom 20
|
||||||
|
:margin-top 8})
|
|
@ -0,0 +1,53 @@
|
||||||
|
(ns status-im2.common.standard-authentication.enter-password.view
|
||||||
|
(:require [utils.i18n :as i18n]
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[status-im2.common.standard-authentication.enter-password.style :as style]
|
||||||
|
[status-im2.common.standard-authentication.password-input.view :as password-input]
|
||||||
|
[status-im.multiaccounts.core :as multiaccounts]))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[{:keys [on-enter-password button-label]}]
|
||||||
|
(let [{:keys [key-uid display-name
|
||||||
|
customization-color]
|
||||||
|
:as account} (rf/sub [:profile/multiaccount])
|
||||||
|
{:keys [error processing password]} (rf/sub [:profile/login])
|
||||||
|
sign-in-enabled? (rf/sub [:sign-in-enabled?])
|
||||||
|
profile-picture (multiaccounts/displayed-photo account)]
|
||||||
|
[:<>
|
||||||
|
[rn/view {:style style/enter-password-container}
|
||||||
|
[rn/view
|
||||||
|
[quo/text
|
||||||
|
{:accessibility-label :sync-code-generated
|
||||||
|
:weight :bold
|
||||||
|
:size :heading-1
|
||||||
|
:style {:margin-bottom 4}}
|
||||||
|
(i18n/label :t/enter-password)]
|
||||||
|
[rn/view
|
||||||
|
{:style style/context-tag}
|
||||||
|
[quo/context-tag
|
||||||
|
{:type :default
|
||||||
|
:blur? true
|
||||||
|
:profile-picture profile-picture
|
||||||
|
:full-name display-name
|
||||||
|
:customization-color customization-color
|
||||||
|
:size 24}]]
|
||||||
|
[password-input/view
|
||||||
|
{:processing processing
|
||||||
|
:error error
|
||||||
|
:default-password password
|
||||||
|
:sign-in-enabled? sign-in-enabled?}]
|
||||||
|
[rn/view {:style style/enter-password-button}
|
||||||
|
[quo/button
|
||||||
|
{:size 40
|
||||||
|
:type :primary
|
||||||
|
:customization-color (or customization-color :primary)
|
||||||
|
:accessibility-label :login-button
|
||||||
|
:icon-left :i/reveal
|
||||||
|
:disabled? (or (not sign-in-enabled?) processing)
|
||||||
|
:on-press (fn []
|
||||||
|
(rf/dispatch [:set-in [:profile/login :key-uid] key-uid])
|
||||||
|
(rf/dispatch [:profile.login/verify-database-password password
|
||||||
|
#(on-enter-password password)]))}
|
||||||
|
button-label]]]]]))
|
|
@ -0,0 +1,6 @@
|
||||||
|
(ns status-im2.common.standard-authentication.forgot-password-doc.style)
|
||||||
|
|
||||||
|
(def container {:margin-right 16})
|
||||||
|
(def step-container {:flex-direction :row :margin-top 14})
|
||||||
|
(def step-content {:margin-left 10})
|
||||||
|
(def step-title {:flex-direction :row})
|
|
@ -0,0 +1,52 @@
|
||||||
|
(ns status-im2.common.standard-authentication.forgot-password-doc.view
|
||||||
|
(:require [status-im2.common.standard-authentication.forgot-password-doc.style :as style]
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[utils.i18n :as i18n]))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[{:keys [shell?]}]
|
||||||
|
[quo/documentation-drawers
|
||||||
|
{:title (i18n/label :t/forgot-your-password-info-title)
|
||||||
|
:shell? shell?}
|
||||||
|
[rn/view
|
||||||
|
{:style style/container}
|
||||||
|
[quo/text {:size :paragraph-2} (i18n/label :t/forgot-your-password-info-description)]
|
||||||
|
|
||||||
|
[rn/view {:style style/step-container}
|
||||||
|
[quo/step {:in-blur-view? shell?} 1]
|
||||||
|
[rn/view
|
||||||
|
{:style style/step-content}
|
||||||
|
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
||||||
|
(i18n/label :t/forgot-your-password-info-remove-app)]
|
||||||
|
[quo/text {:size :paragraph-2} (i18n/label :t/forgot-your-password-info-remove-app-description)]]]
|
||||||
|
|
||||||
|
[rn/view {:style style/step-container}
|
||||||
|
[quo/step {:in-blur-view? shell?} 2]
|
||||||
|
[rn/view
|
||||||
|
{:style style/step-content}
|
||||||
|
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
||||||
|
(i18n/label :t/forgot-your-password-info-reinstall-app)]
|
||||||
|
[quo/text {:size :paragraph-2}
|
||||||
|
(i18n/label :t/forgot-your-password-info-reinstall-app-description)]]]
|
||||||
|
|
||||||
|
[rn/view {:style style/step-container}
|
||||||
|
[quo/step {:in-blur-view? shell?} 3]
|
||||||
|
[rn/view
|
||||||
|
{:style style/step-content}
|
||||||
|
[rn/view
|
||||||
|
{:style style/step-title}
|
||||||
|
[quo/text {:size :paragraph-2} (str (i18n/label :t/sign-up) " ")]
|
||||||
|
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
||||||
|
(i18n/label :t/forgot-your-password-info-signup-with-key)]]
|
||||||
|
[quo/text {:size :paragraph-2}
|
||||||
|
(i18n/label :t/forgot-your-password-info-signup-with-key-description)]]]
|
||||||
|
|
||||||
|
[rn/view {:style style/step-container}
|
||||||
|
[quo/step {:in-blur-view? shell?} 4]
|
||||||
|
[rn/view
|
||||||
|
{:style style/step-content}
|
||||||
|
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
||||||
|
(i18n/label :t/forgot-your-password-info-create-new-password)]
|
||||||
|
[quo/text {:size :paragraph-2}
|
||||||
|
(i18n/label :t/forgot-your-password-info-create-new-password-description)]]]]])
|
|
@ -0,0 +1,6 @@
|
||||||
|
(ns status-im2.common.standard-authentication.password-input.style)
|
||||||
|
|
||||||
|
(def error-message
|
||||||
|
{:margin-top 8
|
||||||
|
:flex-direction :row
|
||||||
|
:align-items :center})
|
|
@ -0,0 +1,70 @@
|
||||||
|
(ns status-im2.common.standard-authentication.password-input.view
|
||||||
|
(:require [quo2.core :as quo]
|
||||||
|
[quo2.foundations.colors :as colors]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[utils.i18n :as i18n]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[utils.security.core :as security]
|
||||||
|
[status-im2.common.standard-authentication.password-input.style :as style]
|
||||||
|
[status-im2.common.standard-authentication.forgot-password-doc.view :as forgot-password-doc]
|
||||||
|
[quo2.theme :as quo.theme]
|
||||||
|
[clojure.string :as string]))
|
||||||
|
|
||||||
|
(defn get-error-message
|
||||||
|
[error]
|
||||||
|
(if (and (some? error)
|
||||||
|
(or (= error "file is not a database")
|
||||||
|
(string/starts-with? error "failed to set ")
|
||||||
|
(string/starts-with? error "Failed")))
|
||||||
|
(i18n/label :t/oops-wrong-password)
|
||||||
|
error))
|
||||||
|
|
||||||
|
(defn- on-change-password
|
||||||
|
[entered-password]
|
||||||
|
(rf/dispatch [:set-in [:profile/login :password]
|
||||||
|
(security/mask-data entered-password)])
|
||||||
|
(rf/dispatch [:set-in [:profile/login :error] ""]))
|
||||||
|
|
||||||
|
(defn- view-internal
|
||||||
|
[{:keys [default-password theme shell?]}]
|
||||||
|
(let [{:keys [error processing]} (rf/sub [:profile/login])
|
||||||
|
error-message (get-error-message error)
|
||||||
|
error? (boolean (seq error-message))]
|
||||||
|
[:<>
|
||||||
|
[quo/input
|
||||||
|
{:type :password
|
||||||
|
:blur? true
|
||||||
|
:disabled? processing
|
||||||
|
:placeholder (i18n/label :t/type-your-password)
|
||||||
|
:auto-focus true
|
||||||
|
:error? error?
|
||||||
|
:label (i18n/label :t/profile-password)
|
||||||
|
:on-change-text on-change-password
|
||||||
|
:default-value (security/safe-unmask-data default-password)}]
|
||||||
|
(when error?
|
||||||
|
[rn/view {:style style/error-message}
|
||||||
|
[quo/info-message
|
||||||
|
{:type :error
|
||||||
|
:size :default
|
||||||
|
:icon :i/info}
|
||||||
|
error-message]
|
||||||
|
[rn/pressable
|
||||||
|
{:hit-slop {:top 6 :bottom 20 :left 0 :right 0}
|
||||||
|
:disabled processing
|
||||||
|
:on-press (fn []
|
||||||
|
(rn/dismiss-keyboard!)
|
||||||
|
(rf/dispatch [:show-bottom-sheet
|
||||||
|
{:content #(forgot-password-doc/view {:shell? shell?})
|
||||||
|
:theme theme
|
||||||
|
:shell? shell?}]))}
|
||||||
|
[rn/text
|
||||||
|
{:style {:text-decoration-line :underline
|
||||||
|
:color (colors/theme-colors
|
||||||
|
(colors/custom-color :danger 50)
|
||||||
|
(colors/custom-color :danger 60)
|
||||||
|
theme)}
|
||||||
|
:size :paragraph-2
|
||||||
|
:suppress-highlighting true}
|
||||||
|
(i18n/label :t/forgot-password)]]])]))
|
||||||
|
|
||||||
|
(def view (quo.theme/with-theme view-internal))
|
|
@ -0,0 +1,79 @@
|
||||||
|
(ns status-im2.common.standard-authentication.standard-auth.view
|
||||||
|
(:require
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[quo2.theme :as quo.theme]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[react-native.touch-id :as biometric]
|
||||||
|
[utils.i18n :as i18n]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[status-im2.common.standard-authentication.enter-password.view :as enter-password]
|
||||||
|
[react-native.core :as rn]))
|
||||||
|
|
||||||
|
(defn reset-password
|
||||||
|
[]
|
||||||
|
(rf/dispatch [:set-in [:profile/login :password] nil])
|
||||||
|
(rf/dispatch [:set-in [:profile/login :error] ""]))
|
||||||
|
|
||||||
|
(defn authorize
|
||||||
|
[{:keys [on-enter-password biometric-auth? on-auth-success on-auth-fail on-close
|
||||||
|
fallback-button-label theme blur?]}]
|
||||||
|
(biometric/get-supported-type
|
||||||
|
(fn [biometric-type]
|
||||||
|
(if (and biometric-auth? biometric-type)
|
||||||
|
(biometric/authenticate
|
||||||
|
{:reason (i18n/label :t/biometric-auth-confirm-message)
|
||||||
|
:on-success (fn [response]
|
||||||
|
(when on-auth-success (on-auth-success response))
|
||||||
|
(log/info "response" response))
|
||||||
|
:on-fail (fn [error]
|
||||||
|
(log/error "Authentication Failed. Error:" error)
|
||||||
|
(when on-auth-fail (on-auth-fail error))
|
||||||
|
(rf/dispatch [:show-bottom-sheet
|
||||||
|
{:theme theme
|
||||||
|
:shell? blur?
|
||||||
|
:content (fn []
|
||||||
|
[enter-password/view
|
||||||
|
{:on-enter-password on-enter-password}])}]))})
|
||||||
|
(do
|
||||||
|
(reset-password)
|
||||||
|
(rf/dispatch [:show-bottom-sheet
|
||||||
|
{:on-close on-close
|
||||||
|
:theme theme
|
||||||
|
:shell? blur?
|
||||||
|
:content (fn []
|
||||||
|
[enter-password/view
|
||||||
|
{:on-enter-password on-enter-password
|
||||||
|
:button-label fallback-button-label}])}]))))))
|
||||||
|
|
||||||
|
(defn- view-internal
|
||||||
|
[_]
|
||||||
|
(let [reset-slider? (reagent/atom false)
|
||||||
|
on-close #(reset! reset-slider? true)]
|
||||||
|
(fn [{:keys [biometric-auth?
|
||||||
|
track-text
|
||||||
|
customization-color
|
||||||
|
fallback-button-label
|
||||||
|
on-enter-password
|
||||||
|
on-auth-success
|
||||||
|
on-auth-fail
|
||||||
|
size
|
||||||
|
theme
|
||||||
|
blur?]}]
|
||||||
|
[rn/view {:style {:flex 1}}
|
||||||
|
[quo/slide-button
|
||||||
|
{:size size
|
||||||
|
:customization-color customization-color
|
||||||
|
:on-reset (when @reset-slider? #(reset! reset-slider? false))
|
||||||
|
:on-complete #(authorize {:on-close on-close
|
||||||
|
:theme theme
|
||||||
|
:blur? blur?
|
||||||
|
:on-enter-password on-enter-password
|
||||||
|
:biometric-auth? biometric-auth?
|
||||||
|
:on-auth-success on-auth-success
|
||||||
|
:on-auth-fail on-auth-fail
|
||||||
|
:fallback-button-label fallback-button-label})
|
||||||
|
:track-icon :i/face-id
|
||||||
|
:track-text track-text}]])))
|
||||||
|
|
||||||
|
(def view (quo.theme/with-theme view-internal))
|
|
@ -181,3 +181,29 @@
|
||||||
(rf/merge cofx
|
(rf/merge cofx
|
||||||
(navigation/init-root :profiles)
|
(navigation/init-root :profiles)
|
||||||
(biometric/show-message code)))
|
(biometric/show-message code)))
|
||||||
|
|
||||||
|
(rf/defn verify-database-password
|
||||||
|
{:events [:profile.login/verify-database-password]}
|
||||||
|
[_ entered-password cb]
|
||||||
|
(let [hashed-password (-> entered-password
|
||||||
|
security/safe-unmask-data
|
||||||
|
native-module/sha3)]
|
||||||
|
{:json-rpc/call [{:method "accounts_verifyPassword"
|
||||||
|
:params [hashed-password]
|
||||||
|
:on-success #(do (rf/dispatch [:profile.login/verified-database-password %]) (cb))
|
||||||
|
:on-error #(log/error "accounts_verifyPassword error" %)}]}))
|
||||||
|
|
||||||
|
(rf/defn verify-database-password-success
|
||||||
|
{:events [:profile.login/verified-database-password]}
|
||||||
|
[{:keys [db] :as cofx} valid?]
|
||||||
|
(if valid?
|
||||||
|
(do
|
||||||
|
{:db (update db
|
||||||
|
:profile/login
|
||||||
|
dissoc
|
||||||
|
:processing :error)})
|
||||||
|
{:db (update db
|
||||||
|
:profile/login
|
||||||
|
#(-> %
|
||||||
|
(dissoc :processing)
|
||||||
|
(assoc :error "Invalid password")))}))
|
||||||
|
|
|
@ -53,12 +53,3 @@
|
||||||
(def login-profile-card
|
(def login-profile-card
|
||||||
{:margin-bottom 20})
|
{:margin-bottom 20})
|
||||||
|
|
||||||
(def error-message
|
|
||||||
{:margin-top 8
|
|
||||||
:flex-direction :row
|
|
||||||
:align-items :center})
|
|
||||||
|
|
||||||
(def forget-password-doc-container {:margin-right 16})
|
|
||||||
(def forget-password-step-container {:flex-direction :row :margin-top 14})
|
|
||||||
(def forget-password-step-content {:margin-left 10})
|
|
||||||
(def forget-password-step-title {:flex-direction :row})
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
(ns status-im2.contexts.profile.profiles.view
|
(ns status-im2.contexts.profile.profiles.view
|
||||||
(:require [clojure.string :as string]
|
(:require [native-module.core :as native-module]
|
||||||
[native-module.core :as native-module]
|
|
||||||
[quo2.core :as quo]
|
[quo2.core :as quo]
|
||||||
[quo2.foundations.colors :as colors]
|
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.reanimated :as reanimated]
|
[react-native.reanimated :as reanimated]
|
||||||
[react-native.safe-area :as safe-area]
|
[react-native.safe-area :as safe-area]
|
||||||
|
@ -15,8 +13,8 @@
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[utils.security.core :as security]
|
[utils.transforms :as transforms]
|
||||||
[utils.transforms :as transforms]))
|
[status-im2.common.standard-authentication.password-input.view :as password-input]))
|
||||||
|
|
||||||
(defonce push-animation-fn-atom (atom nil))
|
(defonce push-animation-fn-atom (atom nil))
|
||||||
(defonce pop-animation-fn-atom (atom nil))
|
(defonce pop-animation-fn-atom (atom nil))
|
||||||
|
@ -166,69 +164,12 @@
|
||||||
[props]
|
[props]
|
||||||
[:f> f-profiles-section props])
|
[:f> f-profiles-section props])
|
||||||
|
|
||||||
(defn forget-password-doc
|
|
||||||
[]
|
|
||||||
[quo/documentation-drawers
|
|
||||||
{:title (i18n/label :t/forgot-your-password-info-title)
|
|
||||||
:shell? true}
|
|
||||||
[rn/view
|
|
||||||
{:style style/forget-password-doc-container}
|
|
||||||
[quo/text {:size :paragraph-2} (i18n/label :t/forgot-your-password-info-description)]
|
|
||||||
|
|
||||||
[rn/view {:style style/forget-password-step-container}
|
|
||||||
[quo/step {:in-blur-view? true} 1]
|
|
||||||
[rn/view
|
|
||||||
{:style style/forget-password-step-content}
|
|
||||||
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
|
||||||
(i18n/label :t/forgot-your-password-info-remove-app)]
|
|
||||||
[quo/text {:size :paragraph-2} (i18n/label :t/forgot-your-password-info-remove-app-description)]]]
|
|
||||||
|
|
||||||
[rn/view {:style style/forget-password-step-container}
|
|
||||||
[quo/step {:in-blur-view? true} 2]
|
|
||||||
[rn/view
|
|
||||||
{:style style/forget-password-step-content}
|
|
||||||
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
|
||||||
(i18n/label :t/forgot-your-password-info-reinstall-app)]
|
|
||||||
[quo/text {:size :paragraph-2}
|
|
||||||
(i18n/label :t/forgot-your-password-info-reinstall-app-description)]]]
|
|
||||||
|
|
||||||
[rn/view {:style style/forget-password-step-container}
|
|
||||||
[quo/step {:in-blur-view? true} 3]
|
|
||||||
[rn/view
|
|
||||||
{:style style/forget-password-step-content}
|
|
||||||
[rn/view
|
|
||||||
{:style style/forget-password-step-title}
|
|
||||||
[quo/text {:size :paragraph-2} (str (i18n/label :t/sign-up) " ")]
|
|
||||||
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
|
||||||
(i18n/label :t/forgot-your-password-info-signup-with-key)]]
|
|
||||||
[quo/text {:size :paragraph-2}
|
|
||||||
(i18n/label :t/forgot-your-password-info-signup-with-key-description)]]]
|
|
||||||
|
|
||||||
[rn/view {:style style/forget-password-step-container}
|
|
||||||
[quo/step {:in-blur-view? true} 4]
|
|
||||||
[rn/view
|
|
||||||
{:style style/forget-password-step-content}
|
|
||||||
[quo/text {:size :paragraph-2 :weight :semi-bold}
|
|
||||||
(i18n/label :t/forgot-your-password-info-create-new-password)]
|
|
||||||
[quo/text {:size :paragraph-2}
|
|
||||||
(i18n/label :t/forgot-your-password-info-create-new-password-description)]]]]])
|
|
||||||
|
|
||||||
(defn- get-error-message
|
|
||||||
[error]
|
|
||||||
(if (and (some? error)
|
|
||||||
(or (= error "file is not a database")
|
|
||||||
(string/starts-with? error "failed to set ")
|
|
||||||
(string/starts-with? error "Failed")))
|
|
||||||
(i18n/label :t/oops-wrong-password)
|
|
||||||
error))
|
|
||||||
|
|
||||||
(defn login-section
|
(defn login-section
|
||||||
[{:keys [set-show-profiles]}]
|
[{:keys [set-show-profiles]}]
|
||||||
(let [{:keys [error processing password]} (rf/sub [:profile/login])
|
(let [{:keys [processing password]} (rf/sub [:profile/login])
|
||||||
{:keys [key-uid name customization-color]} (rf/sub [:profile/login-profile])
|
{:keys [key-uid name customization-color]} (rf/sub [:profile/login-profile])
|
||||||
sign-in-enabled? (rf/sub [:sign-in-enabled?])
|
sign-in-enabled? (rf/sub [:sign-in-enabled?])
|
||||||
profile-picture (rf/sub [:profile/login-profiles-picture key-uid])
|
profile-picture (rf/sub [:profile/login-profiles-picture key-uid])
|
||||||
error (get-error-message error)
|
|
||||||
login-multiaccount #(rf/dispatch [:profile.login/login])]
|
login-multiaccount #(rf/dispatch [:profile.login/login])]
|
||||||
[rn/keyboard-avoiding-view
|
[rn/keyboard-avoiding-view
|
||||||
{:style style/login-container
|
{:style style/login-container
|
||||||
|
@ -263,41 +204,9 @@
|
||||||
:customization-color (or customization-color :primary)
|
:customization-color (or customization-color :primary)
|
||||||
:profile-picture profile-picture
|
:profile-picture profile-picture
|
||||||
:card-style style/login-profile-card}]
|
:card-style style/login-profile-card}]
|
||||||
[quo/input
|
[password-input/view
|
||||||
{:type :password
|
{:shell? true
|
||||||
:blur? true
|
:default-password password}]]
|
||||||
:disabled? processing
|
|
||||||
:placeholder (i18n/label :t/type-your-password)
|
|
||||||
:auto-focus true
|
|
||||||
:error? (seq error)
|
|
||||||
:label (i18n/label :t/profile-password)
|
|
||||||
:on-change-text (fn [password]
|
|
||||||
(rf/dispatch [:set-in [:profile/login :password]
|
|
||||||
(security/mask-data password)])
|
|
||||||
(rf/dispatch [:set-in [:profile/login :error] ""]))
|
|
||||||
:default-value (security/safe-unmask-data password)
|
|
||||||
:on-submit-editing (when sign-in-enabled? login-multiaccount)}]
|
|
||||||
(when (seq error)
|
|
||||||
[rn/view {:style style/error-message}
|
|
||||||
[quo/info-message
|
|
||||||
{:type :error
|
|
||||||
:size :default
|
|
||||||
:icon :i/info}
|
|
||||||
error]
|
|
||||||
[rn/touchable-opacity
|
|
||||||
{:hit-slop {:top 6 :bottom 20 :left 0 :right 0}
|
|
||||||
:disabled processing
|
|
||||||
:active-opacity 1
|
|
||||||
:on-press (fn []
|
|
||||||
(rn/dismiss-keyboard!)
|
|
||||||
(rf/dispatch [:show-bottom-sheet
|
|
||||||
{:content forget-password-doc :shell? true}]))}
|
|
||||||
[rn/text
|
|
||||||
{:style {:text-decoration-line :underline
|
|
||||||
:color colors/danger-60}
|
|
||||||
:size :paragraph-2
|
|
||||||
:suppress-highlighting true}
|
|
||||||
(i18n/label :t/forgot-password)]]])]
|
|
||||||
[quo/button
|
[quo/button
|
||||||
{:size 40
|
{:size 40
|
||||||
:type :primary
|
:type :primary
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
(def descriptor
|
(def descriptor
|
||||||
[{:key :size
|
[{:key :size
|
||||||
:type :select
|
:type :select
|
||||||
:options [{:key :large}
|
:options [{:key :size/s-48}
|
||||||
{:key :small}]}
|
{:key :size/s-40}]}
|
||||||
{:key :disabled?
|
{:key :disabled?
|
||||||
:type :boolean}
|
:type :boolean}
|
||||||
(preview/customization-color-option {:key :color})])
|
(preview/customization-color-option {:key :color})])
|
||||||
|
@ -16,10 +16,8 @@
|
||||||
[]
|
[]
|
||||||
(let [state (reagent/atom {:disabled? false
|
(let [state (reagent/atom {:disabled? false
|
||||||
:color :blue
|
:color :blue
|
||||||
:size :large})
|
:size :size/s-48})
|
||||||
color (reagent/cursor state [:color])
|
color (reagent/cursor state [:color])
|
||||||
disabled? (reagent/cursor state [:disabled?])
|
|
||||||
size (reagent/cursor state [:size])
|
|
||||||
complete? (reagent/atom false)]
|
complete? (reagent/atom false)]
|
||||||
(fn []
|
(fn []
|
||||||
[preview/preview-container
|
[preview/preview-container
|
||||||
|
@ -31,8 +29,8 @@
|
||||||
{:track-text "We gotta slide"
|
{:track-text "We gotta slide"
|
||||||
:track-icon :face-id
|
:track-icon :face-id
|
||||||
:customization-color @color
|
:customization-color @color
|
||||||
:size @size
|
:size (:size @state)
|
||||||
:disabled? @disabled?
|
:disabled? (:disabled? @state)
|
||||||
:on-complete (fn []
|
:on-complete (fn []
|
||||||
(js/setTimeout (fn [] (reset! complete? true))
|
(js/setTimeout (fn [] (reset! complete? true))
|
||||||
1000)
|
1000)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns status-im2.contexts.syncing.events
|
(ns status-im2.contexts.syncing.events
|
||||||
(:require [native-module.core :as native-module]
|
(:require [native-module.core :as native-module]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[clojure.string :as string]
|
||||||
[status-im.data-store.settings :as data-store.settings]
|
[status-im.data-store.settings :as data-store.settings]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[status-im2.config :as config]
|
[status-im2.config :as config]
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[utils.security.core :as security]
|
[utils.security.core :as security]
|
||||||
[utils.transforms :as transforms]
|
[utils.transforms :as transforms]
|
||||||
|
[status-im2.contexts.syncing.utils :as sync-utils]
|
||||||
[react-native.platform :as platform]))
|
[react-native.platform :as platform]))
|
||||||
|
|
||||||
(rf/defn local-pairing-update-role
|
(rf/defn local-pairing-update-role
|
||||||
|
@ -73,16 +75,17 @@
|
||||||
(native-module/prepare-dir-and-update-config "" default-node-config-string callback)))
|
(native-module/prepare-dir-and-update-config "" default-node-config-string callback)))
|
||||||
|
|
||||||
(rf/defn preparations-for-connection-string
|
(rf/defn preparations-for-connection-string
|
||||||
{:events [:syncing/get-connection-string-for-bootstrapping-another-device]}
|
{:events [:syncing/get-connection-string]}
|
||||||
[{:keys [db]} entered-password set-code]
|
[{:keys [db] :as cofx} entered-password on-valid-connection-string]
|
||||||
(let [valid-password? (>= (count entered-password) constants/min-password-length)
|
(let [error (get-in db [:profile/login :error])
|
||||||
show-sheet (fn [connection-string]
|
handle-connection (fn [response]
|
||||||
(set-code connection-string)
|
(when (sync-utils/valid-connection-string? response)
|
||||||
|
(on-valid-connection-string response)
|
||||||
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender])
|
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender])
|
||||||
(rf/dispatch [:bottom-sheet/hide]))]
|
(rf/dispatch [:hide-bottom-sheet])))]
|
||||||
(if valid-password?
|
(when-not (and error (string/blank? error))
|
||||||
(let [sha3-pwd (native-module/sha3 (str (security/safe-unmask-data entered-password)))
|
(let [key-uid (get-in db [:profile/login :key-uid])
|
||||||
key-uid (get-in db [:profile/profile :key-uid])
|
sha3-pwd (native-module/sha3 (str (security/safe-unmask-data entered-password)))
|
||||||
config-map (.stringify js/JSON
|
config-map (.stringify js/JSON
|
||||||
(clj->js {:senderConfig {:keyUID key-uid
|
(clj->js {:senderConfig {:keyUID key-uid
|
||||||
:keystorePath ""
|
:keystorePath ""
|
||||||
|
@ -91,5 +94,4 @@
|
||||||
:serverConfig {:timeout 0}}))]
|
:serverConfig {:timeout 0}}))]
|
||||||
(native-module/get-connection-string-for-bootstrapping-another-device
|
(native-module/get-connection-string-for-bootstrapping-another-device
|
||||||
config-map
|
config-map
|
||||||
#(show-sheet %)))
|
handle-connection)))))
|
||||||
(show-sheet ""))))
|
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
:flex 1})
|
:flex 1})
|
||||||
|
|
||||||
(def page-container
|
(def page-container
|
||||||
{:margin-horizontal 20})
|
{:margin-top 14
|
||||||
|
:margin-horizontal 20})
|
||||||
|
|
||||||
(def title-container
|
(def title-container
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
|
@ -17,17 +18,18 @@
|
||||||
{:height 56})
|
{:height 56})
|
||||||
|
|
||||||
(def sync-code
|
(def sync-code
|
||||||
{:margin-top 36})
|
{:margin-top 20})
|
||||||
|
|
||||||
(defn qr-container
|
(def standard-auth
|
||||||
[valid-code?]
|
{:margin-top 12
|
||||||
(merge {:margin-top 12
|
:flex 1})
|
||||||
|
|
||||||
|
(def qr-container
|
||||||
|
{:margin-top 12
|
||||||
:background-color colors/white-opa-5
|
:background-color colors/white-opa-5
|
||||||
:border-radius 20
|
:border-radius 20
|
||||||
:padding 12}
|
:flex 1
|
||||||
(if valid-code?
|
:padding 12})
|
||||||
{:flex 1}
|
|
||||||
{:aspect-ratio 1})))
|
|
||||||
|
|
||||||
(def sub-text-container
|
(def sub-text-container
|
||||||
{:margin-bottom 8
|
{:margin-bottom 8
|
||||||
|
@ -39,10 +41,3 @@
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:margin 12})
|
:margin 12})
|
||||||
|
|
||||||
(def generate-button
|
|
||||||
{:position :absolute
|
|
||||||
:top "50%"
|
|
||||||
:bottom 0
|
|
||||||
:left 0
|
|
||||||
:right 0
|
|
||||||
:margin-horizontal 60})
|
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.clipboard :as clipboard]
|
[react-native.clipboard :as clipboard]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.hooks :as hooks]
|
|
||||||
[reagent.core :as reagent]
|
|
||||||
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
|
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
|
||||||
|
[reagent.core :as reagent]
|
||||||
[status-im2.common.resources :as resources]
|
[status-im2.common.resources :as resources]
|
||||||
|
[status-im2.common.standard-authentication.standard-auth.view :as standard-auth]
|
||||||
|
[react-native.hooks :as hooks]
|
||||||
[status-im2.contexts.syncing.setup-syncing.style :as style]
|
[status-im2.contexts.syncing.setup-syncing.style :as style]
|
||||||
[status-im2.contexts.syncing.sheets.enter-password.view :as enter-password]
|
|
||||||
[status-im2.contexts.syncing.utils :as sync-utils]
|
[status-im2.contexts.syncing.utils :as sync-utils]
|
||||||
[utils.datetime :as datetime]
|
[utils.datetime :as datetime]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
|
@ -24,31 +24,37 @@
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[]
|
[]
|
||||||
(let [profile-color (rf/sub [:profile/customization-color])
|
(let [{:keys [customization-color]} (rf/sub [:profile/multiaccount])
|
||||||
valid-for-ms (reagent/atom code-valid-for-ms)
|
valid-for-ms (reagent/atom code-valid-for-ms)
|
||||||
code (reagent/atom nil)
|
code (reagent/atom nil)
|
||||||
delay-ms (reagent/atom nil)
|
delay-ms (reagent/atom nil)
|
||||||
timestamp (reagent/atom nil)
|
timestamp (reagent/atom nil)
|
||||||
set-code (fn [connection-string]
|
set-code (fn [connection-string]
|
||||||
(when (sync-utils/valid-connection-string? connection-string)
|
(when (sync-utils/valid-connection-string? connection-string)
|
||||||
(reset! timestamp (* 1000 (js/Math.ceil (/ (datetime/timestamp) 1000))))
|
(reset! timestamp (* 1000
|
||||||
|
(js/Math.ceil (/ (datetime/timestamp)
|
||||||
|
1000))))
|
||||||
(reset! delay-ms 1000)
|
(reset! delay-ms 1000)
|
||||||
(reset! code connection-string)))
|
(reset! code connection-string)))
|
||||||
clock (fn []
|
clock (fn []
|
||||||
(if (pos? (- code-valid-for-ms
|
(if (pos? (- code-valid-for-ms
|
||||||
(- (* 1000 (js/Math.ceil (/ (datetime/timestamp) 1000)))
|
(- (* 1000
|
||||||
|
(js/Math.ceil (/ (datetime/timestamp) 1000)))
|
||||||
@timestamp)))
|
@timestamp)))
|
||||||
(swap! valid-for-ms (fn [_]
|
(swap! valid-for-ms (fn [_]
|
||||||
(- code-valid-for-ms
|
(- code-valid-for-ms
|
||||||
(- (* 1000
|
(- (* 1000
|
||||||
(js/Math.ceil (/ (datetime/timestamp) 1000)))
|
(js/Math.ceil
|
||||||
|
(/ (datetime/timestamp) 1000)))
|
||||||
@timestamp))))
|
@timestamp))))
|
||||||
(reset! delay-ms nil)))
|
(reset! delay-ms nil)))
|
||||||
cleanup-clock (fn []
|
cleanup-clock (fn []
|
||||||
(reset! code nil)
|
(reset! code nil)
|
||||||
(reset! timestamp nil)
|
(reset! timestamp nil)
|
||||||
(reset! valid-for-ms code-valid-for-ms))]
|
(reset! valid-for-ms code-valid-for-ms))
|
||||||
|
on-enter-password (fn [entered-password]
|
||||||
|
(rf/dispatch [:syncing/get-connection-string entered-password
|
||||||
|
set-code]))]
|
||||||
(fn []
|
(fn []
|
||||||
[rn/view {:style style/container-main}
|
[rn/view {:style style/container-main}
|
||||||
[:f> f-use-interval clock cleanup-clock @delay-ms]
|
[:f> f-use-interval clock cleanup-clock @delay-ms]
|
||||||
|
@ -68,29 +74,14 @@
|
||||||
:weight :semi-bold
|
:weight :semi-bold
|
||||||
:style {:color colors/white}}
|
:style {:color colors/white}}
|
||||||
(i18n/label :t/setup-syncing)]]
|
(i18n/label :t/setup-syncing)]]
|
||||||
[rn/view {:style (style/qr-container (sync-utils/valid-connection-string? @code))}
|
[rn/view {:style style/qr-container}
|
||||||
(if (sync-utils/valid-connection-string? @code)
|
(if (sync-utils/valid-connection-string? @code)
|
||||||
[qr-code-viewer/qr-code-view 331 @code]
|
[rn/view {:style {:margin-horizontal 12}}
|
||||||
|
[qr-code-viewer/qr-code-view 311 @code]]
|
||||||
[quo/qr-code
|
[quo/qr-code
|
||||||
{:source (resources/get-image :qr-code)
|
{:source (resources/get-image :qr-code)
|
||||||
:height 220
|
:height 220
|
||||||
:width "100%"}])
|
:width "100%"}])
|
||||||
(when-not (sync-utils/valid-connection-string? @code)
|
|
||||||
[quo/button
|
|
||||||
{:on-press (fn []
|
|
||||||
;TODO https://github.com/status-im/status-mobile/issues/15570
|
|
||||||
;remove old bottom sheet when Authentication process design is
|
|
||||||
;created.
|
|
||||||
(rf/dispatch [:bottom-sheet/hide-old])
|
|
||||||
(rf/dispatch [:bottom-sheet/show-sheet-old
|
|
||||||
{:content (fn []
|
|
||||||
[enter-password/sheet set-code])}]))
|
|
||||||
:type :primary
|
|
||||||
:customization-color profile-color
|
|
||||||
:size 40
|
|
||||||
:container-style style/generate-button
|
|
||||||
:icon-left :i/reveal}
|
|
||||||
(i18n/label :t/reveal-sync-code)])
|
|
||||||
(when (sync-utils/valid-connection-string? @code)
|
(when (sync-utils/valid-connection-string? @code)
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style style/valid-cs-container}
|
{:style style/valid-cs-container}
|
||||||
|
@ -122,7 +113,17 @@
|
||||||
:type :grey
|
:type :grey
|
||||||
:container-style {:margin-top 12}
|
:container-style {:margin-top 12}
|
||||||
:icon-left :i/copy}
|
:icon-left :i/copy}
|
||||||
(i18n/label :t/copy-qr)]])]]
|
(i18n/label :t/copy-qr)]])
|
||||||
|
(when-not (sync-utils/valid-connection-string? @code)
|
||||||
|
[rn/view {:style style/standard-auth}
|
||||||
|
[standard-auth/view
|
||||||
|
{:blur? true
|
||||||
|
:size :size/s-40
|
||||||
|
:track-text (i18n/label :t/slide-to-reveal-code)
|
||||||
|
:customization-color customization-color
|
||||||
|
:on-enter-password on-enter-password
|
||||||
|
:biometric-auth? false
|
||||||
|
:fallback-button-label (i18n/label :t/reveal-sync-code)}]])]]
|
||||||
[rn/view {:style style/sync-code}
|
[rn/view {:style style/sync-code}
|
||||||
[quo/divider-label {:tight? false} (i18n/label :t/have-a-sync-code?)]
|
[quo/divider-label {:tight? false} (i18n/label :t/have-a-sync-code?)]
|
||||||
[quo/action-drawer
|
[quo/action-drawer
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
(ns status-im2.contexts.syncing.sheets.enter-password.view
|
|
||||||
(:require [utils.i18n :as i18n]
|
|
||||||
[quo.core :as quo-old]
|
|
||||||
[quo2.core :as quo]
|
|
||||||
[quo2.foundations.colors :as colors]
|
|
||||||
[react-native.core :as rn]
|
|
||||||
[utils.re-frame :as rf]))
|
|
||||||
|
|
||||||
;;TODO : this file is temporary and will be removed for new design auth method
|
|
||||||
(defn sheet
|
|
||||||
[set-code]
|
|
||||||
(let [entered-password (atom "")]
|
|
||||||
[:<>
|
|
||||||
[rn/view {:margin 20}
|
|
||||||
[rn/view
|
|
||||||
[quo/text
|
|
||||||
{:accessibility-label :sync-code-generated
|
|
||||||
:weight :bold
|
|
||||||
:size :heading-1
|
|
||||||
:style {:color colors/neutral-100
|
|
||||||
:margin 20}}
|
|
||||||
(i18n/label :t/enter-your-password)]
|
|
||||||
[rn/view {:flex-direction :row :align-items :center}
|
|
||||||
[rn/view {:flex 1}
|
|
||||||
[quo-old/text-input
|
|
||||||
{:placeholder (i18n/label :t/enter-your-password)
|
|
||||||
:auto-focus true
|
|
||||||
:accessibility-label :password-input
|
|
||||||
:show-cancel false
|
|
||||||
:on-change-text #(reset! entered-password %)
|
|
||||||
:secure-text-entry true}]]]
|
|
||||||
[rn/view
|
|
||||||
{:padding-horizontal 18
|
|
||||||
:margin-top 20}
|
|
||||||
[quo/button
|
|
||||||
{:on-press (fn []
|
|
||||||
;TODO https://github.com/status-im/status-mobile/issues/15570
|
|
||||||
;remove old bottom sheet when Authentication process design is created.
|
|
||||||
(rf/dispatch [:bottom-sheet/hide-old])
|
|
||||||
(rf/dispatch [:syncing/get-connection-string-for-bootstrapping-another-device
|
|
||||||
@entered-password set-code]))}
|
|
||||||
(i18n/label :t/generate-scan-sync-code)]]]]]))
|
|
|
@ -1892,6 +1892,7 @@
|
||||||
"swap": "Swap",
|
"swap": "Swap",
|
||||||
"select-token-to-swap": "Select token to Swap",
|
"select-token-to-swap": "Select token to Swap",
|
||||||
"select-token-to-receive": "Select token to receive",
|
"select-token-to-receive": "Select token to receive",
|
||||||
|
"slide-to-reveal-code": "Slide to reveal code",
|
||||||
"minimum-received": "Minimum received",
|
"minimum-received": "Minimum received",
|
||||||
"powered-by-paraswap": "Powered by Paraswap",
|
"powered-by-paraswap": "Powered by Paraswap",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
|
@ -2050,7 +2051,7 @@
|
||||||
"local-pairing-experimental-mode": "Local Pairing Mode (alpha)",
|
"local-pairing-experimental-mode": "Local Pairing Mode (alpha)",
|
||||||
"syncing": "Syncing",
|
"syncing": "Syncing",
|
||||||
"synced-devices": "Synced Devices",
|
"synced-devices": "Synced Devices",
|
||||||
"setup-syncing": "Setup Syncing",
|
"setup-syncing": "Pair devices to sync",
|
||||||
"sync-code": "Sync Code",
|
"sync-code": "Sync Code",
|
||||||
"sync-code-generated": "Sync code generated",
|
"sync-code-generated": "Sync code generated",
|
||||||
"generate-scan-sync-code": "Generate Scan Sync Code",
|
"generate-scan-sync-code": "Generate Scan Sync Code",
|
||||||
|
|
Loading…
Reference in New Issue