chore: add generate code to new sync ui (#15584)
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 539 KiB After Width: | Height: | Size: 539 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 153 KiB |
Before Width: | Height: | Size: 377 KiB |
Before Width: | Height: | Size: 738 KiB |
|
@ -132,8 +132,9 @@
|
||||||
:text text}])]]))))
|
:text text}])]]))))
|
||||||
|
|
||||||
(defn- password-input
|
(defn- password-input
|
||||||
[_]
|
[{:keys [default-shown?]
|
||||||
(let [password-shown? (reagent/atom false)]
|
:or {default-shown? false}}]
|
||||||
|
(let [password-shown? (reagent/atom default-shown?)]
|
||||||
(fn [props]
|
(fn [props]
|
||||||
[base-input
|
[base-input
|
||||||
(assoc props
|
(assoc props
|
||||||
|
@ -161,6 +162,7 @@
|
||||||
- :label - A string to set as label for this input.
|
- :label - A string to set as label for this input.
|
||||||
- :char-limit - A number to set a maximum char limit for this input.
|
- :char-limit - A number to set a maximum char limit for this input.
|
||||||
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
|
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
|
||||||
|
- :default-shown? - boolean to show password input initially
|
||||||
and supports the usual React Native's TextInput properties to control its behaviour:
|
and supports the usual React Native's TextInput properties to control its behaviour:
|
||||||
- :value
|
- :value
|
||||||
- :default-value
|
- :default-value
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
{:no-color true})))
|
{:no-color true})))
|
||||||
|
|
||||||
(defn left-section-view
|
(defn left-section-view
|
||||||
[{:keys [on-press icon accessibility-label type icon-background-color] :or {type :grey}}
|
[{:keys [on-press icon accessibility-label type icon-background-color icon-override-theme]
|
||||||
|
:or {type :grey}}
|
||||||
put-middle-section-on-left?]
|
put-middle-section-on-left?]
|
||||||
[rn/view {:style (when put-middle-section-on-left? {:margin-right 5})}
|
[rn/view {:style (when put-middle-section-on-left? {:margin-right 5})}
|
||||||
[button/button
|
[button/button
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
:type type
|
:type type
|
||||||
:size 32
|
:size 32
|
||||||
:accessibility-label accessibility-label
|
:accessibility-label accessibility-label
|
||||||
|
:override-theme icon-override-theme
|
||||||
:override-background-color icon-background-color}
|
:override-background-color icon-background-color}
|
||||||
icon]])
|
icon]])
|
||||||
|
|
||||||
|
@ -150,7 +152,7 @@
|
||||||
:justify-content :flex-end)}
|
:justify-content :flex-end)}
|
||||||
(let [last-icon-index (-> right-section-buttons count dec)]
|
(let [last-icon-index (-> right-section-buttons count dec)]
|
||||||
(map-indexed (fn [index
|
(map-indexed (fn [index
|
||||||
{:keys [icon on-press type style icon-override-theme accessibility-label]
|
{:keys [icon on-press type style icon-override-theme accessibility-label label]
|
||||||
:or {type :grey}}]
|
:or {type :grey}}]
|
||||||
^{:key index}
|
^{:key index}
|
||||||
[rn/view
|
[rn/view
|
||||||
|
@ -161,11 +163,12 @@
|
||||||
:accessible true))
|
:accessible true))
|
||||||
[button/button
|
[button/button
|
||||||
{:on-press on-press
|
{:on-press on-press
|
||||||
:icon true
|
:icon (not label)
|
||||||
:type type
|
:type type
|
||||||
|
:before (when label icon)
|
||||||
:size 32
|
:size 32
|
||||||
:override-theme icon-override-theme}
|
:override-theme icon-override-theme}
|
||||||
icon]])
|
(if label label icon)]])
|
||||||
right-section-buttons))])
|
right-section-buttons))])
|
||||||
|
|
||||||
(defn page-nav
|
(defn page-nav
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
(ns quo2.components.share.qr-code.style)
|
(ns quo2.components.share.qr-code.style
|
||||||
|
(:require [quo2.foundations.colors :as colors]))
|
||||||
|
|
||||||
(def container
|
(def container
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
|
@ -6,7 +7,8 @@
|
||||||
|
|
||||||
(defn image
|
(defn image
|
||||||
[width height]
|
[width height]
|
||||||
{:width width
|
{:width width
|
||||||
:height height
|
:height height
|
||||||
:border-radius 12
|
:background-color colors/white-opa-70
|
||||||
:aspect-ratio 1})
|
:border-radius 12
|
||||||
|
:aspect-ratio 1})
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
(ns react-native.hooks
|
(ns react-native.hooks
|
||||||
(:require ["@react-native-community/hooks" :as hooks]))
|
(:require ["@react-native-community/hooks" :as hooks]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[oops.core :as oops]))
|
||||||
|
|
||||||
(defn use-keyboard
|
(defn use-keyboard
|
||||||
[]
|
[]
|
||||||
|
@ -10,3 +12,21 @@
|
||||||
(defn use-back-handler
|
(defn use-back-handler
|
||||||
[handler]
|
[handler]
|
||||||
(.useBackHandler hooks handler))
|
(.useBackHandler hooks handler))
|
||||||
|
|
||||||
|
(defn use-interval
|
||||||
|
[cb cleanup-cb delay]
|
||||||
|
(let [saved-callback (rn/use-ref)]
|
||||||
|
(rn/use-effect
|
||||||
|
(fn []
|
||||||
|
(oops/oset! saved-callback "current" cb))
|
||||||
|
[cb])
|
||||||
|
|
||||||
|
(rn/use-effect
|
||||||
|
(fn []
|
||||||
|
(let [tick (oops/oget saved-callback "current")]
|
||||||
|
(when delay
|
||||||
|
(let [id (js/setInterval tick delay)]
|
||||||
|
(fn []
|
||||||
|
(cleanup-cb)
|
||||||
|
(js/clearInterval id))))))
|
||||||
|
[delay])))
|
||||||
|
|
|
@ -8,4 +8,4 @@
|
||||||
(def clippath (reagent/adapt-react-class Svg/ClipPath))
|
(def clippath (reagent/adapt-react-class Svg/ClipPath))
|
||||||
(def defs (reagent/adapt-react-class Svg/Defs))
|
(def defs (reagent/adapt-react-class Svg/Defs))
|
||||||
(def circle (reagent/adapt-react-class Svg/Circle))
|
(def circle (reagent/adapt-react-class Svg/Circle))
|
||||||
|
(def svgxml (reagent/adapt-react-class Svg/SvgXml))
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
(ns status-im.ui.components.qr-code-viewer.views
|
|
||||||
(:require ["qrcode" :as qr-code-js]
|
|
||||||
["react-native-svg" :refer (SvgXml)]
|
|
||||||
[cljs-bean.core :as bean]
|
|
||||||
[reagent.core :as reagent]
|
|
||||||
[status-im.ui.components.qr-code-viewer.styles :as styles]
|
|
||||||
[status-im.ui.components.react :as react]))
|
|
||||||
|
|
||||||
(def svgxml (reagent/adapt-react-class SvgXml))
|
|
||||||
|
|
||||||
(defn qr-code
|
|
||||||
[{:keys [size value]}]
|
|
||||||
(let [uri (reagent/atom nil)]
|
|
||||||
(.toString
|
|
||||||
qr-code-js
|
|
||||||
value
|
|
||||||
(bean/->js {:margin 0 :width size})
|
|
||||||
#(reset! uri %2))
|
|
||||||
(fn []
|
|
||||||
(when @uri
|
|
||||||
[svgxml {:xml @uri :width size :height size}]))))
|
|
||||||
|
|
||||||
(defn qr-code-view
|
|
||||||
"Qr Code view including the frame.
|
|
||||||
Note: `size` includes frame with `styles/qr-code-padding.`"
|
|
||||||
[size value]
|
|
||||||
(when (and size value)
|
|
||||||
[react/view
|
|
||||||
{:style (styles/qr-code-container size)
|
|
||||||
:accessibility-label :qr-code-image}
|
|
||||||
[qr-code
|
|
||||||
{:value value
|
|
||||||
:size (- size (* styles/qr-code-padding 2))}]]))
|
|
|
@ -11,7 +11,7 @@
|
||||||
[status-im.ui.components.copyable-text :as copyable-text]
|
[status-im.ui.components.copyable-text :as copyable-text]
|
||||||
[status-im.ui.components.list-selection :as list-selection]
|
[status-im.ui.components.list-selection :as list-selection]
|
||||||
[status-im.ui.components.profile-header.view :as profile-header]
|
[status-im.ui.components.profile-header.view :as profile-header]
|
||||||
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
|
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.screens.profile.user.edit-picture :as edit]
|
[status-im.ui.screens.profile.user.edit-picture :as edit]
|
||||||
[status-im.ui.screens.profile.user.styles :as styles]
|
[status-im.ui.screens.profile.user.styles :as styles]
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
[status-im.ethereum.eip681 :as eip681]
|
[status-im.ethereum.eip681 :as eip681]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[status-im.ui.components.copyable-text :as copyable-text]
|
[status-im.ui.components.copyable-text :as copyable-text]
|
||||||
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
|
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
|
||||||
[status-im.ui.components.react :as react])
|
[status-im.ui.components.react :as react])
|
||||||
(:require-macros [status-im.utils.views :as views]))
|
(:require-macros [status-im.utils.views :as views]))
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
(ns status-im.ui.components.qr-code-viewer.styles
|
(ns status-im2.common.qr-code-viewer.style
|
||||||
(:require [quo.design-system.colors :as colors]))
|
(:require [quo.design-system.colors :as colors]))
|
||||||
|
|
||||||
(def qr-code-padding 16)
|
(def qr-code-padding 16)
|
||||||
|
@ -14,4 +14,4 @@
|
||||||
:align-items :center
|
:align-items :center
|
||||||
:justify-content :center
|
:justify-content :center
|
||||||
:border-width 1
|
:border-width 1
|
||||||
:border-radius 8})
|
:border-radius 8})
|
|
@ -0,0 +1,31 @@
|
||||||
|
(ns status-im2.common.qr-code-viewer.view
|
||||||
|
(:require ["qrcode" :as qr-code-js]
|
||||||
|
[cljs-bean.core :as bean]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im2.common.qr-code-viewer.style :as style]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[react-native.svg :as svg]))
|
||||||
|
|
||||||
|
(defn qr-code
|
||||||
|
[{:keys [size value]}]
|
||||||
|
(let [uri (reagent/atom nil)]
|
||||||
|
(.toString
|
||||||
|
qr-code-js
|
||||||
|
value
|
||||||
|
(bean/->js {:margin 0 :width size})
|
||||||
|
#(reset! uri %2))
|
||||||
|
(fn []
|
||||||
|
(when @uri
|
||||||
|
[svg/svgxml {:xml @uri :width size :height size}]))))
|
||||||
|
|
||||||
|
(defn qr-code-view
|
||||||
|
"Qr Code view including the frame.
|
||||||
|
Note: `size` includes frame with `style/qr-code-padding.`"
|
||||||
|
[size value]
|
||||||
|
(when (and size value)
|
||||||
|
[rn/view
|
||||||
|
{:style (style/qr-code-container size)
|
||||||
|
:accessibility-label :qr-code-image}
|
||||||
|
[qr-code
|
||||||
|
{:value value
|
||||||
|
:size (- size (* style/qr-code-padding 2))}]]))
|
|
@ -5,11 +5,12 @@
|
||||||
:lifestyle (js/require "../resources/images/ui2/lifestyle.png")
|
:lifestyle (js/require "../resources/images/ui2/lifestyle.png")
|
||||||
:music (js/require "../resources/images/ui2/music.png")
|
:music (js/require "../resources/images/ui2/music.png")
|
||||||
:podcasts (js/require "../resources/images/ui2/podcasts.png")
|
:podcasts (js/require "../resources/images/ui2/podcasts.png")
|
||||||
:sync-device (js/require "../resources/images/ui2/sync-new-device-cover-background.png")
|
:generate-keys (js/require "../resources/images/ui2/generate-keys.png")
|
||||||
:generate-keys (js/require "../resources/images/ui2/generate_keys.png")
|
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
|
||||||
:ethereum-address (js/require "../resources/images/ui2/ethereum_address.png")
|
|
||||||
:use-keycard (js/require "../resources/images/ui2/keycard.png")
|
:use-keycard (js/require "../resources/images/ui2/keycard.png")
|
||||||
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")})
|
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")
|
||||||
|
:qr-code (js/require "../resources/images/ui2/qr-code.png")
|
||||||
|
})
|
||||||
|
|
||||||
(def mock-images
|
(def mock-images
|
||||||
{:coinbase (js/require "../resources/images/mock2/coinbase.png")
|
{:coinbase (js/require "../resources/images/mock2/coinbase.png")
|
||||||
|
|
|
@ -158,4 +158,4 @@
|
||||||
[background/view true]
|
[background/view true]
|
||||||
[page
|
[page
|
||||||
{:navigation-bar-top top
|
{:navigation-bar-top top
|
||||||
:onboarding-profile-data onboarding-profile-data}]]))])
|
:onboarding-profile-data onboarding-profile-data}]]))])
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
(ns status-im2.contexts.syncing.events
|
(ns status-im2.contexts.syncing.events
|
||||||
(:require [status-im.native-module.core :as status]
|
(:require [status-im.native-module.core :as status]
|
||||||
[status-im2.contexts.syncing.sheets.enter-password.view :as sheet]
|
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[utils.security.core :as security]
|
[utils.security.core :as security]
|
||||||
|
@ -62,15 +61,12 @@
|
||||||
|
|
||||||
(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-for-bootstrapping-another-device]}
|
||||||
[{:keys [db]} entered-password]
|
[{:keys [db]} entered-password set-code]
|
||||||
(let [valid-password? (>= (count entered-password) constants/min-password-length)
|
(let [valid-password? (>= (count entered-password) constants/min-password-length)
|
||||||
show-sheet (fn [connection-string]
|
show-sheet (fn [connection-string]
|
||||||
(rf/dispatch
|
(set-code connection-string)
|
||||||
[:show-bottom-sheet
|
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender])
|
||||||
{:content (fn []
|
(rf/dispatch [:bottom-sheet/hide]))]
|
||||||
[sheet/qr-code-view-with-connection-string
|
|
||||||
connection-string])}])
|
|
||||||
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender]))]
|
|
||||||
(if valid-password?
|
(if valid-password?
|
||||||
(let [sha3-pwd (status/sha3 (str (security/safe-unmask-data entered-password)))
|
(let [sha3-pwd (status/sha3 (str (security/safe-unmask-data entered-password)))
|
||||||
key-uid (get-in db [:multiaccount :key-uid])
|
key-uid (get-in db [:multiaccount :key-uid])
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
(ns status-im2.contexts.syncing.setup-syncing.style
|
||||||
|
(:require [quo2.foundations.colors :as colors]))
|
||||||
|
|
||||||
|
(defn container-main
|
||||||
|
[top]
|
||||||
|
{:background-color colors/neutral-95
|
||||||
|
:flex 1
|
||||||
|
:padding-top top})
|
||||||
|
|
||||||
|
(def page-container
|
||||||
|
{:margin-horizontal 20})
|
||||||
|
|
||||||
|
(def title-container
|
||||||
|
{:flex-direction :row
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :space-between})
|
||||||
|
|
||||||
|
(def navigation-bar
|
||||||
|
{:height 56})
|
||||||
|
|
||||||
|
(def sync-code
|
||||||
|
{:margin-top 36})
|
||||||
|
|
||||||
|
(defn qr-container
|
||||||
|
[valid-code?]
|
||||||
|
(merge {:margin-top 12
|
||||||
|
:background-color colors/white-opa-5
|
||||||
|
:border-radius 20
|
||||||
|
:padding 12}
|
||||||
|
(if valid-code?
|
||||||
|
{:flex 1}
|
||||||
|
{:aspect-ratio 1})))
|
||||||
|
|
||||||
|
(def sub-text-container
|
||||||
|
{:margin-bottom 8
|
||||||
|
:justify-content :space-between
|
||||||
|
:align-items :center
|
||||||
|
:flex-direction :row})
|
||||||
|
|
||||||
|
(def valid-cs-container
|
||||||
|
{:flex 1
|
||||||
|
:margin 12})
|
||||||
|
|
||||||
|
(def generate-button
|
||||||
|
{:position :absolute
|
||||||
|
:top "50%"
|
||||||
|
:bottom 0
|
||||||
|
:left 0
|
||||||
|
:right 0
|
||||||
|
:margin-horizontal 60})
|
|
@ -0,0 +1,148 @@
|
||||||
|
(ns status-im2.contexts.syncing.setup-syncing.view
|
||||||
|
(:require [utils.i18n :as i18n]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[quo2.foundations.colors :as colors]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[utils.datetime :as datetime]
|
||||||
|
[status-im2.contexts.syncing.setup-syncing.style :as style]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[status-im2.constants :as constants]
|
||||||
|
[react-native.clipboard :as clipboard]
|
||||||
|
[status-im2.contexts.syncing.sheets.enter-password.view :as enter-password]
|
||||||
|
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im2.common.resources :as resources]
|
||||||
|
[react-native.hooks :as hooks]
|
||||||
|
[react-native.safe-area :as safe-area]))
|
||||||
|
|
||||||
|
(def code-valid-for-ms 120000)
|
||||||
|
(def one-min-ms 60000)
|
||||||
|
|
||||||
|
(defn navigation-bar
|
||||||
|
[]
|
||||||
|
[rn/view {:style style/navigation-bar}
|
||||||
|
[quo/page-nav
|
||||||
|
{:align-mid? true
|
||||||
|
:mid-section {:type :text-only :main-text ""}
|
||||||
|
:left-section {:type :grey
|
||||||
|
:icon :i/close
|
||||||
|
:icon-override-theme :dark
|
||||||
|
:on-press #(rf/dispatch [:navigate-back])}
|
||||||
|
:right-section-buttons [{:type :grey
|
||||||
|
:label (i18n/label :t/how-to-scan)
|
||||||
|
:icon :i/info
|
||||||
|
:icon-override-theme :dark
|
||||||
|
:on-press #(js/alert "to be implemented")}]}]])
|
||||||
|
|
||||||
|
(defn valid-cs?
|
||||||
|
[connection-string]
|
||||||
|
(when connection-string
|
||||||
|
(string/starts-with?
|
||||||
|
connection-string
|
||||||
|
constants/local-pairing-connection-string-identifier)))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[]
|
||||||
|
(let [valid-for-ms (reagent/atom code-valid-for-ms)
|
||||||
|
code (reagent/atom nil)
|
||||||
|
delay (reagent/atom nil)
|
||||||
|
timestamp (reagent/atom nil)
|
||||||
|
set-code (fn [connection-string]
|
||||||
|
(when (valid-cs? connection-string)
|
||||||
|
(reset! timestamp (* 1000 (js/Math.ceil (/ (datetime/timestamp) 1000))))
|
||||||
|
(reset! delay 1000)
|
||||||
|
(reset! code connection-string)))
|
||||||
|
clock (fn []
|
||||||
|
(if (pos? (- code-valid-for-ms
|
||||||
|
(- (* 1000 (js/Math.ceil (/ (datetime/timestamp) 1000)))
|
||||||
|
@timestamp)))
|
||||||
|
(swap! valid-for-ms (fn [_]
|
||||||
|
(- code-valid-for-ms
|
||||||
|
(- (* 1000
|
||||||
|
(js/Math.ceil (/ (datetime/timestamp) 1000)))
|
||||||
|
@timestamp))))
|
||||||
|
(reset! delay nil)))
|
||||||
|
cleanup-clock (fn []
|
||||||
|
(reset! code nil)
|
||||||
|
(reset! timestamp nil)
|
||||||
|
(reset! valid-for-ms code-valid-for-ms))]
|
||||||
|
[:f>
|
||||||
|
(fn []
|
||||||
|
(hooks/use-interval clock
|
||||||
|
cleanup-clock
|
||||||
|
@delay)
|
||||||
|
[safe-area/consumer
|
||||||
|
(fn [{:keys [top]}]
|
||||||
|
[rn/view {:style (style/container-main top)}
|
||||||
|
[rn/scroll-view {}
|
||||||
|
[navigation-bar]
|
||||||
|
[rn/view {:style style/page-container}
|
||||||
|
[rn/view {:style style/title-container}
|
||||||
|
[quo/text
|
||||||
|
{:size :heading-1
|
||||||
|
:weight :semi-bold
|
||||||
|
:style {:color colors/white}}
|
||||||
|
(i18n/label :t/setup-syncing)]]
|
||||||
|
[rn/view {:style (style/qr-container (valid-cs? @code))}
|
||||||
|
(if (valid-cs? @code)
|
||||||
|
[qr-code-viewer/qr-code-view 331 @code]
|
||||||
|
[quo/qr-code
|
||||||
|
{:source (resources/get-image :qr-code)
|
||||||
|
:height 220
|
||||||
|
:width "100%"}])
|
||||||
|
(when-not (valid-cs? @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])}]))
|
||||||
|
:size 40
|
||||||
|
:style style/generate-button
|
||||||
|
:before :i/reveal} (i18n/label :t/reveal-sync-code)])
|
||||||
|
(when (valid-cs? @code)
|
||||||
|
[rn/view
|
||||||
|
{:style style/valid-cs-container}
|
||||||
|
[rn/view
|
||||||
|
{:style style/sub-text-container}
|
||||||
|
[quo/text
|
||||||
|
{:size :paragraph-2
|
||||||
|
:style {:color colors/white-opa-40}}
|
||||||
|
(i18n/label :t/sync-code)]
|
||||||
|
[quo/text
|
||||||
|
{:size :paragraph-2
|
||||||
|
:style {:color (if (< @valid-for-ms one-min-ms)
|
||||||
|
colors/danger-60
|
||||||
|
colors/white-opa-40)}}
|
||||||
|
(i18n/label :t/valid-for-time {:valid-for (datetime/ms-to-duration @valid-for-ms)})]]
|
||||||
|
[quo/input
|
||||||
|
{:default-value @code
|
||||||
|
:type :password
|
||||||
|
:override-theme :dark
|
||||||
|
:default-shown? true
|
||||||
|
:editable false}]
|
||||||
|
[quo/button
|
||||||
|
{:on-press (fn []
|
||||||
|
(clipboard/set-string @code)
|
||||||
|
(rf/dispatch [:toasts/upsert
|
||||||
|
{:icon :correct
|
||||||
|
:icon-color colors/success-50
|
||||||
|
:text (i18n/label
|
||||||
|
:t/sharing-copied-to-clipboard)}]))
|
||||||
|
:override-theme :dark
|
||||||
|
:type :grey
|
||||||
|
:style {:margin-top 12}
|
||||||
|
:before :i/copy}
|
||||||
|
(i18n/label :t/copy-qr)]])]]
|
||||||
|
[rn/view {:style style/sync-code}
|
||||||
|
[quo/divider-label
|
||||||
|
{:label (i18n/label :t/have-a-sync-code?)
|
||||||
|
:increase-padding-top? true}]
|
||||||
|
[quo/action-drawer
|
||||||
|
[[{:icon :i/scan
|
||||||
|
:override-theme :dark
|
||||||
|
:on-press #(js/alert "to be implemented")
|
||||||
|
:label (i18n/label :t/Scan-or-enter-sync-code)}]]]]]])])]))
|
|
@ -1,45 +1,14 @@
|
||||||
(ns status-im2.contexts.syncing.sheets.enter-password.view
|
(ns status-im2.contexts.syncing.sheets.enter-password.view
|
||||||
(:require [clojure.string :as string]
|
(:require [utils.i18n :as i18n]
|
||||||
[utils.i18n :as i18n]
|
|
||||||
[quo.core :as quo-old]
|
[quo.core :as quo-old]
|
||||||
[quo2.core :as quo]
|
[quo2.core :as quo]
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[status-im2.constants :as constants]
|
|
||||||
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
|
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn qr-code-view-with-connection-string
|
;;TODO : this file is temporary and will be removed for new design auth method
|
||||||
[connection-string]
|
|
||||||
(let [window-width (rf/sub [:dimensions/window-width])
|
|
||||||
eighty-percent-screen-width (* window-width 0.8)
|
|
||||||
valid-cs? (string/starts-with?
|
|
||||||
connection-string
|
|
||||||
constants/local-pairing-connection-string-identifier)]
|
|
||||||
[:<>
|
|
||||||
(if valid-cs?
|
|
||||||
[rn/view {:margin 20}
|
|
||||||
[quo/text
|
|
||||||
{:accessibility-label :sync-code-generated
|
|
||||||
:weight :bold
|
|
||||||
:size :heading-1
|
|
||||||
:style {:color colors/neutral-100
|
|
||||||
:margin 20}}
|
|
||||||
(i18n/label :t/sync-code-generated)]
|
|
||||||
[qr-code-viewer/qr-code-view eighty-percent-screen-width connection-string]
|
|
||||||
[quo/information-box
|
|
||||||
{:type :informative
|
|
||||||
:closable? false
|
|
||||||
:icon :i/placeholder
|
|
||||||
:style {:margin-top 20}} (i18n/label :t/instruction-after-qr-generated)]]
|
|
||||||
[rn/view {:margin 20}
|
|
||||||
[rn/view {:padding-horizontal 8}
|
|
||||||
[quo/button
|
|
||||||
{:on-press #(rf/dispatch [:preparations-for-connection-string])}
|
|
||||||
(i18n/label :t/try-your-luck-again)]]])]))
|
|
||||||
|
|
||||||
(defn sheet
|
(defn sheet
|
||||||
[]
|
[set-code]
|
||||||
(let [entered-password (atom "")]
|
(let [entered-password (atom "")]
|
||||||
[:<>
|
[:<>
|
||||||
[rn/view {:margin 20}
|
[rn/view {:margin 20}
|
||||||
|
@ -53,7 +22,7 @@
|
||||||
(i18n/label :t/enter-your-password)]
|
(i18n/label :t/enter-your-password)]
|
||||||
[rn/view {:flex-direction :row :align-items :center}
|
[rn/view {:flex-direction :row :align-items :center}
|
||||||
[rn/view {:flex 1}
|
[rn/view {:flex 1}
|
||||||
[quo-old/text-input ;;TODO : migrate text-input from quo to quo2 namespace
|
[quo-old/text-input
|
||||||
{:placeholder (i18n/label :t/enter-your-password)
|
{:placeholder (i18n/label :t/enter-your-password)
|
||||||
:auto-focus true
|
:auto-focus true
|
||||||
:accessibility-label :password-input
|
:accessibility-label :password-input
|
||||||
|
@ -64,6 +33,10 @@
|
||||||
{:padding-horizontal 18
|
{:padding-horizontal 18
|
||||||
:margin-top 20}
|
:margin-top 20}
|
||||||
[quo/button
|
[quo/button
|
||||||
{:on-press #(rf/dispatch [:syncing/get-connection-string-for-bootstrapping-another-device
|
{:on-press (fn []
|
||||||
@entered-password])}
|
;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)]]]]]))
|
(i18n/label :t/generate-scan-sync-code)]]]]]))
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
(ns status-im2.contexts.syncing.sheets.sync-device-notice.styles
|
|
||||||
(:require [quo2.foundations.colors :as colors]))
|
|
||||||
|
|
||||||
(def sync-devices-header
|
|
||||||
{:width "100%"})
|
|
||||||
|
|
||||||
(def sync-devices-header-image
|
|
||||||
{:width "100%"
|
|
||||||
:height 192})
|
|
||||||
|
|
||||||
(def sync-devices-body-container
|
|
||||||
{:margin-bottom 20
|
|
||||||
:border-radius 20
|
|
||||||
:z-index 2
|
|
||||||
:margin-top -16
|
|
||||||
:background-color colors/white
|
|
||||||
:padding 20})
|
|
||||||
|
|
||||||
(def header-text
|
|
||||||
{:color colors/neutral-100})
|
|
||||||
|
|
||||||
(def instructions-text
|
|
||||||
{:color colors/neutral-100
|
|
||||||
:margin-top 8})
|
|
||||||
|
|
||||||
(def list-item-text
|
|
||||||
{:color colors/neutral-100
|
|
||||||
:margin-top 18})
|
|
||||||
|
|
||||||
(def setup-syncing-button
|
|
||||||
{:margin-top 21})
|
|
||||||
|
|
||||||
(def secondary-body-container
|
|
||||||
{:margin-top 21})
|
|
|
@ -1,62 +0,0 @@
|
||||||
(ns status-im2.contexts.syncing.sheets.sync-device-notice.view
|
|
||||||
(:require [quo2.core :as quo]
|
|
||||||
[react-native.core :as rn]
|
|
||||||
[status-im2.contexts.syncing.sheets.enter-password.view :as enter-password]
|
|
||||||
[status-im2.contexts.syncing.sheets.sync-device-notice.styles :as styles]
|
|
||||||
[utils.i18n :as i18n]
|
|
||||||
[utils.re-frame :as rf]
|
|
||||||
[status-im2.common.resources :as resources]))
|
|
||||||
|
|
||||||
(defn sheet
|
|
||||||
[]
|
|
||||||
[:<>
|
|
||||||
[rn/view {:style styles/sync-devices-header}
|
|
||||||
[rn/image
|
|
||||||
{:source (resources/get-image :sync-device)
|
|
||||||
:style styles/sync-devices-header-image}]]
|
|
||||||
[rn/view {:style styles/sync-devices-body-container}
|
|
||||||
[quo/text
|
|
||||||
{:accessibility-label :privacy-policy
|
|
||||||
:weight :bold
|
|
||||||
:size :heading-1
|
|
||||||
:style styles/header-text}
|
|
||||||
(i18n/label :t/sync-new-device)]
|
|
||||||
|
|
||||||
[quo/text
|
|
||||||
{:accessibility-label :privacy-policy
|
|
||||||
:weight :regular
|
|
||||||
:size :paragraph-1
|
|
||||||
:style styles/instructions-text}
|
|
||||||
(i18n/label :t/sync-instructions-text)]
|
|
||||||
|
|
||||||
[quo/text
|
|
||||||
{:accessibility-label :privacy-policy
|
|
||||||
:weight :regular
|
|
||||||
:size :paragraph-2
|
|
||||||
:style styles/list-item-text}
|
|
||||||
(i18n/label :t/sync-instruction-step-1)]
|
|
||||||
|
|
||||||
[quo/text
|
|
||||||
{:accessibility-label :privacy-policy
|
|
||||||
:weight :regular
|
|
||||||
:size :paragraph-2
|
|
||||||
:style styles/list-item-text}
|
|
||||||
(i18n/label :t/sync-instruction-step-2)]
|
|
||||||
|
|
||||||
[quo/text
|
|
||||||
{:accessibility-label :privacy-policy
|
|
||||||
:weight :regular
|
|
||||||
:size :paragraph-2
|
|
||||||
:style styles/list-item-text}
|
|
||||||
(i18n/label :t/sync-instruction-step-3)]
|
|
||||||
|
|
||||||
[quo/button
|
|
||||||
{:type :secondary
|
|
||||||
:size 40
|
|
||||||
:style styles/setup-syncing-button
|
|
||||||
:before :i/face-id20
|
|
||||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
|
||||||
;; this should be a modal screen
|
|
||||||
{:content (fn []
|
|
||||||
[enter-password/sheet])}])}
|
|
||||||
(i18n/label :t/setup-syncing)]]])
|
|
|
@ -1,4 +1,4 @@
|
||||||
(ns status-im2.contexts.syncing.style
|
(ns status-im2.contexts.syncing.syncing-devices-list.style
|
||||||
(:require [quo2.foundations.colors :as colors]))
|
(:require [quo2.foundations.colors :as colors]))
|
||||||
|
|
||||||
(def container-main
|
(def container-main
|
|
@ -1,10 +1,9 @@
|
||||||
(ns status-im2.contexts.syncing.view
|
(ns status-im2.contexts.syncing.syncing-devices-list.view
|
||||||
(:require [utils.i18n :as i18n]
|
(:require [utils.i18n :as i18n]
|
||||||
[quo2.core :as quo]
|
[quo2.core :as quo]
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[status-im2.contexts.syncing.sheets.sync-device-notice.view :as sync-device-notice]
|
[status-im2.contexts.syncing.syncing-devices-list.style :as style]
|
||||||
[status-im2.contexts.syncing.style :as style]
|
|
||||||
[status-im2.common.not-implemented :as not-implemented]
|
[status-im2.common.not-implemented :as not-implemented]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@
|
||||||
[quo/page-nav
|
[quo/page-nav
|
||||||
{:align-mid? true
|
{:align-mid? true
|
||||||
:mid-section {:type :text-only :main-text ""}
|
:mid-section {:type :text-only :main-text ""}
|
||||||
:left-section {:type :blur-bg
|
:left-section {:type :grey
|
||||||
:icon :i/arrow-left
|
:icon :i/arrow-left
|
||||||
:icon-override-theme :dark
|
:icon-override-theme :dark
|
||||||
:on-press #(rf/dispatch [:navigate-back])}}]])
|
:on-press #(rf/dispatch [:navigate-back])}}]])
|
||||||
|
@ -64,10 +63,7 @@
|
||||||
[quo/button
|
[quo/button
|
||||||
{:size 32
|
{:size 32
|
||||||
:icon true
|
:icon true
|
||||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
:on-press #(rf/dispatch [:navigate-to :settings-setup-syncing])}
|
||||||
{:show-handle? false
|
|
||||||
:content (fn []
|
|
||||||
[sync-device-notice/sheet])}])}
|
|
||||||
:i/add]]
|
:i/add]]
|
||||||
[rn/view {:style style/devices-container}
|
[rn/view {:style style/devices-container}
|
||||||
[render-device
|
[render-device
|
|
@ -30,22 +30,26 @@
|
||||||
:backgroundColor (colors/theme-colors colors/white colors/neutral-100)}}))
|
:backgroundColor (colors/theme-colors colors/white colors/neutral-100)}}))
|
||||||
|
|
||||||
(defn navbar
|
(defn navbar
|
||||||
[]
|
([dark?]
|
||||||
{:navigationBar {:backgroundColor (colors/theme-colors colors/white colors/neutral-100)}})
|
{:navigationBar {:backgroundColor (if (or dark? colors/dark?) colors/neutral-100 colors/white)}})
|
||||||
|
([] (navbar nil)))
|
||||||
|
|
||||||
(defn statusbar
|
(defn statusbar
|
||||||
[]
|
([dark?]
|
||||||
(if platform/android?
|
(let [style (if (or dark? colors/dark?) :light :dark)]
|
||||||
{:statusBar {:translucent true
|
(if platform/android?
|
||||||
:backgroundColor :transparent
|
{:statusBar {:translucent true
|
||||||
:drawBehind true
|
:backgroundColor :transparent
|
||||||
:style (if (colors/dark?) :light :dark)}}
|
:drawBehind true
|
||||||
{:statusBar {:style (if (colors/dark?) :light :dark)}}))
|
:style style}}
|
||||||
|
{:statusBar {:style style}})))
|
||||||
|
([] (statusbar nil)))
|
||||||
|
|
||||||
|
|
||||||
(defn statusbar-and-navbar
|
(defn statusbar-and-navbar
|
||||||
[]
|
([dark?]
|
||||||
(merge (navbar) (statusbar)))
|
(merge (navbar dark?) (statusbar dark?)))
|
||||||
|
([] (statusbar-and-navbar nil)))
|
||||||
|
|
||||||
(defn topbar-options
|
(defn topbar-options
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -24,12 +24,12 @@
|
||||||
[status-im2.contexts.onboarding.profiles.view :as profiles]
|
[status-im2.contexts.onboarding.profiles.view :as profiles]
|
||||||
[status-im2.contexts.quo-preview.main :as quo.preview]
|
[status-im2.contexts.quo-preview.main :as quo.preview]
|
||||||
[status-im2.contexts.shell.view :as shell]
|
[status-im2.contexts.shell.view :as shell]
|
||||||
[status-im2.contexts.syncing.view :as settings-syncing]
|
[status-im2.contexts.syncing.syncing-devices-list.view :as settings-syncing]
|
||||||
[status-im2.navigation.options :as options]
|
[status-im2.navigation.options :as options]
|
||||||
[status-im2.contexts.chat.group-details.view :as group-details]
|
[status-im2.contexts.chat.group-details.view :as group-details]
|
||||||
|
|
||||||
[status-im.ui.screens.screens :as old-screens]
|
[status-im.ui.screens.screens :as old-screens]
|
||||||
[status-im2.contexts.communities.menus.request-to-join.view :as join-menu]))
|
[status-im2.contexts.communities.menus.request-to-join.view :as join-menu]
|
||||||
|
[status-im2.contexts.syncing.setup-syncing.view :as settings-setup-syncing]))
|
||||||
|
|
||||||
(defn screens
|
(defn screens
|
||||||
[]
|
[]
|
||||||
|
@ -81,10 +81,15 @@
|
||||||
:component communities.overview/overview}
|
:component communities.overview/overview}
|
||||||
|
|
||||||
{:name :settings-syncing
|
{:name :settings-syncing
|
||||||
:options {:statusBar {:style :light}
|
:options (options/statusbar true)
|
||||||
:insets {:top false}}
|
|
||||||
:component settings-syncing/view}
|
:component settings-syncing/view}
|
||||||
|
|
||||||
|
{:name :settings-setup-syncing
|
||||||
|
:options (options/statusbar true)
|
||||||
|
|
||||||
|
:component settings-setup-syncing/view}
|
||||||
|
|
||||||
|
;; Onboarding
|
||||||
{:name :profiles
|
{:name :profiles
|
||||||
:component profiles/views}
|
:component profiles/views}
|
||||||
|
|
||||||
|
|
|
@ -255,7 +255,7 @@
|
||||||
(* 1000 sec))
|
(* 1000 sec))
|
||||||
|
|
||||||
(defn ms-to-duration
|
(defn ms-to-duration
|
||||||
"milisecods to mm:ss format"
|
"miliseconds to mm:ss format"
|
||||||
[ms]
|
[ms]
|
||||||
(let [sec (quot ms 1000)]
|
(let [sec (quot ms 1000)]
|
||||||
(gstring/format "%02d:%02d" (quot sec 60) (mod sec 60))))
|
(gstring/format "%02d:%02d" (quot sec 60) (mod sec 60))))
|
||||||
|
|
|
@ -659,6 +659,7 @@
|
||||||
"group-info": "Group info",
|
"group-info": "Group info",
|
||||||
"gwei": "Gwei",
|
"gwei": "Gwei",
|
||||||
"hash": "Hash",
|
"hash": "Hash",
|
||||||
|
"have-a-sync-code?": "Have a sync code?",
|
||||||
"help": "help",
|
"help": "help",
|
||||||
"help-capitalized": "Help",
|
"help-capitalized": "Help",
|
||||||
"help-center": "Help Center",
|
"help-center": "Help Center",
|
||||||
|
@ -669,6 +670,7 @@
|
||||||
"hold-card": "Hold card to the back\n of your phone",
|
"hold-card": "Hold card to the back\n of your phone",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"hooks": "Hooks",
|
"hooks": "Hooks",
|
||||||
|
"how-to-scan": "How to scan",
|
||||||
"identifier": "Identifier",
|
"identifier": "Identifier",
|
||||||
"if-you-cancel": "If you cancel, you can request to join this community at any point.",
|
"if-you-cancel": "If you cancel, you can request to join this community at any point.",
|
||||||
"image-remove-current": "Remove current photo",
|
"image-remove-current": "Remove current photo",
|
||||||
|
@ -1196,12 +1198,14 @@
|
||||||
"reset-card": "Reset card",
|
"reset-card": "Reset card",
|
||||||
"reset-card-description": "This operation will reset card to initial state. It will erase all card data including private keys. Operation is not reversible.",
|
"reset-card-description": "This operation will reset card to initial state. It will erase all card data including private keys. Operation is not reversible.",
|
||||||
"retry": "Retry",
|
"retry": "Retry",
|
||||||
|
"reveal-sync-code": "Reveal sync code",
|
||||||
"revoke-access": "Revoke access",
|
"revoke-access": "Revoke access",
|
||||||
"rpc-url": "RPC URL",
|
"rpc-url": "RPC URL",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"save-password": "Save password",
|
"save-password": "Save password",
|
||||||
"save-password-unavailable": "Set device passcode to save password",
|
"save-password-unavailable": "Set device passcode to save password",
|
||||||
"save-password-unavailable-android": "Save password is unavailable: your device may be rooted or lacks necessary security features.",
|
"save-password-unavailable-android": "Save password is unavailable: your device may be rooted or lacks necessary security features.",
|
||||||
|
"Scan-or-enter-sync-code": "Scan or enter sync code",
|
||||||
"scan-qr": "Scan QR code",
|
"scan-qr": "Scan QR code",
|
||||||
"scan-qr-code": "Scan a QR code with a wallet address",
|
"scan-qr-code": "Scan a QR code with a wallet address",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
|
@ -1411,6 +1415,7 @@
|
||||||
"usd-currency": "USD",
|
"usd-currency": "USD",
|
||||||
"use-the-multichain-wallet": "Use the leading multi-chain self-custodial wallet",
|
"use-the-multichain-wallet": "Use the leading multi-chain self-custodial wallet",
|
||||||
"use-valid-contact-code": "Please enter or scan a valid chat key or username",
|
"use-valid-contact-code": "Please enter or scan a valid chat key or username",
|
||||||
|
"valid-for-time": "Valid for {{valid-for}}",
|
||||||
"validation-amount-invalid-number": "Amount is not a valid number",
|
"validation-amount-invalid-number": "Amount is not a valid number",
|
||||||
"validation-amount-is-too-precise": "Amount is too precise. Max number of decimals is {{decimals}}.",
|
"validation-amount-is-too-precise": "Amount is too precise. Max number of decimals is {{decimals}}.",
|
||||||
"version": "App version",
|
"version": "App version",
|
||||||
|
@ -1993,12 +1998,8 @@
|
||||||
"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",
|
||||||
"sync-new-device": "Sync a new device",
|
|
||||||
"sync-instructions-text": "You own your data. Synchronize it among all your devices.",
|
|
||||||
"sync-instruction-step-1": "1. Verify login with password",
|
|
||||||
"sync-instruction-step-2": "2. Reveal a temporary QR and Sync Code",
|
|
||||||
"sync-instruction-step-3": "3. Share that info with your new device",
|
|
||||||
"setup-syncing": "Setup Syncing",
|
"setup-syncing": "Setup Syncing",
|
||||||
|
"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",
|
||||||
"try-your-luck-again": "Try your luck again!",
|
"try-your-luck-again": "Try your luck again!",
|
||||||
|
|