Edit derivation path (#17741)
This commit is contained in:
parent
716007dc3c
commit
94a3e266a9
|
@ -18,13 +18,19 @@
|
||||||
(h/render [bottom-actions/view
|
(h/render [bottom-actions/view
|
||||||
{:actions :2-actions
|
{:actions :2-actions
|
||||||
:button-one-label button-one
|
:button-one-label button-one
|
||||||
|
:button-one-props {:icon-left :i/arrow-left}
|
||||||
:button-two-label button-two}])
|
:button-two-label button-two}])
|
||||||
(h/is-truthy (h/get-by-text button-one))
|
(h/is-truthy (h/get-by-text button-one))
|
||||||
|
(h/is-truthy (h/get-by-label-text :icon))
|
||||||
(h/is-truthy (h/get-by-text button-two))))
|
(h/is-truthy (h/get-by-text button-two))))
|
||||||
|
|
||||||
(h/test "render disabled button"
|
(h/test "render disabled button"
|
||||||
(h/render [bottom-actions/view
|
(h/render [bottom-actions/view
|
||||||
{:description "Sample description"
|
{:description "Sample description"
|
||||||
:disabled? true
|
:button-one-props {:disabled? true}
|
||||||
:button-one-label "button"}])
|
:button-one-label "button"}])
|
||||||
(h/is-disabled (h/get-by-label-text :button-one))))
|
(h/is-disabled (h/get-by-label-text :button-one)))
|
||||||
|
|
||||||
|
(h/test "sane defaults"
|
||||||
|
(h/render [bottom-actions/view {}])
|
||||||
|
(h/is-truthy (h/get-by-label-text :button-one))))
|
||||||
|
|
|
@ -17,34 +17,35 @@
|
||||||
:description - string (default nil) - Description to display below the title
|
:description - string (default nil) - Description to display below the title
|
||||||
:button-one-label - string (default nil) - Label for the first button
|
:button-one-label - string (default nil) - Label for the first button
|
||||||
:button-two-label - string (default nil) - Label for the second button
|
:button-two-label - string (default nil) - Label for the second button
|
||||||
:button-one-press - fn (default nil) - Function to call when the first button is pressed
|
:button-one-props - map with props for button one
|
||||||
:button-two-press - fn (default nil) - Function to call when the second button is pressed
|
:button-two-props - map with props for button two
|
||||||
:theme - :light/:dark
|
:theme - :light/:dark
|
||||||
:scroll - bool (default false) - Whether the iOS Home Indicator should be rendered
|
:scroll? - bool (default false) - Whether the iOS Home Indicator should be rendered"
|
||||||
:button-one-type - same as button/button :type
|
|
||||||
:button-two-type - same as button/button :type"
|
|
||||||
[props]
|
[props]
|
||||||
(let [{:keys [actions description button-one-label button-two-label
|
(let [{:keys [actions description button-one-label button-two-label
|
||||||
button-one-press button-two-press theme
|
button-one-props button-two-props theme scroll?]}
|
||||||
scroll? button-one-type button-two-type disabled?]}
|
|
||||||
(merge default-props props)]
|
(merge default-props props)]
|
||||||
[:<>
|
[:<>
|
||||||
[rn/view {:style style/buttons-container}
|
[rn/view {:style style/buttons-container}
|
||||||
(when (= actions :2-actions)
|
(when (= actions :2-actions)
|
||||||
[button/button
|
[button/button
|
||||||
{:size 40
|
(merge
|
||||||
:background (when scroll? :blur)
|
{:size 40
|
||||||
:container-style style/button-container-2-actions
|
:background (when scroll? :blur)
|
||||||
:type button-two-type
|
:container-style style/button-container-2-actions
|
||||||
:on-press button-two-press} button-two-label])
|
:theme theme
|
||||||
|
:accessibility-label :button-two}
|
||||||
|
button-two-props)
|
||||||
|
button-two-label])
|
||||||
[button/button
|
[button/button
|
||||||
{:size 40
|
(merge
|
||||||
:container-style style/button-container
|
{:size 40
|
||||||
:type button-one-type
|
:container-style style/button-container
|
||||||
:disabled? disabled?
|
:background (when scroll? :blur)
|
||||||
:background (when scroll? :blur)
|
:theme theme
|
||||||
:on-press button-one-press
|
:accessibility-label :button-one}
|
||||||
:accessibility-label :button-one} button-one-label]]
|
button-one-props)
|
||||||
|
button-one-label]]
|
||||||
(when description
|
(when description
|
||||||
[text/text
|
[text/text
|
||||||
{:size :paragraph-2
|
{:size :paragraph-2
|
||||||
|
|
|
@ -21,12 +21,24 @@
|
||||||
:key :actions
|
:key :actions
|
||||||
:options [{:key :1-action}
|
:options [{:key :1-action}
|
||||||
{:key :2-actions}]}
|
{:key :2-actions}]}
|
||||||
{:type :select
|
{:label "Button 1 type"
|
||||||
:key :button-two-type
|
:type :select
|
||||||
:options button-options}
|
:key :type
|
||||||
{:type :select
|
:options button-options
|
||||||
:key :button-one-type
|
:path [:button-one-props]}
|
||||||
:options button-options}
|
{:label "Button 1 disabled?"
|
||||||
|
:type :boolean
|
||||||
|
:key :disabled?
|
||||||
|
:path [:button-one-props]}
|
||||||
|
{:label "Button 2 type"
|
||||||
|
:type :select
|
||||||
|
:key :type
|
||||||
|
:options button-options
|
||||||
|
:path [:button-two-props]}
|
||||||
|
{:label "Button 2 disabled?"
|
||||||
|
:type :boolean
|
||||||
|
:key :disabled?
|
||||||
|
:path [:button-two-props]}
|
||||||
{:key :description
|
{:key :description
|
||||||
:type :text}
|
:type :text}
|
||||||
{:key :button-one-label
|
{:key :button-one-label
|
||||||
|
@ -42,10 +54,11 @@
|
||||||
:description description
|
:description description
|
||||||
:button-one-label button-one
|
:button-one-label button-one
|
||||||
:button-two-label button-two
|
:button-two-label button-two
|
||||||
:button-one-press (button-press 2)
|
:button-one-props {:on-press (button-press 1)
|
||||||
:button-two-press (button-press 1)
|
:type :primary
|
||||||
:button-one-type :primary
|
:icon-left :i/arrow-up}
|
||||||
:button-two-type :grey
|
:button-two-props {:on-press (button-press 2)
|
||||||
|
:type :grey}
|
||||||
:scroll? false})]
|
:scroll? false})]
|
||||||
(fn []
|
(fn []
|
||||||
[preview/preview-container
|
[preview/preview-container
|
||||||
|
|
|
@ -258,7 +258,11 @@
|
||||||
:padding-horizontal 20}}
|
:padding-horizontal 20}}
|
||||||
(doall
|
(doall
|
||||||
(for [desc descriptors
|
(for [desc descriptors
|
||||||
:let [descriptor (merge desc {:state state})]]
|
:let [desc-path (:path desc)
|
||||||
|
new-state (if desc-path
|
||||||
|
(reagent/cursor state desc-path)
|
||||||
|
state)
|
||||||
|
descriptor (assoc desc :state new-state)]]
|
||||||
^{:key (:key desc)}
|
^{:key (:key desc)}
|
||||||
[:<>
|
[:<>
|
||||||
(case (:type desc)
|
(case (:type desc)
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
:data networks-list}]
|
:data networks-list}]
|
||||||
[quo/bottom-actions
|
[quo/bottom-actions
|
||||||
{:button-one-label (i18n/label :t/update)
|
{:button-one-label (i18n/label :t/update)
|
||||||
:disabled? true
|
:button-one-props {:disabled? true
|
||||||
:button-one-press on-save}]])
|
:on-press on-save}}]])
|
||||||
|
|
||||||
(def view (quo.theme/with-theme view-internal))
|
(def view (quo.theme/with-theme view-internal))
|
||||||
|
|
|
@ -24,3 +24,12 @@
|
||||||
(defn get-derivation-path
|
(defn get-derivation-path
|
||||||
[number-of-accounts]
|
[number-of-accounts]
|
||||||
(str constants/path-wallet-root "/" number-of-accounts))
|
(str constants/path-wallet-root "/" number-of-accounts))
|
||||||
|
|
||||||
|
(defn format-derivation-path
|
||||||
|
[path]
|
||||||
|
(string/replace path "/" " / "))
|
||||||
|
|
||||||
|
(defn get-formatted-derivation-path
|
||||||
|
[number-of-accounts]
|
||||||
|
(let [path (get-derivation-path number-of-accounts)]
|
||||||
|
(format-derivation-path path)))
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
(ns status-im2.contexts.wallet.create-account.edit-derivation-path.component-spec
|
||||||
|
(:require
|
||||||
|
[status-im2.contexts.wallet.create-account.edit-derivation-path.view :as edit-derivation-path]
|
||||||
|
[test-helpers.component :as h]))
|
||||||
|
|
||||||
|
(h/describe "Edit derivation path page"
|
||||||
|
(h/test "Default render"
|
||||||
|
(h/render [edit-derivation-path/view {}])
|
||||||
|
(h/is-truthy (h/get-by-translation-text :t/edit-derivation-path))
|
||||||
|
(h/is-truthy (h/get-by-translation-text :t/path-format))
|
||||||
|
(h/is-truthy (h/get-by-translation-text :t/derivation-path))
|
||||||
|
(h/is-truthy (h/get-by-translation-text :t/reveal-address))
|
||||||
|
(h/is-truthy (h/get-by-translation-text :t/save)))
|
||||||
|
|
||||||
|
|
||||||
|
(h/test "Reveal address pressed"
|
||||||
|
(let [on-reveal (h/mock-fn)]
|
||||||
|
(h/render [edit-derivation-path/view {:on-reveal on-reveal}])
|
||||||
|
(h/fire-event :press (h/get-by-translation-text :t/reveal-address))
|
||||||
|
(h/was-called on-reveal)
|
||||||
|
(h/wait-for #(h/is-truthy (h/get-by-translation-text :t/address-activity)))))
|
||||||
|
|
||||||
|
(h/test "Reset button pressed"
|
||||||
|
(let [on-reset (h/mock-fn)]
|
||||||
|
(h/render [edit-derivation-path/view {:on-reset on-reset}])
|
||||||
|
(h/fire-event :press (h/get-by-translation-text :t/reset))
|
||||||
|
(h/was-called on-reset)
|
||||||
|
(h/wait-for #(h/is-truthy (h/get-by-translation-text :t/derive-addresses))))))
|
|
@ -0,0 +1,49 @@
|
||||||
|
(ns status-im2.contexts.wallet.create-account.edit-derivation-path.style
|
||||||
|
(:require [quo.foundations.colors :as colors]))
|
||||||
|
|
||||||
|
(defn screen
|
||||||
|
[top]
|
||||||
|
{:flex 1
|
||||||
|
:margin-top top})
|
||||||
|
|
||||||
|
(def header
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:padding-top 12
|
||||||
|
:padding-bottom 8})
|
||||||
|
|
||||||
|
(def tag
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:flex-direction :row})
|
||||||
|
|
||||||
|
(def input-container
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:padding-top 12})
|
||||||
|
|
||||||
|
(defn save-button-container
|
||||||
|
[bottom]
|
||||||
|
{:flex 1
|
||||||
|
:justify-content :flex-end
|
||||||
|
:padding-bottom bottom})
|
||||||
|
|
||||||
|
(def revealed-address-container
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:padding-top 24})
|
||||||
|
|
||||||
|
(defn revealed-address
|
||||||
|
[theme]
|
||||||
|
{:border-width 1
|
||||||
|
:border-color (colors/resolve-color :success theme 40)
|
||||||
|
:border-style :dashed
|
||||||
|
:border-radius 16
|
||||||
|
:padding-horizontal 12
|
||||||
|
:padding-vertical 7})
|
||||||
|
|
||||||
|
(def info
|
||||||
|
{:margin-vertical 9
|
||||||
|
:padding-left 2})
|
||||||
|
|
||||||
|
(def temporal-placeholder
|
||||||
|
{:height 94
|
||||||
|
:background-color colors/danger-50
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center})
|
|
@ -0,0 +1,120 @@
|
||||||
|
(ns status-im2.contexts.wallet.create-account.edit-derivation-path.view
|
||||||
|
(:require
|
||||||
|
[quo.core :as quo]
|
||||||
|
[quo.theme :as quo.theme]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[react-native.safe-area :as safe-area]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im2.contexts.wallet.common.temp :as temp]
|
||||||
|
[status-im2.contexts.wallet.common.utils :as utils]
|
||||||
|
[status-im2.contexts.wallet.create-account.edit-derivation-path.style :as style]
|
||||||
|
[utils.i18n :as i18n]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(defn- view-internal
|
||||||
|
"States:
|
||||||
|
default(filled)
|
||||||
|
| -> (reveal-action) -> show
|
||||||
|
| -> (clear-action) -> empty -> (derive-action) -> choose -> (choose-action) -> show"
|
||||||
|
[{:keys [on-reset on-reveal]}]
|
||||||
|
(let [top (safe-area/get-top)
|
||||||
|
bottom (safe-area/get-bottom)
|
||||||
|
state (reagent/atom :default)
|
||||||
|
reveal-action (fn [_]
|
||||||
|
(reset! state :show)
|
||||||
|
(when on-reveal
|
||||||
|
(on-reveal)))
|
||||||
|
clear-action #(reset! state :empty)
|
||||||
|
derive-action #(reset! state :choose)
|
||||||
|
choose-action #(reset! state :show)
|
||||||
|
path-value (reagent/atom (utils/get-formatted-derivation-path 3))
|
||||||
|
handle-path-change (fn [v]
|
||||||
|
(reset! path-value v)
|
||||||
|
(when (empty? v)
|
||||||
|
(clear-action)))
|
||||||
|
reset-path-value (fn [_]
|
||||||
|
(reset! path-value "")
|
||||||
|
(clear-action)
|
||||||
|
(when on-reset
|
||||||
|
(on-reset)))]
|
||||||
|
(fn [{:keys [theme]}]
|
||||||
|
[rn/view
|
||||||
|
{:style (style/screen top)}
|
||||||
|
[quo/page-nav
|
||||||
|
{:background :blur
|
||||||
|
:icon-name :i/close
|
||||||
|
:on-press #(rf/dispatch [:navigate-back])}]
|
||||||
|
[quo/text
|
||||||
|
{:size :heading-1
|
||||||
|
:weight :semi-bold
|
||||||
|
:style style/header}
|
||||||
|
(i18n/label :t/edit-derivation-path)]
|
||||||
|
[rn/view {:style style/tag}
|
||||||
|
[quo/context-tag
|
||||||
|
{:type :icon
|
||||||
|
:size 24
|
||||||
|
:icon :i/placeholder
|
||||||
|
:style style/tag
|
||||||
|
:context "Alisher Card"}]]
|
||||||
|
[rn/view {:style style/temporal-placeholder}
|
||||||
|
[quo/text "Dropdown input will be here"]
|
||||||
|
[quo/text (i18n/label :t/path-format)]]
|
||||||
|
[quo/input
|
||||||
|
{:container-style style/input-container
|
||||||
|
:value @path-value
|
||||||
|
:label (i18n/label :t/derivation-path)
|
||||||
|
:placeholder (utils/get-formatted-derivation-path 3)
|
||||||
|
:button {:on-press reset-path-value
|
||||||
|
:text (i18n/label :t/reset)}
|
||||||
|
:on-change-text handle-path-change}]
|
||||||
|
|
||||||
|
(case @state
|
||||||
|
:default
|
||||||
|
[quo/bottom-actions
|
||||||
|
{:theme theme
|
||||||
|
:actions :1-action
|
||||||
|
:button-one-label (i18n/label :t/reveal-address)
|
||||||
|
:button-one-props {:type :outline
|
||||||
|
:icon-left :i/keycard-card
|
||||||
|
:on-press reveal-action}}]
|
||||||
|
|
||||||
|
:empty
|
||||||
|
[quo/bottom-actions
|
||||||
|
{:theme theme
|
||||||
|
:actions :1-action
|
||||||
|
:button-one-label (i18n/label :t/derive-addresses)
|
||||||
|
:button-one-props {:type :outline
|
||||||
|
:icon-left :i/keycard-card
|
||||||
|
:on-press derive-action}}]
|
||||||
|
|
||||||
|
:show
|
||||||
|
[rn/view {:style style/revealed-address-container}
|
||||||
|
[rn/view {:style (style/revealed-address theme)}
|
||||||
|
[quo/text
|
||||||
|
{:weight :monospace}
|
||||||
|
temp/address]]
|
||||||
|
[quo/info-message
|
||||||
|
{:type :success
|
||||||
|
:icon :i/done
|
||||||
|
:style style/info}
|
||||||
|
(i18n/label :t/address-activity)]]
|
||||||
|
|
||||||
|
:choose
|
||||||
|
[rn/view {:style style/temporal-placeholder}
|
||||||
|
[quo/text "Dropdown input will be here"]
|
||||||
|
[quo/button
|
||||||
|
{:on-press (fn [_]
|
||||||
|
(reset! path-value (utils/get-formatted-derivation-path 1))
|
||||||
|
(choose-action))} "Choose"]]
|
||||||
|
nil)
|
||||||
|
|
||||||
|
[rn/view {:style (style/save-button-container bottom)}
|
||||||
|
[quo/bottom-actions
|
||||||
|
{:theme theme
|
||||||
|
:actions :1-action
|
||||||
|
:button-one-label (i18n/label :t/save)
|
||||||
|
:button-one-props {:type :primary
|
||||||
|
:on-press #(js/alert "Save!")
|
||||||
|
:disabled? true}}]]])))
|
||||||
|
|
||||||
|
(def view (quo.theme/with-theme view-internal))
|
|
@ -21,12 +21,19 @@
|
||||||
(defn get-keypair-data
|
(defn get-keypair-data
|
||||||
[name derivation-path]
|
[name derivation-path]
|
||||||
[{:title (keypair-string name)
|
[{:title (keypair-string name)
|
||||||
:button-props {:title (i18n/label :t/edit)}
|
|
||||||
:left-icon :i/placeholder
|
:left-icon :i/placeholder
|
||||||
|
:action :button
|
||||||
|
:action-props {:on-press #(js/alert "Button pressed!")
|
||||||
|
:button-text (i18n/label :t/edit)
|
||||||
|
:alignment :flex-start}
|
||||||
:description :text
|
:description :text
|
||||||
:description-props {:text (i18n/label :t/on-device)}}
|
:description-props {:text (i18n/label :t/on-device)}}
|
||||||
{:title (i18n/label :t/derivation-path)
|
{:title (i18n/label :t/derivation-path)
|
||||||
:button-props {:title (i18n/label :t/edit)}
|
:action :button
|
||||||
|
:action-props {:on-press #(rf/dispatch [:navigate-to :wallet-edit-derivation-path])
|
||||||
|
:button-text (i18n/label :t/edit)
|
||||||
|
:icon-left :i/placeholder
|
||||||
|
:alignment :flex-start}
|
||||||
:left-icon :i/derivated-path
|
:left-icon :i/derivated-path
|
||||||
:description :text
|
:description :text
|
||||||
:description-props {:text derivation-path}}])
|
:description-props {:text derivation-path}}])
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
(ns status-im2.core-spec
|
(ns status-im2.core-spec
|
||||||
(:require
|
(:require
|
||||||
[status-im2.contexts.chat.messages.content.audio.component-spec]
|
[status-im2.contexts.chat.messages.content.audio.component-spec]
|
||||||
[status-im2.contexts.communities.actions.community-options.component-spec]))
|
[status-im2.contexts.communities.actions.community-options.component-spec]
|
||||||
|
[status-im2.contexts.wallet.create-account.edit-derivation-path.component-spec]))
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
[status-im2.contexts.wallet.account.view :as wallet-accounts]
|
[status-im2.contexts.wallet.account.view :as wallet-accounts]
|
||||||
[status-im2.contexts.wallet.address-watch.view :as wallet-address-watch]
|
[status-im2.contexts.wallet.address-watch.view :as wallet-address-watch]
|
||||||
[status-im2.contexts.wallet.collectible.view :as wallet-collectible]
|
[status-im2.contexts.wallet.collectible.view :as wallet-collectible]
|
||||||
|
[status-im2.contexts.wallet.create-account.edit-derivation-path.view :as wallet-edit-derivation-path]
|
||||||
[status-im2.contexts.wallet.create-account.view :as wallet-create-account]
|
[status-im2.contexts.wallet.create-account.view :as wallet-create-account]
|
||||||
[status-im2.contexts.wallet.edit-account.view :as wallet-edit-account]
|
[status-im2.contexts.wallet.edit-account.view :as wallet-edit-account]
|
||||||
[status-im2.contexts.wallet.saved-address.view :as wallet-saved-address]
|
[status-im2.contexts.wallet.saved-address.view :as wallet-saved-address]
|
||||||
|
@ -258,6 +259,9 @@
|
||||||
{:name :wallet-create-account
|
{:name :wallet-create-account
|
||||||
:component wallet-create-account/view}
|
:component wallet-create-account/view}
|
||||||
|
|
||||||
|
{:name :wallet-edit-derivation-path
|
||||||
|
:component wallet-edit-derivation-path/view}
|
||||||
|
|
||||||
{:name :wallet-saved-address
|
{:name :wallet-saved-address
|
||||||
:component wallet-saved-address/view}
|
:component wallet-saved-address/view}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,13 @@ jest.mock('react-native-blob-util', () => ({
|
||||||
|
|
||||||
jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock'));
|
jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock'));
|
||||||
|
|
||||||
|
jest.mock('react-native-static-safe-area-insets', () => ({
|
||||||
|
default: {
|
||||||
|
safeAreaInsetsTop: 0,
|
||||||
|
safeAreaInsetsBottom: 0,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
NativeModules.ReactLocalization = {
|
NativeModules.ReactLocalization = {
|
||||||
language: 'en',
|
language: 'en',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
|
|
|
@ -2366,5 +2366,12 @@
|
||||||
"network-preferences-desc": "Select which network this address is happy to receive funds on",
|
"network-preferences-desc": "Select which network this address is happy to receive funds on",
|
||||||
"layer-2": "Layer 2",
|
"layer-2": "Layer 2",
|
||||||
"manage-tokens": "Manage tokens",
|
"manage-tokens": "Manage tokens",
|
||||||
"sign transactions": "sign transactions"
|
"sign transactions": "sign transactions",
|
||||||
|
"edit-derivation-path": "Edit derivation path",
|
||||||
|
"path-format": "Path format",
|
||||||
|
"derivation-path": "Derivation path",
|
||||||
|
"reset": "Reset",
|
||||||
|
"reveal-address": "Reveal address",
|
||||||
|
"derive-addresses": "Derive addresses",
|
||||||
|
"address-activity": "This address has activity"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue