add keycard installation

Signed-off-by: Dmitry Novotochinov <dmitry.novot@gmail.com>
This commit is contained in:
Dmitry Novotochinov 2018-12-04 16:41:34 +03:00
parent e40e495e11
commit 962c49e345
No known key found for this signature in database
GPG Key ID: 43D1DAF5AD39C927
47 changed files with 1435 additions and 376 deletions

View File

@ -219,7 +219,6 @@ configurations.all {
} }
dependencies { dependencies {
compile project(':react-native-nfc-manager')
implementation project(':react-native-background-timer') implementation project(':react-native-background-timer')
implementation project(':react-native-svg') implementation project(':react-native-svg')
implementation 'com.android.support:multidex:1.0.2' implementation 'com.android.support:multidex:1.0.2'
@ -249,6 +248,7 @@ dependencies {
exclude group: "com.google.android.gms" exclude group: "com.google.android.gms"
compile 'com.android.support:exifinterface:27.+' compile 'com.android.support:exifinterface:27.+'
} }
implementation project(':react-native-status-keycard')
implementation 'com.google.firebase:firebase-core:16.0.3' //this decides your firebase SDK version implementation 'com.google.firebase:firebase-core:16.0.3' //this decides your firebase SDK version
implementation 'com.google.firebase:firebase-messaging:17.1.0' implementation 'com.google.firebase:firebase-messaging:17.1.0'
implementation project(':react-native-keychain') implementation project(':react-native-keychain')

View File

@ -4,7 +4,6 @@ import android.support.multidex.MultiDexApplication;
import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage; import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage;
import org.devio.rn.splashscreen.SplashScreenReactPackage; import org.devio.rn.splashscreen.SplashScreenReactPackage;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import community.revteltech.nfc.NfcManagerPackage;
import io.invertase.firebase.RNFirebasePackage; import io.invertase.firebase.RNFirebasePackage;
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage; import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage; import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
@ -23,6 +22,7 @@ import com.reactnative.ivpusic.imagepicker.PickerPackage;
import com.rnfs.RNFSPackage; import com.rnfs.RNFSPackage;
import fr.bamlab.rnimageresizer.ImageResizerPackage; import fr.bamlab.rnimageresizer.ImageResizerPackage;
import im.status.ethereum.module.StatusPackage; import im.status.ethereum.module.StatusPackage;
import im.status.ethereum.keycard.RNStatusKeycardPackage;
import io.realm.react.RealmReactPackage; import io.realm.react.RealmReactPackage;
import me.alwx.HttpServer.HttpServerReactPackage; import me.alwx.HttpServer.HttpServerReactPackage;
import com.oblador.keychain.KeychainPackage; import com.oblador.keychain.KeychainPackage;
@ -56,7 +56,6 @@ public class MainApplication extends MultiDexApplication implements ReactApplica
Function<String, String> callRPC = statusPackage.getCallRPC(); Function<String, String> callRPC = statusPackage.getCallRPC();
List<ReactPackage> packages = new ArrayList<ReactPackage>(Arrays.asList( List<ReactPackage> packages = new ArrayList<ReactPackage>(Arrays.asList(
new MainReactPackage(), new MainReactPackage(),
new NfcManagerPackage(),
new RNFirebasePackage(), new RNFirebasePackage(),
new RNFirebaseMessagingPackage(), new RNFirebaseMessagingPackage(),
new RNFirebaseNotificationsPackage(), new RNFirebaseNotificationsPackage(),
@ -66,6 +65,7 @@ public class MainApplication extends MultiDexApplication implements ReactApplica
new HttpServerReactPackage(), new HttpServerReactPackage(),
new SplashScreenReactPackage(), new SplashScreenReactPackage(),
statusPackage, statusPackage,
new RNStatusKeycardPackage(),
new RealmReactPackage(), new RealmReactPackage(),
new RNI18nPackage(), new RNI18nPackage(),
new RNCameraPackage(), new RNCameraPackage(),

View File

@ -26,6 +26,8 @@ include ':react-native-status'
project(':react-native-status').projectDir = new File(rootProject.projectDir, '../modules/react-native-status/android') project(':react-native-status').projectDir = new File(rootProject.projectDir, '../modules/react-native-status/android')
include ':react-native-camera' include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android') project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
include ':react-native-status-keycard'
project(':react-native-status-keycard').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-status-keycard/android')
include ':react-native-fs' include ':react-native-fs'
project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android') project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android')
include ':react-native-image-crop-picker' include ':react-native-image-crop-picker'

View File

@ -10,6 +10,7 @@
"dismissKeyboard" "dismissKeyboard"
"react-native-splash-screen" "react-native-splash-screen"
"react-native-status" "react-native-status"
"react-native-status-keycard"
"react-native-camera" "react-native-camera"
"react-native-qrcode" "react-native-qrcode"
"identicon.js" "identicon.js"
@ -37,7 +38,6 @@
"react-native/Libraries/vendor/emitter/EventEmitter" "react-native/Libraries/vendor/emitter/EventEmitter"
"react-native-background-timer" "react-native-background-timer"
"react-native-fetch-polyfill" "react-native-fetch-polyfill"
"react-native-nfc-manager"
"text-encoding" "text-encoding"
"js-sha3" "js-sha3"
"react-navigation"] "react-navigation"]

View File

@ -18,8 +18,6 @@ target 'StatusIm' do
pod 'RNKeychain', :path => '../node_modules/react-native-keychain' pod 'RNKeychain', :path => '../node_modules/react-native-keychain'
pod 'react-native-camera', path: '../node_modules/react-native-camera' pod 'react-native-camera', path: '../node_modules/react-native-camera'
pod 'react-native-nfc-manager', :path => '../node_modules/react-native-nfc-manager'
target 'StatusImTests' do target 'StatusImTests' do
inherit! :search_paths inherit! :search_paths
# Pods for testing # Pods for testing

View File

@ -66,8 +66,6 @@ PODS:
- React - React
- react-native-camera/RN (1.1.5): - react-native-camera/RN (1.1.5):
- React - React
- react-native-nfc-manager (0.5.5):
- React
- React/Core (0.56.0): - React/Core (0.56.0):
- yoga (= 0.56.0.React) - yoga (= 0.56.0.React)
- RNKeychain (3.0.0): - RNKeychain (3.0.0):
@ -80,7 +78,6 @@ DEPENDENCIES:
- React (from `../node_modules/react-native`) - React (from `../node_modules/react-native`)
- react-native-background-timer (from `../node_modules/react-native-background-timer`) - react-native-background-timer (from `../node_modules/react-native-background-timer`)
- react-native-camera (from `../node_modules/react-native-camera`) - react-native-camera (from `../node_modules/react-native-camera`)
- react-native-nfc-manager (from `../node_modules/react-native-nfc-manager`)
- RNKeychain (from `../node_modules/react-native-keychain`) - RNKeychain (from `../node_modules/react-native-keychain`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga`) - yoga (from `../node_modules/react-native/ReactCommon/yoga`)
@ -103,8 +100,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-background-timer" :path: "../node_modules/react-native-background-timer"
react-native-camera: react-native-camera:
:path: "../node_modules/react-native-camera" :path: "../node_modules/react-native-camera"
react-native-nfc-manager:
:path: "../node_modules/react-native-nfc-manager"
RNKeychain: RNKeychain:
:path: "../node_modules/react-native-keychain" :path: "../node_modules/react-native-keychain"
yoga: yoga:
@ -123,10 +118,9 @@ SPEC CHECKSUMS:
React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11 React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11
react-native-background-timer: bb7a98c8e97fc7c290de2d423dd09ddb73dcbcbb react-native-background-timer: bb7a98c8e97fc7c290de2d423dd09ddb73dcbcbb
react-native-camera: 68ad5143d2d0636236d46c7de8d2a6455ca52a36 react-native-camera: 68ad5143d2d0636236d46c7de8d2a6455ca52a36
react-native-nfc-manager: a74ef58b29f0015ae9e70f120645b796668ba5c2
RNKeychain: 627c6095cef215dd3d9804a9a9cf45ab96aa3997 RNKeychain: 627c6095cef215dd3d9804a9a9cf45ab96aa3997
yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85 yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85
PODFILE CHECKSUM: b24b9e1dd90a715fd354083342dceb8f1a2f6d75 PODFILE CHECKSUM: 7636f960a0dbec2dd55b8b20e244befa3fdb4438
COCOAPODS: 1.5.2 COCOAPODS: 1.5.2

View File

@ -49,13 +49,13 @@
"react-native-invertible-scroll-view": "1.1.0", "react-native-invertible-scroll-view": "1.1.0",
"react-native-keychain": "3.0.0", "react-native-keychain": "3.0.0",
"react-native-level-fs": "3.0.1", "react-native-level-fs": "3.0.1",
"react-native-nfc-manager": "^0.5.5",
"react-native-os": "https://github.com/status-im/react-native-os.git#1.1.0-1", "react-native-os": "https://github.com/status-im/react-native-os.git#1.1.0-1",
"react-native-qrcode": "0.2.7", "react-native-qrcode": "0.2.7",
"react-native-randombytes": "3.5.0", "react-native-randombytes": "3.5.0",
"react-native-safe-area-view": "0.9.0", "react-native-safe-area-view": "0.9.0",
"react-native-securerandom": "https://github.com/status-im/react-native-securerandom#0.1.1-1", "react-native-securerandom": "https://github.com/status-im/react-native-securerandom#0.1.1-1",
"react-native-splash-screen": "3.1.1", "react-native-splash-screen": "3.1.1",
"react-native-status-keycard": "github:status-im/react-native-status-keycard",
"react-native-svg": "6.5.2", "react-native-svg": "6.5.2",
"react-native-tcp": "https://github.com/status-im/react-native-tcp.git#3.3.0-1", "react-native-tcp": "https://github.com/status-im/react-native-tcp.git#3.3.0-1",
"react-native-udp": "https://github.com/status-im/react-native-udp.git#2.3.1-1", "react-native-udp": "https://github.com/status-im/react-native-udp.git#2.3.1-1",

View File

@ -5949,11 +5949,6 @@ react-native-level-fs@3.0.1:
level-filesystem "^1.0.1" level-filesystem "^1.0.1"
levelup "^0.18.2" levelup "^0.18.2"
react-native-nfc-manager@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/react-native-nfc-manager/-/react-native-nfc-manager-0.5.5.tgz#5b60376bbc2287fc5e1a75c6c15e5511be788e7b"
integrity sha512-4gFuyDnNWXe81R7tTbc1AFlrz1LfBHp/S7daWL7gEsBFdeRegDmopecUJER511UR5d5Ymttw37LzTZUbnNKTlQ==
"react-native-os@https://github.com/status-im/react-native-os.git#1.1.0-1": "react-native-os@https://github.com/status-im/react-native-os.git#1.1.0-1":
version "1.1.0" version "1.1.0"
resolved "https://github.com/status-im/react-native-os.git#1a6d0835f919cb075793ad7c602f2724eee4702d" resolved "https://github.com/status-im/react-native-os.git#1a6d0835f919cb075793ad7c602f2724eee4702d"
@ -6010,6 +6005,10 @@ react-native-splash-screen@3.1.1:
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.1.1.tgz#1a4e46c9fdce53ff52af2a2cb4181788c4e30b30" resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.1.1.tgz#1a4e46c9fdce53ff52af2a2cb4181788c4e30b30"
integrity sha512-PU2YocOSGbLjL9Vgcq/cwMNuHHKNjjuPpa1IPMuWo+6EB/fSZ5VOmxSa7+eucQe3631s3NhGuk3eHKahU03a4Q== integrity sha512-PU2YocOSGbLjL9Vgcq/cwMNuHHKNjjuPpa1IPMuWo+6EB/fSZ5VOmxSa7+eucQe3631s3NhGuk3eHKahU03a4Q==
"react-native-status-keycard@github:status-im/react-native-status-keycard":
version "1.0.0"
resolved "https://codeload.github.com/status-im/react-native-status-keycard/tar.gz/b6c7324a8fd69acba42127000189bf9d58f4b774"
react-native-svg@6.5.2: react-native-svg@6.5.2:
version "6.5.2" version "6.5.2"
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-6.5.2.tgz#1105896b8873b0856821b18daa0c6898cea6c00c" resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-6.5.2.tgz#1105896b8873b0856821b18daa0c6898cea6c00c"

View File

@ -17,8 +17,8 @@
(def desktop-config (js/require "react-native-desktop-config")) (def desktop-config (js/require "react-native-desktop-config"))
(def react-native-firebase #js {}) (def react-native-firebase #js {})
(def nfc-manager #js {})
(def camera #js {:default #js {:constants {:Aspect "Portrait"}}}) (def camera #js {:default #js {:constants {:Aspect "Portrait"}}})
(def status-keycard #js {:default #js {}})
(def dialogs #js {}) (def dialogs #js {})
(def dismiss-keyboard #js {}) (def dismiss-keyboard #js {})
(def image-crop-picker #js {}) (def image-crop-picker #js {})

View File

@ -6,6 +6,7 @@
(def keychain (js/require "react-native-keychain")) (def keychain (js/require "react-native-keychain"))
(def qr-code (js/require "react-native-qrcode")) (def qr-code (js/require "react-native-qrcode"))
(def react-native (js/require "react-native")) (def react-native (js/require "react-native"))
(def status-keycard (js/require "react-native-status-keycard"))
(def realm (js/require "realm")) (def realm (js/require "realm"))
(def webview-bridge (js/require "react-native-webview-bridge")) (def webview-bridge (js/require "react-native-webview-bridge"))
(def secure-random (.-generateSecureRandom (js/require "react-native-securerandom"))) (def secure-random (.-generateSecureRandom (js/require "react-native-securerandom")))
@ -19,7 +20,6 @@
(def image-resizer (js/require "react-native-image-resizer")) (def image-resizer (js/require "react-native-image-resizer"))
(def svg (js/require "react-native-svg")) (def svg (js/require "react-native-svg"))
(def react-native-firebase (js/require "react-native-firebase")) (def react-native-firebase (js/require "react-native-firebase"))
(def nfc-manager (js/require "react-native-nfc-manager"))
(def snoopy (js/require "rn-snoopy")) (def snoopy (js/require "rn-snoopy"))
(def snoopy-filter (js/require "rn-snoopy/stream/filter")) (def snoopy-filter (js/require "rn-snoopy/stream/filter"))
(def snoopy-bars (js/require "rn-snoopy/stream/bars")) (def snoopy-bars (js/require "rn-snoopy/stream/bars"))

5
resources/icons/link.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 5.75C4.08579 5.75 3.75 6.08579 3.75 6.5V11.5C3.75 11.9142 4.08579 12.25 4.5 12.25H9.5C9.91421 12.25 10.25 11.9142 10.25 11.5V8.70711C10.25 8.5745 10.3027 8.44732 10.3964 8.35355L11.3232 7.42678C11.4807 7.26929 11.75 7.38083 11.75 7.60355V11.5C11.75 12.7426 10.7426 13.75 9.5 13.75H4.5C3.25736 13.75 2.25 12.7426 2.25 11.5V6.5C2.25 5.25736 3.25736 4.25 4.5 4.25H8.39645C8.61917 4.25 8.73071 4.51929 8.57322 4.67678L7.64645 5.60355C7.55268 5.69732 7.4255 5.75 7.29289 5.75H4.5Z" fill="#4360DF"/>
<path d="M14.75 2C14.75 1.80811 14.6768 1.61621 14.5303 1.46973C14.3838 1.32324 14.1919 1.25 14 1.25H9C8.58569 1.25 8.25 1.58582 8.25 2C8.25 2.41418 8.58569 2.75 9 2.75H11.7066C11.8848 2.75 11.974 2.96543 11.848 3.09142L6.46973 8.46973C6.17676 8.76257 6.17676 9.23743 6.46973 9.53027C6.76245 9.82324 7.23755 9.82324 7.53027 9.53027L12.9086 4.15197C13.0346 4.02598 13.25 4.11521 13.25 4.29339V7C13.25 7.41418 13.5859 7.75 14 7.75C14.4141 7.75 14.75 7.41418 14.75 7V2Z" fill="#4360DF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -8,7 +8,6 @@
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.data-store.accounts :as accounts-store] [status-im.data-store.accounts :as accounts-store]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.hardwallet.core :as hardwallet]
[status-im.native-module.core :as status] [status-im.native-module.core :as status]
[status-im.ui.screens.navigation :as navigation] [status-im.ui.screens.navigation :as navigation]
[status-im.utils.config :as config] [status-im.utils.config :as config]
@ -62,7 +61,7 @@
[{:keys [signing-phrase [{:keys [signing-phrase
status status
db] :as cofx} db] :as cofx}
{:keys [pubkey address mnemonic installation-id]} password seed-backed-up] {:keys [pubkey address mnemonic installation-id keycard-instance-uid]} password seed-backed-up]
(let [normalized-address (utils.hex/normalize-hex address) (let [normalized-address (utils.hex/normalize-hex address)
account {:public-key pubkey account {:public-key pubkey
:installation-id (or installation-id (get-in db [:accounts/new-installation-id])) :installation-id (or installation-id (get-in db [:accounts/new-installation-id]))
@ -75,6 +74,7 @@
:signing-phrase signing-phrase :signing-phrase signing-phrase
:seed-backed-up? seed-backed-up :seed-backed-up? seed-backed-up
:mnemonic mnemonic :mnemonic mnemonic
:keycard-instance-uid keycard-instance-uid
:settings (constants/default-account-settings)}] :settings (constants/default-account-settings)}]
(log/debug "account-created") (log/debug "account-created")
(when-not (string/blank? pubkey) (when-not (string/blank? pubkey)
@ -128,12 +128,6 @@
(dissoc :password :password-confirm :name :error)))} (dissoc :password :password-confirm :name :error)))}
(navigation/navigate-to-cofx :create-account nil))) (navigation/navigate-to-cofx :create-account nil)))
(fx/defn navigate-to-authentication-method
[{:keys [db] :as cofx}]
(if (hardwallet/hardwallet-supported? db)
(navigation/navigate-to-cofx cofx :hardwallet-authentication-method nil)
(navigate-to-create-account-screen cofx)))
;;;; COFX ;;;; COFX
(re-frame/reg-cofx (re-frame/reg-cofx

View File

@ -213,3 +213,7 @@
{:type :bool :default false})) {:type :bool :default false}))
(def v15 (update v14 :properties dissoc :email)) (def v15 (update v14 :properties dissoc :email))
(def v16 (assoc-in v15
[:properties :keycard-instance-uid]
{:type :string :optional true}))

View File

@ -66,6 +66,11 @@
(def v17 v16) (def v17 v16)
(def v18 [network/v1
bootnode/v4
extension/v12
account/v16])
;; put schemas ordered by version ;; put schemas ordered by version
(def schemas [{:schema v1 (def schemas [{:schema v1
:schemaVersion 1 :schemaVersion 1
@ -117,4 +122,7 @@
:migration migrations/v16} :migration migrations/v16}
{:schema v17 {:schema v17
:schemaVersion 17 :schemaVersion 17
:migration migrations/v17}]) :migration migrations/v17}
{:schema v18
:schemaVersion 18
:migration migrations/v18}])

View File

@ -127,3 +127,6 @@
(contains? % :BQX) (conj :ETHOS))) (contains? % :BQX) (conj :ETHOS)))
updated (serialize new-settings)] updated (serialize new-settings)]
(aset account "settings" updated))))) (aset account "settings" updated)))))
(defn v18 [old-realm new-realm]
(log/debug "migrating base database v18: " old-realm new-realm))

View File

@ -196,7 +196,7 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:accounts.create.ui/create-new-account-button-pressed :accounts.create.ui/create-new-account-button-pressed
(fn [cofx _] (fn [cofx _]
(accounts.create/navigate-to-authentication-method cofx))) (hardwallet/navigate-to-authentication-method cofx)))
;; accounts recover module ;; accounts recover module
@ -825,6 +825,26 @@
;; hardwallet module ;; hardwallet module
(handlers/register-handler-fx
:hardwallet.ui/get-application-info
(fn [_ _]
{:hardwallet/get-application-info nil}))
(handlers/register-handler-fx
:hardwallet.callback/on-register-card-events
(fn [cofx [_ listeners]]
(hardwallet/on-register-card-events cofx listeners)))
(handlers/register-handler-fx
:hardwallet.callback/on-get-application-info-success
(fn [cofx [_ info]]
(hardwallet/on-get-application-info-success cofx info)))
(handlers/register-handler-fx
:hardwallet.callback/on-get-application-info-error
(fn [cofx [_ error]]
(hardwallet/on-get-application-info-error cofx error)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.callback/check-nfc-support-success :hardwallet.callback/check-nfc-support-success
(fn [cofx [_ supported?]] (fn [cofx [_ supported?]]
@ -835,6 +855,59 @@
(fn [cofx [_ enabled?]] (fn [cofx [_ enabled?]]
(hardwallet/set-nfc-enabled cofx enabled?))) (hardwallet/set-nfc-enabled cofx enabled?)))
(handlers/register-handler-fx
:hardwallet.callback/on-card-connected
(fn [cofx [_ data]]
(hardwallet/on-card-connected cofx data)))
(handlers/register-handler-fx
:hardwallet.callback/on-card-disconnected
(fn [cofx [_ data]]
(hardwallet/on-card-disconnected cofx data)))
(handlers/register-handler-fx
:hardwallet.callback/on-install-applet-and-init-card-success
(fn [cofx [_ secrets]]
(hardwallet/on-install-applet-and-init-card-success cofx secrets)))
(handlers/register-handler-fx
:hardwallet.callback/on-install-applet-and-init-card-error
(fn [cofx [_ error]]
(hardwallet/on-install-applet-and-init-card-error cofx error)))
(handlers/register-handler-fx
:hardwallet.callback/on-pairing-success
(fn [cofx [_ pairing]]
(hardwallet/on-pairing-success cofx pairing)))
(handlers/register-handler-fx
:hardwallet.callback/on-pairing-error
(fn [cofx [_ error]]
(hardwallet/on-pairing-error cofx error)))
(handlers/register-handler-fx
:hardwallet.callback/on-generate-mnemonic-success
(fn [cofx [_ mnemonic]]
(hardwallet/on-generate-mnemonic-success cofx mnemonic)))
(handlers/register-handler-fx
:hardwallet.callback/on-generate-mnemonic-error
(fn [cofx [_ error]]
(hardwallet/on-generate-mnemonic-error cofx error)))
(handlers/register-handler-fx
:hardwallet.callback/on-generate-and-load-key-success
[(re-frame/inject-cofx :random-guid-generator)
(re-frame/inject-cofx :accounts.create/get-signing-phrase)
(re-frame/inject-cofx :accounts.create/get-status)]
(fn [cofx [_ data]]
(hardwallet/on-generate-and-load-key-success cofx data)))
(handlers/register-handler-fx
:hardwallet.callback/on-generate-and-load-key-error
(fn [cofx [_ error]]
(hardwallet/on-generate-and-load-key-error cofx error)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/status-hardwallet-option-pressed :hardwallet.ui/status-hardwallet-option-pressed
(fn [cofx _] (fn [cofx _]
@ -850,11 +923,6 @@
(fn [_ _] (fn [_ _]
{:hardwallet/open-nfc-settings nil})) {:hardwallet/open-nfc-settings nil}))
(handlers/register-handler-fx
:hardwallet.ui/connect-info-button-pressed
(fn [cofx _]
(browser/open-url cofx "https://hardwallet.status.im")))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/hold-card-button-pressed :hardwallet.ui/hold-card-button-pressed
(fn [{:keys [db] :as cofx} _] (fn [{:keys [db] :as cofx} _]
@ -864,8 +932,23 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/begin-setup-button-pressed :hardwallet.ui/begin-setup-button-pressed
(fn [{:keys [db]} _] (fn [_ _]
{:db (assoc-in db [:hardwallet :setup-step] :preparing)})) {:ui/show-confirmation {:title ""
:content (i18n/label :t/begin-keycard-setup-confirmation-text)
:confirm-button-text (i18n/label :t/yes)
:cancel-button-text (i18n/label :t/no)
:on-accept #(re-frame/dispatch [:hardwallet.ui/begin-setup-confirm-button-pressed])
:on-cancel #()}}))
(handlers/register-handler-fx
:hardwallet.ui/begin-setup-confirm-button-pressed
(fn [cofx _]
(hardwallet/load-preparing-screen cofx)))
(handlers/register-handler-fx
:hardwallet/install-applet-and-init-card
(fn [cofx _]
(hardwallet/install-applet-and-init-card cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/pair-card-button-pressed :hardwallet.ui/pair-card-button-pressed
@ -882,14 +965,34 @@
(fn [{:keys [db]} _])) (fn [{:keys [db]} _]))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/no-pairing-slots-help-button-pressed :hardwallet.ui/recovery-phrase-next-button-pressed
(fn [cofx _] (fn [cofx _]
(browser/open-url "https://hardwallet.status.im" cofx))) (hardwallet/recovery-phrase-start-confirmation cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/card-already-linked-help-button-pressed :hardwallet.ui/recovery-phrase-confirm-word-next-button-pressed
(fn [cofx _] (fn [cofx _]
(browser/open-url "https://hardwallet.status.im" cofx))) (hardwallet/recovery-phrase-confirm-word cofx)))
(handlers/register-handler-fx
:hardwallet.ui/recovery-phrase-confirm-word-back-button-pressed
(fn [{:keys [db]} _]
{:db (assoc-in db [:hardwallet :setup-step] :recovery-phrase)}))
(handlers/register-handler-fx
:hardwallet.ui/recovery-phrase-confirm-word-input-changed
(fn [{:keys [db]} [_ input]]
{:db (assoc-in db [:hardwallet :recovery-phrase :input-word] input)}))
(handlers/register-handler-fx
:hardwallet.ui/recovery-phrase-confirm-pressed
(fn [cofx _]
(hardwallet/load-loading-keys-screen cofx)))
(handlers/register-handler-fx
:hardwallet.ui/recovery-phrase-cancel-pressed
(fn [{:keys [db]} _]
{:db (assoc-in db [:hardwallet :setup-step] :recovery-phrase)}))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet/connection-error :hardwallet/connection-error
@ -917,13 +1020,18 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/secret-keys-dialog-confirm-pressed :hardwallet.ui/secret-keys-dialog-confirm-pressed
(fn [{:keys [db]} _] (fn [cofx _]
{:db (assoc-in db [:hardwallet :setup-step] :complete)})) (hardwallet/load-pairing-screen cofx)))
(handlers/register-handler-fx
:hardwallet/pair
(fn [cofx _]
(hardwallet/pair cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/success-button-pressed :hardwallet.ui/success-button-pressed
(fn [cofx _] (fn [cofx _]
(navigation/navigate-to-cofx cofx :home nil))) (hardwallet/success-button-pressed cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/pin-numpad-button-pressed :hardwallet.ui/pin-numpad-button-pressed
@ -936,10 +1044,32 @@
(when-not (empty? (get-in db [:hardwallet :pin step])) (when-not (empty? (get-in db [:hardwallet :pin step]))
{:db (update-in db [:hardwallet :pin step] pop)}))) {:db (update-in db [:hardwallet :pin step] pop)})))
(handlers/register-handler-fx
:hardwallet.ui/card-ready-next-button-pressed
(fn [cofx _]
(hardwallet/load-generating-mnemonic-screen cofx)))
(handlers/register-handler-fx
:hardwallet/generate-mnemonic
(fn [cofx _]
(hardwallet/generate-mnemonic cofx)))
(handlers/register-handler-fx
:hardwallet/generate-and-load-key
(fn [cofx _]
(hardwallet/generate-and-load-key cofx)))
(handlers/register-handler-fx (handlers/register-handler-fx
:hardwallet.ui/create-pin-button-pressed :hardwallet.ui/create-pin-button-pressed
(fn [{:keys [db]} _] (fn [{:keys [db]} _]
{:db (update-in db [:hardwallet :setup-step] :pin)})) {:db (-> db
(assoc-in [:hardwallet :setup-step] :pin)
(assoc-in [:hardwallet :pin :enter-step] :original))}))
(handlers/register-handler-fx
:hardwallet.ui/error-button-pressed
(fn [cofx _]
(hardwallet/error-button-pressed cofx)))
;; browser module ;; browser module

View File

@ -0,0 +1,92 @@
(ns status-im.hardwallet.card
(:require [re-frame.core :as re-frame]
[status-im.react-native.js-dependencies :as js-dependencies]
[status-im.utils.config :as config]
[status-im.utils.platform :as platform]
[taoensso.timbre :as log]))
(defonce keycard (.-default js-dependencies/status-keycard))
(defonce event-emitter (.-DeviceEventEmitter js-dependencies/react-native))
(defn- error-object->map [object]
{:code (.-code object)
:error (.-message object)})
(defn check-nfc-support []
(when config/hardwallet-enabled?
(.. keycard
nfcIsSupported
(then #(re-frame/dispatch [:hardwallet.callback/check-nfc-support-success %])))))
(defn check-nfc-enabled []
(when platform/android?
(.. keycard
nfcIsEnabled
(then #(re-frame/dispatch [:hardwallet.callback/check-nfc-enabled-success %])))))
(defn open-nfc-settings []
(when platform/android?
(.openNfcSettings keycard)))
(defn remove-event-listeners []
(doseq [event ["keyCardOnConnected" "keyCardOnDisconnected"]]
(.removeAllListeners event-emitter event)))
(defn register-card-events []
(when (and config/hardwallet-enabled?)
(remove-event-listeners)
(re-frame/dispatch [:hardwallet.callback/on-register-card-events
{:on-card-connected
(.addListener event-emitter
"keyCardOnConnected"
#(re-frame/dispatch [:hardwallet.callback/on-card-connected %]))
:on-card-disconnected
(.addListener event-emitter
"keyCardOnDisconnected"
#(re-frame/dispatch [:hardwallet.callback/on-card-disconnected %]))}])))
(defn get-application-info []
(.. keycard
getApplicationInfo
(then #(re-frame/dispatch [:hardwallet.callback/on-get-application-info-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-get-application-info-error (error-object->map %)]))))
(defn start []
(when config/hardwallet-enabled?
(.. keycard
start
(then #(log/debug "[hardwallet] module started"))
(catch #(log/debug "[hardwallet] module not started " %)))))
(defn install-applet-and-init-card []
(when config/hardwallet-enabled?
(.. keycard
installAppletAndInitCard
(then #(re-frame/dispatch [:hardwallet.callback/on-install-applet-and-init-card-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-install-applet-and-init-card-error (error-object->map %)])))))
(defn pair
[{:keys [password]}]
(when password
(.. keycard
(pair password)
(then #(re-frame/dispatch [:hardwallet.callback/on-pairing-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-pairing-error (error-object->map %)])))))
(defn generate-mnemonic
[{:keys [pairing]}]
(when pairing
(.. keycard
(generateMnemonic pairing)
(then #(re-frame/dispatch [:hardwallet.callback/on-generate-mnemonic-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-generate-mnemonic-error (error-object->map %)])))))
(defn generate-and-load-key
[{:keys [mnemonic pairing pin]}]
(when pairing
(.. keycard
(generateAndLoadKey mnemonic pairing pin)
(then #(re-frame/dispatch [:hardwallet.callback/on-generate-and-load-key-success %]))
(catch #(re-frame/dispatch [:hardwallet.callback/on-generate-and-load-key-error (error-object->map %)])))))

View File

@ -1,24 +1,44 @@
(ns status-im.hardwallet.core (ns status-im.hardwallet.core
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[status-im.react-native.js-dependencies :as js-dependencies] status-im.hardwallet.fx
[status-im.ui.screens.navigation :as navigation] [status-im.ui.screens.navigation :as navigation]
[status-im.utils.config :as config] [status-im.utils.config :as config]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.utils.platform :as platform])) [status-im.utils.platform :as platform]
[taoensso.timbre :as log]
[status-im.i18n :as i18n]
[status-im.accounts.create.core :as accounts.create]
[status-im.accounts.login.core :as accounts.login]))
(defn check-nfc-support [] (defn hardwallet-supported? [{:keys [db]}]
(when config/hardwallet-enabled? (and config/hardwallet-enabled?
(.. js-dependencies/nfc-manager platform/android?
-default (get-in db [:hardwallet :nfc-supported?])))
isSupported
(then #(re-frame/dispatch [:hardwallet.callback/check-nfc-support-success %])))))
(defn check-nfc-enabled [] (fx/defn navigate-to-authentication-method
(when platform/android? [cofx]
(.. js-dependencies/nfc-manager (if (hardwallet-supported? cofx)
-default (navigation/navigate-to-cofx cofx :hardwallet-authentication-method nil)
isEnabled (accounts.create/navigate-to-create-account-screen cofx)))
(then #(re-frame/dispatch [:hardwallet.callback/check-nfc-enabled-success %])))))
(fx/defn on-register-card-events
[{:keys [db]} listeners]
{:db (update-in db [:hardwallet :listeners] merge listeners)})
(fx/defn on-get-application-info-success
[{:keys [db]} info]
(let [info' (js->clj info :keywordize-keys true)]
{:db (-> db
(assoc-in [:hardwallet :application-info] info')
(assoc-in [:hardwallet :application-info :applet-installed?] true)
(assoc-in [:hardwallet :application-info-error] nil))}))
(fx/defn on-get-application-info-error
[{:keys [db]} error]
(log/debug "[hardwallet] application info error " error)
{:db (-> db
(assoc-in [:hardwallet :application-info-error] error)
(assoc-in [:hardwallet :application-info :applet-installed?] false))})
(fx/defn set-nfc-support (fx/defn set-nfc-support
[{:keys [db]} supported?] [{:keys [db]} supported?]
@ -28,21 +48,31 @@
[{:keys [db]} enabled?] [{:keys [db]} enabled?]
{:db (assoc-in db [:hardwallet :nfc-enabled?] enabled?)}) {:db (assoc-in db [:hardwallet :nfc-enabled?] enabled?)})
(defn open-nfc-settings [] (fx/defn navigate-to-connect-screen [{:keys [db] :as cofx}]
(when platform/android?
(.. js-dependencies/nfc-manager
-default
goToNfcSetting)))
(fx/defn navigate-to-connect-screen [cofx]
(fx/merge cofx (fx/merge cofx
{:hardwallet/check-nfc-enabled nil} {:hardwallet/check-nfc-enabled nil
:hardwallet/register-card-events nil
:db (assoc-in db [:hardwallet :setup-step] :begin)}
(navigation/navigate-to-cofx :hardwallet-connect nil))) (navigation/navigate-to-cofx :hardwallet-connect nil)))
(defn hardwallet-supported? [db] (fx/defn success-button-pressed [cofx]
(and config/hardwallet-enabled? ;; login not implemented yet
platform/android? )
(get-in db [:hardwallet :nfc-supported?])))
(fx/defn error-button-pressed [{:keys [db] :as cofx}]
(let [return-to-step (get-in db [:hardwallet :return-to-step] :begin)]
(fx/merge cofx
{:db (assoc-in db [:hardwallet :setup-step] return-to-step)}
(when-not return-to-step
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn load-pairing-screen [{:keys [db]}]
{:db (assoc-in db [:hardwallet :setup-step] :pairing)
:dispatch [:hardwallet/pair]})
(fx/defn pair [cofx]
(let [{:keys [password]} (get-in cofx [:db :hardwallet :secrets])]
{:hardwallet/pair {:password password}}))
(fx/defn return-back-from-nfc-settings [{:keys [db]}] (fx/defn return-back-from-nfc-settings [{:keys [db]}]
(when (= :hardwallet-connect (:view-id db)) (when (= :hardwallet-connect (:view-id db))
@ -81,14 +111,184 @@
(get-in db' [:hardwallet :pin :confirmation]))) (get-in db' [:hardwallet :pin :confirmation])))
(pin-mismatch)))) (pin-mismatch))))
(re-frame/reg-fx (fx/defn load-loading-keys-screen
:hardwallet/check-nfc-support [{:keys [db]}]
check-nfc-support) {:db (assoc-in db [:hardwallet :setup-step] :loading-keys)
:dispatch [:hardwallet/generate-and-load-key]})
(re-frame/reg-fx (fx/defn load-generating-mnemonic-screen
:hardwallet/check-nfc-enabled [{:keys [db]}]
check-nfc-enabled) {:db (assoc-in db [:hardwallet :setup-step] :generating-mnemonic)
:dispatch [:hardwallet/generate-mnemonic]})
(re-frame/reg-fx (fx/defn generate-mnemonic
:hardwallet/open-nfc-settings [cofx]
open-nfc-settings) (let [{:keys [pairing]} (get-in cofx [:db :hardwallet :secrets])]
{:hardwallet/generate-mnemonic {:pairing pairing}}))
(fx/defn on-card-connected
[{:keys [db] :as cofx} data]
(log/debug "[hardwallet] card connected " data)
(let [return-to-step (get-in db [:hardwallet :return-to-step])
setup-running? (get-in db [:hardwallet :setup-step])]
(fx/merge cofx
{:db (cond-> db
return-to-step (assoc-in [:hardwallet :setup-step] return-to-step)
true (assoc-in [:hardwallet :card-connected?] true)
true (assoc-in [:hardwallet :return-to-step] nil))
:hardwallet/get-application-info nil}
(when setup-running?
(navigation/navigate-to-cofx :hardwallet-setup nil)))))
(fx/defn on-card-disconnected
[{:keys [db] :as cofx} _]
(log/debug "[hardwallet] card disconnected ")
(let [setup-running? (get-in db [:hardwallet :setup-step])]
(fx/merge cofx
{:db (assoc-in db [:hardwallet :card-connected?] false)}
(when setup-running?
(navigation/navigate-to-cofx :hardwallet-connect nil)))))
(fx/defn load-preparing-screen
[{:keys [db]}]
{:db (assoc-in db [:hardwallet :setup-step] :preparing)
:dispatch [:hardwallet/install-applet-and-init-card]})
(fx/defn install-applet-and-init-card
[{:keys [db]}]
{:hardwallet/install-applet-and-init-card nil})
(fx/defn on-install-applet-and-init-card-success
[{:keys [db]} secrets]
(let [secrets' (js->clj secrets :keywordize-keys true)]
{:db (-> db
(assoc-in [:hardwallet :setup-step] :secret-keys)
(assoc-in [:hardwallet :secrets] secrets'))}))
(defn- tag-lost-exception? [code]
(= code "android.nfc.TagLostException"))
(fx/defn process-error [{:keys [db] :as cofx} code]
(if (tag-lost-exception? code)
(navigation/navigate-to-cofx cofx :hardwallet-connect nil)
{:db (assoc-in db [:hardwallet :setup-step] :error)}))
(fx/defn on-install-applet-and-init-card-error
[{:keys [db] :as cofx} {:keys [code error]}]
(log/debug "[hardwallet] install applet and init card error: " error)
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :return-to-step] :begin)
(assoc-in [:hardwallet :setup-error] error))}
(process-error code)))
(fx/defn on-pairing-success
[{:keys [db]} pairing]
{:db (-> db
(assoc-in [:hardwallet :setup-step] :card-ready)
(assoc-in [:hardwallet :secrets :pairing] pairing))})
(fx/defn on-pairing-error
[{:keys [db] :as cofx} {:keys [error code]}]
(log/debug "[hardwallet] pairing error: " error)
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :return-to-step] :secret-keys)
(assoc-in [:hardwallet :setup-error] error))}
(process-error code)))
(fx/defn on-generate-mnemonic-success
[{:keys [db]} mnemonic]
{:db (-> db
(assoc-in [:hardwallet :setup-step] :recovery-phrase)
(assoc-in [:hardwallet :secrets :mnemonic] mnemonic))})
(fx/defn on-generate-mnemonic-error
[{:keys [db] :as cofx} {:keys [error code]}]
(log/debug "[hardwallet] generate mnemonic error: " error)
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :return-to-step] :card-ready)
(assoc-in [:hardwallet :setup-error] error))}
(process-error code)))
(fx/defn recovery-phrase-start-confirmation [{:keys [db]}]
(let [mnemonic (get-in db [:hardwallet :secrets :mnemonic])
[word1 word2] (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))
word1 (zipmap [:idx :word] word1)
word2 (zipmap [:idx :word] word2)]
{:db (-> db
(assoc-in [:hardwallet :setup-step] :recovery-phrase-confirm-word1)
(assoc-in [:hardwallet :recovery-phrase :step] :word1)
(assoc-in [:hardwallet :recovery-phrase :confirm-error] nil)
(assoc-in [:hardwallet :recovery-phrase :input-word] nil)
(assoc-in [:hardwallet :recovery-phrase :word1] word1)
(assoc-in [:hardwallet :recovery-phrase :word2] word2))}))
(defn- show-recover-confirmation []
{:ui/show-confirmation {:title (i18n/label :t/are-you-sure?)
:content (i18n/label :t/are-you-sure-description)
:confirm-button-text (clojure.string/upper-case (i18n/label :t/yes))
:cancel-button-text (i18n/label :t/see-it-again)
:on-accept #(re-frame/dispatch [:hardwallet.ui/recovery-phrase-confirm-pressed])
:on-cancel #(re-frame/dispatch [:hardwallet.ui/recovery-phrase-cancel-pressed])}})
(defn- recovery-phrase-next-word [db]
{:db (-> db
(assoc-in [:hardwallet :recovery-phrase :step] :word2)
(assoc-in [:hardwallet :recovery-phrase :confirm-error] nil)
(assoc-in [:hardwallet :recovery-phrase :input-word] nil)
(assoc-in [:hardwallet :setup-step] :recovery-phrase-confirm-word2))})
(fx/defn recovery-phrase-confirm-word
[{:keys [db]}]
(let [step (get-in db [:hardwallet :recovery-phrase :step])
input-word (get-in db [:hardwallet :recovery-phrase :input-word])
{:keys [word]} (get-in db [:hardwallet :recovery-phrase step])]
(if (= word input-word)
(if (= step :word1)
(recovery-phrase-next-word db)
(show-recover-confirmation))
{:db (assoc-in db [:hardwallet :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
(fx/defn generate-and-load-key
[{:keys [db] :as cofx}]
(let [{:keys [mnemonic pairing pin]} (get-in db [:hardwallet :secrets])]
(fx/merge cofx
{:hardwallet/generate-and-load-key {:mnemonic mnemonic
:pairing pairing
:pin pin}})))
(fx/defn on-generate-and-load-key-success
[{:keys [db] :as cofx} data]
(let [{:keys [whisper-public-key
whisper-private-key
whisper-address
wallet-address
encryption-public-key]} (js->clj data :keywordize-keys true)
whisper-public-key' (str "0x" whisper-public-key)
keycard-instance-uid (get-in db [:hardwallet :application-info :instance-uid])]
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :whisper-public-key] whisper-public-key')
(assoc-in [:hardwallet :whisper-private-key] whisper-private-key)
(assoc-in [:hardwallet :whisper-address] whisper-address)
(assoc-in [:hardwallet :wallet-address] wallet-address)
(assoc-in [:hardwallet :encryption-public-key] encryption-public-key)
(assoc-in [:hardwallet :setup-step] nil))}
(accounts.create/on-account-created {:pubkey whisper-public-key'
:address wallet-address
:mnemonic ""
:keycard-instance-uid keycard-instance-uid}
encryption-public-key
true)
(navigation/navigate-to-cofx :hardwallet-success nil))))
(fx/defn on-generate-and-load-key-error
[{:keys [db] :as cofx} {:keys [error code]}]
(log/debug "[hardwallet] generate and load key error: " error)
(fx/merge cofx
{:db (-> db
(assoc-in [:hardwallet :return-to-step] :recovery-phrase)
(assoc-in [:hardwallet :setup-error] error))}
(process-error code)))

View File

@ -0,0 +1,48 @@
(ns status-im.hardwallet.fx
(:require [re-frame.core :as re-frame]
[status-im.hardwallet.card :as card]
[status-im.react-native.js-dependencies :as js-dependencies]))
(re-frame/reg-fx
:hardwallet/get-application-info
card/get-application-info)
(re-frame/reg-fx
:hardwallet/check-nfc-support
card/check-nfc-support)
(re-frame/reg-fx
:hardwallet/check-nfc-enabled
card/check-nfc-enabled)
(re-frame/reg-fx
:hardwallet/open-nfc-settings
card/open-nfc-settings)
(re-frame/reg-fx
:hardwallet/start-module
card/start)
(re-frame/reg-fx
:hardwallet/install-applet-and-init-card
card/install-applet-and-init-card)
(re-frame/reg-fx
:hardwallet/register-card-events
card/register-card-events)
(re-frame/reg-fx
:hardwallet/remove-event-listeners
card/remove-event-listeners)
(re-frame/reg-fx
:hardwallet/pair
card/pair)
(re-frame/reg-fx
:hardwallet/generate-mnemonic
card/generate-mnemonic)
(re-frame/reg-fx
:hardwallet/generate-and-load-key
card/generate-and-load-key)

View File

@ -79,7 +79,9 @@
:network/listen-to-network-status nil :network/listen-to-network-status nil
:network/listen-to-connection-status nil :network/listen-to-connection-status nil
:hardwallet/check-nfc-support nil :hardwallet/check-nfc-support nil
:hardwallet/check-nfc-enabled nil} :hardwallet/check-nfc-enabled nil
:hardwallet/start-module nil
:hardwallet/register-card-events nil}
(initialize-keychain))) (initialize-keychain)))
(fx/defn initialize-app-db (fx/defn initialize-app-db
@ -88,7 +90,7 @@
initial-props desktop/desktop initial-props desktop/desktop
network-status network peers-count peers-summary device-UUID] network-status network peers-count peers-summary device-UUID]
:node/keys [status] :node/keys [status]
:or {network (get app-db :network)}} :db}] :or {network (get app-db :network)}} :db}]
{:db (assoc app-db {:db (assoc app-db
:contacts/contacts {} :contacts/contacts {}
:initial-props initial-props :initial-props initial-props
@ -99,9 +101,9 @@
:status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?) :status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?)
:node/status status :node/status status
:network network :network network
:hardwallet hardwallet
:device-UUID device-UUID :device-UUID device-UUID
:view-id view-id :view-id view-id)})
:hardwallet (select-keys hardwallet [:nfc-enabled? :nfc-supported?]))})
(fx/defn initialize-app (fx/defn initialize-app
[cofx encryption-key] [cofx encryption-key]
@ -157,7 +159,7 @@
(let [{:universal-links/keys [url] (let [{:universal-links/keys [url]
:keys [accounts/accounts accounts/create networks/networks network :keys [accounts/accounts accounts/create networks/networks network
network-status peers-count peers-summary view-id navigation-stack network-status peers-count peers-summary view-id navigation-stack
desktop/desktop desktop/desktop hardwallet
status-module-initialized? device-UUID semaphores accounts/login] status-module-initialized? device-UUID semaphores accounts/login]
:node/keys [status on-ready] :node/keys [status on-ready]
:or {network (get app-db :network)}} db :or {network (get app-db :network)}} db
@ -184,6 +186,7 @@
:peers-count peers-count :peers-count peers-count
:device-UUID device-UUID :device-UUID device-UUID
:semaphores semaphores :semaphores semaphores
:hardwallet hardwallet
:web3 web3) :web3 web3)
(= view-id :create-account) (= view-id :create-account)
(assoc-in [:accounts/create :step] :enter-name))})) (assoc-in [:accounts/create :step] :enter-name))}))
@ -205,6 +208,10 @@
(= (get-in cofx [:db :view-id]) (= (get-in cofx [:db :view-id])
:create-account)) :create-account))
(defn finishing-hardwallet-setup? [cofx]
(= (get-in cofx [:db :view-id])
:hardwallet-success))
(fx/defn initialize-account [cofx address] (fx/defn initialize-account [cofx address]
(fx/merge cofx (fx/merge cofx
{:notifications/get-fcm-token nil} {:notifications/get-fcm-token nil}
@ -218,7 +225,8 @@
(browser/initialize-dapp-permissions) (browser/initialize-dapp-permissions)
(extensions.registry/initialize) (extensions.registry/initialize)
(accounts.update/update-sign-in-time) (accounts.update/update-sign-in-time)
#(when-not (creating-account? %) #(when-not (or (creating-account? %)
(finishing-hardwallet-setup? %))
(login-only-events % address)))) (login-only-events % address))))
(re-frame/reg-fx (re-frame/reg-fx

View File

@ -57,13 +57,17 @@
:console (js/require "./resources/images/contacts/console.png")}) :console (js/require "./resources/images/contacts/console.png")})
(def ui (def ui
{:empty-hashtags (js/require "./resources/images/ui/empty-hashtags.png") {:empty-hashtags (js/require "./resources/images/ui/empty-hashtags.png")
:empty-recent (js/require "./resources/images/ui/empty-recent.png") :empty-recent (js/require "./resources/images/ui/empty-recent.png")
:analytics-image (js/require "./resources/images/ui/analytics-image.png") :analytics-image (js/require "./resources/images/ui/analytics-image.png")
:welcome-image (js/require "./resources/images/ui/welcome-image.png") :welcome-image (js/require "./resources/images/ui/welcome-image.png")
:lock {:image (js/require "./resources/images/ui/lock.png") :lock {:image (js/require "./resources/images/ui/lock.png")
:width 993 :width 993
:height 933} :height 933}
:wallet-welcome (js/require "./resources/images/ui/wallet-welcome.png") :wallet-welcome (js/require "./resources/images/ui/wallet-welcome.png")
:hardwallet-card (js/require "./resources/images/ui/hardwallet-card.png") :hardwallet-card (js/require "./resources/images/ui/hardwallet-card.png")
:phone-nfc (js/require "./resources/images/ui/phone-nfc.png")}) :secret-keys (js/require "./resources/images/ui/secret-keys.png")
:keycard-lock (js/require "./resources/images/ui/keycard-lock.png")
:hold-card-animation (js/require "./resources/images/ui/hold-card-animation.png")
:phone-nfc-on (js/require "./resources/images/ui/phone-nfc-on.png")
:phone-nfc-off (js/require "./resources/images/ui/phone-nfc-off.png")})

View File

@ -40,6 +40,7 @@
;; GREEN ;; GREEN
(def green "#44d058") ;; icon for successful inboud transaction (def green "#44d058") ;; icon for successful inboud transaction
(def green-transparent-10 (alpha green 0.1)) ;; icon for successful inboud transaction
(def chat-colors ["#fa6565" (def chat-colors ["#fa6565"
"#7cda00" "#7cda00"

View File

@ -68,11 +68,15 @@
[react/view {:style (styles/logo-container size shadow?)} [react/view {:style (styles/logo-container size shadow?)}
[icons/icon :icons/logo (styles/logo icon-size)]])) [icons/icon :icons/logo (styles/logo icon-size)]]))
(defn bottom-button [{:keys [label disabled? on-press forward?]}] (defn bottom-button [{:keys [label disabled? on-press forward? back? uppercase?]
:or {uppercase? true}}]
[react/touchable-highlight {:on-press on-press :disabled disabled?} [react/touchable-highlight {:on-press on-press :disabled disabled?}
[react/view (styles/bottom-button disabled?) [react/view (styles/bottom-button disabled?)
(when back?
[icons/icon :icons/back {:color colors/blue
:container-style {:align-self :baseline}}])
[react/text {:style styles/bottom-button-label [react/text {:style styles/bottom-button-label
:uppercase? true} :uppercase? uppercase?}
(or label (i18n/label :t/next))] (or label (i18n/label :t/next))]
(when forward? (when forward?
[icons/icon :icons/forward {:color colors/blue}])]]) [icons/icon :icons/forward {:color colors/blue}])]])

View File

@ -96,6 +96,7 @@
:icons/dots (js/require "./resources/icons/dots.svg") :icons/dots (js/require "./resources/icons/dots.svg")
:icons/warning (js/require "./resources/icons/warning.svg") :icons/warning (js/require "./resources/icons/warning.svg")
:icons/info (js/require "./resources/icons/info.svg") :icons/info (js/require "./resources/icons/info.svg")
:icons/link (js/require "./resources/icons/link.svg")
:icons/hardwallet (js/require "./resources/icons/hardwallet.svg") :icons/hardwallet (js/require "./resources/icons/hardwallet.svg")
:icons/password (js/require "./resources/icons/password.svg") :icons/password (js/require "./resources/icons/password.svg")
:icons/nfc (js/require "./resources/icons/nfc.svg") :icons/nfc (js/require "./resources/icons/nfc.svg")
@ -175,6 +176,7 @@
:icons/warning (components.svg/slurp-svg "./resources/icons/warning.svg") :icons/warning (components.svg/slurp-svg "./resources/icons/warning.svg")
:icons/settings (components.svg/slurp-svg "./resources/icons/settings.svg") :icons/settings (components.svg/slurp-svg "./resources/icons/settings.svg")
:icons/info (components.svg/slurp-svg "./resources/icons/info.svg") :icons/info (components.svg/slurp-svg "./resources/icons/info.svg")
:icons/link (components.svg/slurp-svg "./resources/icons/link.svg")
:icons/hardwallet (components.svg/slurp-svg "./resources/icons/hardwallet.svg") :icons/hardwallet (components.svg/slurp-svg "./resources/icons/hardwallet.svg")
:icons/password (components.svg/slurp-svg "./resources/icons/password.svg") :icons/password (components.svg/slurp-svg "./resources/icons/password.svg")
:icons/nfc (components.svg/slurp-svg "./resources/icons/nfc.svg") :icons/nfc (components.svg/slurp-svg "./resources/icons/nfc.svg")

View File

@ -188,7 +188,7 @@
(spec/def ::semaphores set?) (spec/def ::semaphores set?)
(spec/def ::hardwallet map?) (spec/def ::hardwallet (spec/nilable map?))
(spec/def ::db (spec/keys :opt [:contacts/contacts (spec/def ::db (spec/keys :opt [:contacts/contacts
:contacts/dapps :contacts/dapps

View File

@ -5,6 +5,18 @@
{:flex 1 {:flex 1
:background-color colors/white}) :background-color colors/white})
(def lock-image-container
{:background-color colors/blue-light
:width 160
:height 160
:border-radius 80
:align-items :center
:justify-content :center})
(def lock-image
{:width 160
:height 160})
(def choose-authentication-method (def choose-authentication-method
{:flex-direction :column {:flex-direction :column
:flex 1 :flex 1
@ -13,6 +25,7 @@
(def choose-authentication-method-text (def choose-authentication-method-text
{:color colors/black {:color colors/black
:margin-top 51
:padding-horizontal 60 :padding-horizontal 60
:text-align :center :text-align :center
:font-weight :bold :font-weight :bold

View File

@ -8,7 +8,8 @@
[status-im.ui.components.common.common :as common] [status-im.ui.components.common.common :as common]
[status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.status-bar.view :as status-bar]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.components.colors :as colors])) [status-im.ui.components.colors :as colors]
[status-im.react-native.resources :as resources]))
(defn authentication-method-row [{:keys [title on-press icon]}] (defn authentication-method-row [{:keys [title on-press icon]}]
[react/touchable-highlight {:on-press on-press} [react/touchable-highlight {:on-press on-press}
@ -30,11 +31,14 @@
nil] nil]
[common/separator] [common/separator]
[react/view styles/choose-authentication-method [react/view styles/choose-authentication-method
[react/view styles/lock-image-container
[react/image {:source (:keycard-lock resources/ui)
:style styles/lock-image}]]
[react/text {:style styles/choose-authentication-method-text [react/text {:style styles/choose-authentication-method-text
:number-of-lines 3} :number-of-lines 3}
(i18n/label :t/choose-authentication-method)]] (i18n/label :t/choose-authentication-method)]]
[react/view styles/authentication-methods [react/view styles/authentication-methods
[authentication-method-row {:title (i18n/label :t/status-hardwallet-capitalized) [authentication-method-row {:title (i18n/label :t/keycard)
:icon :icons/hardwallet :icon :icons/hardwallet
:on-press #(re-frame/dispatch [:hardwallet.ui/status-hardwallet-option-pressed])}] :on-press #(re-frame/dispatch [:hardwallet.ui/status-hardwallet-option-pressed])}]
[authentication-method-row {:title (i18n/label :t/password) [authentication-method-row {:title (i18n/label :t/password)

View File

@ -6,10 +6,81 @@
[status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.components.colors :as colors])) [status-im.ui.components.colors :as colors]
[re-frame.core :as re-frame]))
(defn maintain-card [] (defview application-info [visible?]
(let [animation-value (animation/create-value 0) (letsubs [info [:hardwallet-application-info]
error [:hardwallet-application-info-error]]
[react/modal {:visible @visible?
:transparent false
:on-request-close #()}
[react/view {:padding 20
:justify-content :center}
[react/text {:style {:font-size 18
:font-weight :bold}}
"Application info"]
[react/view {:margin-top 20}
(if-not error
(for [[k v] info]
^{:key k} [react/text {:style {:font-size 15}}
(str k " " v)])
[react/text {:style {:font-size 15}}
"Applet is not installed"])]
[react/touchable-highlight
{:on-press #(reset! visible? false)}
[react/view {:align-items :center
:text-style :underline
:margin-top 48}
[react/text {:style {:font-size 18}}
"Close window"]]]]]))
(def step-name
{:preparing {:label :t/initialization
:number 1
:next-step :secret-keys}
:secret-keys {:label :t/puk-and-pair-codes
:number 2
:next-step :pairing}
:pairing {:label :t/pairing
:number 3
:next-step :recovery-phrase}
:card-ready {:label :t/pairing
:number 3
:next-step :recovery-phrase}
:generating-mnemonic {:label :t/recovery-phrase
:number 4}
:recovery-phrase-confirm-word1 {:label :t/recovery-phrase
:number 4}
:recovery-phrase-confirm-word2 {:label :t/recovery-phrase
:number 4}
:loading-keys {:label :t/recovery-phrase
:number 4}
:recovery-phrase {:label :t/recovery-phrase
:number 4}})
(defn- setup-steps [step]
(let [current-step (step-name step)
{current-label :label current-number :number second-step :next-step} current-step
{second-label :label second-number :number third-step :next-step} (step-name second-step)
{third-label :label third-number :number} (step-name third-step)]
(if current-label
[react/view styles/setup-steps-container
[react/text {:style styles/maintain-card-current-step-text}
(str current-number ". " (i18n/label current-label))]
(when second-label
[react/text {:style styles/maintain-card-second-step-text}
(str second-number ". " (i18n/label second-label))])
(when third-label
[react/text {:style styles/maintain-card-third-step-text}
(str third-number ". " (i18n/label third-label))])]
[react/text {:style styles/maintain-card-text
:number-of-lines 2}
(i18n/label :t/maintain-card-to-phone-contact)])))
(defn maintain-card [step]
(let [modal-visible? (reagent/atom false)
animation-value (animation/create-value 0)
;TODO(dmitryn): make animation smoother ;TODO(dmitryn): make animation smoother
interpolate-fn (fn [output-range] interpolate-fn (fn [output-range]
(animation/interpolate animation-value (animation/interpolate animation-value
@ -24,21 +95,24 @@
(animation/anim-loop) (animation/anim-loop)
(animation/start))) (animation/start)))
:display-name "maintain-card" :display-name "maintain-card"
:reagent-render (fn [] [react/view styles/maintain-card-container :reagent-render (fn [step] [react/view styles/maintain-card-container
[react/view styles/hardwallet-icon-container [react/touchable-highlight
[vector-icons/icon :icons/hardwallet {:color colors/blue}] {:on-press #(do
[vector-icons/icon :icons/indicator-small {:color colors/blue (re-frame/dispatch [:hardwallet.ui/get-application-info])
:container-style (styles/hardwallet-icon-indicator-small-container (reset! modal-visible? true))}
(interpolate-fn [0 0.5 1 0.5 0]))}] [react/view styles/hardwallet-icon-container
[vector-icons/icon :icons/indicator-middle {:color colors/blue [vector-icons/icon :icons/hardwallet {:color colors/blue}]
:container-style (styles/hardwallet-icon-indicator-middle-container [vector-icons/icon :icons/indicator-small {:color colors/blue
(interpolate-fn [1 0.4 0 0.4 0.8]))}] :container-style (styles/hardwallet-icon-indicator-small-container
[vector-icons/icon :icons/indicator-big {:color colors/blue (interpolate-fn [0 0.5 1 0.5 0]))}]
:container-style (styles/hardwallet-icon-indicator-big-container [vector-icons/icon :icons/indicator-middle {:color colors/blue
(interpolate-fn [0.5 0.8 0.5 0.8 0.4]))}]] :container-style (styles/hardwallet-icon-indicator-middle-container
[react/text {:style styles/maintain-card-text (interpolate-fn [1 0.4 0 0.4 0.8]))}]
:number-of-lines 2} [vector-icons/icon :icons/indicator-big {:color colors/blue
(i18n/label :t/maintain-card-to-phone-contact)]])}))) :container-style (styles/hardwallet-icon-indicator-big-container
(interpolate-fn [0.5 0.8 0.5 0.8 0.4]))}]]]
[setup-steps step]
[application-info modal-visible?]])})))
(defn wizard-step [step-number] (defn wizard-step [step-number]
(when step-number (when step-number

View File

@ -11,24 +11,12 @@
:align-items :center :align-items :center
:justify-content :space-between}) :justify-content :space-between})
(def hardwallet-card-image-container
{:margin-top 120})
(def hardwallet-card-image (def hardwallet-card-image
{:width 255 {:width 255
:height 160}) :height 160})
(def hardwallet-card-image-small (def turn-nfc-text-container
{:width 44 {:margin-top 55})
:height 28
:position :absolute
:left 58
:top 13
:z-index 1
:margin-right 20})
(def status-hardwallet-text-container
{:margin-top 30})
(def status-hardwallet-text (def status-hardwallet-text
{:font-size 22 {:font-size 22
@ -52,44 +40,37 @@
:border-radius 10 :border-radius 10
:margin-bottom 20}) :margin-bottom 20})
(def nfc-enabled-container (def phone-nfc-on-image
{:flex-direction :row {:width 401
:justify-content :space-between :height 250})
:align-items :center})
(def phone-nfc-image (def phone-nfc-off-image
{:width 54 {:width 301
:height 72 :height 180})
:z-index 2
:margin-left 20
:margin-top 8
:align-items :baseline})
(def hold-card-text (def hold-card-text
{:width 186 {:width 186
:text-align :center :text-align :center
:font-size 14 :font-size 14
:color colors/blue :line-height 20
:line-height 20 :margin-right 40})
:text-transform :uppercase
:margin-right 40}) (def nfc-enabled-container
{:flex-direction :column
:justify-content :space-between
:align-items :center
:margin-top 50})
(def nfc-disabled-container (def nfc-disabled-container
{:flex-direction :row {:flex-direction :column
:justify-content :space-between :justify-content :space-between
:align-items :center}) :align-items :center
:margin-top 120})
(def nfc-icon (def nfc-icon
{:margin-left 52 {:margin-left 52
:margin-top 22}) :margin-top 22})
(def nfc-disabled-actions-container
{:flex-direction :column
:align-items :center
:justify-content :space-between
:margin-right 100
:margin-top 20})
(def turn-nfc-text (def turn-nfc-text
{:text-transform :uppercase {:text-transform :uppercase
:line-height 20 :line-height 20
@ -97,5 +78,25 @@
:color colors/gray}) :color colors/gray})
(def go-to-settings-text (def go-to-settings-text
{:color colors/gray}) {:text-align :center
:padding-top 9
:color colors/gray})
(def bottom-container
{:height 52
:justify-content :center
:border-top-width 1
:border-color colors/gray-light})
(def product-info-container
{:flex-direction :row
:align-items :center
:justify-content :center})
(def product-info-text
{:text-align :center
:font-size 15
:color colors/blue})
(def external-link-icon
{:margin-left 5})

View File

@ -11,53 +11,47 @@
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.components.colors :as colors])) [status-im.ui.components.colors :as colors]))
(defn nfc-enabled []
[react/view styles/nfc-enabled-container
[react/view
[react/image {:source (:hold-card-animation resources/ui)
:style styles/phone-nfc-on-image}]]
[react/view styles/turn-nfc-text-container
[react/text {:style styles/status-hardwallet-text
:number-of-lines 2}
(i18n/label :t/hold-card)]]])
(defn nfc-disabled []
[react/view styles/nfc-disabled-container
[react/view
[react/image {:source (:phone-nfc-off resources/ui)
:style styles/phone-nfc-off-image}]]
[react/view styles/turn-nfc-text-container
[react/text {:style styles/status-hardwallet-text
:on-press #(re-frame/dispatch [:hardwallet.ui/go-to-settings-button-pressed])}
(i18n/label :t/turn-nfc-on)]
[react/text {:style styles/go-to-settings-text
:on-press #(re-frame/dispatch [:hardwallet.ui/go-to-settings-button-pressed])}
(i18n/label :t/go-to-settings)]]])
(defview hardwallet-connect [] (defview hardwallet-connect []
(letsubs [nfc-enabled? [:hardwallet/nfc-enabled?]] (letsubs [nfc-enabled? [:hardwallet/nfc-enabled?]]
[react/view styles/container [react/view styles/container
[status-bar/status-bar] [status-bar/status-bar]
[react/view components.styles/flex [react/view {:flex 1
:flex-direction :column
:justify-content :space-between}
[toolbar/toolbar {} [toolbar/toolbar {}
toolbar/default-nav-back toolbar/default-nav-back
nil nil]
[toolbar/actions [{:icon :icons/info
:icon-opts {:color :black
:accessibility-label :hardwallet-connect-info-button}
:handler #(re-frame/dispatch [:hardwallet.ui/connect-info-button-pressed])}]]]
[react/view styles/hardwallet-connect [react/view styles/hardwallet-connect
[react/view styles/hardwallet-card-image-container (if nfc-enabled?
[react/image {:source (:hardwallet-card resources/ui) [nfc-enabled]
:style styles/hardwallet-card-image}]] [nfc-disabled])]
[react/view styles/status-hardwallet-text-container [react/view styles/bottom-container
[react/text {:style styles/status-hardwallet-text} [react/touchable-highlight {:on-press #(.openURL react/linking "https://hardwallet.status.im")}
(i18n/label :t/status-hardwallet)] [react/view styles/product-info-container
[react/text {:style styles/status-hardwallet-text} [react/text {:style styles/product-info-text}
(i18n/label :t/secure-your-assets)] (i18n/label :t/product-information)]
[react/text {:style styles/link-card-text [vector-icons/icon :icons/link {:color colors/blue
:number-of-lines 2} :container-style styles/external-link-icon}]]]]]]))
(i18n/label :t/link-card)]]
[react/view (styles/bottom-action-container nfc-enabled?)
(if nfc-enabled?
[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}]
[react/view styles/nfc-disabled-actions-container
[react/text {:style styles/turn-nfc-text
:font :medium
:on-press #(re-frame/dispatch [:hardwallet.ui/go-to-settings-button-pressed])
:uppercase? true}
(i18n/label :t/turn-nfc-on)]
[react/text {:style styles/go-to-settings-text
:on-press #(re-frame/dispatch [:hardwallet.ui/go-to-settings-button-pressed])}
(i18n/label :t/go-to-settings)]]])]]]]))

View File

@ -14,7 +14,7 @@
(re-frame/reg-sub (re-frame/reg-sub
:hardwallet/pin-enter-step :hardwallet/pin-enter-step
(fn [db] (fn [db]
(get-in db [:hardwallet :pin :enter-step]))) (get-in db [:hardwallet :pin :enter-step] :original)))
(re-frame/reg-sub (re-frame/reg-sub
:hardwallet/pin-status :hardwallet/pin-status

View File

@ -60,7 +60,7 @@
(let [enabled? (not= status :validating)] (let [enabled? (not= status :validating)]
[react/view styles/pin-container [react/view styles/pin-container
[react/view styles/center-container [react/view styles/center-container
[components/wizard-step 4] ;[components/wizard-step 4]
[react/text {:style styles/center-title-text [react/text {:style styles/center-title-text
:font :bold} :font :bold}
(i18n/label title)] (i18n/label title)]

View File

@ -23,15 +23,38 @@
:height 60 :height 60
:border-radius 10 :border-radius 10
:border-width 1 :border-width 1
:border-color colors/blue :border-color colors/blue-light})
:border-style :dashed})
(def maintain-card-text (def maintain-card-text
{:padding-horizontal 20 {:font-size 12
:font-size 12 :padding-horizontal 30
:width 232
:color colors/blue}) :color colors/blue})
(def setup-steps-container
{:flex-direction :row
:align-items :baseline
:flex 1
:width "95%"
:background-color :white
:padding-left 20
:margin-right 20})
(def maintain-card-current-step-text
{:font-size 12
:color colors/blue})
(def maintain-card-second-step-text
{:font-size 12
:padding-left 8
;:background-color :red
:color colors/gray})
(def maintain-card-third-step-text
{:font-size 12
;:background-color :yellow
:padding-left 8
:color colors/gray})
(def hardwallet-icon-container (def hardwallet-icon-container
{:margin-left 20 {:margin-left 20
:flex-direction :row :flex-direction :row
@ -49,7 +72,7 @@
{:opacity opacity}) {:opacity opacity})
(def hardwallet-card-image-container (def hardwallet-card-image-container
{:margin-top 81 {:margin-top 47
:flex 1 :flex 1
:align-items :center}) :align-items :center})
@ -68,6 +91,10 @@
:flex-direction :column :flex-direction :column
:align-items :center}) :align-items :center})
(def card-blank-container
{:flex 1
:flex-direction :column})
(def enter-pair-code-container (def enter-pair-code-container
{:flex 1 {:flex 1
:flex-direction :column :flex-direction :column
@ -83,9 +110,17 @@
:text-align :center}) :text-align :center})
(def center-title-text (def center-title-text
{:font-size 22 {:font-size 22
:text-align :center :font-weight :bold
:color colors/black}) :text-align :center
:color colors/black})
(def bottom-container
{:height 60
:justify-content :center
:align-items :center
:border-top-width 1
:border-color colors/gray-light})
(def bottom-button-container (def bottom-button-container
{:background-color colors/gray-background {:background-color colors/gray-background
@ -95,20 +130,36 @@
:width 160 :width 160
:height 44 :height 44
:border-radius 10 :border-radius 10
:margin-bottom 40}) :margin-bottom 14})
(def begin-button-container
{:background-color colors/gray-background
:align-items :center
:justify-content :center
:flex-direction :row
:width 160
:height 42
:border-radius 10
:margin-bottom 1})
(def bottom-button-text (def bottom-button-text
{:font-size 14 {:font-size 15
:color colors/blue :color colors/blue
:line-height 20 :line-height 20})
:text-transform :uppercase})
(def next-button-container (def next-button-container
{:flex-direction :row
:justify-content :space-between
:align-items :center
:width "100%"
:height 52
:border-top-width 1
:border-color colors/gray-light})
(def back-and-next-buttons-container
{:flex-direction :row {:flex-direction :row
:align-self :flex-end :justify-content :space-between
:width "100%" :margin-vertical 15})
:margin-vertical 15
:margin-right 21})
;; prepare step ;; prepare step
@ -133,6 +184,27 @@
(def estimated-time-text (def estimated-time-text
(assoc generating-codes-for-pairing-text :padding-top 25)) (assoc generating-codes-for-pairing-text :padding-top 25))
(def recovery-phrase-inner-container
{:align-self :center})
(def check-recovery-phrase-text
{:font-size 22
:font-weight :bold
:text-align :center
:color colors/gray})
(def recovery-phrase-word-n-text
{:font-size 22
:font-weight :bold
:text-align :center
:color colors/black})
(def recovery-phrase-description
{:padding 16})
(def recovery-phrase-description-text
{:color colors/black})
(def waiting-indicator-container (def waiting-indicator-container
{:height 200}) {:height 200})
@ -142,58 +214,86 @@
{:flex 1 {:flex 1
:flex-direction :column :flex-direction :column
:justify-content :space-between :justify-content :space-between
:margin-top 40}) :margin-top 30})
(def secret-keys-inner-container (def secret-keys-inner-container
{:flex-direction :column {:flex-direction :column
:align-items :center}) :justify-content :space-between
:align-items :center})
(def secret-keys-title-container (def secret-keys-title-container
{:width 292}) {:width 292
:margin-vertical 25})
(def secret-keys-title-text (def secret-keys-title-text
{:font-size 22 {:font-size 22
:text-align :center :font-weight :bold
:color colors/black}) :text-align :center
:color colors/black})
(def secret-keys-image-container
{:width 120
:height 120})
(def puk-code-title-text (def puk-code-title-text
{:font-size 17 {:font-size 17
:padding-top 32 :font-weight :bold
:padding-top 12
:color colors/black}) :color colors/black})
(def secret-code-explanation-container
{:margin-top 5
:margin-bottom 15})
(def puk-code-explanation-text (def puk-code-explanation-text
{:font-size 15 {:font-size 15
:width 292 :padding-horizontal 32
:text-align :center :text-align :center
:padding-top 5 :padding-top 5
:color colors/gray}) :padding-bottom 10
:color colors/gray})
(def puk-code-numbers-container (def puk-code-numbers-container
{:justify-content :center {:justify-content :center
:flex-direction :row}) :flex-direction :row})
(def puk-code-numbers-border-container
{:border-bottom-width 2
:width 302
:text-align :center
;:justify-content :center
;:align-items :center
;:flex-direction :column
;:padding-bottom 10
:border-color colors/gray-lighter})
(defstyle puk-code-numbers-inner-container (defstyle puk-code-numbers-inner-container
{:width "85%" {:width "85%"
:android {:margin-horizontal 16} :android {:margin-horizontal 16}
:height 64 :height 94
:margin-top 20 ;:margin-top 10
:align-items :center :align-items :center
:justify-content :center :justify-content :space-between
:border-width 1 :flex-direction :column
:border-color colors/gray-light :border-width 2
:border-color colors/gray-lighter
:border-radius 10}) :border-radius 10})
(def puk-code-text (def puk-code-text
{:font-size 17 {:font-size 17
:text-align :center :font-weight :bold
:color colors/green}) :padding-bottom 10
:text-align :center
:color colors/green})
;; card ready ;; card ready
(def card-ready-container secret-keys-container) (def card-ready-container secret-keys-container)
(def card-ready-inner-container (def card-ready-inner-container
{:align-self :center}) {:align-self :center
:flex 1
:justify-content :space-between})
;; enter pair code ;; enter pair code
@ -214,3 +314,43 @@
{:font-size 15 {:font-size 15
:padding-top 5 :padding-top 5
:color colors/gray}) :color colors/gray})
(def card-is-empty-text
{:color colors/black
:font-size 17
:font-weight :bold
:margin-bottom 20})
(def card-is-empty-prepare-text
{:margin-top 25
:padding-horizontal 40})
(def remaining-steps-container
{:margin-top 55
:margin-left 16
:flex 1
:width "90%"
:flex-direction :column})
(def remaining-steps-text
{:color colors/gray
:font-size 15})
(def remaining-step-row
{:flex-direction :row
:margin-top 15})
(def remaining-step-row-text
{:border-width 1
:border-radius 16
:border-color colors/gray-light
:align-items :center
:justify-content :center
:width 32
:height 32})
(def remaining-step-row-text2
{:align-items :center
:justify-content :center
:margin-left 11})

View File

@ -10,3 +10,50 @@
:hardwallet-pair-code :hardwallet-pair-code
(fn [db] (fn [db]
(get-in db [:hardwallet :pair-code]))) (get-in db [:hardwallet :pair-code])))
(re-frame/reg-sub
:hardwallet-recovery-phrase-word
(fn [db]
(get-in db [:hardwallet
:recovery-phrase
(get-in db [:hardwallet :recovery-phrase :step])])))
(re-frame/reg-sub
:hardwallet-recovery-phrase-input-word
(fn [db]
(get-in db [:hardwallet :recovery-phrase :input-word])))
(re-frame/reg-sub
:hardwallet-recovery-phrase-confirm-error
(fn [db]
(get-in db [:hardwallet :recovery-phrase :confirm-error])))
(re-frame/reg-sub
:hardwallet-recovery-phrase-step
(fn [db]
(get-in db [:hardwallet :recovery-phrase :step])))
(re-frame/reg-sub
:hardwallet-secrets
(fn [db]
(get-in db [:hardwallet :secrets])))
(re-frame/reg-sub
:hardwallet-setup-error
(fn [db]
(get-in db [:hardwallet :setup-error])))
(re-frame/reg-sub
:hardwallet-mnemonic
(fn [db]
(get-in db [:hardwallet :secrets :mnemonic])))
(re-frame/reg-sub
:hardwallet-application-info
(fn [db]
(get-in db [:hardwallet :application-info])))
(re-frame/reg-sub
:hardwallet-application-info-error
(fn [db]
(get-in db [:hardwallet :application-info-error])))

View File

@ -2,6 +2,7 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.ui.screens.profile.seed.views :as seed.views]
[status-im.ui.screens.hardwallet.components :as components] [status-im.ui.screens.hardwallet.components :as components]
[status-im.ui.screens.hardwallet.pin.views :as pin.views] [status-im.ui.screens.hardwallet.pin.views :as pin.views]
[status-im.ui.components.animation :as animation] [status-im.ui.components.animation :as animation]
@ -13,58 +14,149 @@
[status-im.ui.components.styles :as components.styles] [status-im.ui.components.styles :as components.styles]
[status-im.ui.components.text-input.view :as text-input] [status-im.ui.components.text-input.view :as text-input]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.components.colors :as colors])) [status-im.utils.utils :as utils]
[status-im.ui.components.colors :as colors]
[status-im.ui.screens.hardwallet.setup.styles :as styles]))
(defn secret-keys [] (defview secret-keys []
[react/view styles/secret-keys-container (letsubs [secrets [:hardwallet-secrets]]
[react/view styles/secret-keys-inner-container [react/view styles/secret-keys-container
[react/view styles/secret-keys-title-container [react/scroll-view
[components/wizard-step 2] [react/view styles/secret-keys-inner-container
[react/text {:style styles/secret-keys-title-text [react/view
:number-of-lines 2 [react/image {:source (:secret-keys resources/ui)
:font :bold} :style styles/secret-keys-image-container}]]
(i18n/label :t/write-down-and-store-securely)]] [react/view styles/secret-keys-title-container
[react/text {:style styles/puk-code-title-text [react/text {:style styles/secret-keys-title-text
:font :bold} :number-of-lines 2}
(i18n/label :t/puk-code)] (i18n/label :t/write-down-and-store-securely)]]
[react/text {:style styles/puk-code-explanation-text} [react/view styles/puk-code-numbers-container
(i18n/label :t/puk-code-explanation)] [react/view styles/puk-code-numbers-inner-container
[react/view styles/puk-code-numbers-container [react/text {:style styles/puk-code-title-text}
[react/view styles/puk-code-numbers-inner-container (i18n/label :t/pin-code)]
[react/text {:style styles/puk-code-text [react/view styles/puk-code-numbers-border-container]
:font :bold} [react/text {:style styles/puk-code-text}
"1234 5678 9123"]]] (:pin secrets)]]]
[react/text {:style styles/puk-code-title-text [react/view styles/secret-code-explanation-container
:font :bold} [react/text {:style styles/puk-code-explanation-text}
(i18n/label :t/pair-code)] (i18n/label :t/pin-code-description)]]
[react/text {:style styles/puk-code-explanation-text [react/view styles/puk-code-numbers-container
:number-of-lines 2} [react/view styles/puk-code-numbers-inner-container
(i18n/label :t/pair-code-explanation)] [react/text {:style styles/puk-code-title-text}
[react/view styles/puk-code-numbers-container (i18n/label :t/puk-code)]
[react/view styles/puk-code-numbers-inner-container [react/view styles/puk-code-numbers-border-container]
[react/text {:style styles/puk-code-text [react/text {:style styles/puk-code-text}
:font :bold} (:puk secrets)]]]
"a12k52kh0x"]]]] [react/view styles/secret-code-explanation-container
[react/view styles/next-button-container [react/text {:style styles/puk-code-explanation-text}
[react/view components.styles/flex] (i18n/label :t/puk-code-explanation)]]
[components.common/bottom-button [react/view styles/puk-code-numbers-container
{:on-press #(re-frame/dispatch [:hardwallet.ui/secret-keys-next-button-pressed]) [react/view styles/puk-code-numbers-inner-container
:forward? true}]]]) [react/text {:style styles/puk-code-title-text}
(i18n/label :t/pair-code)]
[react/view styles/puk-code-numbers-border-container]
[react/text {:style styles/puk-code-text}
(:password secrets)]]]
[react/view styles/secret-code-explanation-container
[react/text {:style styles/puk-code-explanation-text
:number-of-lines 2}
(i18n/label :t/pair-code-explanation)]]]
[react/view styles/next-button-container
[react/view components.styles/flex]
[react/view {:margin-right 20}
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:hardwallet.ui/secret-keys-next-button-pressed])
:uppercase? false
:forward? true}]]]]]))
(defn card-ready [] (defn card-ready []
[react/view styles/card-ready-container [react/view styles/card-ready-container
[react/view styles/card-ready-inner-container [react/view styles/card-ready-inner-container
[components/wizard-step 3] [react/view (assoc styles/center-container :margin-top 68)
[react/text {:style styles/center-title-text [react/text {:style styles/center-title-text}
:number-of-lines 2 (i18n/label :t/card-is-paired)]
:font :bold} [react/text {:style styles/estimated-time-text}
(i18n/label :t/card-is-ready)]] (i18n/label :t/next-step-generating-mnemonic)]]
[react/view styles/next-button-container [react/view]
[react/view components.styles/flex] [react/view styles/next-button-container
[components.common/bottom-button [react/view components.styles/flex]
{:on-press #(re-frame/dispatch [:hardwallet.ui/create-pin-button-pressed]) [react/view {:margin-right 20}
:label (i18n/label :t/create-pin) [components.common/bottom-button
:forward? true}]]]) {:on-press #(re-frame/dispatch [:hardwallet.ui/card-ready-next-button-pressed])
:forward? true}]]]]])
(defview recovery-phrase []
(letsubs [mnemonic [:hardwallet-mnemonic]]
(let [mnemonic-vec (vec (map-indexed vector (clojure.string/split mnemonic #" ")))]
[react/view styles/card-ready-container
[react/view styles/recovery-phrase-inner-container
[react/view styles/center-container
[react/text {:style styles/center-title-text
:number-of-lines 2
:font :bold}
(i18n/label :t/your-recovery-phrase)]
[react/view {:style {:margin-top 17
:margin-bottom 16
:margin-horizontal 16
:flex-direction :row
:border-radius 8
:background-color colors/white
:border-width 1
:border-color colors/gray-lighter}}
[seed.views/six-words (subvec mnemonic-vec 0 6)]
[react/view {:style {:width 1
:background-color colors/gray-lighter}}]
[seed.views/six-words (subvec mnemonic-vec 6 12)]]
[react/view styles/recovery-phrase-description
[react/text {:style styles/recovery-phrase-description-text}
(i18n/label :t/your-recovery-phrase-description)]]]]
[react/view styles/next-button-container
[react/view components.styles/flex]
[react/view {:margin-right 20}
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:hardwallet.ui/recovery-phrase-next-button-pressed])
:label (i18n/label :t/next)
:uppercase? false
:forward? true}]]]])))
(defview confirm-word-input [error ref step]
{:component-will-update #(.clear @ref)}
[text-input/text-input-with-label
{:on-change-text #(re-frame/dispatch [:hardwallet.ui/recovery-phrase-confirm-word-input-changed %])
:auto-focus true
:ref (partial reset! ref)
:on-submit-editing #(re-frame/dispatch [:hardwallet.ui/recovery-phrase-confirm-word-next-button-pressed])
:error error
:placeholder (i18n/label :t/enter-word)}])
(defview recovery-phrase-confirm-word [step]
^{:key (str step)}
(letsubs [width [:dimensions/window-width]
word [:hardwallet-recovery-phrase-word]
input-word [:hardwallet-recovery-phrase-input-word]
error [:hardwallet-recovery-phrase-confirm-error]
ref (reagent/atom nil)]
(let [{:keys [word idx]} word]
[react/view styles/enter-pair-code-container
[react/view styles/enter-pair-code-title-container
[react/view
[react/text {:style styles/check-recovery-phrase-text}
(i18n/label :t/check-your-recovery-phrase)]
[react/text {:style styles/recovery-phrase-word-n-text}
(i18n/label :t/word-n {:number (inc idx)})]]
[react/view (styles/enter-pair-code-input-container width)
[confirm-word-input error ref step]]]
[react/view styles/back-and-next-buttons-container
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:hardwallet.ui/recovery-phrase-confirm-word-back-button-pressed])
:back? true
:uppercase? false
:label (i18n/label :t/back)}]
[components.common/bottom-button
{:on-press #(re-frame/dispatch [:hardwallet.ui/recovery-phrase-confirm-word-next-button-pressed])
:disabled? (empty? input-word)
:uppercase? false
:forward? true}]]])))
(defview enter-pair-code [] (defview enter-pair-code []
(letsubs [pair-code [:hardwallet-pair-code] (letsubs [pair-code [:hardwallet-pair-code]
@ -84,13 +176,15 @@
:placeholder ""}]]] :placeholder ""}]]]
[react/view styles/next-button-container [react/view styles/next-button-container
[react/view components.styles/flex] [react/view components.styles/flex]
[components.common/bottom-button [react/view {:margin-right 20}
{:on-press #(re-frame/dispatch [:hardwallet.ui/pair-code-next-button-pressed]) [components.common/bottom-button
:disabled? (empty? pair-code) {:on-press #(re-frame/dispatch [:hardwallet.ui/pair-code-next-button-pressed])
:forward? true}]]])) :disabled? (empty? pair-code)
:uppercase? false
:forward? true}]]]]))
(defn- card-with-button-view (defn- card-with-button-view
[{:keys [text-label button-label button-container-style on-press-event]}] [{:keys [text-label button-label button-container-style on-press]}]
"Generic view with centered card image and button at the bottom. "Generic view with centered card image and button at the bottom.
Used by 'Prepare', 'Pair', 'No slots', 'Card is linked' screens" Used by 'Prepare', 'Pair', 'No slots', 'Card is linked' screens"
[react/view styles/card-with-button-view-container [react/view styles/card-with-button-view-container
@ -101,41 +195,86 @@
[react/text {:style styles/center-text} [react/text {:style styles/center-text}
(i18n/label text-label)]]] (i18n/label text-label)]]]
[react/touchable-highlight [react/touchable-highlight
{:on-press #(re-frame/dispatch [on-press-event])} {:on-press on-press}
[react/view (merge styles/bottom-button-container button-container-style) [react/view (merge styles/bottom-button-container button-container-style)
[react/text {:style styles/bottom-button-text [react/text {:style styles/bottom-button-text}
:font :medium
:uppercase? true}
(i18n/label button-label)]]]]) (i18n/label button-label)]]]])
(defn begin [] (defn begin []
[card-with-button-view {:text-label :t/card-is-empty [react/view styles/card-blank-container
:button-label :t/begin-set-up [react/scroll-view
:on-press-event :hardwallet.ui/begin-setup-button-pressed}]) [react/view styles/hardwallet-card-image-container
[react/text {:style styles/card-is-empty-text}
(i18n/label :t/card-is-blank)]
[react/view {:margin-top 15}
[react/image {:source (:hardwallet-card resources/ui)
:style styles/hardwallet-card-image}]]
[react/view styles/card-is-empty-prepare-text
[react/text {:style styles/center-text}
(i18n/label :t/card-setup-prepare-text)]]]
[react/view styles/remaining-steps-container
[react/text {:style styles/remaining-steps-text}
(i18n/label :t/remaining-steps)]
[react/view {:margin-bottom 25}
(for [[number text] [["1" (i18n/label :t/initialization-of-the-card)]
["2" (i18n/label :t/puk-and-pairing-codes-displayed)]
["3" (i18n/label :t/device-pairing)]
["4" (i18n/label :t/recovery-phrase)]]]
^{:key number} [react/view styles/remaining-step-row
[react/view styles/remaining-step-row-text
[react/text {:style {:color colors/black}}
number]]
[react/view styles/remaining-step-row-text2
[react/text {:style {:color colors/black}}
text]]])]]
[react/view styles/bottom-container
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:hardwallet.ui/begin-setup-button-pressed])}
[react/view styles/begin-button-container
[react/text {:style styles/bottom-button-text}
(i18n/label :t/begin-set-up)]]]]]])
(defn pair [] (defn pair []
[card-with-button-view {:text-label :t/pair-card-question [card-with-button-view {:text-label :t/pair-card-question
:button-label :t/pair-card :button-label :t/pair-card
:on-press-event :hardwallet.ui/pair-card-button-pressed}]) :on-press-event #(re-frame/dispatch [:hardwallet.ui/pair-card-button-pressed])}])
(defn no-slots [] (defn no-slots []
[card-with-button-view {:text-label :t/no-pairing-slots-available [card-with-button-view {:text-label :t/no-pairing-slots-available
:button-label :t/help :button-label :t/help
:button-container-style {:background-color colors/white} :button-container-style {:background-color colors/white}
:on-press-event :hardwallet.ui/no-pairing-slots-help-button-pressed}]) :on-press-event (.openURL react/linking "https://hardwallet.status.im")}])
(defn card-already-linked [] (defn card-already-linked []
[card-with-button-view {:text-label :t/card-already-linked [card-with-button-view {:text-label :t/card-already-linked
:button-label :t/help :button-label :t/help
:button-container-style {:background-color colors/white} :button-container-style {:background-color colors/white}
:on-press-event :hardwallet.ui/card-already-linked-help-button-pressed}]) :on-press-event (.openURL react/linking "https://hardwallet.status.im")}])
(defview error []
(letsubs [error [:hardwallet-setup-error]]
[react/view styles/card-with-button-view-container
[react/view styles/hardwallet-card-image-container
[react/image {:source (:hardwallet-card resources/ui)
:style styles/hardwallet-card-image}]
[react/view styles/center-text-container
[react/text {:style styles/center-text}
(i18n/label :t/something-went-wrong)]
[react/text {:style styles/center-text}
(str (:code error) "\n" (:error error))]]]
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:hardwallet.ui/error-button-pressed])}
[react/view styles/bottom-button-container
[react/text {:style styles/bottom-button-text
:font :medium
:uppercase? false}
(i18n/label :t/try-again)]]]]))
(defn- loading-view [{:keys [title-label text-label estimated-time-seconds step-number]}] (defn- loading-view [{:keys [title-label text-label estimated-time-seconds step-number]}]
"Generic view with waiting time estimate and loading indicator. "Generic view with waiting time estimate and loading indicator.
Used by 'Prepare', 'Pairing', 'Completing' screens" Used by 'Prepare', 'Pairing', 'Completing' screens"
[react/view styles/loading-view-container [react/view styles/loading-view-container
[react/view styles/center-container [react/view styles/center-container
[components/wizard-step step-number]
[react/text {:style styles/center-title-text [react/text {:style styles/center-title-text
:font :bold} :font :bold}
(i18n/label title-label)] (i18n/label title-label)]
@ -144,26 +283,64 @@
:number-of-lines 2} :number-of-lines 2}
(i18n/label text-label)]) (i18n/label text-label)])
[react/text {:style styles/estimated-time-text} [react/text {:style styles/estimated-time-text}
(str (i18n/label :t/this-will-take-few-seconds)]]
(i18n/label :t/estimated-time)
" ~"
estimated-time-seconds
" "
(i18n/label-pluralize estimated-time-seconds
:t/datetime-second))]]
[react/view styles/waiting-indicator-container [react/view styles/waiting-indicator-container
[react/activity-indicator {:animating true [react/activity-indicator {:animating true
:size :large}]]]) :size :large}]]])
(defn preparing [] (defn- preparing []
[loading-view {:title-label :t/preparing-card [react/view styles/loading-view-container
:text-label :t/generating-codes-for-pairing [react/view styles/center-container
:estimated-time-seconds 20 [react/text {:style styles/center-title-text
:step-number 1}]) :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/taking-long-hold-phone-connected)]]
[react/view styles/waiting-indicator-container
[react/activity-indicator {:animating true
:size :large}]]])
(defn pairing [] (defn- generating-mnemonic []
[loading-view {:title-label :t/pairing-card [react/view styles/loading-view-container
:estimated-time-seconds 30}]) [react/view styles/center-container
[react/text {:style styles/center-title-text
:font :bold}
(i18n/label :t/generating-mnemonic)]
[react/text {:style styles/estimated-time-text}
(i18n/label :t/this-will-take-few-seconds)]]
[react/view styles/waiting-indicator-container
[react/activity-indicator {:animating true
:size :large}]]])
(defn- loading-keys []
[react/view styles/loading-view-container
[react/view styles/center-container
[react/text {:style styles/center-title-text
:font :bold}
(i18n/label :t/finishing-card-setup)]
[react/text {:style styles/generating-codes-for-pairing-text
:number-of-lines 2}
(i18n/label :t/finishing-card-setup-steps)]
[react/text {:style styles/estimated-time-text}
(i18n/label :t/this-will-take-few-seconds)]]
[react/view styles/waiting-indicator-container
[react/activity-indicator {:animating true
:size :large}]]])
(defn- pairing []
[react/view styles/loading-view-container
[react/view styles/center-container
[react/text {:style styles/center-title-text
:font :bold}
(i18n/label :t/pairing-card)]
[react/text {:style styles/estimated-time-text}
(i18n/label :t/this-will-take-few-seconds)]]
[react/view styles/waiting-indicator-container
[react/activity-indicator {:animating true
:size :large}]]])
(defn complete [] (defn complete []
[loading-view {:title-label :t/completing-card-setup [loading-view {:title-label :t/completing-card-setup
@ -178,11 +355,17 @@
:card-ready [card-ready] :card-ready [card-ready]
:complete [complete] :complete [complete]
:pair [pair] :pair [pair]
:generating-mnemonic [generating-mnemonic]
:loading-keys [loading-keys]
:enter-pair-code [enter-pair-code] :enter-pair-code [enter-pair-code]
:no-slots [no-slots] :no-slots [no-slots]
:card-already-linked [card-already-linked] :card-already-linked [card-already-linked]
:pairing [pairing] :pairing [pairing]
:pin [pin.views/main] :pin [pin.views/main]
:recovery-phrase [recovery-phrase]
:recovery-phrase-confirm-word1 [recovery-phrase-confirm-word step]
:recovery-phrase-confirm-word2 [recovery-phrase-confirm-word step]
:error [error]
[begin])) [begin]))
(defview hardwallet-setup [] (defview hardwallet-setup []
@ -190,5 +373,5 @@
[react/keyboard-avoiding-view components.styles/flex [react/keyboard-avoiding-view components.styles/flex
[react/view styles/container [react/view styles/container
[react/view styles/inner-container [react/view styles/inner-container
[components/maintain-card] [components/maintain-card step]
[content step]]]])) [content step]]]]))

View File

@ -17,22 +17,25 @@
:align-items :center :align-items :center
:justify-content :center}) :justify-content :center})
(def hardwallet-card-image
{:width 255
:height 160})
(def icon-check-container (def icon-check-container
{:width 64 {:width 160
:height 64 :height 160
:bottom -40
:position :absolute
:align-items :center :align-items :center
:justify-content :center :justify-content :center
:background-color colors/green :background-color colors/green-transparent-10
:border-radius 100})
(def icon-check-inner-container
{:width 80
:height 80
:align-items :center
:justify-content :center
:background-color colors/white
:border-radius 50}) :border-radius 50})
(def complete-text-container (def complete-text-container
{:margin-top 40}) {:flex-direction :column
:align-items :center})
(def complete-text (def complete-text
{:font-size 22 {:font-size 22
@ -43,9 +46,11 @@
(def complete-information-text (def complete-information-text
{:text-align :center {:text-align :center
:font-size 15 :font-size 15
:line-height 22
:color colors/gray :color colors/gray
:margin-bottom 21
:padding-horizontal 80 :padding-horizontal 80
:padding-vertical 10}) :padding-top 20})
(def bottom-action-container (def bottom-action-container
{:background-color colors/gray-background {:background-color colors/gray-background
@ -58,7 +63,11 @@
:margin-bottom 40}) :margin-bottom 40})
(def bottom-action-text (def bottom-action-text
{:font-size 14 {:font-size 15
:color colors/blue :color colors/blue
:line-height 20 :line-height 20
:text-transform :uppercase}) :text-transform :uppercase})
(def waiting-indicator-container
{:height 20
:margin-bottom 70})

View File

@ -1,36 +1,46 @@
(ns status-im.ui.screens.hardwallet.success.views (ns status-im.ui.screens.hardwallet.success.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame] (: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.screens.hardwallet.success.styles :as styles]
[status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.components.styles :as components.styles] [status-im.ui.components.styles :as components.styles]
[status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.status-bar.view :as status-bar]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.components.colors :as colors])) [status-im.ui.components.colors :as colors]
[reagent.core :as reagent]))
(defn- activity-indicator [show?]
[react/view styles/waiting-indicator-container
(when @show?
[react/view
[react/text {:style {:padding-bottom 20}}
(i18n/label :t/sign-in-to-status)]
[react/activity-indicator {:animating true
:size :large}]])])
(defn hardwallet-success [] (defn hardwallet-success []
[react/view styles/container (let [processing? (reagent/atom false)]
[status-bar/status-bar] [react/view styles/container
[react/view components.styles/flex [status-bar/status-bar]
[react/view styles/inner-container [react/view components.styles/flex
[react/view styles/hardwallet-card-image-container [react/view styles/inner-container
[react/image {:source (:hardwallet-card resources/ui) [react/view styles/hardwallet-card-image-container
:style styles/hardwallet-card-image}] [react/view styles/icon-check-container
[react/view styles/icon-check-container [react/view styles/icon-check-inner-container
[vector-icons/icon :icons/check {:color :white [vector-icons/icon :icons/check {:color colors/green
:width 30 :width 30
:height 30}]]] :height 30}]]]]
[react/view styles/complete-text-container [react/view styles/complete-text-container
[react/text {:style styles/complete-text} [activity-indicator processing?]
(i18n/label :t/complete-exclamation)] [react/text {:style styles/complete-text}
[react/text {:style styles/complete-information-text (i18n/label :t/complete-exclamation)]
:number-of-lines 3} [react/text {:style styles/complete-information-text}
(i18n/label :t/complete-hardwallet-setup)]] (i18n/label :t/complete-hardwallet-setup)]
[react/touchable-highlight [react/touchable-highlight
{:on-press #(re-frame/dispatch [:hardwallet.ui/success-button-pressed])} {:on-press #(do
[react/view styles/bottom-action-container (reset! processing? true)
[react/text {:style styles/bottom-action-text (re-frame/dispatch [:hardwallet.ui/success-button-pressed]))}
:font :medium [react/view styles/bottom-action-container
:uppercase? true} [react/text {:style styles/bottom-action-text}
(i18n/label :t/okay)]]]]]]) (i18n/label :t/okay)]]]]]]]))

View File

@ -15,7 +15,6 @@
(def nfc #js {}) (def nfc #js {})
(def orientation #js {}) (def orientation #js {})
(def qr-code #js {}) (def qr-code #js {})
(def nfc-manager #js {:default #js {}})
(def react-native (def react-native
#js {:NativeModules #js {} #js {:NativeModules #js {}
:Animated #js {:View #js {} :Animated #js {:View #js {}
@ -28,6 +27,7 @@
(def vector-icons #js {:default #js {}}) (def vector-icons #js {:default #js {}})
(def webview-bridge #js {:default #js {}}) (def webview-bridge #js {:default #js {}})
(def svg #js {:default #js {}}) (def svg #js {:default #js {}})
(def status-keycard #js {:default #js {}})
(defrecord Notification []) (defrecord Notification [])
(def react-native-firebase #js {:default #js {:notifications #js {:Notification Notification}}}) (def react-native-firebase #js {:default #js {:notifications #js {:Notification Notification}}})

View File

@ -0,0 +1,35 @@
(ns status-im.test.accounts.create.core
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.accounts.create.core :as models]))
(deftest on-account-created
(let [result (models/on-account-created {:random-guid-generator (constantly "")
:signing-phrase ""
:status ""
:db {}}
{:pubkey "04de2e21f1642ebee03b9aa4bf1936066124cc89967eaf269544c9b90c539fd5c980166a897d06dd4d3732b38116239f63c89395a8d73eac72881fab802010cb56"
:address "7e92236392a850980d00d0cd2a4b92886bd7fe7b"
:mnemonic "hello world"}
"password"
true)]
(is (= (:db result)
{:accounts/login {:address "7e92236392a850980d00d0cd2a4b92886bd7fe7b", :password "password", :processing true},
:accounts/accounts {"7e92236392a850980d00d0cd2a4b92886bd7fe7b"
{:address "7e92236392a850980d00d0cd2a4b92886bd7fe7b", :mnemonic "hello world", :signing-phrase "",
:signed-up? true, :name "Dark Woozy Alligatorsnappingturtle", :desktop-notifications? false,
:settings {:wallet {:visible-tokens {:testnet #{:STT :HND},
:mainnet #{:SNT},
:rinkeby #{:MOKSHA :KDO}, :xdai #{}, :poa #{}}}},
:networks nil,
:photo-path "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX////YjowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRS2MAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoRUBAbwwC1cAAAAASUVORK5CYII=",
:status "",
:seed-backed-up? true,
:network "mainnet_rpc",
:public-key "04de2e21f1642ebee03b9aa4bf1936066124cc89967eaf269544c9b90c539fd5c980166a897d06dd4d3732b38116239f63c89395a8d73eac72881fab802010cb56",
:installation-id ""}},
:network "mainnet_rpc",
:node/status :starting}))
(is (= (keys result)
[:db
:node/start
:data-store/base-tx]))))

View File

@ -24,10 +24,10 @@
6 6
:original)))) :original))))
(testing "confirmation entered" (testing "confirmation entered"
(is (= {:db {:hardwallet {:pin {:original [1 2 3 4 5 6] (is (= {:db {:hardwallet {:pin {:original [1 2 3 4 5 6]
:confirmation [1 2 3 4 5 6] :confirmation [1 2 3 4 5 6]
:enter-step :confirmation :enter-step :confirmation
:status :validating}}}} :status :validating}}}}
(hardwallet/process-pin-input {:db {:hardwallet {:pin {:original [1 2 3 4 5 6] (hardwallet/process-pin-input {:db {:hardwallet {:pin {:original [1 2 3 4 5 6]
:confirmation [1 2 3 4 5] :confirmation [1 2 3 4 5]
:enter-step :confirmation}}}} :enter-step :confirmation}}}}
@ -44,3 +44,28 @@
:enter-step :confirmation}}}} :enter-step :confirmation}}}}
7 7
:confirmation))))) :confirmation)))))
(deftest on-generate-and-load-key-success
(is (= (select-keys
(get-in
(hardwallet/on-generate-and-load-key-success
{:random-guid-generator (constantly "")
:signing-phrase ""
:status ""
:db {}}
#js {"whisper-private-key" "f342f3ef17ce86abfa92b912b3a108a4546cfc687fd8e0f02fedf87a60ee4c0f"
"whisper-public-key" "04de2e21f1642ebee03b9aa4bf1936066124cc89967eaf269544c9b90c539fd5c980166a897d06dd4d3732b38116239f63c89395a8d73eac72881fab802010cb56"
"encryption-public-key" "04f2a432677a1b7c4f1bb22078135821d1d10fce23422297b5c808a545f2b61cdba38ee7394762172fc6ff5e9e28db7535e555efe2812905ffd4e0c25e82a98ae8"
"whisper-address" "87df2285f90b71221fab6267b7cb37532fedbb1f"
"wallet-address" "7e92236392a850980d00d0cd2a4b92886bd7fe7b"})
[:db :hardwallet])
[:whisper-private-key
:whisper-public-key
:encryption-public-key
:wallet-address
:whisper-address]))
{:whisper-private-key "f342f3ef17ce86abfa92b912b3a108a4546cfc687fd8e0f02fedf87a60ee4c0f"
:whisper-public-key "0x04de2e21f1642ebee03b9aa4bf1936066124cc89967eaf269544c9b90c539fd5c980166a897d06dd4d3732b38116239f63c89395a8d73eac72881fab802010cb56"
:encryption-public-key "04f2a432677a1b7c4f1bb22078135821d1d10fce23422297b5c808a545f2b61cdba38ee7394762172fc6ff5e9e28db7535e555efe2812905ffd4e0c25e82a98ae8"
:whisper-address "87df2285f90b71221fab6267b7cb37532fedbb1f"
:wallet-address "7e92236392a850980d00d0cd2a4b92886bd7fe7b"}))

View File

@ -452,6 +452,7 @@
"currency-display-name-thb": "Thailand Baht", "currency-display-name-thb": "Thailand Baht",
"transactions-filter-type": "Type", "transactions-filter-type": "Type",
"next": "Next", "next": "Next",
"back": "Back",
"recent": "Recent statuses", "recent": "Recent statuses",
"wallet-send-token": "Send {{symbol}}", "wallet-send-token": "Send {{symbol}}",
"bootnodes-enabled": "Bootnodes enabled", "bootnodes-enabled": "Bootnodes enabled",
@ -751,31 +752,52 @@
"send-command-payment": "Send a payment", "send-command-payment": "Send a payment",
"request-command-payment": "Request a payment", "request-command-payment": "Request a payment",
"choose-authentication-method": "Choose an authentication method to protect your account", "choose-authentication-method": "Choose an authentication method to protect your account",
"keycard": "Keycard",
"status-hardwallet-capitalized": "Status Hardwallet", "status-hardwallet-capitalized": "Status Hardwallet",
"status-hardwallet": "Status hardwallet", "status-hardwallet": "Status hardwallet",
"secure-your-assets": "secure your assets", "secure-your-assets": "secure your assets",
"link-card": "Link the card and use it to confirm your identity on the platform.", "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", "hold-card": "Hold card to the back\n of your phone",
"turn-nfc-on": "turn nfc on", "turn-nfc-on": "Turn NFC on to continue",
"go-to-settings": "Go to Settings", "go-to-settings": "Go to Settings...",
"card-is-empty": "Card is empty", "card-is-empty": "Card is empty",
"begin-set-up": "begin set up", "card-is-blank": "This card is blank",
"card-setup-prepare-text": "The whole process will take a few minutes.",
"card-is-paired": "Card is paired",
"begin-set-up": "Begin setup",
"maintain-card-to-phone-contact": "Maintain card-to-phone contact during process.", "maintain-card-to-phone-contact": "Maintain card-to-phone contact during process.",
"preparing-card": "Preparing card", "preparing-card": "Preparing card",
"generating-codes-for-pairing": "Generating codes for pairing with your Status account.", "generating-codes-for-pairing": "> Downloading product software to card\n > Generating unlocking & pairing codes",
"estimated-time": "Estimated time", "estimated-time": "Estimated time",
"cant-read-card": "Can't read card", "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", "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", "write-down-and-store-securely": "Write codes down\n & store them securely",
"puk-code": "PUK code", "puk-code": "PUK code",
"puk-code-explanation": "Unlocks card if you lose access", "puk-code-explanation": "If you forget your PIN or enter it incorrectly 3 times, you'll need this code to unlock your card.",
"pair-code": "Pair code", "pair-code": "Pair code",
"pair-code-explanation": "Pairs card to a different device with the same Status account on it", "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-title": "Did you write them down?",
"secret-keys-confirmation-text": "Record these now because you won't see this screen again", "secret-keys-confirmation-text": "Record these now because you won't see this screen again",
"secret-keys-confirmation-confirm": "GOT IT", "secret-keys-confirmation-confirm": "GOT IT",
"secret-keys-confirmation-cancel": "SEE IT AGAIN", "secret-keys-confirmation-cancel": "SEE IT AGAIN",
"see-it-again": "SEE IT AGAIN",
"completing-card-setup": "Completing card setup", "completing-card-setup": "Completing card setup",
"generating-mnemonic": "Generating mnemonic phrase",
"next-step-generating-mnemonic": "Next step is generating mnemonic phrase for your card",
"this-will-take-few-seconds": "This will take a few seconds",
"finishing-card-setup": "Finishing card setup",
"finishing-card-setup-steps": "> Loading keys to the card\n> Generating account",
"product-information": "Product Information",
"remaining-steps": "Remaining steps",
"initialization-of-the-card": "Initialization of the card",
"puk-and-pairing-codes-displayed": "PUK and pairing codes displayed",
"begin-keycard-setup-confirmation-text": "Setup will erase your card including the keys already stored on your card. Would you like to continue?",
"device-pairing": "Device pairing",
"something-went-wrong": "Something went wrong",
"try-again": "Try again",
"taking-long-hold-phone-connected": "This will take a few seconds.\n Hold card connected to the phone.",
"pin-code": "PIN code",
"pin-code-description": "Unlocks the card",
"create-pin": "Create a PIN", "create-pin": "Create a PIN",
"create-pin-description": "You'll need your card + this PIN to log in and to confirm transactions", "create-pin-description": "You'll need your card + this PIN to log in and to confirm transactions",
"repeat-pin": "Repeate your PIN", "repeat-pin": "Repeate your PIN",
@ -788,6 +810,12 @@
"card-already-linked": "Card is already linked to another account", "card-already-linked": "Card is already linked to another account",
"help": "help", "help": "help",
"pairing-card": "Pairing card", "pairing-card": "Pairing card",
"complete-exclamation": "Complete!",
"complete-hardwallet-setup": "This card is now an essential part your account security. Transactions can't be sent without it.",
"okay": "Okay",
"initialization": "Initialization",
"puk-and-pair-codes": "PUK and pair codes",
"pairing": "Pairing",
"view-my-wallet": "View my wallet", "view-my-wallet": "View my wallet",
"share-my-profile": "Share my profile", "share-my-profile": "Share my profile",
"share-chat": "Share chat", "share-chat": "Share chat",