Edit derivation path (#17741)

This commit is contained in:
Nikolay 2023-11-01 16:04:21 +03:00 committed by GitHub
parent 716007dc3c
commit 94a3e266a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 294 additions and 38 deletions

View File

@ -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))))

View File

@ -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
(merge
{:size 40 {:size 40
:background (when scroll? :blur) :background (when scroll? :blur)
:container-style style/button-container-2-actions :container-style style/button-container-2-actions
:type button-two-type :theme theme
:on-press button-two-press} button-two-label]) :accessibility-label :button-two}
button-two-props)
button-two-label])
[button/button [button/button
(merge
{:size 40 {:size 40
:container-style style/button-container :container-style style/button-container
:type button-one-type
:disabled? disabled?
:background (when scroll? :blur) :background (when scroll? :blur)
:on-press button-one-press :theme theme
:accessibility-label :button-one} button-one-label]] :accessibility-label :button-one}
button-one-props)
button-one-label]]
(when description (when description
[text/text [text/text
{:size :paragraph-2 {:size :paragraph-2

View File

@ -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

View File

@ -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)

View File

@ -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))

View File

@ -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)))

View File

@ -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))))))

View File

@ -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})

View File

@ -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))

View File

@ -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}}])

View File

@ -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]))

View File

@ -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}

View File

@ -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',

View File

@ -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"
} }