diff --git a/android/app/src/main/res/drawable-mdpi/keycard_logo_big.png b/android/app/src/main/res/drawable-mdpi/keycard_logo_big.png new file mode 100644 index 0000000000..bfcbe8a44e Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/keycard_logo_big.png differ diff --git a/android/app/src/main/res/drawable-mdpi/union_nfc.png b/android/app/src/main/res/drawable-mdpi/union_nfc.png new file mode 100644 index 0000000000..9f8fd24420 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/union_nfc.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/keycard_logo_big.png b/android/app/src/main/res/drawable-xhdpi/keycard_logo_big.png new file mode 100644 index 0000000000..53eb0d6854 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/keycard_logo_big.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/union_nfc.png b/android/app/src/main/res/drawable-xhdpi/union_nfc.png new file mode 100644 index 0000000000..4870dd05f7 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/union_nfc.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/keycard_logo_big.png b/android/app/src/main/res/drawable-xxhdpi/keycard_logo_big.png new file mode 100644 index 0000000000..332afc2f0c Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/keycard_logo_big.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/union_nfc.png b/android/app/src/main/res/drawable-xxhdpi/union_nfc.png new file mode 100644 index 0000000000..01ddc55359 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/union_nfc.png differ diff --git a/components/src/status_im/react_native/resources.cljs b/components/src/status_im/react_native/resources.cljs index 7b3c68056a..98375fca5f 100644 --- a/components/src/status_im/react_native/resources.cljs +++ b/components/src/status_im/react_native/resources.cljs @@ -19,17 +19,16 @@ :keycard-empty (js/require "./resources/images/ui/keycard-empty.png") :keycard-phone (js/require "./resources/images/ui/keycard-phone.png") :keycard-connection (js/require "./resources/images/ui/keycard-connection.png") - :keycard-nfc-on (js/require "./resources/images/ui/keycard-nfc-on.png") :keycard-wrong (js/require "./resources/images/ui/keycard-wrong.png") :not-keycard (js/require "./resources/images/ui/not-keycard.png") :status-logo (js/require "./resources/images/ui/status-logo.png") - :hold-card-animation (js/require "./resources/images/ui/hold-card-animation.gif") :warning-sign (js/require "./resources/images/ui/warning-sign.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") :dapp-store (js/require "./resources/images/ui/dapp-store.png") :ens-header (js/require "./resources/images/ui/ens-header.png") - :new-chat-header (js/require "./resources/images/ui/new-chat-header.png")}) + :new-chat-header (js/require "./resources/images/ui/new-chat-header.png") + :onboarding-phone (js/require "./resources/images/ui/onboarding-phone.png")}) (def loaded-images (atom {})) diff --git a/externs.js b/externs.js index 08fc9b2128..8a3f8b7c22 100644 --- a/externs.js +++ b/externs.js @@ -551,6 +551,7 @@ var TopLevel = { "Uri" : function () {}, "url" : function () {}, "Value" : function () {}, + "ValueXY": function() {}, "value" : function () {}, "verify" : function () {}, "verifyPin" : function () {}, diff --git a/fiddle/src/status_im/react_native/resources.cljs b/fiddle/src/status_im/react_native/resources.cljs index ea775ca964..153181a200 100644 --- a/fiddle/src/status_im/react_native/resources.cljs +++ b/fiddle/src/status_im/react_native/resources.cljs @@ -14,7 +14,6 @@ :keycard-empty "images/ui/keycard-empty.png" :keycard-phone "images/ui/keycard-phone.png" :keycard-connection "images/ui/keycard-connection.png" - :keycard-nfc-on "images/ui/keycard-nfc-on.png" :keycard-wrong "images/ui/keycard-wrong.png" :not-keycard "images/ui/not-keycard.png" :status-logo "images/ui/status-logo.png" diff --git a/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/Contents.json b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/Contents.json new file mode 100644 index 0000000000..5038a7a890 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "keycard_logo_big.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "keycard_logo_big@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "keycard_logo_big@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big.png b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big.png new file mode 100644 index 0000000000..bfcbe8a44e Binary files /dev/null and b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big.png differ diff --git a/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big@2x.png b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big@2x.png new file mode 100644 index 0000000000..53eb0d6854 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big@2x.png differ diff --git a/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big@3x.png b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big@3x.png new file mode 100644 index 0000000000..332afc2f0c Binary files /dev/null and b/ios/StatusIm/Images.xcassets/keycard-logo-big.imageset/keycard_logo_big@3x.png differ diff --git a/ios/StatusIm/Images.xcassets/union-nfc.imageset/Contents.json b/ios/StatusIm/Images.xcassets/union-nfc.imageset/Contents.json new file mode 100644 index 0000000000..76a3682076 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/union-nfc.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "union-nfc.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "union-nfc@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "union-nfc@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc.png b/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc.png new file mode 100644 index 0000000000..9f8fd24420 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc.png differ diff --git a/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc@2x.png b/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc@2x.png new file mode 100644 index 0000000000..4870dd05f7 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc@2x.png differ diff --git a/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc@3x.png b/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc@3x.png new file mode 100644 index 0000000000..01ddc55359 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/union-nfc.imageset/union-nfc@3x.png differ diff --git a/resources/images/ui/hold-card-animation.gif b/resources/images/ui/hold-card-animation.gif deleted file mode 100644 index 68c549303a..0000000000 Binary files a/resources/images/ui/hold-card-animation.gif and /dev/null differ diff --git a/resources/images/ui/keycard-nfc-on.png b/resources/images/ui/keycard-nfc-on.png deleted file mode 100644 index 4593d59ccb..0000000000 Binary files a/resources/images/ui/keycard-nfc-on.png and /dev/null differ diff --git a/resources/images/ui/onboarding-phone.png b/resources/images/ui/onboarding-phone.png new file mode 100644 index 0000000000..7927217813 Binary files /dev/null and b/resources/images/ui/onboarding-phone.png differ diff --git a/src/status_im/hardwallet/card.cljs b/src/status_im/hardwallet/card.cljs index 0e5bc4addc..f4aee640eb 100644 --- a/src/status_im/hardwallet/card.cljs +++ b/src/status_im/hardwallet/card.cljs @@ -37,23 +37,20 @@ (doseq [event ["keyCardOnConnected" "keyCardOnDisconnected"]] (.removeAllListeners event-emitter event))) -(defn register-card-events [] - (log/debug "[keycard] register-card-events") +(defn on-card-connected [callback] (when (and config/hardwallet-enabled? platform/android?) + (.addListener event-emitter "keyCardOnConnected" callback))) - (remove-event-listeners) +(defn on-card-disconnected [callback] + (when (and config/hardwallet-enabled? + platform/android?) + (.addListener event-emitter "keyCardOnDisconnected" callback))) - (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 register-card-events [] + (remove-event-listeners) + (on-card-connected #(re-frame/dispatch [:hardwallet.callback/on-card-connected %])) + (on-card-disconnected #(re-frame/dispatch [:hardwallet.callback/on-card-disconnected %]))) (defn get-application-info [{:keys [pairing on-success]}] (log/debug "[keycard] get-application-info") diff --git a/src/status_im/hardwallet/common.cljs b/src/status_im/hardwallet/common.cljs index 19c1a0b840..beaae2ad96 100644 --- a/src/status_im/hardwallet/common.cljs +++ b/src/status_im/hardwallet/common.cljs @@ -1,6 +1,7 @@ (ns status-im.hardwallet.common (:require [clojure.string :as string] [re-frame.core :as re-frame] + [status-im.ui.screens.keycard.keycard-interaction :as keycard-sheet] [status-im.ethereum.core :as ethereum] [status-im.i18n :as i18n] [status-im.ui.screens.navigation :as navigation] @@ -9,6 +10,7 @@ [status-im.utils.platform :as platform] [status-im.utils.types :as types] [taoensso.timbre :as log] + [status-im.ui.components.bottom-sheet.events :as bottom-sheet] [status-im.utils.keychain.core :as keychain] [status-im.hardwallet.nfc :as nfc])) @@ -156,6 +158,69 @@ (assoc-in [:hardwallet :on-card-read] nil) (assoc-in [:hardwallet :last-on-card-read] nil))}) +(defn keycard-sheet-content [on-cancel] + (fn [] + (keycard-sheet/connect-keycard + {:on-cancel #(re-frame/dispatch on-cancel) + :on-connect :hardwallet.callback/on-card-connected + :on-disconnect :hardwallet.callback/on-card-disconnected}))) + +(fx/defn show-pair-sheet + [cofx {:keys [on-cancel] + :or {on-cancel [::cancel-sheet-confirm]}}] + (log/debug "[hardwallet] show-pair-sheet") + (fx/merge cofx + {:dismiss-keyboard true} + (bottom-sheet/show-bottom-sheet + {:view {:show-handle? false + :backdrop-dismiss? false + :disable-drag? true + :content (keycard-sheet-content on-cancel)}}))) + +(fx/defn hide-pair-sheet + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (-> db + (assoc-in [:hardwallet :card-connected?] false) + (assoc-in [:hardwallet :card-read-in-progress?] false))} + (restore-on-card-connected) + (restore-on-card-read) + (bottom-sheet/hide-bottom-sheet))) + +(fx/defn clear-pin + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (update-in db + [:hardwallet :pin] + merge + {:status nil + :login (get-in db [:hardwallet :pin :original]) + :export-key [] + :sign [] + :puk [] + :current [] + :original [] + :confirmation [] + :error-label nil})})) + +(fx/defn cancel-sheet-confirm + {:events [::cancel-sheet-confirm + :hardwallet/back-button-pressed]} + [cofx] + (fx/merge cofx + (hide-pair-sheet) + (clear-pin))) + +(fx/defn cancel-sheet + {:events [::cancel-sheet]} + [_] + {:ui/show-confirmation {:title (i18n/label :t/keycard-cancel-setup-title) + :content (i18n/label :t/keycard-cancel-setup-text) + :confirm-button-text (i18n/label :t/yes) + :cancel-button-text (i18n/label :t/no) + :on-accept #(re-frame/dispatch [::cancel-sheet-confirm]) + :on-cancel #()}}) + (fx/defn on-add-listener-to-hardware-back-button "Adds listener to hardware back button on Android. During keycard setup we show user a warning that setup will be cancelled diff --git a/src/status_im/hardwallet/core.cljs b/src/status_im/hardwallet/core.cljs index a649b81e5f..a5197758e8 100644 --- a/src/status_im/hardwallet/core.cljs +++ b/src/status_im/hardwallet/core.cljs @@ -82,11 +82,6 @@ (onboarding/proceed-with-generating-key))) (recovery/load-pair-screen cofx))))) -(fx/defn on-register-card-events - {:events [:hardwallet.callback/on-register-card-events]} - [{:keys [db]} listeners] - {:db (update-in db [:hardwallet :listeners] merge listeners)}) - (fx/defn navigate-to-keycard-settings {:events [:profile.ui/keycard-settings-button-pressed]} [{:keys [db] :as cofx}] diff --git a/src/status_im/hardwallet/recovery.cljs b/src/status_im/hardwallet/recovery.cljs index 2af2d6e71b..fb21c9f05a 100644 --- a/src/status_im/hardwallet/recovery.cljs +++ b/src/status_im/hardwallet/recovery.cljs @@ -61,7 +61,7 @@ (navigation/navigate-to-cofx :keycard-recovery-enter-mnemonic nil))) (fx/defn start-import-flow - {:events [:hardwallet/recover-with-keycard-pressed]} + {:events [::recover-with-keycard-pressed]} [{:keys [db] :as cofx}] (fx/merge cofx {:db (assoc-in db [:hardwallet :flow] :import) @@ -149,7 +149,7 @@ (if (nil? name) {:hardwallet/generate-name-and-photo {:public-key whisper-public-key - :on-success :hardwallet/on-name-and-photo-generated}} + :on-success ::on-name-and-photo-generated}} (fx/merge cofx {:db (-> db (assoc-in [:hardwallet :setup-step] nil) @@ -247,7 +247,7 @@ (navigation/navigate-to-cofx :keycard-recovery-pin nil))) (fx/defn on-name-and-photo-generated - {:events [:hardwallet/on-name-and-photo-generated] + {:events [::on-name-and-photo-generated] :interceptors [(re-frame/inject-cofx :random-guid-generator) (re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]} [{:keys [db] :as cofx} whisper-name photo-path] diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 7aae83a325..bfcbad7120 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -47,7 +47,7 @@ [status-im.wallet.db :as wallet.db] [status-im.signing.gas :as signing.gas] [status-im.utils.gfycat.core :as gfycat] - status-im.ui.screens.hardwallet.connect.subs + status-im.ui.screens.keycard.subs status-im.ui.screens.hardwallet.settings.subs status-im.ui.screens.hardwallet.pin.subs status-im.ui.screens.hardwallet.setup.subs diff --git a/src/status_im/ui/components/animation.cljs b/src/status_im/ui/components/animation.cljs index 81f79d466b..8bad1c9464 100644 --- a/src/status_im/ui/components/animation.cljs +++ b/src/status_im/ui/components/animation.cljs @@ -60,6 +60,9 @@ (defn create-value [value] (js/ReactNative.Animated.Value. value)) +(defn create-value-xy [value] + (js/ReactNative.Animated.ValueXY. value)) + (defn add [anim-x anim-y] (js/ReactNative.Animated.add. anim-x anim-y)) @@ -80,3 +83,4 @@ (defn easing-out [] (.-out (easing))) (defn cubic [] (.-cubic (easing))) +(def bezier (.-bezier (easing))) diff --git a/src/status_im/ui/screens/keycard/components/description.cljs b/src/status_im/ui/screens/keycard/components/description.cljs new file mode 100644 index 0000000000..230c1183a6 --- /dev/null +++ b/src/status_im/ui/screens/keycard/components/description.cljs @@ -0,0 +1,46 @@ +(ns status-im.ui.screens.keycard.components.description + (:require [reagent.core :as reagent] + [status-im.ui.components.animation :as animation] + [status-im.ui.components.react :as react] + [status-im.ui.screens.keycard.components.style :as styles])) + +(defn text-block-style [animated] + {:height 66 + :margin-bottom 8 + :opacity (animation/interpolate animated + {:inputRange [0 1] + :outputRange [1 0]}) + :transform [{:translateY (animation/interpolate animated + {:inputRange [0 1] + :outputRange [0 10]})}]}) + +(def easing (animation/bezier 0.77 0 0.175 1)) + +(defonce animating (atom nil)) + +(defn animate-description [animated] + (when-not @animating + (reset! animating true) + ;; TODO; Animate exit + (animation/set-value animated 1) + (animation/start + (animation/timing animated + {:toValue 0 + :timing 300 + :easing easing}) + #(reset! animating false)))) + +(defn animated-description [] + (let [current-text (reagent/atom nil) + animated-value (animation/create-value 0)] + (fn [{:keys [title description]}] + (when-not (= @current-text [title description]) + (reset! current-text [title description]) + (animate-description animated-value)) + [react/animated-view {:style (text-block-style animated-value)} + [react/text {:style styles/title-style + :number-of-lines 1} + title] + [react/text {:style styles/helper-text-style + :number-of-lines 2} + description]]))) diff --git a/src/status_im/ui/screens/keycard/components/keycard_animation.cljs b/src/status_im/ui/screens/keycard/components/keycard_animation.cljs new file mode 100644 index 0000000000..637a296d4b --- /dev/null +++ b/src/status_im/ui/screens/keycard/components/keycard_animation.cljs @@ -0,0 +1,339 @@ +(ns status-im.ui.screens.keycard.components.keycard-animation + (:require [status-im.ui.components.react :as react] + [reagent.core :as reagent] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.components.animation :as animation] + [status-im.hardwallet.card :as keycard-nfc] + [status-im.react-native.resources :as resources] + [status-im.ui.components.colors :as colors])) + +(defn circle [{:keys [animation-value color size]}] + [react/animated-view + {:style {:width size + :height size + :position "absolute" + :background-color color + :border-radius (/ size 2) + :opacity (animation/interpolate + animation-value + {:inputRange [0 1 2] + :outputRange [0.7 1 0]}) + :transform [{:scale (animation/interpolate + animation-value + {:inputRange [0 1] + :outputRange [0.9 1]})}]}}]) + +(defn indicator-container [anim children] + [react/animated-view + {:style {:position "absolute" + :justify-content :center + :align-items :center + :border-radius 21 + :width 42 + :height 42 + :top 16.5 + :right -24 + :shadow-offset {:width 0 :height 2} + :shadow-radius 16 + :elevation 8 + :shadow-opacity 0.1 + :shadow-color "gba(0, 9, 26, 0.12)" + :background-color :white + :opacity anim + :transform [{:scale (animation/interpolate + anim + {:inputRange [0 1] + :outputRange [0 1]})}]}} + children]) + +(defn indicator [{:keys [state animation-value]}] + [indicator-container animation-value + (case @state + :error + [vector-icons/icon :main-icons/close {:color colors/red + :height 28 + :width 28}] + :success + [vector-icons/icon :main-icons/check {:color colors/green + :height 28 + :width 28}] + :connected + [vector-icons/icon :main-icons/check {:color colors/blue + :height 28 + :width 28}] + :processing + [react/activity-indicator {:color colors/blue}] + + nil)]) + +(defn animate-card-position [card-scale animation-value] + {:transform [{:scale card-scale} + {:translateX (animation/x animation-value)} + {:translateY (animation/y animation-value)}]}) + +(defn card-colors [state] + (case state + (:init :awaiting) + {:card-color "#2D2D2D" + :key-color "#27D8B9" + :chip-color "#F0CC73"} + (:connected :processing) + {:card-color colors/blue + :key-color :white + :chip-color :white} + :success + {:card-color colors/green + :key-color :white + :chip-color :white} + :error + {:card-color colors/red + :key-color :white + :chip-color :white} + nil)) + +(defn card [{:keys [card-scale state indicator-value animation-value]}] + (let [{:keys [card-color + chip-color + key-color]} (card-colors @state)] + [react/animated-view + {:style (merge + (animate-card-position card-scale animation-value) + {:height 80 + :width 120 + :border-radius 12 + :position :absolute + :shadow-offset {:width 0 :height 2} + :shadow-radius 16 + :elevation 8 + :shadow-opacity 0.1 + :shadow-color "gba(0, 9, 26, 0.12)" + :background-color card-color})} + [react/animated-view + {:style {:width 12 + :height 9 + :border-radius 3 + :left 19.5 + :top 30 + :background-color chip-color}}] + [react/view + {:style {:position :absolute + :justify-content :center + :top 18 + :right 19.5 + :height 42 + :width 25}} + [vector-icons/icon :main-icons/keycard-logo-big + {:color key-color + :width 25 + :height 42}]] + [indicator {:state state + :animation-value indicator-value}]])) + +(defn phone [{:keys [animation-value]}] + [react/animated-view {:style {:position :absolute + :bottom 0 + :elevation 9 + :opacity (animation/interpolate + animation-value + {:inputRange [0 1] + :outputRange [0 0.9]}) + :transform [{:translateY (animation/interpolate + animation-value + {:inputRange [0 1] + :outputRange [125 10]})}]}} + [react/image + {:source (resources/get-image :onboarding-phone) + :style {:height 125 + :width 86}}]]) + +(def circle-easing (animation/bezier 0.455 0.03 0.515 0.955)) +(def card-easing (animation/bezier 0.77 0 0.175 1)) + +(defn- circle-animation [animation-value to delay] + (animation/timing animation-value + {:toValue to + :delay delay + :duration 1000 + :easing circle-easing})) + +(defn start-animation + [{:keys [small medium big card-scale phone + indicator card state]}] + (animation/set-value indicator 0) + (animation/set-value phone 0) + (let [phone-enter-at 7000 + resets (animation/timing card-scale + {:toValue 0.66 + :duration 1000 + :easing card-easing}) + card-loop (animation/anim-loop + (animation/anim-sequence + [(animation/timing card + {:toValue #js {:x -30 + :y 30} + :duration 1000 + :easing card-easing}) + (animation/timing card + {:toValue {:x 45 + :y 65} + :duration 1000 + :delay 2000 + :easing card-easing}) + (animation/timing card + {:toValue #js {:x -30 + :y 105} + :duration 1000 + :delay 2000 + :easing card-easing}) + (animation/anim-delay 2000)])) + phone-entrance (animation/anim-sequence + [(animation/anim-delay phone-enter-at) + (animation/parallel + [(animation/timing card-scale + {:toValue 0.528 + :duration 1000 + :easing card-easing}) + (animation/timing phone + {:toValue 1 + :duration 1000 + :easing card-easing}) + card-loop])]) + circles (animation/anim-loop + (animation/parallel + [(animation/anim-sequence + [(circle-animation small 1 0) + (circle-animation small 0 0)]) + (animation/anim-sequence + [(circle-animation medium 1 200) + (circle-animation medium 0 0)]) + (animation/anim-sequence + [(circle-animation big 1 400) + (circle-animation big 0 0)])])) + animation (animation/parallel + [resets + phone-entrance + circles])] + (reset! state :init) + ;; TODO(Ferossgp): Think how to improve that, this creates desync of state with animation + (js/setTimeout #(compare-and-set! state :init :awaiting) + phone-enter-at) + (animation/start animation))) + +(defn on-error [{:keys [state restart]}] + (reset! state :error) + (js/setTimeout #(when (= @state :error) + (restart)) 3000)) + +(defn on-success [{:keys [state]}] + (reset! state :success)) + +(defn on-connect + [{:keys [state card small indicator + medium big card-scale phone]}] + (let [connect-animation (animation/parallel + [(animation/timing card-scale + {:toValue 1 + :timing 1000 + :easing card-easing}) + (animation/timing indicator + {:toValue 1 + :timing 1000 + :easing card-easing}) + (animation/timing small + {:toValue 2 + :timing 1000 + :easing circle-easing}) + (animation/timing medium + {:toValue 2 + :timing 1000 + :easing circle-easing}) + (animation/timing big + {:toValue 2 + :timing 1000 + :easing circle-easing}) + (animation/timing phone + {:toValue 0 + :timing 1000 + :easing card-easing}) + (animation/timing card + {:toValue #js {:x 0 + :y 0} + :timing 3000 + :easing card-easing})])] + (reset! state :connected) + (js/setTimeout #(compare-and-set! state :connected :processing) + 2000) + (animation/start connect-animation))) + +(defn animated-circles [{:keys [state on-card-connected on-card-disconnected]}] + (let [animation-small (animation/create-value 0) + animation-medium (animation/create-value 0) + animation-big (animation/create-value 0) + animation-card (animation/create-value-xy #js {:x 0 + :y 0}) + card-scale (animation/create-value 0.66) + animation-phone (animation/create-value 0) + animation-indicator (animation/create-value 0) + on-start-animation #(start-animation + {:state state + :small animation-small + :medium animation-medium + :big animation-big + :phone animation-phone + :card animation-card + :card-scale card-scale + :indicator animation-indicator}) + on-card-connected #(do + (on-card-connected) + (on-connect + {:state state + :indicator animation-indicator + :card animation-card + :card-scale card-scale + :phone animation-phone + :small animation-small + :medium animation-medium + :big animation-big})) + on-success #(on-success + {:state state}) + on-error #(do + (on-card-disconnected) + (on-error + {:state state + :restart on-start-animation}))] + (reagent/create-class + {:component-did-mount + (fn [] + (keycard-nfc/remove-event-listeners) + (keycard-nfc/on-card-connected on-card-connected) + (keycard-nfc/on-card-disconnected on-error) + (on-start-animation)) + :component-will-unmount + (fn [] + (keycard-nfc/remove-event-listeners)) + :render + (fn [] + [react/view {:style {:position :absolute + :top 0 + :bottom 0 + :left 0 + :right 0 + :justify-content :center + :align-items :center}} + + [circle {:animation-value animation-big + :size 200 + :color "#F1F4FF"}] + [circle {:animation-value animation-medium + :size 140 + :color "#E3E8FA"}] + [circle {:animation-value animation-small + :size 80 + :color "#D2D9F0"}] + + [card {:animation-value animation-card + :state state + :indicator-value animation-indicator + :card-scale card-scale}] + + [phone {:animation-value animation-phone}]])}))) diff --git a/src/status_im/ui/screens/keycard/components/style.cljs b/src/status_im/ui/screens/keycard/components/style.cljs new file mode 100644 index 0000000000..cf4ebd4461 --- /dev/null +++ b/src/status_im/ui/screens/keycard/components/style.cljs @@ -0,0 +1,17 @@ +(ns status-im.ui.screens.keycard.components.style + (:require [status-im.ui.components.colors :as colors])) + +(def wrapper-style {:flex 1 + :align-items :center + :justify-content :center}) + +(def container-style {:flex-direction :column + :align-items :center + :padding-horizontal 40}) + +(def helper-text-style {:text-align :center + :color colors/gray + :line-height 22}) + +(def title-style {:text-align :center + :line-height 22}) diff --git a/src/status_im/ui/screens/keycard/components/turn_nfc.cljs b/src/status_im/ui/screens/keycard/components/turn_nfc.cljs new file mode 100644 index 0000000000..8bb9388d9d --- /dev/null +++ b/src/status_im/ui/screens/keycard/components/turn_nfc.cljs @@ -0,0 +1,26 @@ +(ns status-im.ui.screens.keycard.components.turn-nfc + (:require [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.components.react :as react] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.button :as button] + [status-im.ui.screens.keycard.components.style :as styles])) + +(defn turn-nfc-on [] + [react/view {:style styles/wrapper-style} + [react/view {:style styles/container-style} + [vector-icons/icon :main-icons/union-nfc {:color colors/blue + :height 36 + :width 36}] + [react/view {:margin-top 16} + [react/text {:style {:typography :title-bold}} + (i18n/label :t/turn-nfc-on)]] + [react/view {:margin-top 8} + [react/text {:number-of-lines 2 + :style styles/helper-text-style} + (i18n/label :t/turn-nfc-description)]] + + [button/button {:label :t/open-nfc-settings + :style {:margin-top 16} + :on-press #(re-frame/dispatch [:keycard.onboarding.nfc-on/open-nfc-settings-pressed])}]]]) diff --git a/src/status_im/ui/screens/keycard/keycard_interaction.cljs b/src/status_im/ui/screens/keycard/keycard_interaction.cljs new file mode 100644 index 0000000000..8b5193a60e --- /dev/null +++ b/src/status_im/ui/screens/keycard/keycard_interaction.cljs @@ -0,0 +1,63 @@ +(ns status-im.ui.screens.keycard.keycard-interaction + (:require [reagent.core :as reagent] + [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.ui.components.react :as react] + [status-im.ui.screens.keycard.components.keycard-animation + :refer [animated-circles]] + [status-im.ui.components.colors :as colors] + [status-im.ui.screens.keycard.components.description :as description] + [status-im.ui.screens.keycard.components.turn-nfc :as turn-nfc] + [status-im.ui.screens.keycard.components.style :as styles])) + +(def state->translations + {:init {:title :t/keycard-init-title + :description :t/keycard-init-description} + :awaiting {:title :t/keycard-awaiting-title + :description :t/keycard-awaiting-description} + :processing {:title :t/keycard-processing-title + :description :t/keycard-processing-description} + :connected {:title :t/keycard-connected-title + :description :t/keycard-connected-description} + :error {:title :t/keycard-error-title + :description :t/keycard-error-description} + :success {:title :t/keycard-success-title + :description :t/keycard-success-description}}) + +(defn card-sync-flow [] + (let [state (reagent/atom nil)] + (fn [{:keys [on-card-connected on-card-disconnected]}] + (let [translation (get state->translations @state)] + [react/view {:style styles/container-style} + [react/view {:height 200 + :margin-bottom 20} + [animated-circles {:state state + :on-card-disconnected on-card-disconnected + :on-card-connected on-card-connected}]] + (when translation + [description/animated-description + {:title (i18n/label (:title translation)) + :description (i18n/label (:description translation))}])])))) + +(defn connect-keycard [{:keys [on-connect on-cancel on-disconnect]}] + (fn [] + [react/view {:style {:flex 1 + :align-items :center + :justify-content :center}} + (when on-cancel + [react/touchable-highlight + {:on-press on-cancel + :style {:position :absolute + :top 0 + :right 0}} + [react/text {:style {:line-height 22 + :padding-horizontal 16 + :color colors/blue + :text-align :center}} + (i18n/label :t/cancel)]]) + (if @(re-frame/subscribe [:hardwallet/nfc-enabled?]) + [card-sync-flow {:on-card-disconnected + #(re-frame/dispatch [on-disconnect]) + :on-card-connected + #(re-frame/dispatch [on-connect])}] + [turn-nfc/turn-nfc-on])])) diff --git a/src/status_im/ui/screens/hardwallet/connect/subs.cljs b/src/status_im/ui/screens/keycard/subs.cljs similarity index 84% rename from src/status_im/ui/screens/hardwallet/connect/subs.cljs rename to src/status_im/ui/screens/keycard/subs.cljs index 0743f57f8c..78fc199356 100644 --- a/src/status_im/ui/screens/hardwallet/connect/subs.cljs +++ b/src/status_im/ui/screens/keycard/subs.cljs @@ -1,4 +1,4 @@ -(ns status-im.ui.screens.hardwallet.connect.subs +(ns status-im.ui.screens.keycard.subs (:require [re-frame.core :as re-frame])) (re-frame/reg-sub diff --git a/src/status_im/ui/screens/multiaccounts/recover/views.cljs b/src/status_im/ui/screens/multiaccounts/recover/views.cljs index e49c263276..94eed04017 100644 --- a/src/status_im/ui/screens/multiaccounts/recover/views.cljs +++ b/src/status_im/ui/screens/multiaccounts/recover/views.cljs @@ -3,7 +3,7 @@ (:require [re-frame.core :as re-frame] [status-im.ui.components.react :as react] [status-im.multiaccounts.recover.core :as multiaccounts.recover] - [status-im.hardwallet.core :as hardwallet] + [status-im.hardwallet.recovery :as hardwallet] [status-im.hardwallet.nfc :as nfc] [status-im.i18n :as i18n] [status-im.utils.config :as config] diff --git a/test/cljs/status_im/react_native/js_dependencies.cljs b/test/cljs/status_im/react_native/js_dependencies.cljs index 9ec3f0f971..4734c3218d 100644 --- a/test/cljs/status_im/react_native/js_dependencies.cljs +++ b/test/cljs/status_im/react_native/js_dependencies.cljs @@ -19,8 +19,11 @@ :Animated #js {:View #js {} :FlatList #js {} :Text #js {}} + :Easing #js {:bezier (fn [])} :DeviceEventEmitter #js {:addListener (fn [])} - :Dimensions #js {:get (fn [])}}) + :Dimensions #js {:get (fn [])}}) + +(set! js/ReactNative react-native) (def vector-icons #js {:default #js {}}) (def webview-bridge #js {:default #js {}}) @@ -53,4 +56,4 @@ (def react-native-shake #js {}) (def net-info #js {}) (def touchid #js {}) -(def safe-area-context #js {}) \ No newline at end of file +(def safe-area-context #js {}) diff --git a/translations/en.json b/translations/en.json index 3427c9c5c6..9c30256463 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1067,6 +1067,19 @@ "tribute-to-talk-you-require-snt": "You require SNT for new people to start a chat.", "try-again": "Try again", "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...", + "keycard-init-description": "Put the card to the back of your phone to continue", + "keycard-awaiting-title": "Still looking...", + "keycard-awaiting-description": "Try moving the card around to find the NFC reader on your device", + "keycard-processing-title": "Processing...", + "keycard-processing-description": "Try keeping the card still", + "keycard-connected-title": "Connected", + "keycard-connected-description": "Try keeping the card still", + "keycard-error-title": "Connection lost", + "keycard-error-description": "Connect the card again to continue", + "keycard-success-title": "Success", + "keycard-success-description": "You may remove the card now", "type-a-message": "Type a message...", "ulc-enabled": "ULC enabled", "unable-to-read-this-code": "Unable to read this code",