diff --git a/android/app/src/main/res/drawable-hdpi/nfc.png b/android/app/src/main/res/drawable-hdpi/nfc.png new file mode 100644 index 0000000000..57429ac2c5 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/nfc.png differ diff --git a/android/app/src/main/res/drawable-mdpi/nfc.png b/android/app/src/main/res/drawable-mdpi/nfc.png new file mode 100644 index 0000000000..685858afa1 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/nfc.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/nfc.png b/android/app/src/main/res/drawable-xhdpi/nfc.png new file mode 100644 index 0000000000..f4d8a14600 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/nfc.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/nfc.png b/android/app/src/main/res/drawable-xxhdpi/nfc.png new file mode 100644 index 0000000000..36535b29a6 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/nfc.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/nfc.png b/android/app/src/main/res/drawable-xxxhdpi/nfc.png new file mode 100644 index 0000000000..5dad02d58b Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/nfc.png differ diff --git a/externs.js b/externs.js index e9afb45002..8b7be452a0 100644 --- a/externs.js +++ b/externs.js @@ -218,6 +218,7 @@ var TopLevel = { "injectJavaScript" : function () {}, "installApplet" : function () {}, "installAppletAndInitCard" : function () {}, + "installCashApplet" : function () {}, "Int8Array" : function () {}, "integer" : function () {}, "interpolate" : function () {}, @@ -491,6 +492,7 @@ var TopLevel = { "sign" : function () {}, "signGroupMembership" : function () {}, "signMessage" : function () {}, + "signPinless" : function () {}, "signTypedData" : function () {}, "slice" : function () {}, "SplashScreen" : function () {}, diff --git a/ios/StatusIm/Images.xcassets/nfc.imageset/Contents.json b/ios/StatusIm/Images.xcassets/nfc.imageset/Contents.json new file mode 100644 index 0000000000..6df42d7746 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/nfc.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "nfc.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "nfc-1.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "nfc-2.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/nfc.imageset/nfc-1.png b/ios/StatusIm/Images.xcassets/nfc.imageset/nfc-1.png new file mode 100644 index 0000000000..f4d8a14600 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/nfc.imageset/nfc-1.png differ diff --git a/ios/StatusIm/Images.xcassets/nfc.imageset/nfc-2.png b/ios/StatusIm/Images.xcassets/nfc.imageset/nfc-2.png new file mode 100644 index 0000000000..36535b29a6 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/nfc.imageset/nfc-2.png differ diff --git a/ios/StatusIm/Images.xcassets/nfc.imageset/nfc.png b/ios/StatusIm/Images.xcassets/nfc.imageset/nfc.png new file mode 100644 index 0000000000..685858afa1 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/nfc.imageset/nfc.png differ diff --git a/src/status_im/browser/core.cljs b/src/status_im/browser/core.cljs index f6a6c4447c..d4957e8cbb 100644 --- a/src/status_im/browser/core.cljs +++ b/src/status_im/browser/core.cljs @@ -325,9 +325,12 @@ (when (or (not message?) (and address data)) (signing/sign cofx (merge (if message? - {:message {:address address :data data :typed? (not= constants/web3-personal-sign method) - :from dapps-address}} - {:tx-obj (update (first params) :from #(or % dapps-address))}) + {:message {:address address + :data data + :typed? (not= constants/web3-personal-sign method) + :pinless? (= method constants/web3-keycard-sign-typed-data) + :from dapps-address}} + {:tx-obj (update (first params) :from #(or % dapps-address))}) {:on-result [:browser.dapp/transaction-on-result message-id id] :on-error [:browser.dapp/transaction-on-error message-id]})))) (if (#{"eth_accounts" "eth_coinbase"} method) @@ -347,6 +350,7 @@ [{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id] (let [{:dapps/keys [permissions]} db] (if (and (#{"eth_accounts" "eth_coinbase" "eth_sendTransaction" "eth_sign" + "keycard_signTypedData" "eth_signTypedData" "personal_sign" "personal_ecRecover"} method) (not (some #{constants/dapp-permission-web3} (get-in permissions [dapp-name :permissions])))) (send-to-bridge cofx diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index efca78d9f6..080469c126 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -225,8 +225,12 @@ (def ^:const web3-shh-get-filter-changes "shh_getFilterChanges") (def ^:const web3-shh-get-messages "shh_getMessages") +;; Keycard ns + +(def ^:const web3-keycard-sign-typed-data "keycard_signTypedData") + (defn web3-sign-message? [method] - (#{web3-sign-typed-data web3-sign-typed-data-v3 web3-personal-sign} method)) + (#{web3-sign-typed-data web3-sign-typed-data-v3 web3-personal-sign web3-keycard-sign-typed-data} method)) (def ^:const status-create-address "status_createaddress") diff --git a/src/status_im/hardwallet/card.cljs b/src/status_im/hardwallet/card.cljs index 960558e50e..b94e19b8d7 100644 --- a/src/status_im/hardwallet/card.cljs +++ b/src/status_im/hardwallet/card.cljs @@ -423,3 +423,40 @@ (re-frame/dispatch [:hardwallet.callback/on-sign-error (error-object->map response)])))}))) + +(defn install-cash-applet [] + (log/info "[keycard] install-cash-applet") + (keycard/install-cash-applet + card + {:on-success + (fn [response] + (log/info "[keycard response succ] install-cash-applet" + (js->clj response :keywordize-keys true)) + (re-frame/dispatch + [:hardwallet.callback/on-install-applet-success response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] install-cash-applet" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-install-applet-error + (error-object->map response)]))})) + +(defn sign-typed-data + [{:keys [hash] :as args}] + (log/info "[keycard] sign-typed-data" args) + (keycard/sign-typed-data + card + {:hash hash + :on-success + (fn [response] + (log/info "[keycard response succ] sign-typed-data" (js->clj response :keywordize-keys true)) + (re-frame/dispatch [:hardwallet.callback/on-sign-success + response])) + :on-failure + (fn [response] + (log/info "[keycard response fail] sign-typed-data" + (error-object->map response)) + (re-frame/dispatch + [:hardwallet.callback/on-sign-error + (error-object->map response)]))})) diff --git a/src/status_im/hardwallet/common.cljs b/src/status_im/hardwallet/common.cljs index dd1dcf893f..9d41859853 100644 --- a/src/status_im/hardwallet/common.cljs +++ b/src/status_im/hardwallet/common.cljs @@ -411,7 +411,7 @@ [{:keys [db] :as cofx} error] (log/debug "[hardwallet] application info error " error) (let [on-card-read (get-in db [:hardwallet :on-card-read]) - on-card-connected (get-in db [:hardwallet :on-card-conncted]) + on-card-connected (get-in db [:hardwallet :on-card-connected]) login? (= on-card-read :hardwallet/login-with-keycard) tag-was-lost? (tag-lost? (:error error))] (when-not tag-was-lost? diff --git a/src/status_im/hardwallet/fx.cljs b/src/status_im/hardwallet/fx.cljs index 4258b14e21..390a10123f 100644 --- a/src/status_im/hardwallet/fx.cljs +++ b/src/status_im/hardwallet/fx.cljs @@ -94,6 +94,10 @@ :hardwallet/sign card/sign) +(re-frame/reg-fx + :hardwallet/sign-typed-data + card/sign-typed-data) + (re-frame/reg-fx :hardwallet/login-with-keycard status/login-with-keycard) diff --git a/src/status_im/hardwallet/keycard.cljs b/src/status_im/hardwallet/keycard.cljs index d54eccddbb..95763aa219 100644 --- a/src/status_im/hardwallet/keycard.cljs +++ b/src/status_im/hardwallet/keycard.cljs @@ -11,6 +11,7 @@ (remove-event-listeners [this]) (get-application-info [this args]) (install-applet [this args]) + (install-cash-applet [this args]) (init-card [this args]) (install-applet-and-init-card [this args]) (pair [this args]) @@ -26,4 +27,5 @@ (export-key [this args]) (unpair-and-delete [this args]) (get-keys [this args]) - (sign [this args])) + (sign [this args]) + (sign-typed-data [this args])) diff --git a/src/status_im/hardwallet/real_keycard.cljs b/src/status_im/hardwallet/real_keycard.cljs index 2ccd367cbb..53f09ff09c 100644 --- a/src/status_im/hardwallet/real_keycard.cljs +++ b/src/status_im/hardwallet/real_keycard.cljs @@ -59,6 +59,12 @@ (then on-success) (catch on-failure))) +(defn install-cash-applet [{:keys [on-success on-failure]}] + (.. status-keycard + installCashApplet + (then on-success) + (catch on-failure))) + (defn init-card [{:keys [pin on-success on-failure]}] (.. status-keycard (init pin) @@ -178,6 +184,14 @@ (then on-success) (catch on-failure)))) +(defn sign-typed-data + [{:keys [hash on-success on-failure]}] + (when hash + (.. status-keycard + (signPinless hash) + (then on-success) + (catch on-failure)))) + (defrecord RealKeycard [] keycard/Keycard (keycard/check-nfc-support [this args] @@ -200,6 +214,8 @@ (get-application-info args)) (keycard/install-applet [this args] (install-applet args)) + (keycard/install-cash-applet [this args] + (install-cash-applet args)) (keycard/init-card [this args] (init-card args)) (keycard/install-applet-and-init-card [this args] @@ -231,4 +247,6 @@ (keycard/get-keys [this args] (get-keys args)) (keycard/sign [this args] - (sign args))) + (sign args)) + (keycard/sign-typed-data [this args] + (sign-typed-data args))) diff --git a/src/status_im/hardwallet/sign.cljs b/src/status_im/hardwallet/sign.cljs index d5dc8e3be5..6c7477de20 100644 --- a/src/status_im/hardwallet/sign.cljs +++ b/src/status_im/hardwallet/sign.cljs @@ -2,7 +2,10 @@ (:require [clojure.string :as string] [re-frame.core :as re-frame] [status-im.ethereum.core :as ethereum] + [status-im.ethereum.json-rpc :as json-rpc] + [status-im.hardwallet.card :as card] [status-im.utils.fx :as fx] + [status-im.utils.money :as money] [status-im.utils.types :as types] [taoensso.timbre :as log] [status-im.hardwallet.common :as common])) @@ -74,6 +77,63 @@ (common/get-application-info (common/get-pairing db) nil) (common/hide-connection-sheet))) +(def sign-typed-data-listener (atom nil)) + +(fx/defn sign-typed-data + {:events [:hardwallet/sign-typed-data]} + [{:keys [db] :as cofx}] + (let [card-connected? (get-in db [:hardwallet :card-connected?]) + hash (get-in db [:hardwallet :hash])] + (if card-connected? + (do + (when @sign-typed-data-listener + (card/remove-event-listener @sign-typed-data-listener)) + {:db (-> db + (assoc-in [:hardwallet :card-read-in-progress?] true) + (assoc-in [:signing/sign :keycard-step] :signing)) + :hardwallet/sign-typed-data {:hash (ethereum/naked-address hash)}}) + (do + (reset! sign-typed-data-listener + (card/on-card-connected #(re-frame/dispatch [:hardwallet/sign-typed-data]))) + (fx/merge cofx + (common/set-on-card-connected :hardwallet/sign-typed-data) + {:db (assoc-in db [:signing/sign :keycard-step] :signing)}))))) + +(fx/defn fetch-currency-symbol-on-success + {:events [:hardwallet/fetch-currency-symbol-on-success]} + [{:keys [db] :as cofx} currency] + {:db (assoc-in db [:signing/sign :formatted-data :message :formatted-currency] currency)}) + +(fx/defn fetch-currency-decimals-on-success + {:events [:hardwallet/fetch-currency-decimals-on-success]} + [{:keys [db] :as cofx} decimals] + {:db (update-in db [:signing/sign :formatted-data :message] + #(assoc % :formatted-amount (.dividedBy (money/bignumber (:amount %)) + (money/bignumber (money/from-decimal decimals)))))}) + +(fx/defn store-hash-and-sign-typed + {:events [:hardwallet/store-hash-and-sign-typed]} + [{:keys [db] :as cofx} result] + (let [{:keys [result error]} (types/json->clj result) + message (get-in db [:signing/sign :formatted-data :message]) + currency-contract (:currency message)] + (when-not (or (:receiver message) (:code message)) + (json-rpc/eth-call {:contract currency-contract + :method "decimals()" + :outputs ["uint8"] + :on-success (fn [[decimals]] + (re-frame/dispatch [:hardwallet/fetch-currency-decimals-on-success decimals]))}) + + (json-rpc/eth-call {:contract currency-contract + :method "symbol()" + :outputs ["string"] + :on-success (fn [[currency]] + (re-frame/dispatch [:hardwallet/fetch-currency-symbol-on-success currency]))})) + + (fx/merge cofx + {:db (assoc-in db [:hardwallet :hash] result)} + sign-typed-data))) + (fx/defn prepare-to-sign {:events [:hardwallet/prepare-to-sign]} [{:keys [db] :as cofx}] diff --git a/src/status_im/hardwallet/simulated_keycard.cljs b/src/status_im/hardwallet/simulated_keycard.cljs index 02428c60d7..e4961f5274 100644 --- a/src/status_im/hardwallet/simulated_keycard.cljs +++ b/src/status_im/hardwallet/simulated_keycard.cljs @@ -60,6 +60,7 @@ (later #(on-success (get @state :application-info)))) (defn install-applet [args]) +(defn install-cash-applet [args]) (def kk1-password "6d9ZHjn94kFP4bPm") @@ -121,6 +122,7 @@ (defn unpair-and-delete [args]) (defn get-keys [args]) (defn sign [args]) +(defn sign-typed-data [args]) (defrecord SimulatedKeycard [] keycard/Keycard diff --git a/src/status_im/signing/core.cljs b/src/status_im/signing/core.cljs index 8b6edad268..cdddcf4496 100644 --- a/src/status_im/signing/core.cljs +++ b/src/status_im/signing/core.cljs @@ -10,6 +10,7 @@ [status-im.ethereum.eip55 :as eip55] [status-im.ethereum.tokens :as tokens] [status-im.i18n :as i18n] + [status-im.signing.keycard :as signing.keycard] [status-im.native-module.core :as status] [status-im.utils.fx :as fx] [status-im.hardwallet.common :as hardwallet.common] @@ -179,17 +180,26 @@ (fx/defn show-sign [{:keys [db] :as cofx}] (let [{:signing/keys [queue]} db - {{:keys [gas gasPrice] :as tx-obj} :tx-obj {:keys [data typed?] :as message} :message :as tx} (last queue) + {{:keys [gas gasPrice] :as tx-obj} :tx-obj {:keys [data typed? pinless?] :as message} :message :as tx} (last queue) keycard-multiaccount? (boolean (get-in db [:multiaccount :keycard-pairing])) wallet-set-up-passed? (get-in db [:multiaccount :wallet-set-up-passed?]) updated-db (if wallet-set-up-passed? db (assoc db :popover/popover {:view :signing-phrase}))] (if message - {:db (assoc updated-db - :signing/in-progress? true - :signing/queue (drop-last queue) - :signing/tx tx - :signing/sign {:type (if keycard-multiaccount? :keycard :password) - :formatted-data (if typed? (types/json->clj data) (ethereum/hex-to-utf8 data))})} + (fx/merge + cofx + {:db (assoc updated-db + :signing/in-progress? true + :signing/queue (drop-last queue) + :signing/tx tx + :signing/sign {:type (cond pinless? :pinless + keycard-multiaccount? :keycard + :else :password) + :formatted-data (if typed? (types/json->clj data) (ethereum/hex-to-utf8 data)) + :keycard-step (when pinless? :connect)})} + (when pinless? + (signing.keycard/hash-message {:data data + :typed? true + :on-completed #(re-frame/dispatch [:hardwallet/store-hash-and-sign-typed %])}))) (fx/merge cofx {:db (assoc updated-db @@ -295,18 +305,28 @@ (when on-error {:dispatch (conj on-error message)}))))) +(fx/defn dissoc-signing-db-entries-and-check-queue + {:events [:signing/dissoc-entries-and-check-queue]} + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (dissoc db :signing/tx :signing/in-progress? :signing/sign)} + check-queue)) + (fx/defn sign-message-completed {:events [:signing/sign-message-completed]} [{:keys [db] :as cofx} result] (let [{:keys [result error]} (types/json->clj result) on-result (get-in db [:signing/tx :on-result])] (if error - {:db (update db :signing/sign assoc - :error (if (= 5 (:code error)) (i18n/label :t/wrong-password) (:message error)) - :in-progress? false)} + {:db (-> db + (assoc-in [:signing/sign :error] (if (= 5 (:code error)) (i18n/label :t/wrong-password) (:message error))) + (assoc :signing/in-progress? false))} (fx/merge cofx - {:db (dissoc db :signing/tx :signing/in-progress? :signing/sign)} - (check-queue) + (when-not (= (-> db :signing/sign :type) :pinless) + (dissoc-signing-db-entries-and-check-queue)) + #(when (= (-> db :signing/sign :type) :pinless) + {:dispatch-later [{:ms 3000 + :dispatch [:signing/dissoc-entries-and-check-queue]}]}) #(when on-result {:dispatch (conj on-result result)}))))) @@ -314,7 +334,7 @@ {:events [:signing/transaction-completed] :interceptors [(re-frame/inject-cofx :random-id-generator)]} [cofx response tx-obj hashed-password] - (let [cofx-in-progress-false (assoc-in cofx [:db :signing/sign :in-progress?] false) + (let [cofx-in-progress-false (assoc-in cofx [:db :signing/in-progress?] false) {:keys [result error]} (types/json->clj response)] (log/debug "transaction-completed" error tx-obj) (if error diff --git a/src/status_im/signing/keycard.cljs b/src/status_im/signing/keycard.cljs index 1833b1e794..7f3d46abb0 100644 --- a/src/status_im/signing/keycard.cljs +++ b/src/status_im/signing/keycard.cljs @@ -79,11 +79,12 @@ {:events [:signing.ui/sign-with-keycard-pressed]} [{:keys [db] :as cofx}] (let [message (get-in db [:signing/tx :message])] - (fx/merge cofx - {:db (-> db - (assoc-in [:hardwallet :pin :enter-step] :sign) - (assoc-in [:signing/sign :keycard-step] :pin) - (assoc-in [:signing/sign :type] :keycard))} - (if message - (hash-message message) - (hash-transaction))))) + (fx/merge + cofx + {:db (-> db + (assoc-in [:hardwallet :pin :enter-step] :sign) + (assoc-in [:signing/sign :type] :keycard) + (assoc-in [:signing/sign :keycard-step] :pin))} + (if message + (hash-message message nil) + (hash-transaction))))) diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 3903b8ccad..48ca624fb0 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -177,7 +177,6 @@ ;;signing (reg-root-key-sub :signing/tx :signing/tx) -(reg-root-key-sub :signing/sign :signing/sign) (reg-root-key-sub :signing/edit-fee :signing/edit-fee) ;;intro-wizard @@ -2069,6 +2068,21 @@ (fn [{:keys [signing-phrase]}] signing-phrase)) +(re-frame/reg-sub + :signing/sign + (fn [db] + (let [sign (:signing/sign db)] + (if (= :pinless (:type sign)) + (let [message (get-in sign [:formatted-data :message])] + (if (and (:amount message) (:currency message)) + (assoc sign :fiat-amount + (money/fiat-amount-value (:amount message) + (:currency message) + :USD (:prices db)) + :fiat-currency "USD") + sign)) + sign)))) + (defn- too-precise-amount? "Checks if number has any extra digit beyond the allowed number of decimals. It does so by checking the number against its rounded value." diff --git a/src/status_im/ui/screens/popover/views.cljs b/src/status_im/ui/screens/popover/views.cljs index b556c587b4..adf77ac663 100644 --- a/src/status_im/ui/screens/popover/views.cljs +++ b/src/status_im/ui/screens/popover/views.cljs @@ -10,8 +10,9 @@ [status-im.ui.screens.profile.user.views :as profile.user] [status-im.ui.screens.multiaccounts.recover.views :as multiaccounts.recover] [status-im.react-native.js-dependencies :as js-dependencies] - [status-im.ui.screens.biometric.views :as biometric] - [status-im.ui.components.colors :as colors])) + [status-im.ui.components.colors :as colors] + [status-im.ui.screens.signing.views :as signing] + [status-im.ui.screens.biometric.views :as biometric])) (defn hide-panel-anim [bottom-anim-value alpha-value window-height] @@ -133,6 +134,9 @@ (= :disable-password-saving view) [biometric/disable-password-saving-popover] + (= :transaction-data view) + [signing/transaction-data] + :else [view])]]]]])))}))) diff --git a/src/status_im/ui/screens/signing/styles.cljs b/src/status_im/ui/screens/signing/styles.cljs index b252128010..f96077a577 100644 --- a/src/status_im/ui/screens/signing/styles.cljs +++ b/src/status_im/ui/screens/signing/styles.cljs @@ -58,3 +58,22 @@ :color (if disabled? colors/black colors/white) :padding-horizontal 16 :padding-vertical 10}) + +(defn sheet-title [small-screen?] + {:font-weight "500" + :font-size (if small-screen? 16 19) + :margin-top 16}) + +(defn sheet-subtitle [small-screen?] + {:font-size (if small-screen? 16 19) + :text-align :center + :margin-bottom 12 + :color colors/gray}) + +(defn sheet-icon [bg-color] + {:height 64 + :width 64 + :border-radius 32 + :justify-content :center + :align-items :center + :background-color bg-color}) diff --git a/src/status_im/ui/screens/signing/views.cljs b/src/status_im/ui/screens/signing/views.cljs index d2fff83f2b..d90bf1d09c 100644 --- a/src/status_im/ui/screens/signing/views.cljs +++ b/src/status_im/ui/screens/signing/views.cljs @@ -133,6 +133,105 @@ [react/view {:align-items :center :margin-top 16 :margin-bottom 40} [sign-with-keycard-button nil nil]])]) +(defn signature-request [{:keys [error formatted-data + fiat-amount fiat-currency + keycard-step + in-progress? enabled?] :as sign} small-screen?] + (let [message (:message formatted-data) + title (case keycard-step + :connect :t/looking-for-cards + :signing :t/processing + :error :t/lost-connection + :success :t/success) + subtitle (case keycard-step + :connect :t/hold-card + :signing :t/try-keeping-the-card-still + :error :t/tap-card-again + :success :t/transaction-signed)] + [react/view (assoc styles/message :padding-vertical 16 :align-items :center) + [react/view {:style {:align-self :flex-start :padding-left 16 :margin-bottom 24}} + [react/text {:style {:font-size (if small-screen? 15 17) :font-weight "700"}} + (i18n/label :t/confirmation-request)]] + (when (and (:formatted-amount message) (:formatted-currency message)) + [react/view {:style {:margin-bottom 24 :align-self :stretch}} + [react/nested-text {:style {:font-weight "500" :font-size (if small-screen? 34 44) + :text-align :center}} + (str (:formatted-amount message) " ") + [{:style {:color colors/gray}} (:formatted-currency message)]] + [react/text {:style {:font-size 19 :text-align :center + :margin-bottom 16}} + (str fiat-amount " " fiat-currency)] + [separator]]) + [react/view {:style (styles/sheet-icon (case keycard-step + (:connect :signing) colors/blue-transparent-10 + :error colors/red-transparent-10 + :success colors/green-transparent-10))} + (case keycard-step + :connect + [icons/icon :main-icons/nfc {:color colors/blue :width 27 :height 21}] + :signing + [react/activity-indicator {:animating true :color colors/blue}] + :error + [icons/icon :main-icons/close {:color colors/red}] + :success + [icons/icon :main-icons/check {:color colors/green}])] + [react/text {:style (styles/sheet-title small-screen?)} (i18n/label title)] + [react/text {:style (styles/sheet-subtitle small-screen?)} (i18n/label subtitle)] + [button/button {:type :main + :disabled? (= keycard-step :success) + :text-style {:font-size (if small-screen? 18 20)} + :style {:align-self :stretch} + :container-style {:height (if small-screen? 52 64)} + :label (i18n/label :t/show-transaction-data) + :on-press #(re-frame/dispatch [:show-popover {:view :transaction-data}])}] + [button/button {:type :main + :theme :red + :disabled? (= keycard-step :success) + :container-style {:margin-top 8 + :height 64 :margin-bottom 16} + :style {:align-self :stretch} + :text-style {:font-size 20} + :label (i18n/label :t/decline) + :on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])}]])) + +(defn- transaction-data-item [{:keys [label data]}] + [react/view + [react/text {:style {:font-size 17 + :line-height 20 + :margin-bottom 8 + :color colors/gray}} + label] + [react/text {:style {:font-size 17 + :line-height 20 + :margin-bottom 24}} + data]]) + +(views/defview transaction-data [] + (views/letsubs + [{:keys [formatted-data]} [:signing/sign]] + [react/view {:style {:flex 1}} + [react/view {:style {:margin-horizontal 24 + :margin-top 24}} + [react/text {:style {:font-size 17 + :font-weight "700"}} + (i18n/label :t/transaction-data)]] + [react/scroll-view {:style {:flex 1 + :margin-horizontal 8 + :padding-horizontal 16 + :padding-vertical 10 + :margin-vertical 14}} + [transaction-data-item {:label "Label" + :data formatted-data}]] + [separator] + [react/view {:style {:margin-horizontal 8 + :margin-vertical 16}} + [button/button {:type :main + :text-style {:font-size 20} + :style {:margin-horizontal 0} + :container-style {:height 64} + :label (i18n/label :t/close) + :on-press #(re-frame/dispatch [:hide-popover])}]]])) + (views/defview password-view [{:keys [type error in-progress? enabled?] :as sign}] (views/letsubs [phrase [:signing/phrase]] (case type @@ -160,19 +259,22 @@ [react/view]))) (views/defview message-sheet [] - (views/letsubs [{:keys [formatted-data type] :as sign} [:signing/sign]] - [react/view styles/message - [react/view styles/message-header - [react/text {:style {:typography :title-bold}} (i18n/label :t/signing-a-message)] - [react/touchable-highlight {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])} - [react/view {:padding 6} - [react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]] - [separator] - [react/view {:padding-top 16 :flex 1} - [react/view styles/message-border - [react/scroll-view - [react/text (or formatted-data "")]]] - [password-view sign]]])) + (views/letsubs [{:keys [formatted-data type] :as sign} [:signing/sign] + small-screen? [:dimensions/small-screen?]] + (if (= type :pinless) + [signature-request sign small-screen?] + [react/view styles/message + [react/view styles/message-header + [react/text {:style {:typography :title-bold}} (i18n/label :t/signing-a-message)] + [react/touchable-highlight {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])} + [react/view {:padding 6} + [react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]] + [separator] + [react/view {:padding-top 16 :flex 1} + [react/view styles/message-border + [react/scroll-view + [react/text (or formatted-data "")]]] + [password-view sign]]]))) (defn amount-item [prices wallet-currency amount amount-error display-symbol fee-display-symbol prices-loading?] (let [converted-value (* amount (get-in prices [(keyword display-symbol) (keyword (:code wallet-currency)) :price]))] diff --git a/translations/en.json b/translations/en.json index be89ca681b..7bbacaffe0 100644 --- a/translations/en.json +++ b/translations/en.json @@ -135,6 +135,7 @@ "clear-history-confirmation": "Clear history?", "clear-history-confirmation-content": "Are you sure you want to clear this chat history?", "clear-history-title": "Clear history?", + "close": "Close", "close-app-button": "Confirm", "close-app-content": "The app will stop and close. When you reopen it, the selected network will be used", "close-app-title": "Warning!", @@ -142,6 +143,7 @@ "complete-hardwallet-setup": "This card is now an essential part your multiaccount security. Transactions can't be sent without it.", "completed": "Completed", "confirm": "Confirm", + "confirmation-request": "Confirmation request", "confirmations": "Confirmations", "confirmations-helper-text": "When the transaction has 12 confirmations you can consider it settled.", "connect": "Connect", @@ -593,6 +595,8 @@ "logout-app-content": "The account will be logged out. When you unlock it again, the selected network will be used", "logout-are-you-sure": "Are you sure you want\nto log out?", "logout-title": "Log out?", + "looking-for-cards": "Looking for cards...", + "lost-connection": "Lost connection", "mailserver-address": "Mailserver address", "mailserver-automatic": "Automatic selection", "mailserver-connection-error": "Could not connect to mailserver", @@ -875,6 +879,7 @@ "show-less": "Show less", "show-more": "Show more", "show-qr": "Show QR code", + "show-transaction-data": "Show transaction data", "sign-and-send": "Sign and send", "sign-in": "Unlock", "sign-message": "Sign Message", @@ -916,6 +921,7 @@ "sync-synced": "In sync", "syncing-devices": "Syncing...", "tag-was-lost": "Tag was lost", + "tap-card-again": "Tap the card to the back of your phone again", "test-networks": "Test networks", "text-input-disabled": "Please wait a moment...", "this-device": "This device", @@ -934,6 +940,7 @@ "token-details": "Token details", "topic-name-error": "Use only lowercase letters (a to z), numbers & dashes (-). Do not use chat keys", "transaction": "Transaction", + "transaction-data": "Transaction data", "transaction-declined": "Transaction declined", "transaction-description": "Consider it complete after 12 confirmations on the network.", "transaction-details": "Transaction details", @@ -941,6 +948,7 @@ "transaction-history": "Transaction history", "transaction-request": "Transaction Request", "transaction-sent": "Transaction sent", + "transaction-signed": "The transaction has been successfully signed", "transactions": "Transactions", "transactions-filter-select-all": "Select all", "transactions-filter-title": "Filter history", @@ -978,6 +986,7 @@ "tribute-to-talk-tribute-received2": " are now contacts and can securely chat with each other.", "tribute-to-talk-you-require-snt": "You require SNT for new people to start a chat.", "try-again": "Try again", + "try-keeping-the-card-still": "Try keeping the card still", "turn-nfc-on": "Turn NFC on to continue", "turn-nfc-description": "NFC is disabled on yor device. You can enable it in settings", "keycard-init-title": "Looking for cards...",