Wallet: network receiver preferences (#18583)
* wallet: network receiver preferences
This commit is contained in:
parent
8999b2b9e8
commit
1fb6c60f72
|
@ -4,7 +4,7 @@
|
|||
|
||||
(defn container
|
||||
[network state theme]
|
||||
{:flex 1
|
||||
{:width 136
|
||||
:height 44
|
||||
:border-width 1
|
||||
:border-radius 12
|
||||
|
|
|
@ -10,8 +10,12 @@
|
|||
[react-native.core :as rn]))
|
||||
|
||||
(defn network-bridge-add
|
||||
[{:keys [network state theme]}]
|
||||
[rn/view {:style (merge (style/container network state theme) (style/add-container theme))}
|
||||
[{:keys [network state theme container-style on-press]}]
|
||||
[rn/pressable
|
||||
{:style (merge (style/container network state theme)
|
||||
(style/add-container theme)
|
||||
container-style)
|
||||
:on-press on-press}
|
||||
[icon/icon :i/add-circle {:size 12 :no-color true}]])
|
||||
|
||||
(defn- network->text
|
||||
|
@ -21,13 +25,14 @@
|
|||
:else (string/capitalize (name network))))
|
||||
|
||||
(defn view-internal
|
||||
[{:keys [theme network status amount container-style] :as args}]
|
||||
[{:keys [theme network status amount container-style on-press] :as args}]
|
||||
(if (= status :add)
|
||||
[network-bridge-add args]
|
||||
[rn/view
|
||||
[rn/pressable
|
||||
{:style (merge (style/container network status theme) container-style)
|
||||
:accessible true
|
||||
:accessibility-label :container}
|
||||
:accessibility-label :container
|
||||
:on-press on-press}
|
||||
(if (= status :loading)
|
||||
[rn/view
|
||||
{:style (style/loading-skeleton theme)
|
||||
|
|
|
@ -185,6 +185,11 @@
|
|||
constants/arbitrum-chain-id :arbitrum
|
||||
constants/arbitrum-test-chain-id :arbitrum})
|
||||
|
||||
(def short-name->id
|
||||
{:eth constants/mainnet-chain-id
|
||||
:opt constants/optimism-chain-id
|
||||
:arb1 constants/arbitrum-chain-id})
|
||||
|
||||
(defn get-standard-fiat-format
|
||||
[crypto-value currency-symbol fiat-value]
|
||||
(if (string/includes? crypto-value "<")
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require
|
||||
[camel-snake-kebab.core :as csk]
|
||||
[camel-snake-kebab.extras :as cske]
|
||||
[clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
|
@ -57,16 +58,23 @@
|
|||
|
||||
(rf/reg-event-fx :wallet/select-send-address
|
||||
(fn [{:keys [db]} [{:keys [address token recipient stack-id]}]]
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)]
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)
|
||||
prefix-seq (string/split prefix #":")
|
||||
selected-networks (mapv #(utils/short-name->id (keyword %)) prefix-seq)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
|
||||
(assoc-in [:wallet :ui :send :to-address] to-address)
|
||||
(assoc-in [:wallet :ui :send :address-prefix] prefix))
|
||||
(assoc-in [:wallet :ui :send :address-prefix] prefix)
|
||||
(assoc-in [:wallet :ui :send :selected-networks] selected-networks))
|
||||
:fx [[:navigate-to-within-stack
|
||||
(if token
|
||||
[:wallet-send-input-amount stack-id]
|
||||
[:wallet-select-asset stack-id])]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/update-receiver-networks
|
||||
(fn [{:keys [db]} [selected-networks]]
|
||||
{:db (assoc-in db [:wallet :ui :send :selected-networks] selected-networks)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-select-token
|
||||
(fn [{:keys [db]} [{:keys [token stack-id]}]]
|
||||
{:db (assoc-in db [:wallet :ui :send :token] token)
|
||||
|
@ -92,10 +100,11 @@
|
|||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
account-address (get-in db [:wallet :ui :send :send-account-address])
|
||||
selected-networks (get-in db [:wallet :ui :send :selected-networks])
|
||||
to-address (or account-address (get-in db [:wallet :ui :send :to-address]))
|
||||
token-decimal (:decimals token)
|
||||
token-id (:symbol token)
|
||||
network-preferences []
|
||||
network-preferences selected-networks
|
||||
gas-rates constants/gas-rate-medium
|
||||
amount-in (send-utils/amount-in-hex amount token-decimal)
|
||||
from-address wallet-address
|
||||
|
|
|
@ -44,7 +44,8 @@
|
|||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route {:route []}
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}})
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}
|
||||
:wallet/wallet-send-selected-networks []})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/setup-restorable-re-frame)
|
||||
|
|
|
@ -54,13 +54,6 @@
|
|||
(normalize-input current v)
|
||||
current))
|
||||
|
||||
(defn- find-affordable-networks
|
||||
[{:keys [balances-per-chain]} input-value]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_ {:keys [balance]}]]
|
||||
(>= (js/parseFloat balance) input-value)))
|
||||
(map first)))
|
||||
|
||||
(defn- reset-input-error
|
||||
[new-value prev-value input-error]
|
||||
(reset! input-error
|
||||
|
@ -129,21 +122,22 @@
|
|||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))
|
||||
amount (str @input-value " " token-symbol)
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])]
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
|
||||
fetch-routes (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(when-not (or
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))
|
||||
(debounce/debounce-and-dispatch [:wallet/get-suggested-routes
|
||||
@input-value]
|
||||
100)))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
||||
#(.remove app-keyboard-listener))))
|
||||
(rn/use-effect (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(when-not (or
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))
|
||||
(debounce/debounce-and-dispatch [:wallet/get-suggested-routes @input-value]
|
||||
100)))
|
||||
[@input-value])
|
||||
(rn/use-effect #(fetch-routes) [@input-value])
|
||||
[rn/view
|
||||
{:style style/screen
|
||||
:accessibility-label (str "container" (when @input-error "-error"))}
|
||||
|
@ -166,10 +160,11 @@
|
|||
:on-change-text (fn [text]
|
||||
(handle-on-change text))}]
|
||||
[routes/view
|
||||
{:amount amount
|
||||
:routes suggested-routes
|
||||
:loading-networks (find-affordable-networks token @input-value)
|
||||
:networks (:networks token)}]
|
||||
{:amount amount
|
||||
:routes suggested-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes fetch-routes}]
|
||||
[quo/bottom-actions
|
||||
{:actions :1-action
|
||||
:button-one-label (i18n/label :t/confirm)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
(ns status-im.contexts.wallet.send.routes.style)
|
||||
(ns status-im.contexts.wallet.send.routes.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def routes-container
|
||||
{:padding-horizontal 20
|
||||
|
@ -30,3 +31,26 @@
|
|||
{:flex-grow 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def add-network
|
||||
{:margin-top 8
|
||||
:align-self :flex-end
|
||||
:left 12})
|
||||
|
||||
(defn warning-container
|
||||
[color theme]
|
||||
{:flex-direction :row
|
||||
:border-width 1
|
||||
:border-color (colors/resolve-color color theme 10)
|
||||
:background-color (colors/resolve-color color theme 5)
|
||||
:margin-horizontal 20
|
||||
:margin-top 4
|
||||
:margin-bottom 8
|
||||
:padding-left 12
|
||||
:padding-vertical 11
|
||||
:border-radius 12})
|
||||
|
||||
(def warning-text
|
||||
{:margin-left 8
|
||||
:margin-right 12
|
||||
:padding-right 12})
|
||||
|
|
|
@ -1,39 +1,134 @@
|
|||
(ns status-im.contexts.wallet.send.routes.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.foundations.resources :as resources]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.routes.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn route-item
|
||||
[{:keys [amount from-network to-network status]}]
|
||||
[rn/view {:style style/routes-inner-container}
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network from-network
|
||||
:status status}]
|
||||
(if (= status :default)
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
[rn/view {:style {:width 73}}])
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network to-network
|
||||
:status status
|
||||
:container-style {:right 12}}]])
|
||||
(defn- find-affordable-networks
|
||||
[{:keys [balances-per-chain]} input-value selected-networks]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_ {:keys [balance chain-id]}]]
|
||||
(and
|
||||
(>= (js/parseFloat balance) input-value)
|
||||
(some #(= % chain-id) selected-networks))))
|
||||
(map first)))
|
||||
|
||||
(defn view
|
||||
[{:keys [amount routes loading-networks]}]
|
||||
(let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
candidates (:candidates routes)]
|
||||
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty candidates))
|
||||
(defn- make-network-item
|
||||
[{:keys [network-name chain-id] :as _network}
|
||||
{:keys [title color on-change network-preferences] :as _options}]
|
||||
{:title (or title (string/capitalize (name network-name)))
|
||||
:image :icon-avatar
|
||||
:image-props {:icon (resources/get-network network-name)
|
||||
:size :size-20}
|
||||
:action :selector
|
||||
:action-props {:type :checkbox
|
||||
:customization-color color
|
||||
:checked? (some #(= % chain-id) @network-preferences)
|
||||
:on-change on-change}})
|
||||
|
||||
(defn networks-drawer
|
||||
[{:keys [fetch-routes theme]}]
|
||||
(let [network-details (rf/sub [:wallet/network-details])
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
|
||||
selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
prefix (rf/sub [:wallet/wallet-send-address-prefix])
|
||||
prefix-seq (string/split prefix #":")
|
||||
grouped-details (group-by #(contains? (set prefix-seq) (:short-name %)) network-details)
|
||||
preferred (get grouped-details true [])
|
||||
not-preferred (get grouped-details false [])
|
||||
network-preferences (reagent/atom selected-networks)
|
||||
toggle-network (fn [{:keys [chain-id]}]
|
||||
(swap! network-preferences
|
||||
(fn [preferences]
|
||||
(if (some #(= % chain-id) preferences)
|
||||
(vec (remove #(= % chain-id) preferences))
|
||||
(conj preferences chain-id)))))]
|
||||
(fn []
|
||||
[rn/view
|
||||
[quo/drawer-top {:title (i18n/label :t/edit-receiver-networks)}]
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:label (i18n/label :t/preferred-by-receiver)
|
||||
:data (mapv (fn [network]
|
||||
(make-network-item network
|
||||
{:color color
|
||||
:network-preferences network-preferences
|
||||
:on-change #(toggle-network network)}))
|
||||
preferred)}]
|
||||
(when (pos? (count not-preferred))
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:label (i18n/label :t/not-preferred-by-receiver)
|
||||
:data (mapv (fn [network]
|
||||
(make-network-item network
|
||||
{:color color
|
||||
:network-preferences network-preferences
|
||||
:on-change #(toggle-network network)}))
|
||||
not-preferred)}])
|
||||
(when (not= selected-networks @network-preferences)
|
||||
[rn/view {:style (style/warning-container color theme)}
|
||||
[quo/icon :i/info {:color (colors/resolve-color color theme)}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style style/warning-text} (i18n/label :t/receiver-networks-warning)]])
|
||||
[quo/bottom-actions
|
||||
{:button-one-label (i18n/label :t/apply-changes)
|
||||
:button-one-props {:disabled? (= selected-networks @network-preferences)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:wallet/update-receiver-networks
|
||||
@network-preferences])
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(fetch-routes))
|
||||
:customization-color color}}]])))
|
||||
|
||||
(defn route-item
|
||||
[{:keys [amount from-network to-network status theme fetch-routes]}]
|
||||
(if (= status :add)
|
||||
[quo/network-bridge
|
||||
{:status :add
|
||||
:container-style style/add-network
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [networks-drawer
|
||||
{:theme theme
|
||||
:fetch-routes fetch-routes}])}])}]
|
||||
[rn/view {:style style/routes-inner-container}
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network from-network
|
||||
:status status}]
|
||||
(if (= status :default)
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
[rn/view {:style {:width 73}}])
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network to-network
|
||||
:status status
|
||||
:container-style {:right 12}}]]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [amount routes token input-value theme fetch-routes]}]
|
||||
(let [selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
loading-networks (find-affordable-networks token input-value selected-networks)
|
||||
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
best-routes (:best routes)
|
||||
data (if loading-suggested-routes? loading-networks best-routes)]
|
||||
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty best-routes))
|
||||
[rn/flat-list
|
||||
{:data (if loading-suggested-routes? loading-networks candidates)
|
||||
{:data (if (and (< (count data) 3) (pos? (count data)))
|
||||
(concat data [{:status :add}])
|
||||
data)
|
||||
:content-container-style style/routes-container
|
||||
:header [rn/view {:style style/routes-header-container}
|
||||
[quo/section-label
|
||||
|
@ -45,7 +140,12 @@
|
|||
:render-fn (fn [item]
|
||||
[route-item
|
||||
{:amount amount
|
||||
:status (if loading-suggested-routes? :loading :default)
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:status (cond
|
||||
(= (:status item) :add) :add
|
||||
loading-suggested-routes? :loading
|
||||
:else :default)
|
||||
:from-network (if loading-suggested-routes?
|
||||
(utils/id->network item)
|
||||
(utils/id->network (get-in item [:from :chain-id])))
|
||||
|
@ -54,5 +154,7 @@
|
|||
(utils/id->network (get-in item
|
||||
[:to :chain-id])))}])}]
|
||||
[rn/view {:style style/empty-container}
|
||||
(when (and (not (nil? candidates)) (not loading-suggested-routes?))
|
||||
(when (and (not (nil? best-routes)) (not loading-suggested-routes?))
|
||||
[quo/text (i18n/label :t/no-routes-found)])])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
|
|
@ -48,6 +48,11 @@
|
|||
:<- [:wallet/wallet-send]
|
||||
:-> :address-prefix)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-selected-networks
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :selected-networks)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-route
|
||||
:<- [:wallet/wallet-send]
|
||||
|
|
|
@ -2453,11 +2453,10 @@
|
|||
"share-details": "Share details",
|
||||
"what-are-you-waiting-for": "What are you waiting for?",
|
||||
"no-relevant-tokens": "No relevant tokens",
|
||||
"on-the-web": "On the web",
|
||||
"sending-with-ellipsis": "Sending...",
|
||||
"sending-with-elipsis": "Sending...",
|
||||
"transaction-confirmed": "Transaction confirmed!",
|
||||
"transacation-finalised": "Transaction finalised!",
|
||||
"no-relevant-tokens": "No relevant tokens",
|
||||
"from-label": "From",
|
||||
"to-label": "To",
|
||||
"oops-wrong-word": "Oops! Wrong word",
|
||||
|
@ -2469,5 +2468,10 @@
|
|||
"remove-account-title": "Remove account",
|
||||
"remove-account-desc": "The account will be removed from all of your synced devices. Make sure you have a backup of your keypair or recovery phrase and derivation path (if it’s not default).",
|
||||
"derivation-path-copied": "Derivation path copied",
|
||||
"remove-account-confirmation": "I have taken note of the derivation path"
|
||||
"remove-account-confirmation": "I have taken note of the derivation path",
|
||||
"edit-receiver-networks": "Edit receiver networks",
|
||||
"preferred-by-receiver": "Preferred by receiver",
|
||||
"not-preferred-by-receiver": "Not preferred by receiver",
|
||||
"apply-changes": "Apply changes",
|
||||
"receiver-networks-warning": "Changing these settings may result in sending tokens to networks the recipient doesn't use"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue