From 41347ae5e0df49d28fef09b432dcfe9907d27055 Mon Sep 17 00:00:00 2001 From: Dmitry Novotochinov Date: Thu, 20 Sep 2018 14:24:14 +0300 Subject: [PATCH] [#5898] add HW setup screens Signed-off-by: Dmitry Novotochinov --- src/status_im/accounts/create/core.cljs | 2 +- src/status_im/events.cljs | 58 +++++++ src/status_im/hardwallet/core.cljs | 36 ++++- src/status_im/ui/components/colors.cljs | 1 + src/status_im/ui/screens/db.cljs | 5 +- src/status_im/ui/screens/events.cljs | 4 +- .../ui/screens/hardwallet/connect/styles.cljs | 11 +- .../ui/screens/hardwallet/connect/views.cljs | 23 +-- .../ui/screens/hardwallet/pin/styles.cljs | 111 ++++++++++++++ .../ui/screens/hardwallet/pin/subs.cljs | 27 ++++ .../ui/screens/hardwallet/pin/views.cljs | 101 +++++++++++++ .../ui/screens/hardwallet/setup/styles.cljs | 142 ++++++++++++++++++ .../ui/screens/hardwallet/setup/subs.cljs | 7 + .../ui/screens/hardwallet/setup/views.cljs | 120 +++++++++++++++ .../ui/screens/hardwallet/success/styles.cljs | 64 ++++++++ .../ui/screens/hardwallet/success/views.cljs | 36 +++++ src/status_im/ui/screens/subs.cljs | 4 +- src/status_im/ui/screens/views.cljs | 17 ++- src/status_im/utils/utils.cljs | 38 ++--- test/cljs/status_im/test/hardwallet/core.cljs | 46 ++++++ test/cljs/status_im/test/runner.cljs | 2 + translations/en.json | 25 ++- 22 files changed, 833 insertions(+), 47 deletions(-) create mode 100644 src/status_im/ui/screens/hardwallet/pin/styles.cljs create mode 100644 src/status_im/ui/screens/hardwallet/pin/subs.cljs create mode 100644 src/status_im/ui/screens/hardwallet/pin/views.cljs create mode 100644 src/status_im/ui/screens/hardwallet/setup/styles.cljs create mode 100644 src/status_im/ui/screens/hardwallet/setup/subs.cljs create mode 100644 src/status_im/ui/screens/hardwallet/setup/views.cljs create mode 100644 src/status_im/ui/screens/hardwallet/success/styles.cljs create mode 100644 src/status_im/ui/screens/hardwallet/success/views.cljs create mode 100644 test/cljs/status_im/test/hardwallet/core.cljs diff --git a/src/status_im/accounts/create/core.cljs b/src/status_im/accounts/create/core.cljs index ec3398e0f1..87487c2228 100644 --- a/src/status_im/accounts/create/core.cljs +++ b/src/status_im/accounts/create/core.cljs @@ -109,7 +109,7 @@ (defn navigate-to-authentication-method [{:keys [db] :as cofx}] (if (hardwallet/hardwallet-supported? db) - (navigation/navigate-to-cofx :hardwallet/authentication-method nil cofx) + (navigation/navigate-to-cofx :hardwallet-authentication-method nil cofx) (navigate-to-create-account-screen cofx))) ;;;; COFX diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index e853ff4abb..1253a7e99c 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -1,4 +1,5 @@ (ns status-im.events + (:require-macros [status-im.utils.handlers-macro :as handlers-macro]) (:require [re-frame.core :as re-frame] [status-im.accounts.core :as accounts] [status-im.accounts.create.core :as accounts.create] @@ -537,6 +538,63 @@ (fn [cofx _] (browser/open-url "https://hardwallet.status.im" cofx))) +(handlers/register-handler-fx + :hardwallet.ui/hold-card-button-pressed + (fn [{:keys [db] :as cofx} _] + (handlers-macro/merge-fx cofx + {:db (assoc-in db [:hardwallet :setup-step] :begin)} + (navigation/navigate-to-cofx :hardwallet-setup nil)))) + +(handlers/register-handler-fx + :hardwallet.ui/begin-setup-button-pressed + (fn [{:keys [db]} _] + {:db (assoc-in db [:hardwallet :setup-step] :prepare)})) + +(handlers/register-handler-fx + :hardwallet/connection-error + (fn [_ _] + {:utils/show-popup {:title (i18n/label :t/cant-read-card) + :content (i18n/label :t/cant-read-card-error-explanation) + :on-dismiss #(re-frame/dispatch [:hardwallet.ui/connection-error-confirm-button-pressed])}})) + +(handlers/register-handler-fx + :hardwallet.ui/connection-error-confirm-button-pressed + (fn [{:keys [db] :as cofx} _] + (handlers-macro/merge-fx cofx + {:db (assoc-in db [:hardwallet :setup-step] :begin)} + (navigation/navigate-to-cofx :hardwallet-setup nil)))) + +(handlers/register-handler-fx + :hardwallet.ui/secret-keys-next-button-pressed + (fn [_ _] + {:ui/show-confirmation {:title (i18n/label :t/secret-keys-confirmation-title) + :content (i18n/label :t/secret-keys-confirmation-text) + :confirm-button-text (i18n/label :t/secret-keys-confirmation-confirm) + :cancel-button-text (i18n/label :t/secret-keys-confirmation-cancel) + :on-accept #(re-frame/dispatch [:hardwallet.ui/secret-keys-dialog-confirm-pressed]) + :on-cancel #()}})) + +(handlers/register-handler-fx + :hardwallet.ui/secret-keys-dialog-confirm-pressed + (fn [{:keys [db]} _] + {:db (assoc-in db [:hardwallet :setup-step] :complete)})) + +(handlers/register-handler-fx + :hardwallet.ui/success-button-pressed + (fn [cofx _] + (navigation/navigate-to-cofx :home nil cofx))) + +(handlers/register-handler-fx + :hardwallet.ui/pin-numpad-button-pressed + (fn [cofx [_ number step]] + (hardwallet/process-pin-input number step cofx))) + +(handlers/register-handler-fx + :hardwallet.ui/pin-numpad-delete-button-pressed + (fn [{:keys [db]} [_ step]] + (when-not (empty? (get-in db [:hardwallet :pin step])) + {:db (update-in db [:hardwallet :pin step] pop)}))) + ;; browser module (handlers/register-handler-fx diff --git a/src/status_im/hardwallet/core.cljs b/src/status_im/hardwallet/core.cljs index fd8305daa2..5ee5bdb6bb 100644 --- a/src/status_im/hardwallet/core.cljs +++ b/src/status_im/hardwallet/core.cljs @@ -36,7 +36,7 @@ (handlers-macro/merge-fx cofx {:hardwallet/check-nfc-enabled nil} - (navigation/navigate-to-cofx :hardwallet/connect nil))) + (navigation/navigate-to-cofx :hardwallet-connect nil))) (defn hardwallet-supported? [db] (and config/hardwallet-enabled? @@ -45,9 +45,41 @@ (defn return-back-from-nfc-settings [app-coming-from-background? {:keys [db]}] (when (and app-coming-from-background? - (= :hardwallet/connect (:view-id db))) + (= :hardwallet-connect (:view-id db))) {:hardwallet/check-nfc-enabled nil})) +(defn- proceed-to-pin-confirmation [fx] + (assoc-in fx [:db :hardwallet :pin :enter-step] :confirmation)) + +(defn- pin-match [fx] + (assoc-in fx [:db :hardwallet :pin :status] :validating)) + +(defn- pin-mismatch [fx] + (assoc-in fx [:db :hardwallet :pin] {:status :error + :error :t/pin-mismatch + :original [] + :confirmation [] + :enter-step :original})) + +(defn process-pin-input [number enter-step {:keys [db]}] + (let [db' (update-in db [:hardwallet :pin enter-step] conj number) + numbers-entered (count (get-in db' [:hardwallet :pin enter-step]))] + (cond-> {:db (assoc-in db' [:hardwallet :pin :status] nil)} + (and (= enter-step :original) + (= 6 numbers-entered)) + (proceed-to-pin-confirmation) + + (and (= enter-step :confirmation) + (= (get-in db' [:hardwallet :pin :original]) + (get-in db' [:hardwallet :pin :confirmation]))) + (pin-match) + + (and (= enter-step :confirmation) + (= 6 numbers-entered) + (not= (get-in db' [:hardwallet :pin :original]) + (get-in db' [:hardwallet :pin :confirmation]))) + (pin-mismatch)))) + (re-frame/reg-fx :hardwallet/check-nfc-support check-nfc-support) diff --git a/src/status_im/ui/components/colors.cljs b/src/status_im/ui/components/colors.cljs index 733c8ce26d..bc8ab36acb 100644 --- a/src/status_im/ui/components/colors.cljs +++ b/src/status_im/ui/components/colors.cljs @@ -16,6 +16,7 @@ (def gray-transparent "rgba(184, 193, 199, 0.5)") ;; Used for tabs (def gray-notifications "#4A5054cc") ;; Used for notifications background (def gray-border "#ececf0") +(def gray-background "#eceffc") (def blue "#4360df") ;; Used as main wallet color, and ios home add button (def blue-transparent "rgba(67, 96, 223, 0.2)") (def blue-transparent-10 "rgba(67, 96, 223, 0.1)") diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index c6f9bf2409..b170d29106 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -60,7 +60,10 @@ :push-notifications/stored {} :registry {} :hardwallet {:nfc-supported? false - :nfc-enabled? false}}) + :nfc-enabled? false + :pin {:original [] + :confirmation [] + :enter-step :original}}}) ;;;;GLOBAL diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index 18be10d893..1f08618306 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -80,8 +80,8 @@ (re-frame/reg-fx :ui/show-confirmation - (fn [{:keys [title content confirm-button-text on-accept on-cancel]}] - (utils/show-confirmation title content confirm-button-text on-accept on-cancel))) + (fn [options] + (utils/show-confirmation options))) (re-frame/reg-fx :ui/close-application diff --git a/src/status_im/ui/screens/hardwallet/connect/styles.cljs b/src/status_im/ui/screens/hardwallet/connect/styles.cljs index 1ae2eadf53..e76981dac5 100644 --- a/src/status_im/ui/screens/hardwallet/connect/styles.cljs +++ b/src/status_im/ui/screens/hardwallet/connect/styles.cljs @@ -21,6 +21,10 @@ (def hardwallet-card-image-small {:width 44 :height 28 + :position :absolute + :left 58 + :top 13 + :z-index 1 :margin-right 20}) (def status-hardwallet-text-container @@ -39,8 +43,10 @@ :padding-horizontal 80 :padding-vertical 10}) -(def bottom-action-container - {:background-color colors/gray-lighter +(defn bottom-action-container [nfc-enabled?] + {:background-color (if nfc-enabled? + colors/gray-background + colors/gray-lighter) :width 369 :height 80 :border-radius 10 @@ -54,6 +60,7 @@ (def phone-nfc-image {:width 54 :height 72 + :z-index 2 :margin-left 20 :margin-top 8 :align-items :baseline}) diff --git a/src/status_im/ui/screens/hardwallet/connect/views.cljs b/src/status_im/ui/screens/hardwallet/connect/views.cljs index 271191b49d..d54a02fd20 100644 --- a/src/status_im/ui/screens/hardwallet/connect/views.cljs +++ b/src/status_im/ui/screens/hardwallet/connect/views.cljs @@ -35,17 +35,20 @@ [react/text {:style styles/link-card-text :number-of-lines 2} (i18n/label :t/link-card)]] - [react/view styles/bottom-action-container + [react/view (styles/bottom-action-container nfc-enabled?) (if nfc-enabled? - [react/view styles/nfc-enabled-container - [react/image {:source (:phone-nfc resources/ui) - :style styles/phone-nfc-image}] - [react/image {:source (:hardwallet-card resources/ui) - :style styles/hardwallet-card-image-small}] - [react/text {:style styles/hold-card-text - :number-of-lines 2 - :uppercase? true} - (i18n/label :t/hold-card)]] + [react/touchable-highlight + {:on-press #(re-frame/dispatch [:hardwallet.ui/hold-card-button-pressed])} + [react/view styles/nfc-enabled-container + [react/image {:source (:phone-nfc resources/ui) + :style styles/phone-nfc-image}] + [react/image {:source (:hardwallet-card resources/ui) + :style styles/hardwallet-card-image-small}] + [react/text {:style styles/hold-card-text + :number-of-lines 2 + :font :medium + :uppercase? true} + (i18n/label :t/hold-card)]]] [react/view styles/nfc-disabled-container [vector-icons/icon :icons/nfc {:color colors/gray :container-style styles/nfc-icon}] diff --git a/src/status_im/ui/screens/hardwallet/pin/styles.cljs b/src/status_im/ui/screens/hardwallet/pin/styles.cljs new file mode 100644 index 0000000000..246155d1fc --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/pin/styles.cljs @@ -0,0 +1,111 @@ +(ns status-im.ui.screens.hardwallet.pin.styles + (:require-macros [status-im.utils.styles :refer [defstyle]]) + (:require [status-im.ui.components.colors :as colors])) + +(def container + {:flex 1 + :background-color colors/white}) + +(def inner-container + {:flex-direction :column + :flex 1 + :align-items :center}) + +(defstyle error-container + {:android {:margin-top 25} + :ios {:margin-top 28}}) + +(def error-text + {:color colors/red + :font-size 15 + :text-align :center}) + +(def maintain-card-container + {:flex-direction :row + :align-items :center + :justify-content :center + :margin-top 81 + :width 369 + :height 60 + :border-radius 10 + :border-width 1 + :border-color colors/blue + :border-style :dashed}) + +(def maintain-card-text + {:padding-horizontal 20 + :font-size 12 + :color colors/blue}) + +(def center-container + {:flex-direction :column + :align-items :center + :margin-top 28}) + +(def center-title-text + {:font-size 22 + :color colors/black}) + +(def create-pin-text + {:font-size 15 + :padding-top 8 + :width 314 + :text-align :center + :color colors/gray}) + +(def pin-indicator-container + {:flex-direction :row + :justify-content :space-between + :margin-top 30}) + +(def pin-indicator-group-container + {:padding-horizontal 12 + :flex-direction :row + :justify-content :space-between}) + +(defn pin-indicator [pressed?] + {:width 16 + :height 16 + :background-color (if pressed? + colors/blue + colors/gray-light) + :border-radius 50 + :margin-horizontal 12}) + +(def waiting-indicator-container + {:margin-top 26}) + +(def numpad-container + {:margin-top 30}) + +(def numpad-row-container + {:flex-direction :row + :justify-content :center + :align-items :center + :margin-vertical 6}) + +(def numpad-button + {:width 72 + :margin-horizontal 12 + :height 72 + :align-items :center + :justify-content :center + :flex-direction :row + :border-radius 50 + :background-color colors/gray-background}) + +(def numpad-delete-button + (assoc numpad-button :background-color colors/white + :border-width 2 + :border-color colors/gray-background)) + +(def numpad-empty-button + (assoc numpad-button :background-color colors/white + :border-color colors/white)) + +(def numpad-button-text + {:font-size 34 + :color colors/blue}) + +(def numpad-empty-button-text + {:color colors/white}) diff --git a/src/status_im/ui/screens/hardwallet/pin/subs.cljs b/src/status_im/ui/screens/hardwallet/pin/subs.cljs new file mode 100644 index 0000000000..49ccd25c37 --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/pin/subs.cljs @@ -0,0 +1,27 @@ +(ns status-im.ui.screens.hardwallet.pin.subs + (:require [re-frame.core :as re-frame])) + +(re-frame/reg-sub + :hardwallet/pin + (fn [db] + (get-in db [:hardwallet :pin :original]))) + +(re-frame/reg-sub + :hardwallet/pin-confirmation + (fn [db] + (get-in db [:hardwallet :pin :confirmation]))) + +(re-frame/reg-sub + :hardwallet/pin-enter-step + (fn [db] + (get-in db [:hardwallet :pin :enter-step]))) + +(re-frame/reg-sub + :hardwallet/pin-status + (fn [db] + (get-in db [:hardwallet :pin :status]))) + +(re-frame/reg-sub + :hardwallet/pin-error + (fn [db] + (get-in db [:hardwallet :pin :error]))) diff --git a/src/status_im/ui/screens/hardwallet/pin/views.cljs b/src/status_im/ui/screens/hardwallet/pin/views.cljs new file mode 100644 index 0000000000..b9ffd4b506 --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/pin/views.cljs @@ -0,0 +1,101 @@ +(ns status-im.ui.screens.hardwallet.pin.views + (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.components.react :as react] + [status-im.ui.components.styles :as components.styles] + [status-im.ui.screens.hardwallet.pin.styles :as styles])) + +(defn numpad-button [n step enabled?] + [react/touchable-highlight + {:on-press #(when enabled? + (re-frame/dispatch [:hardwallet.ui/pin-numpad-button-pressed n step]))} + [react/view styles/numpad-button + [react/text {:style styles/numpad-button-text} + n]]]) + +(defn numpad-row [[a b c] step enabled?] + [react/view styles/numpad-row-container + [numpad-button a step enabled?] + [numpad-button b step enabled?] + [numpad-button c step enabled?]]) + +(defn numpad [step enabled?] + [react/view styles/numpad-container + [numpad-row [1 2 3] step enabled?] + [numpad-row [4 5 6] step enabled?] + [numpad-row [7 8 9] step enabled?] + [react/view styles/numpad-row-container + [react/view styles/numpad-empty-button + [react/text {:style styles/numpad-empty-button-text}]] + [numpad-button 0 step enabled?] + [react/touchable-highlight + {:on-press #(when enabled? + (re-frame/dispatch [:hardwallet.ui/pin-numpad-delete-button-pressed step]))} + [react/view styles/numpad-delete-button + [vector-icons/icon :icons/back {:color colors/blue}]]]]]) + +(defn pin-indicator [pressed?] + [react/view (styles/pin-indicator pressed?)]) + +(defn pin-indicators [pin] + [react/view styles/pin-indicator-container + (map-indexed + (fn [i group] + ^{:key i} + [react/view styles/pin-indicator-group-container + group]) + (partition 3 + (map-indexed + (fn [i n] + ^{:key i} + [pin-indicator (number? n)]) + (concat pin + (repeat (- 6 (count pin)) + nil)))))]) + +(defn pin-view [{:keys [pin title step status error]}] + (let [enabled? (not= status :validating)] + [react/view styles/container + [react/view styles/inner-container + [react/view styles/maintain-card-container + [vector-icons/icon :icons/hardwallet {:color colors/blue}] + [react/text {:style styles/maintain-card-text} + (i18n/label :t/maintain-card-to-phone-contact)]] + [react/view styles/center-container + [react/text {:style styles/center-title-text + :font :bold} + (i18n/label title)] + [react/text {:style styles/create-pin-text + :number-of-lines 2} + (i18n/label :t/create-pin-description)] + (case status + :validating [react/view styles/waiting-indicator-container + [react/activity-indicator {:animating true + :size :small}]] + :error [react/view styles/error-container + [react/text {:style styles/error-text + :font :medium} + (i18n/label error)]] + [pin-indicators pin]) + [numpad step enabled?]]]])) + +(defview hardwallet-pin [] + (letsubs [original [:hardwallet/pin] + confirmation [:hardwallet/pin-confirmation] + enter-step [:hardwallet/pin-enter-step] + status [:hardwallet/pin-status] + error [:hardwallet/pin-error]] + (case enter-step + :original [pin-view {:pin original + :title :t/create-pin + :step :original + :status status + :error error}] + :confirmation [pin-view {:pin confirmation + :title :t/repeat-pin + :step :confirmation + :status status + :error error}]))) \ No newline at end of file diff --git a/src/status_im/ui/screens/hardwallet/setup/styles.cljs b/src/status_im/ui/screens/hardwallet/setup/styles.cljs new file mode 100644 index 0000000000..ffbd41e912 --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/setup/styles.cljs @@ -0,0 +1,142 @@ +(ns status-im.ui.screens.hardwallet.setup.styles + (:require [status-im.ui.components.colors :as colors])) + +(def container + {:flex 1 + :background-color colors/white}) + +(def inner-container + {:flex-direction :column + :flex 1 + :align-items :center + :justify-content :space-between}) + +;; setup step + +(def maintain-card-container + {:flex-direction :row + :align-items :center + :justify-content :center + :margin-top 81 + :width 369 + :height 60 + :border-radius 10 + :border-width 1 + :border-color colors/blue + :border-style :dashed}) + +(def maintain-card-text + {:padding-horizontal 20 + :font-size 12 + :color colors/blue}) + +(def hardwallet-card-image-container + {:margin-top -50}) + +(def hardwallet-card-image + {:width 255 + :height 160}) + +(def card-is-empty-text-container + {:margin-top 37}) + +(def card-is-empty-text + {:font-size 15 + :color colors/gray + :text-align :center}) + +(def bottom-action-container + {:background-color colors/gray-background + :align-items :center + :justify-content :center + :flex-direction :row + :width 160 + :height 44 + :border-radius 10 + :margin-bottom 40}) + +(def begin-set-up-text + {:font-size 14 + :color colors/blue + :line-height 20 + :text-transform :uppercase}) + +;; prepare step + +(def center-container + {:flex-direction :column + :align-items :center + :height 200}) + +(def center-title-text + {:font-size 22 + :color colors/black}) + +(def generating-codes-for-pairing-text + {:font-size 15 + :padding-top 8 + :width 314 + :text-align :center + :color colors/gray}) + +(def estimated-time-text + (assoc generating-codes-for-pairing-text :padding-top 25)) + +(def waiting-indicator-container + {:height 200}) + +;; secret keys step + +(def secret-keys-container + {:flex-direction :column + :align-items :center}) + +(def secret-keys-title-container + {:width 292}) + +(def secret-keys-title-text + {:font-size 22 + :text-align :center + :color colors/black}) + +(def puk-code-title-text + {:font-size 17 + :padding-top 32 + :color colors/black}) + +(def puk-code-explanation-text + {:font-size 15 + :padding-top 5 + :color colors/gray}) + +(def puk-code-numbers-container + {:width 369 + :height 64 + :margin-top 20 + :align-items :center + :justify-content :center + :border-width 1 + :border-color colors/gray-light + :border-radius 10}) + +(def puk-code-text + {:font-size 17 + :text-align :center + :color colors/green}) + +(def pair-code-title-text + puk-code-title-text) + +(def pair-code-explanation-text + (assoc puk-code-explanation-text :text-align :center)) + +(def pair-code-text-container + puk-code-numbers-container) + +(def pair-code-text + puk-code-text) + +(def next-button-container + {:flex-direction :row + :margin-horizontal 12 + :margin-vertical 15}) diff --git a/src/status_im/ui/screens/hardwallet/setup/subs.cljs b/src/status_im/ui/screens/hardwallet/setup/subs.cljs new file mode 100644 index 0000000000..4cb2f5145c --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/setup/subs.cljs @@ -0,0 +1,7 @@ +(ns status-im.ui.screens.hardwallet.setup.subs + (:require [re-frame.core :as re-frame])) + +(re-frame/reg-sub + :hardwallet-setup-step + (fn [db] + (get-in db [:hardwallet :setup-step]))) \ No newline at end of file diff --git a/src/status_im/ui/screens/hardwallet/setup/views.cljs b/src/status_im/ui/screens/hardwallet/setup/views.cljs new file mode 100644 index 0000000000..1afc8755e9 --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/setup/views.cljs @@ -0,0 +1,120 @@ +(ns status-im.ui.screens.hardwallet.setup.views + (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require [re-frame.core :as re-frame] + [status-im.ui.components.common.common :as components.common] + [status-im.react-native.resources :as resources] + [status-im.ui.screens.hardwallet.setup.styles :as styles] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.components.react :as react] + [status-im.ui.components.styles :as components.styles] + [status-im.i18n :as i18n] + [status-im.ui.components.colors :as colors])) + +(defn begin [] + [react/view styles/container + [react/view components.styles/flex + [react/view styles/inner-container + [react/view styles/maintain-card-container + [vector-icons/icon :icons/hardwallet {:color colors/blue}] + [react/text {:style styles/maintain-card-text} + (i18n/label :t/maintain-card-to-phone-contact)]] + [react/view styles/hardwallet-card-image-container + [react/image {:source (:hardwallet-card resources/ui) + :style styles/hardwallet-card-image}] + [react/view styles/card-is-empty-text-container + [react/text {:style styles/card-is-empty-text} + (i18n/label :t/card-is-empty)]]] + [react/touchable-highlight + {:on-press #(re-frame/dispatch [:hardwallet.ui/begin-setup-button-pressed])} + [react/view styles/bottom-action-container + [react/text {:style styles/begin-set-up-text + :font :medium + :uppercase? true} + (i18n/label :t/begin-set-up)]]]]]]) + +(defn prepare [] + [react/view styles/container + [react/view components.styles/flex + [react/view styles/inner-container + [react/view styles/maintain-card-container + [vector-icons/icon :icons/hardwallet {:color colors/blue}] + [react/text {:style styles/maintain-card-text} + (i18n/label :t/maintain-card-to-phone-contact)]] + [react/view styles/center-container + [react/text {:style styles/center-title-text + :font :bold} + (i18n/label :t/preparing-card)] + [react/text {:style styles/generating-codes-for-pairing-text + :number-of-lines 2} + (i18n/label :t/generating-codes-for-pairing)] + [react/text {:style styles/estimated-time-text} + (i18n/label :t/estimated-time + {:time "~20 seconds"})]] + [react/view styles/waiting-indicator-container + [react/activity-indicator {:animating true + :size :large}]]]]]) + +(defn secret-keys [] + [react/view styles/container + [react/view components.styles/flex + [react/view styles/inner-container + [react/view styles/maintain-card-container + [vector-icons/icon :icons/hardwallet {:color colors/blue}] + [react/text {:style styles/maintain-card-text} + (i18n/label :t/maintain-card-to-phone-contact)]] + [react/view styles/secret-keys-container + [react/view styles/secret-keys-title-container + [react/text {:style styles/secret-keys-title-text + :number-of-lines 2 + :font :bold} + (i18n/label :t/write-down-and-store-securely)]] + [react/text {:style styles/puk-code-title-text + :font :bold} + (i18n/label :t/puk-code)] + [react/text {:style styles/puk-code-explanation-text} + (i18n/label :t/puk-code-explanation)] + [react/view styles/puk-code-numbers-container + [react/text {:style styles/puk-code-text + :font :bold} + "1234 5678 9123"]] + [react/text {:style styles/pair-code-title-text + :font :bold} + (i18n/label :t/pair-code)] + [react/text {:style styles/pair-code-explanation-text + :number-of-lines 2} + (i18n/label :t/pair-code-explanation)] + [react/view styles/pair-code-text-container + [react/text {:style styles/pair-code-text + :font :bold} + "a12k52kh0x"]]] + [react/view styles/next-button-container + [react/view components.styles/flex] + [components.common/bottom-button + {:on-press #(re-frame/dispatch [:hardwallet.ui/secret-keys-next-button-pressed]) + :forward? true}]]]]]) + +(defn complete [] + [react/view styles/container + [react/view components.styles/flex + [react/view styles/inner-container + [react/view styles/maintain-card-container + [vector-icons/icon :icons/hardwallet {:color colors/blue}] + [react/text {:style styles/maintain-card-text} + (i18n/label :t/maintain-card-to-phone-contact)]] + [react/view styles/center-container + [react/text {:style styles/center-title-text + :font :bold} + (i18n/label :t/completing-card-setup)] + [react/text {:style styles/estimated-time-text} + (i18n/label :t/estimated-time {:time "~30 seconds"})]] + [react/view styles/waiting-indicator-container + [react/activity-indicator {:animating true + :size :large}]]]]]) + +(defview hardwallet-setup [] + (letsubs [step [:hardwallet-setup-step]] + (case step + :begin [begin] + :prepare [prepare] + :secret-keys [secret-keys] + :complete [complete]))) \ No newline at end of file diff --git a/src/status_im/ui/screens/hardwallet/success/styles.cljs b/src/status_im/ui/screens/hardwallet/success/styles.cljs new file mode 100644 index 0000000000..d00167cbc3 --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/success/styles.cljs @@ -0,0 +1,64 @@ +(ns status-im.ui.screens.hardwallet.success.styles + (:require [status-im.ui.components.colors :as colors])) + +(def container + {:flex 1 + :background-color colors/white}) + +(def inner-container + {:flex-direction :column + :flex 1 + :align-items :center + :justify-content :space-between}) + +(def hardwallet-card-image-container + {:margin-top 120 + :flex-direction :column + :align-items :center + :justify-content :center}) + +(def hardwallet-card-image + {:width 255 + :height 160}) + +(def icon-check-container + {:width 64 + :height 64 + :bottom -40 + :position :absolute + :align-items :center + :justify-content :center + :background-color colors/green + :border-radius 50}) + +(def complete-text-container + {:margin-top 40}) + +(def complete-text + {:font-size 22 + :font-weight :bold + :color colors/black + :text-align :center}) + +(def complete-information-text + {:text-align :center + :font-size 15 + :color colors/gray + :padding-horizontal 80 + :padding-vertical 10}) + +(def bottom-action-container + {:background-color colors/gray-background + :align-items :center + :justify-content :center + :flex-direction :row + :width 104 + :height 44 + :border-radius 10 + :margin-bottom 40}) + +(def bottom-action-text + {:font-size 14 + :color colors/blue + :line-height 20 + :text-transform :uppercase}) \ No newline at end of file diff --git a/src/status_im/ui/screens/hardwallet/success/views.cljs b/src/status_im/ui/screens/hardwallet/success/views.cljs new file mode 100644 index 0000000000..6944b24ca2 --- /dev/null +++ b/src/status_im/ui/screens/hardwallet/success/views.cljs @@ -0,0 +1,36 @@ +(ns status-im.ui.screens.hardwallet.success.views + (:require [re-frame.core :as re-frame] + [status-im.react-native.resources :as resources] + [status-im.ui.screens.hardwallet.success.styles :as styles] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.components.react :as react] + [status-im.ui.components.styles :as components.styles] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.i18n :as i18n] + [status-im.ui.components.colors :as colors])) + +(defn hardwallet-success [] + [react/view styles/container + [status-bar/status-bar] + [react/view components.styles/flex + [react/view styles/inner-container + [react/view styles/hardwallet-card-image-container + [react/image {:source (:hardwallet-card resources/ui) + :style styles/hardwallet-card-image}] + [react/view styles/icon-check-container + [vector-icons/icon :icons/check {:color :white + :width 30 + :height 30}]]] + [react/view styles/complete-text-container + [react/text {:style styles/complete-text} + (i18n/label :t/complete-exclamation)] + [react/text {:style styles/complete-information-text + :number-of-lines 3} + (i18n/label :t/complete-hardwallet-setup)]] + [react/touchable-highlight + {:on-press #(re-frame/dispatch [:hardwallet.ui/success-button-pressed])} + [react/view styles/bottom-action-container + [react/text {:style styles/bottom-action-text + :font :medium + :uppercase? true} + (i18n/label :t/okay)]]]]]]) \ No newline at end of file diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index b46b6360ca..2d60dd2114 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -22,7 +22,9 @@ status-im.ui.screens.add-new.new-chat.subs status-im.ui.screens.add-new.new-public-chat.subs status-im.ui.screens.profile.subs - status-im.ui.screens.hardwallet.connect.subs)) + status-im.ui.screens.hardwallet.connect.subs + status-im.ui.screens.hardwallet.pin.subs + status-im.ui.screens.hardwallet.setup.subs)) (reg-sub :get (fn [db [_ k]] diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 494c3885cd..a1137f33fe 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -58,6 +58,9 @@ [status-im.ui.screens.accounts.create.views :refer [create-account]] [status-im.ui.screens.hardwallet.authentication-method.views :refer [hardwallet-authentication-method]] [status-im.ui.screens.hardwallet.connect.views :refer [hardwallet-connect]] + [status-im.ui.screens.hardwallet.pin.views :refer [hardwallet-pin]] + [status-im.ui.screens.hardwallet.setup.views :refer [hardwallet-setup]] + [status-im.ui.screens.hardwallet.success.views :refer [hardwallet-success]] [status-im.ui.screens.profile.seed.views :refer [backup-seed]] [status-im.ui.screens.about-app.views :as about-app] [status-im.utils.navigation :as navigation] @@ -131,8 +134,11 @@ :create-account create-account :recover recover :accounts accounts - :hardwallet/authentication-method hardwallet-authentication-method - :hardwallet/connect hardwallet-connect} + :hardwallet-authentication-method hardwallet-authentication-method + :hardwallet-connect hardwallet-connect + :hardwallet-setup hardwallet-setup + :hardwallet-pin hardwallet-pin + :hardwallet-success hardwallet-success} (= :intro view-id) (assoc :intro intro))) (cond-> {:headerMode "none"} @@ -272,8 +278,11 @@ :create-account create-account :recover recover :accounts accounts - :hardwallet/authentication-method hardwallet-authentication-method - :hardwallet/connect hardwallet-connect + :hardwallet-authentication-method hardwallet-authentication-method + :hardwallet-connect hardwallet-connect + :hardwallet-pin hardwallet-pin + :hardwallet-setup hardwallet-setup + :hardwallet-success hardwallet-success :qr-scanner qr-scanner}) {:headerMode "none" :initialRouteName "my-profile"})} diff --git a/src/status_im/utils/utils.cljs b/src/status_im/utils/utils.cljs index 6540644da1..1722880966 100644 --- a/src/status_im/utils/utils.cljs +++ b/src/status_im/utils/utils.cljs @@ -24,29 +24,21 @@ (show-popup title content on-dismiss))) (defn show-confirmation - ([title content on-accept] - (show-confirmation title content nil on-accept)) - ([title content confirm-button-text on-accept] - (show-confirmation title content confirm-button-text on-accept nil)) - ([title content confirm-button-text on-accept on-cancel] - (show-confirmation nil title content confirm-button-text on-accept on-cancel)) - ([ios-style title content confirm-button-text on-accept on-cancel] - (show-confirmation ios-style title content confirm-button-text on-accept on-cancel nil)) - ([{:keys [ios-confirm-style] :or {ios-confirm-style "destructive"}} - title content confirm-button-text on-accept on-cancel cancel-button-text] - (.alert (.-Alert rn-dependencies/react-native) - title - content - ;; Styles are only relevant on iOS. On Android first button is 'neutral' and second is 'positive' - (clj->js - (vector (merge {:text (or cancel-button-text (i18n/label :t/cancel)) - :style "cancel" - :accessibility-label :cancel-button} - (when on-cancel {:onPress on-cancel})) - {:text (or confirm-button-text "OK") - :onPress on-accept - :style ios-confirm-style - :accessibility-label :confirm-button}))))) + [{:keys [title content confirm-button-text on-accept on-cancel cancel-button-text]}] + (.alert (.-Alert rn-dependencies/react-native) + title + content + ;; Styles are only relevant on iOS. On Android first button is 'neutral' and second is 'positive' + (clj->js + (vector (merge {:text (or cancel-button-text (i18n/label :t/cancel)) + :style "cancel" + :accessibility-label :cancel-button} + (when on-cancel {:onPress on-cancel})) + {:text (or confirm-button-text (i18n/label :t/ok)) + :onPress on-accept + :style "default" + :accessibility-label :confirm-button}) + #js {:cancelable false}))) (defn show-question ([title content on-accept] diff --git a/test/cljs/status_im/test/hardwallet/core.cljs b/test/cljs/status_im/test/hardwallet/core.cljs new file mode 100644 index 0000000000..d505be770d --- /dev/null +++ b/test/cljs/status_im/test/hardwallet/core.cljs @@ -0,0 +1,46 @@ +(ns status-im.test.hardwallet.core + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.hardwallet.core :as hardwallet])) + +(deftest process-pin-input + (testing "start entering PIN" + (is (= {:db {:hardwallet {:pin {:original [1] + :confirmation [] + :status nil + :enter-step :original}}}} + (hardwallet/process-pin-input 1 + :original + {:db {:hardwallet {:pin {:original [] + :confirmation [] + :enter-step :original}}}})))) + (testing "first 6 numbers entered" + (is (= {:db {:hardwallet {:pin {:original [1 2 3 4 5 6] + :confirmation [] + :status nil + :enter-step :confirmation}}}} + (hardwallet/process-pin-input 6 + :original + {:db {:hardwallet {:pin {:original [1 2 3 4 5] + :confirmation [] + :enter-step :original}}}})))) + (testing "confirmation entered" + (is (= {:db {:hardwallet {:pin {:original [1 2 3 4 5 6] + :confirmation [1 2 3 4 5 6] + :enter-step :confirmation + :status :validating}}}} + (hardwallet/process-pin-input 6 + :confirmation + {:db {:hardwallet {:pin {:original [1 2 3 4 5 6] + :confirmation [1 2 3 4 5] + :enter-step :confirmation}}}})))) + (testing "confirmation doesn't match" + (is (= {:db {:hardwallet {:pin {:original [] + :confirmation [] + :enter-step :original + :error :t/pin-mismatch + :status :error}}}} + (hardwallet/process-pin-input 7 + :confirmation + {:db {:hardwallet {:pin {:original [1 2 3 4 5 6] + :confirmation [1 2 3 4 5] + :enter-step :confirmation}}}}))))) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index fb7999ad6a..c3e3c18a2b 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -52,6 +52,7 @@ [status-im.test.ui.screens.add-new.models] [status-im.test.accounts.recover.core] + [status-im.test.hardwallet.core] [status-im.test.ui.screens.currency-settings.models] [status-im.test.ui.screens.wallet.db])) @@ -113,6 +114,7 @@ 'status-im.test.utils.http 'status-im.test.ui.screens.add-new.models 'status-im.test.accounts.recover.core + 'status-im.test.hardwallet.core 'status-im.test.ui.screens.currency-settings.models 'status-im.test.ui.screens.wallet.db 'status-im.test.browser.core diff --git a/translations/en.json b/translations/en.json index 311ee259bc..cc68dac679 100644 --- a/translations/en.json +++ b/translations/en.json @@ -305,6 +305,7 @@ "mainnet-text": "You’re on the Mainnet. Real ETH will be sent", "receive": "Receive", "ok-got-it": "Ok, got it", + "ok": "OK", "main-currency": "Main currency", "clear-history-title": "Clear history?", "image-source-make-photo": "Capture", @@ -714,5 +715,27 @@ "link-card": "Link the card and use it to confirm your identity on the platform.", "hold-card": "hold card to the back of your phone", "turn-nfc-on": "turn nfc on", - "go-to-settings": "Go to Settings" + "go-to-settings": "Go to Settings", + "card-is-empty": "Card is empty", + "begin-set-up": "begin set up", + "maintain-card-to-phone-contact": "Maintain card-to-phone contact during process.", + "preparing-card": "Preparing card", + "generating-codes-for-pairing": "Generating codes for pairing with your Status account.", + "estimated-time": "Estimated time {{time}}", + "cant-read-card": "Can't read card", + "cant-read-card-error-explanation": "Card must stay in contact with phone during setup so it can connect to the NFC reader", + "write-down-and-store-securely": "Write these down and store them securely", + "puk-code": "PUK code", + "puk-code-explanation": "Unlocks card if you lose access", + "pair-code": "Pair code", + "pair-code-explanation": "Pairs card to a different device with the same Status account on it", + "secret-keys-confirmation-title": "Did you write them down?", + "secret-keys-confirmation-text": "Record these now because you won't see this screen again", + "secret-keys-confirmation-confirm": "GOT IT", + "secret-keys-confirmation-cancel": "SEE IT AGAIN", + "completing-card-setup": "Completing card setup", + "create-pin": "Create a PIN", + "create-pin-description": "You'll need your card + this PIN to log in and to confirm transactions", + "repeat-pin": "Repeate your PIN", + "pin-mismatch": "PIN does not match" }