Skip to content

Commit

Permalink
Wallet: network receiver preferences (#18583)
Browse files Browse the repository at this point in the history
* wallet: network receiver preferences
  • Loading branch information
OmarBasem authored Jan 25, 2024
1 parent 8999b2b commit 1fb6c60
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 61 deletions.
2 changes: 1 addition & 1 deletion src/quo/components/wallet/network_bridge/style.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

(defn container
[network state theme]
{:flex 1
{:width 136
:height 44
:border-width 1
:border-radius 12
Expand Down
15 changes: 10 additions & 5 deletions src/quo/components/wallet/network_bridge/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/status_im/contexts/wallet/common/utils.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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 "<")
Expand Down
15 changes: 12 additions & 3 deletions src/status_im/contexts/wallet/send/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
37 changes: 16 additions & 21 deletions src/status_im/contexts/wallet/send/input_amount/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"))}
Expand All @@ -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)
Expand Down
26 changes: 25 additions & 1 deletion src/status_im/contexts/wallet/send/routes/style.cljs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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})
154 changes: 128 additions & 26 deletions src/status_im/contexts/wallet/send/routes/view.cljs
Original file line number Diff line number Diff line change
@@ -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- 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- 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]}]
[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}}]])
[{: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
[{: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- 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
Expand All @@ -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])))
Expand All @@ -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))
Loading

0 comments on commit 1fb6c60

Please sign in to comment.