feat(wallet): Add new saved address from wallet settings (#20304)
This commit adds flow for adding new saved addresses from wallet settings Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
This commit is contained in:
parent
00d288fb94
commit
577dc16188
|
@ -44,14 +44,14 @@
|
||||||
:monospace? - boolean (default: false) - use monospace font
|
:monospace? - boolean (default: false) - use monospace font
|
||||||
:lowercase? - boolean (default: false) - lowercase text
|
:lowercase? - boolean (default: false) - lowercase text
|
||||||
:neutral? - boolean (default: false) - use neutral colors variant"
|
:neutral? - boolean (default: false) - use neutral colors variant"
|
||||||
[{:keys [full-name customization-color size monospace? lowercase? neutral?]
|
[{:keys [full-name customization-color size monospace? lowercase? neutral? container-style]
|
||||||
:or {size biggest-possible}}]
|
:or {size biggest-possible}}]
|
||||||
(let [theme (quo.theme/use-theme)
|
(let [theme (quo.theme/use-theme)
|
||||||
circle-size (:size (size properties))
|
circle-size (:size (size properties))
|
||||||
small? (check-if-size-small size)
|
small? (check-if-size-small size)
|
||||||
initials (utils.string/get-initials full-name (if small? 1 2))]
|
initials (utils.string/get-initials full-name (if small? 1 2))]
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style (style/container circle-size customization-color neutral? theme)}
|
{:style (merge (style/container circle-size customization-color neutral? theme) container-style)}
|
||||||
[text/text
|
[text/text
|
||||||
{:accessibility-label :wallet-user-avatar
|
{:accessibility-label :wallet-user-avatar
|
||||||
:size (:font-size (size properties))
|
:size (:font-size (size properties))
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
(ns status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.style
|
||||||
|
(:require [quo.foundations.colors :as colors]))
|
||||||
|
|
||||||
|
(def header-container
|
||||||
|
{:padding-bottom 8})
|
||||||
|
|
||||||
|
(def input-container
|
||||||
|
{:flex-direction :row
|
||||||
|
:margin-horizontal 20})
|
||||||
|
|
||||||
|
(def input
|
||||||
|
{:flex 1
|
||||||
|
:margin-right 12})
|
||||||
|
|
||||||
|
(def scan-button
|
||||||
|
{:margin-top 26})
|
||||||
|
|
||||||
|
(def info-message
|
||||||
|
{:margin-top 8
|
||||||
|
:margin-left 20})
|
||||||
|
|
||||||
|
(def existing-saved-address-container
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:padding-vertical 12})
|
||||||
|
|
||||||
|
(def existing-saved-address-text
|
||||||
|
{:color colors/white-opa-40})
|
||||||
|
|
||||||
|
(def saved-address-item
|
||||||
|
{:margin-top 4})
|
|
@ -0,0 +1,174 @@
|
||||||
|
(ns status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.view
|
||||||
|
(:require
|
||||||
|
[clojure.string :as string]
|
||||||
|
[quo.core :as quo]
|
||||||
|
[react-native.clipboard :as clipboard]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[react-native.safe-area :as safe-area]
|
||||||
|
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||||
|
[status-im.common.not-implemented :as not-implemented]
|
||||||
|
[status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.style :as style]
|
||||||
|
[status-im.contexts.wallet.common.validation :as validation]
|
||||||
|
[utils.i18n :as i18n]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(defn- navigate-back
|
||||||
|
[]
|
||||||
|
(rf/dispatch [:navigate-back]))
|
||||||
|
|
||||||
|
(defn- validate-input
|
||||||
|
[account-addresses saved-addresses user-input]
|
||||||
|
(cond
|
||||||
|
(or (nil? user-input) (= user-input ""))
|
||||||
|
nil
|
||||||
|
|
||||||
|
(contains? saved-addresses user-input)
|
||||||
|
:existing-saved-address
|
||||||
|
|
||||||
|
(contains? account-addresses user-input)
|
||||||
|
:own-account
|
||||||
|
|
||||||
|
(not
|
||||||
|
(or (validation/eth-address? user-input)
|
||||||
|
(validation/ens-name? user-input)))
|
||||||
|
:invalid-address-or-ens))
|
||||||
|
|
||||||
|
(defn- address-input
|
||||||
|
[{:keys [input-value on-change-text paste-into-input clear-input]}]
|
||||||
|
(let [empty-input? (string/blank? input-value)]
|
||||||
|
[rn/view {:style style/input-container}
|
||||||
|
[quo/input
|
||||||
|
{:accessibility-label :add-address-to-save
|
||||||
|
:placeholder (i18n/label :t/address-placeholder)
|
||||||
|
:container-style style/input
|
||||||
|
:blur? true
|
||||||
|
:label (i18n/label :t/address-or-ens-name)
|
||||||
|
:auto-capitalize :none
|
||||||
|
:multiline? true
|
||||||
|
:on-clear clear-input
|
||||||
|
:return-key-type :done
|
||||||
|
:clearable? (not empty-input?)
|
||||||
|
:on-change-text on-change-text
|
||||||
|
:button (when empty-input?
|
||||||
|
{:on-press paste-into-input
|
||||||
|
:text (i18n/label :t/paste)})
|
||||||
|
:value input-value}]
|
||||||
|
[quo/button
|
||||||
|
{:type :outline
|
||||||
|
:on-press not-implemented/alert
|
||||||
|
:container-style style/scan-button
|
||||||
|
:background :blur
|
||||||
|
:size 40
|
||||||
|
:icon-only? true}
|
||||||
|
:i/scan]]))
|
||||||
|
|
||||||
|
(defn- error-view
|
||||||
|
[{:keys [error]}]
|
||||||
|
(let [error-msg (condp = error
|
||||||
|
:existing-saved-address
|
||||||
|
(i18n/label :t/this-address-is-already-saved)
|
||||||
|
|
||||||
|
:own-account
|
||||||
|
(i18n/label :t/you-cannot-add-your-own-account-as-a-saved-address)
|
||||||
|
|
||||||
|
:invalid-address-or-ens
|
||||||
|
(i18n/label :t/this-is-not-an-eth-address-or-ens-name)
|
||||||
|
|
||||||
|
:ens-not-registered
|
||||||
|
(i18n/label :t/this-ens-name-is-not-registered-yet)
|
||||||
|
nil)]
|
||||||
|
(when error-msg
|
||||||
|
[quo/info-message
|
||||||
|
{:accessibility-label :error-message
|
||||||
|
:size :default
|
||||||
|
:icon :i/info
|
||||||
|
:type :error
|
||||||
|
:style style/info-message}
|
||||||
|
error-msg])))
|
||||||
|
|
||||||
|
(defn- existing-saved-address
|
||||||
|
[{:keys [address]}]
|
||||||
|
(let [{:keys [name customization-color chain-short-names ens has-ens?]}
|
||||||
|
(rf/sub [:wallet/saved-address-by-address
|
||||||
|
address])]
|
||||||
|
[rn/view {:style style/existing-saved-address-container}
|
||||||
|
[quo/text
|
||||||
|
{:size :paragraph-1
|
||||||
|
:weight :medium
|
||||||
|
:style style/existing-saved-address-text}
|
||||||
|
(i18n/label :t/existing-saved-address)]
|
||||||
|
[quo/saved-address
|
||||||
|
{:blur? true
|
||||||
|
:active-state? true
|
||||||
|
:user-props {:name name
|
||||||
|
:address (str chain-short-names address)
|
||||||
|
:ens (when has-ens? ens)
|
||||||
|
:customization-color customization-color
|
||||||
|
:blur? true}
|
||||||
|
:container-style style/saved-address-item}]]))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[]
|
||||||
|
(let [profile-color (rf/sub [:profile/customization-color])
|
||||||
|
accounts-addresses (rf/sub [:wallet/addresses])
|
||||||
|
saved-addresses-addresses (rf/sub [:wallet/saved-addresses-addresses])
|
||||||
|
[input-value set-input-value] (rn/use-state nil)
|
||||||
|
[error set-error] (rn/use-state nil)
|
||||||
|
error? (some? error)
|
||||||
|
validate #(validate-input accounts-addresses
|
||||||
|
saved-addresses-addresses
|
||||||
|
%)
|
||||||
|
clear-input (rn/use-callback
|
||||||
|
(fn []
|
||||||
|
(set-input-value nil)
|
||||||
|
(set-error nil)))
|
||||||
|
on-change-text (rn/use-callback
|
||||||
|
(fn [new-value]
|
||||||
|
(let [lowercase-value (string/lower-case new-value)]
|
||||||
|
(set-error (validate lowercase-value))
|
||||||
|
(set-input-value lowercase-value))))
|
||||||
|
paste-into-input (rn/use-callback #(clipboard/get-string
|
||||||
|
(fn [clipboard-text]
|
||||||
|
(on-change-text clipboard-text))))
|
||||||
|
on-press-continue (rn/use-callback
|
||||||
|
(fn []
|
||||||
|
(rf/dispatch [:wallet/set-address-to-save
|
||||||
|
{:address input-value}])
|
||||||
|
(rf/dispatch
|
||||||
|
[:navigate-to-within-stack
|
||||||
|
[:screen/settings.save-address
|
||||||
|
:screen/settings.add-address-to-save]]))
|
||||||
|
[input-value])]
|
||||||
|
(rn/use-unmount #(rf/dispatch [:wallet/clear-address-to-save]))
|
||||||
|
[quo/overlay {:type :shell}
|
||||||
|
[floating-button-page/view
|
||||||
|
{:footer-container-padding 0
|
||||||
|
:header [quo/page-nav
|
||||||
|
{:type :no-title
|
||||||
|
:icon-name :i/close
|
||||||
|
:behind-overlay? true
|
||||||
|
:on-press navigate-back
|
||||||
|
:margin-top (safe-area/get-top)
|
||||||
|
:accessibility-label :add-address-to-save-page-nav}]
|
||||||
|
:footer [quo/button
|
||||||
|
{:customization-color profile-color
|
||||||
|
:disabled? (or (string/blank? input-value)
|
||||||
|
error?)
|
||||||
|
:on-press on-press-continue}
|
||||||
|
(i18n/label :t/continue)]}
|
||||||
|
[quo/page-top
|
||||||
|
{:container-style style/header-container
|
||||||
|
:blur? true
|
||||||
|
:title (i18n/label :t/add-address)
|
||||||
|
:description :text
|
||||||
|
:description-text (i18n/label :t/add-address-to-save-description)}]
|
||||||
|
[address-input
|
||||||
|
{:input-value input-value
|
||||||
|
:on-change-text on-change-text
|
||||||
|
:paste-into-input paste-into-input
|
||||||
|
:clear-input clear-input}]
|
||||||
|
(when error?
|
||||||
|
[:<>
|
||||||
|
[error-view {:error error}]
|
||||||
|
(when (= error :existing-saved-address)
|
||||||
|
[existing-saved-address {:address input-value}])])]]))
|
|
@ -1,20 +1,12 @@
|
||||||
(ns status-im.contexts.settings.wallet.saved-addresses.events
|
(ns status-im.contexts.settings.wallet.saved-addresses.events
|
||||||
(:require
|
(:require
|
||||||
[status-im.constants :as constants]
|
|
||||||
[status-im.contexts.wallet.data-store :as data-store]
|
[status-im.contexts.wallet.data-store :as data-store]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn save-address
|
(defn save-address
|
||||||
[{:keys [db]}
|
[{:keys [db]}
|
||||||
[{:keys [address name customization-color on-success on-error chain-short-names ens]
|
[{:keys [address name customization-color on-success on-error chain-short-names ens]}]]
|
||||||
:or {on-success (fn [])
|
|
||||||
on-error (fn [])
|
|
||||||
name ""
|
|
||||||
customization-color constants/account-default-customization-color
|
|
||||||
ens ""
|
|
||||||
;; the chain short names should be a string like eth: or eth:arb:oeth:
|
|
||||||
chain-short-names (str constants/mainnet-short-name ":")}}]]
|
|
||||||
(let [test-networks-enabled? (boolean (get-in db [:profile/profile :test-networks-enabled?]))
|
(let [test-networks-enabled? (boolean (get-in db [:profile/profile :test-networks-enabled?]))
|
||||||
address-to-save {:address address
|
address-to-save {:address address
|
||||||
:name name
|
:name name
|
||||||
|
@ -93,3 +85,39 @@
|
||||||
:on-error [:wallet/delete-saved-address-failed]}]]]}))
|
:on-error [:wallet/delete-saved-address-failed]}]]]}))
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet/delete-saved-address delete-saved-address)
|
(rf/reg-event-fx :wallet/delete-saved-address delete-saved-address)
|
||||||
|
|
||||||
|
(defn add-saved-address-success
|
||||||
|
[_ [toast-message]]
|
||||||
|
{:fx [[:dispatch [:wallet/get-saved-addresses]]
|
||||||
|
[:dispatch [:navigate-back-to :screen/settings.saved-addresses]]
|
||||||
|
[:dispatch-later
|
||||||
|
{:ms 100
|
||||||
|
:dispatch [:toasts/upsert
|
||||||
|
{:type :positive
|
||||||
|
:theme :dark
|
||||||
|
:text toast-message}]}]]})
|
||||||
|
|
||||||
|
(rf/reg-event-fx :wallet/add-saved-address-success add-saved-address-success)
|
||||||
|
|
||||||
|
(defn add-saved-address-failed
|
||||||
|
[_ [error]]
|
||||||
|
{:fx [[:dispatch [:wallet/saved-addresses-rpc-error :add-save-address error]]
|
||||||
|
[:dispatch
|
||||||
|
[:toasts/upsert
|
||||||
|
{:type :negative
|
||||||
|
:theme :dark
|
||||||
|
:text error}]]]})
|
||||||
|
|
||||||
|
(rf/reg-event-fx :wallet/add-saved-address-failed add-saved-address-failed)
|
||||||
|
|
||||||
|
(defn set-address-to-save
|
||||||
|
[{:keys [db]} [args]]
|
||||||
|
{:db (assoc-in db [:wallet :ui :saved-address] args)})
|
||||||
|
|
||||||
|
(rf/reg-event-fx :wallet/set-address-to-save set-address-to-save)
|
||||||
|
|
||||||
|
(defn clear-address-to-save
|
||||||
|
[{:keys [db]}]
|
||||||
|
{:db (update-in db [:wallet :ui] dissoc :saved-address)})
|
||||||
|
|
||||||
|
(rf/reg-event-fx :wallet/clear-address-to-save clear-address-to-save)
|
||||||
|
|
|
@ -150,3 +150,20 @@
|
||||||
:on-success [:wallet/delete-saved-address-success toast-message]
|
:on-success [:wallet/delete-saved-address-success toast-message]
|
||||||
:on-error [:wallet/delete-saved-address-failed]}]]]]
|
:on-error [:wallet/delete-saved-address-failed]}]]]]
|
||||||
(is (match? expected-fx result-fx)))))
|
(is (match? expected-fx result-fx)))))
|
||||||
|
|
||||||
|
(deftest add-saved-address-success-test
|
||||||
|
(testing "add saved address success test - gets saved addresses, dismiss modals and dispatch toast"
|
||||||
|
(let [cofx {:db {}}
|
||||||
|
toast-message "Address saved"
|
||||||
|
effects (events/add-saved-address-success cofx [toast-message])
|
||||||
|
result-fx (:fx effects)
|
||||||
|
expected-fx [[:dispatch [:wallet/get-saved-addresses]]
|
||||||
|
[:dispatch [:navigate-back-to :screen/settings.saved-addresses]]
|
||||||
|
[:dispatch-later
|
||||||
|
{:ms 100
|
||||||
|
:dispatch [:toasts/upsert
|
||||||
|
{:type :positive
|
||||||
|
:theme :dark
|
||||||
|
:text toast-message}]}]]]
|
||||||
|
(is (= (count result-fx) 3))
|
||||||
|
(is (match? expected-fx result-fx)))))
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
(ns status-im.contexts.settings.wallet.saved-addresses.save-address.style)
|
||||||
|
|
||||||
|
(def title-input
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:padding-top 12
|
||||||
|
:padding-bottom 16})
|
||||||
|
|
||||||
|
(def avatar
|
||||||
|
{:margin-horizontal 20
|
||||||
|
:margin-top 12})
|
||||||
|
|
||||||
|
(def color-picker-top-divider
|
||||||
|
{:margin-bottom 12})
|
||||||
|
|
||||||
|
(def section-label
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:padding-bottom 4})
|
||||||
|
|
||||||
|
(def color-picker
|
||||||
|
{:padding-horizontal 20
|
||||||
|
:padding-vertical 12})
|
||||||
|
|
||||||
|
(def color-picker-bottom-divider
|
||||||
|
{:margin-top 8
|
||||||
|
:margin-bottom 12})
|
||||||
|
|
||||||
|
(def data-item
|
||||||
|
{:margin-horizontal 20
|
||||||
|
:padding-vertical 8
|
||||||
|
:margin-top 8
|
||||||
|
:margin-bottom 12})
|
|
@ -0,0 +1,113 @@
|
||||||
|
(ns status-im.contexts.settings.wallet.saved-addresses.save-address.view
|
||||||
|
(:require
|
||||||
|
[clojure.string :as string]
|
||||||
|
[quo.core :as quo]
|
||||||
|
[quo.foundations.colors :as colors]
|
||||||
|
[quo.theme]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[react-native.safe-area :as safe-area]
|
||||||
|
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||||
|
[status-im.common.not-implemented :as not-implemented]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.contexts.settings.wallet.saved-addresses.save-address.style :as style]
|
||||||
|
[utils.i18n :as i18n]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(defn- navigate-back
|
||||||
|
[]
|
||||||
|
(rf/dispatch [:navigate-back]))
|
||||||
|
|
||||||
|
(defn- extract-address
|
||||||
|
[address]
|
||||||
|
(re-find constants/regx-address-contains address))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[]
|
||||||
|
(let [{:keys [address]} (rf/sub [:wallet/saved-address])
|
||||||
|
[address-label set-address-label] (rn/use-state "")
|
||||||
|
[address-color set-address-color] (rn/use-state (rand-nth colors/account-colors))
|
||||||
|
placeholder (i18n/label :t/address-name)
|
||||||
|
on-press-save (rn/use-callback
|
||||||
|
(fn []
|
||||||
|
(let [address-without-prefix (extract-address address)]
|
||||||
|
(rf/dispatch [:wallet/save-address
|
||||||
|
{:on-success
|
||||||
|
[:wallet/add-saved-address-success
|
||||||
|
(i18n/label :t/address-saved)]
|
||||||
|
:on-error
|
||||||
|
[:wallet/add-saved-address-failed]
|
||||||
|
:name address-label
|
||||||
|
:address address-without-prefix
|
||||||
|
:customization-color address-color}])))
|
||||||
|
[address address-label address-color])]
|
||||||
|
[quo/overlay {:type :shell}
|
||||||
|
[floating-button-page/view
|
||||||
|
{:footer-container-padding 0
|
||||||
|
:header [quo/page-nav
|
||||||
|
{:type :no-title
|
||||||
|
:background :blur
|
||||||
|
:icon-name :i/arrow-left
|
||||||
|
:on-press navigate-back
|
||||||
|
:margin-top (safe-area/get-top)
|
||||||
|
:accessibility-label :save-address-page-nav}]
|
||||||
|
:footer [quo/button
|
||||||
|
{:accessibility-label :save-address-button
|
||||||
|
:type :primary
|
||||||
|
:customization-color address-color
|
||||||
|
:disabled? (string/blank? address-label)
|
||||||
|
:on-press on-press-save}
|
||||||
|
(i18n/label :t/save-address)]
|
||||||
|
:customization-color address-color
|
||||||
|
:gradient-cover? true}
|
||||||
|
[quo/wallet-user-avatar
|
||||||
|
{:full-name (if (string/blank? address-label)
|
||||||
|
placeholder
|
||||||
|
address-label)
|
||||||
|
:customization-color address-color
|
||||||
|
:blur? true
|
||||||
|
:size :size-80
|
||||||
|
:container-style style/avatar}]
|
||||||
|
[quo/title-input
|
||||||
|
{:blur? true
|
||||||
|
:auto-focus true
|
||||||
|
:max-length 24
|
||||||
|
:size :heading-1
|
||||||
|
:placeholder placeholder
|
||||||
|
:default-value address-label
|
||||||
|
:on-change-text set-address-label
|
||||||
|
:customization-color address-color
|
||||||
|
:container-style style/title-input}]
|
||||||
|
[quo/divider-line
|
||||||
|
{:blur? true
|
||||||
|
:container-style style/color-picker-top-divider}]
|
||||||
|
[quo/section-label
|
||||||
|
{:section (i18n/label :t/colour)
|
||||||
|
:blur? true
|
||||||
|
:container-style style/section-label}]
|
||||||
|
[quo/color-picker
|
||||||
|
{:default-selected address-color
|
||||||
|
:on-change set-address-color
|
||||||
|
:blur? true
|
||||||
|
:container-style style/color-picker}]
|
||||||
|
[quo/divider-line
|
||||||
|
{:blur? true
|
||||||
|
:container-style style/color-picker-bottom-divider}]
|
||||||
|
[quo/data-item
|
||||||
|
{:status :default
|
||||||
|
:size :default
|
||||||
|
:subtitle-type :default
|
||||||
|
:label :none
|
||||||
|
:blur? true
|
||||||
|
:icon-right? true
|
||||||
|
:right-icon :i/advanced
|
||||||
|
:card? true
|
||||||
|
:title (i18n/label :t/address)
|
||||||
|
:custom-subtitle (rn/use-callback
|
||||||
|
(fn []
|
||||||
|
[quo/address-text
|
||||||
|
{:full-address? true
|
||||||
|
:address address
|
||||||
|
:format :long}])
|
||||||
|
[address])
|
||||||
|
:on-press not-implemented/alert
|
||||||
|
:container-style style/data-item}]]]))
|
|
@ -36,7 +36,8 @@
|
||||||
:customization-color customization-color}])}])
|
:customization-color customization-color}])}])
|
||||||
[address chain-short-names full-address name customization-color])]
|
[address chain-short-names full-address name customization-color])]
|
||||||
[quo/saved-address
|
[quo/saved-address
|
||||||
{:user-props {:name name
|
{:blur? true
|
||||||
|
:user-props {:name name
|
||||||
:address full-address
|
:address full-address
|
||||||
:ens (when has-ens? ens)
|
:ens (when has-ens? ens)
|
||||||
:customization-color customization-color
|
:customization-color customization-color
|
||||||
|
@ -59,6 +60,11 @@
|
||||||
[]
|
[]
|
||||||
(rf/dispatch [:navigate-back]))
|
(rf/dispatch [:navigate-back]))
|
||||||
|
|
||||||
|
(defn- add-address-to-save
|
||||||
|
[]
|
||||||
|
(rf/dispatch [:navigate-to-within-stack
|
||||||
|
[:screen/settings.add-address-to-save :screen/settings.saved-addresses]]))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[]
|
[]
|
||||||
(let [inset-top (safe-area/get-top)
|
(let [inset-top (safe-area/get-top)
|
||||||
|
@ -77,6 +83,7 @@
|
||||||
{:title (i18n/label :t/saved-addresses)
|
{:title (i18n/label :t/saved-addresses)
|
||||||
:accessibility-label :saved-addresses-header
|
:accessibility-label :saved-addresses-header
|
||||||
:right :action
|
:right :action
|
||||||
|
:on-press add-address-to-save
|
||||||
:customization-color customization-color
|
:customization-color customization-color
|
||||||
:icon :i/add}]]
|
:icon :i/add}]]
|
||||||
[rn/section-list
|
[rn/section-list
|
||||||
|
|
|
@ -150,7 +150,7 @@
|
||||||
(i18n/label :t/continue)]}
|
(i18n/label :t/continue)]}
|
||||||
[quo/page-top
|
[quo/page-top
|
||||||
{:container-style style/header-container
|
{:container-style style/header-container
|
||||||
:title (i18n/label :t/add-address)
|
:title (i18n/label :t/add-address-to-watch)
|
||||||
:description :text
|
:description :text
|
||||||
:description-text (i18n/label :t/enter-eth)}]
|
:description-text (i18n/label :t/enter-eth)}]
|
||||||
[:f> address-input
|
[:f> address-input
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.create-account])}
|
:on-press #(rf/dispatch [:navigate-to :screen/wallet.create-account])}
|
||||||
{:icon :i/reveal
|
{:icon :i/reveal
|
||||||
:accessibility-label :add-a-contact
|
:accessibility-label :add-a-contact
|
||||||
:label (i18n/label :t/add-address)
|
:label (i18n/label :t/add-address-to-watch)
|
||||||
:sub-label (i18n/label :t/add-address-description)
|
:sub-label (i18n/label :t/add-address-to-watch-description)
|
||||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.add-address-to-watch])
|
:on-press #(rf/dispatch [:navigate-to :screen/wallet.add-address-to-watch])
|
||||||
:add-divider? true}]]])
|
:add-divider? true}]]])
|
||||||
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
(ns status-im.contexts.wallet.save-address.style)
|
|
||||||
|
|
||||||
(def title-input-container
|
|
||||||
{:padding-horizontal 20
|
|
||||||
:padding-top 12
|
|
||||||
:padding-bottom 16})
|
|
||||||
|
|
||||||
(def account-avatar-container
|
|
||||||
{:padding-horizontal 20
|
|
||||||
:padding-top 12})
|
|
||||||
|
|
||||||
(def color-picker-top-divider
|
|
||||||
{:margin-bottom 12})
|
|
||||||
|
|
||||||
(def color-picker-container
|
|
||||||
{:padding-vertical 12})
|
|
||||||
|
|
||||||
(def section-container
|
|
||||||
{:padding-horizontal 20
|
|
||||||
:padding-bottom 4})
|
|
||||||
|
|
||||||
(def color-picker
|
|
||||||
{:padding-horizontal 20
|
|
||||||
:padding-top 12})
|
|
||||||
|
|
||||||
(def color-picker-bottom-divider
|
|
||||||
{:padding-top 8
|
|
||||||
:padding-bottom 12})
|
|
||||||
|
|
||||||
(def save-address-button
|
|
||||||
{:padding-horizontal 20})
|
|
||||||
|
|
||||||
(def data-item
|
|
||||||
{:margin-horizontal 20
|
|
||||||
:padding-vertical 8})
|
|
||||||
|
|
||||||
(def address-container
|
|
||||||
{:padding-top 8
|
|
||||||
:padding-bottom 12})
|
|
|
@ -1,90 +0,0 @@
|
||||||
(ns status-im.contexts.wallet.save-address.view
|
|
||||||
(:require
|
|
||||||
[clojure.string :as string]
|
|
||||||
[quo.core :as quo]
|
|
||||||
[quo.theme]
|
|
||||||
[react-native.core :as rn]
|
|
||||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
|
||||||
[status-im.contexts.wallet.save-address.style :as style]
|
|
||||||
[status-im.contexts.wallet.sheets.network-preferences.view
|
|
||||||
:as network-preferences]
|
|
||||||
[utils.i18n :as i18n]
|
|
||||||
[utils.re-frame :as rf]))
|
|
||||||
|
|
||||||
(defn- address-view
|
|
||||||
[]
|
|
||||||
(let [network-details (rf/sub [:wallet/network-preference-details])
|
|
||||||
address (rf/sub [:wallet/wallet-send-to-address])]
|
|
||||||
[rn/view {:style style/address-container}
|
|
||||||
[quo/data-item
|
|
||||||
{:status :default
|
|
||||||
:size :default
|
|
||||||
:subtitle-type :default
|
|
||||||
:label :none
|
|
||||||
:blur? false
|
|
||||||
:icon-right? true
|
|
||||||
:right-icon :i/advanced
|
|
||||||
:card? true
|
|
||||||
:title (i18n/label :t/address)
|
|
||||||
:custom-subtitle (rn/use-callback
|
|
||||||
(fn [] [quo/address-text
|
|
||||||
{:networks network-details
|
|
||||||
:address address
|
|
||||||
:format :long}]))
|
|
||||||
:on-press (rn/use-callback
|
|
||||||
(fn []
|
|
||||||
(rf/dispatch [:show-bottom-sheet
|
|
||||||
{:content
|
|
||||||
(fn []
|
|
||||||
[network-preferences/view
|
|
||||||
{:on-save (fn [])}])}])))
|
|
||||||
:container-style style/data-item}]]))
|
|
||||||
|
|
||||||
(defn view
|
|
||||||
[]
|
|
||||||
(let [[address-label set-address-label] (rn/use-state "")
|
|
||||||
[address-color set-address-color] (rn/use-state :blue)
|
|
||||||
placeholder (i18n/label :t/address-name)]
|
|
||||||
[floating-button-page/view
|
|
||||||
{:footer-container-padding 0
|
|
||||||
:header [quo/page-nav
|
|
||||||
{:type :no-title
|
|
||||||
:background :blur
|
|
||||||
:icon-name :i/close
|
|
||||||
:on-press (rn/use-callback #(rf/dispatch [:navigate-back]))
|
|
||||||
:accessibility-label :save-address-top-bar}]
|
|
||||||
:footer [quo/button
|
|
||||||
{:accessibility-label :save-address-button
|
|
||||||
:type :primary
|
|
||||||
:container-style style/save-address-button}
|
|
||||||
(i18n/label :t/save-address)]
|
|
||||||
:customization-color address-color
|
|
||||||
:gradient-cover? true}
|
|
||||||
[rn/view
|
|
||||||
{:style style/account-avatar-container}
|
|
||||||
[quo/user-avatar
|
|
||||||
{:full-name (if (string/blank? address-label)
|
|
||||||
placeholder
|
|
||||||
address-label)
|
|
||||||
:customization-color address-color
|
|
||||||
:size :big}]]
|
|
||||||
[quo/title-input
|
|
||||||
{:blur? true
|
|
||||||
:auto-focus true
|
|
||||||
:max-length 24
|
|
||||||
:size :heading-1
|
|
||||||
:placeholder placeholder
|
|
||||||
:default-value address-label
|
|
||||||
:on-change-text set-address-label
|
|
||||||
:customization-color address-color
|
|
||||||
:container-style style/title-input-container}]
|
|
||||||
[quo/divider-line {:container-style style/color-picker-top-divider}]
|
|
||||||
[quo/section-label
|
|
||||||
{:section (i18n/label :t/colour)
|
|
||||||
:container-style style/section-container}]
|
|
||||||
[quo/color-picker
|
|
||||||
{:default-selected address-color
|
|
||||||
:on-change set-address-color
|
|
||||||
:container-style style/color-picker}]
|
|
||||||
[quo/divider-line {:container-style style/color-picker-bottom-divider}]
|
|
||||||
[address-view]]))
|
|
|
@ -36,7 +36,9 @@
|
||||||
:icon-left :i/contact-book
|
:icon-left :i/contact-book
|
||||||
:accessibility-label :save-address
|
:accessibility-label :save-address
|
||||||
:on-press (rn/use-callback
|
:on-press (rn/use-callback
|
||||||
#(rf/dispatch [:open-modal :screen/wallet.save-address]))}
|
#(rf/dispatch [:open-modal
|
||||||
|
:screen/settings.save-address
|
||||||
|
{:address send-to-address}]))}
|
||||||
:button-one-label (i18n/label :t/done)
|
:button-one-label (i18n/label :t/done)
|
||||||
:button-one-props {:customization-color color
|
:button-one-props {:customization-color color
|
||||||
:type :primary
|
:type :primary
|
||||||
|
|
|
@ -63,6 +63,9 @@
|
||||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.scan-qr.view :as scan-keypair-qr]
|
[status-im.contexts.settings.wallet.keypairs-and-accounts.scan-qr.view :as scan-keypair-qr]
|
||||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.view :as keypairs-and-accounts]
|
[status-im.contexts.settings.wallet.keypairs-and-accounts.view :as keypairs-and-accounts]
|
||||||
[status-im.contexts.settings.wallet.network-settings.view :as network-settings]
|
[status-im.contexts.settings.wallet.network-settings.view :as network-settings]
|
||||||
|
[status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.view :as
|
||||||
|
wallet-add-address-to-save]
|
||||||
|
[status-im.contexts.settings.wallet.saved-addresses.save-address.view :as wallet-save-address]
|
||||||
[status-im.contexts.settings.wallet.saved-addresses.view :as saved-addresses-settings]
|
[status-im.contexts.settings.wallet.saved-addresses.view :as saved-addresses-settings]
|
||||||
[status-im.contexts.settings.wallet.wallet-options.view :as wallet-options]
|
[status-im.contexts.settings.wallet.wallet-options.view :as wallet-options]
|
||||||
[status-im.contexts.shell.activity-center.view :as activity-center]
|
[status-im.contexts.shell.activity-center.view :as activity-center]
|
||||||
|
@ -98,7 +101,6 @@
|
||||||
[status-im.contexts.wallet.collectible.view :as wallet-collectible]
|
[status-im.contexts.wallet.collectible.view :as wallet-collectible]
|
||||||
[status-im.contexts.wallet.common.scan-account.view :as wallet-scan-address]
|
[status-im.contexts.wallet.common.scan-account.view :as wallet-scan-address]
|
||||||
[status-im.contexts.wallet.connected-dapps.view :as wallet-connected-dapps]
|
[status-im.contexts.wallet.connected-dapps.view :as wallet-connected-dapps]
|
||||||
[status-im.contexts.wallet.save-address.view :as wallet-save-address]
|
|
||||||
[status-im.contexts.wallet.send.from.view :as wallet-select-from]
|
[status-im.contexts.wallet.send.from.view :as wallet-select-from]
|
||||||
[status-im.contexts.wallet.send.select-address.view :as wallet-select-address]
|
[status-im.contexts.wallet.send.select-address.view :as wallet-select-address]
|
||||||
[status-im.contexts.wallet.send.select-asset.view :as wallet-select-asset]
|
[status-im.contexts.wallet.send.select-asset.view :as wallet-select-asset]
|
||||||
|
@ -450,10 +452,6 @@
|
||||||
:options options/transparent-screen-options
|
:options options/transparent-screen-options
|
||||||
:component wallet-share-address/view}
|
:component wallet-share-address/view}
|
||||||
|
|
||||||
{:name :screen/wallet.save-address
|
|
||||||
:options {:sheet? true}
|
|
||||||
:component wallet-save-address/view}
|
|
||||||
|
|
||||||
{:name :screen/wallet.send-input-amount
|
{:name :screen/wallet.send-input-amount
|
||||||
:options {:modalPresentationStyle :overCurrentContext
|
:options {:modalPresentationStyle :overCurrentContext
|
||||||
:insets {:top? true
|
:insets {:top? true
|
||||||
|
@ -540,6 +538,14 @@
|
||||||
:options options/transparent-modal-screen-options
|
:options options/transparent-modal-screen-options
|
||||||
:component network-settings/view}
|
:component network-settings/view}
|
||||||
|
|
||||||
|
{:name :screen/settings.save-address
|
||||||
|
:options options/transparent-modal-screen-options
|
||||||
|
:component wallet-save-address/view}
|
||||||
|
|
||||||
|
{:name :screen/settings.add-address-to-save
|
||||||
|
:options options/transparent-modal-screen-options
|
||||||
|
:component wallet-add-address-to-save/view}
|
||||||
|
|
||||||
{:name :screen/settings-messages
|
{:name :screen/settings-messages
|
||||||
:options options/transparent-modal-screen-options
|
:options options/transparent-modal-screen-options
|
||||||
:component settings.messages/view}
|
:component settings.messages/view}
|
||||||
|
|
|
@ -3,32 +3,49 @@
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[re-frame.core :as rf]))
|
[re-frame.core :as rf]))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/saved-address
|
||||||
|
:<- [:wallet/ui]
|
||||||
|
:-> :saved-address)
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet/saved-addresses
|
:wallet/saved-addresses
|
||||||
:<- [:wallet]
|
:<- [:wallet]
|
||||||
:-> :saved-addresses)
|
:-> :saved-addresses)
|
||||||
|
|
||||||
(rf/reg-sub
|
|
||||||
:wallet/address-saved?
|
|
||||||
:<- [:wallet]
|
|
||||||
(fn [wallet [address]]
|
|
||||||
(some #(= address (:address %))
|
|
||||||
(:saved-addresses wallet))))
|
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet/saved-addresses-by-network-mode
|
:wallet/saved-addresses-by-network-mode
|
||||||
:<- [:wallet/saved-addresses]
|
:<- [:wallet/saved-addresses]
|
||||||
:<- [:profile/test-networks-enabled?]
|
:<- [:profile/test-networks-enabled?]
|
||||||
(fn [[saved-addresses test-networks-enabled?]]
|
(fn [[saved-addresses test-networks-enabled?]]
|
||||||
(vals (get saved-addresses (if test-networks-enabled? :test :prod)))))
|
(get saved-addresses (if test-networks-enabled? :test :prod))))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/address-saved?
|
||||||
|
:<- [:wallet/saved-addresses-by-network-mode]
|
||||||
|
(fn [saved-addresses [_ address]]
|
||||||
|
(contains? saved-addresses address)))
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet/grouped-saved-addresses
|
:wallet/grouped-saved-addresses
|
||||||
:<- [:wallet/saved-addresses-by-network-mode]
|
:<- [:wallet/saved-addresses-by-network-mode]
|
||||||
(fn [saved-addresses]
|
(fn [saved-addresses]
|
||||||
(->> saved-addresses
|
(->> saved-addresses
|
||||||
|
vals
|
||||||
(sort-by :name)
|
(sort-by :name)
|
||||||
(group-by #(string/upper-case (first (:name %))))
|
(group-by #(string/upper-case (first (:name %))))
|
||||||
(map (fn [[k v]]
|
(map (fn [[k v]]
|
||||||
{:title k
|
{:title k
|
||||||
:data v})))))
|
:data v})))))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/saved-addresses-addresses
|
||||||
|
:<- [:wallet/saved-addresses-by-network-mode]
|
||||||
|
(fn [saved-addresses]
|
||||||
|
(-> saved-addresses keys set)))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/saved-address-by-address
|
||||||
|
:<- [:wallet/saved-addresses-by-network-mode]
|
||||||
|
(fn [saved-addresses [_ address]]
|
||||||
|
(get saved-addresses address)))
|
||||||
|
|
|
@ -91,7 +91,17 @@
|
||||||
#(-> %
|
#(-> %
|
||||||
(assoc-in [:wallet :saved-addresses] saved-addresses-db)
|
(assoc-in [:wallet :saved-addresses] saved-addresses-db)
|
||||||
(assoc-in [:profile/profile :test-networks-enabled?] true)))
|
(assoc-in [:profile/profile :test-networks-enabled?] true)))
|
||||||
(is (= (vals (:test saved-addresses-db)) (rf/sub [sub-name])))))
|
(is (= (:test saved-addresses-db) (rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/address-saved?
|
||||||
|
[sub-name]
|
||||||
|
(testing "returns boolean if given address is saved"
|
||||||
|
(swap! rf-db/app-db
|
||||||
|
#(-> %
|
||||||
|
(assoc-in [:wallet :saved-addresses] saved-addresses-db)
|
||||||
|
(assoc-in [:profile/profile :test-networks-enabled?] false)))
|
||||||
|
(is (true? (rf/sub [sub-name "0x1"])))
|
||||||
|
(is (false? (rf/sub [sub-name "0x3"])))))
|
||||||
|
|
||||||
(h/deftest-sub :wallet/grouped-saved-addresses
|
(h/deftest-sub :wallet/grouped-saved-addresses
|
||||||
[sub-name]
|
[sub-name]
|
||||||
|
@ -101,3 +111,22 @@
|
||||||
(assoc-in [:wallet :saved-addresses] saved-addresses-db)
|
(assoc-in [:wallet :saved-addresses] saved-addresses-db)
|
||||||
(assoc-in [:profile/profile :test-networks-enabled?] false)))
|
(assoc-in [:profile/profile :test-networks-enabled?] false)))
|
||||||
(is (= grouped-saved-addresses-data (rf/sub [sub-name])))))
|
(is (= grouped-saved-addresses-data (rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/saved-addresses-addresses
|
||||||
|
[sub-name]
|
||||||
|
(testing "returns saved addresses addresses set"
|
||||||
|
(swap! rf-db/app-db
|
||||||
|
#(-> %
|
||||||
|
(assoc-in [:wallet :saved-addresses] saved-addresses-db)
|
||||||
|
(assoc-in [:profile/profile :test-networks-enabled?] true)))
|
||||||
|
(is (= (-> saved-addresses-db :test keys set) (rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/saved-address-by-address
|
||||||
|
[sub-name]
|
||||||
|
(testing "returns a saved address"
|
||||||
|
(let [address "0x1"]
|
||||||
|
(swap! rf-db/app-db
|
||||||
|
#(-> %
|
||||||
|
(assoc-in [:wallet :saved-addresses] saved-addresses-db)
|
||||||
|
(assoc-in [:profile/profile :test-networks-enabled?] false)))
|
||||||
|
(is (= (get-in saved-addresses-db [:prod address]) (rf/sub [sub-name address]))))))
|
||||||
|
|
|
@ -2423,8 +2423,8 @@
|
||||||
"days": "Days",
|
"days": "Days",
|
||||||
"add-account": "Add account",
|
"add-account": "Add account",
|
||||||
"add-account-description": "Create new or import existing account",
|
"add-account-description": "Create new or import existing account",
|
||||||
"add-address": "Add address to watch",
|
"add-address-to-watch": "Add address to watch",
|
||||||
"add-address-description": "Watch a public address or ENS name",
|
"add-address-to-watch-description": "Watch a public address or ENS name",
|
||||||
"colour": "Colour",
|
"colour": "Colour",
|
||||||
"origin": "Origin",
|
"origin": "Origin",
|
||||||
"slide-to-sign": "Slide to sign",
|
"slide-to-sign": "Slide to sign",
|
||||||
|
@ -2673,5 +2673,13 @@
|
||||||
"saved-address-removed": "Saved address removed",
|
"saved-address-removed": "Saved address removed",
|
||||||
"remove-address": "Remove address",
|
"remove-address": "Remove address",
|
||||||
"remove-saved-address": "Remove saved address",
|
"remove-saved-address": "Remove saved address",
|
||||||
"remove-saved-address-description": "Transaction history relating to this address will no longer be labelled ‘{{name}}’."
|
"remove-saved-address-description": "Transaction history relating to this address will no longer be labelled ‘{{name}}’.",
|
||||||
|
"add-address": "Add address",
|
||||||
|
"add-address-to-save-description": "Paste, scan or type ETH address or ENS name",
|
||||||
|
"existing-saved-address": "Existing saved address",
|
||||||
|
"this-is-not-an-eth-address-or-ens-name": "This is not an Ethereum address or ENS name",
|
||||||
|
"you-cannot-add-your-own-account-as-a-saved-address": "You cannot add your own account as a saved address",
|
||||||
|
"this-address-is-already-saved": "This address is already saved",
|
||||||
|
"this-ens-name-is-not-registered-yet": "This ENS name is not registered yet",
|
||||||
|
"address-saved": "Address saved"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue