🔁 SWAP UI

CLJ Refactor x Hydra are cool. Add modal

Swap UI

Swap token input and gas slider in place

Asset selector sheets

WIP

Selector events

Tabs are back

Hide Swaps behind ff, add cards and modals for advanced settings

Fix lint issues

Signed-off-by: Shivek Khurana <shivek@status.im>
This commit is contained in:
Shivek Khurana 2021-10-19 14:44:36 +05:30
parent 3499cdc123
commit eeb8db00f7
No known key found for this signature in database
GPG Key ID: 9BEB56E6E62968C7
13 changed files with 622 additions and 37 deletions

1
.env
View File

@ -33,3 +33,4 @@ DELETE_MESSAGE_ENABLED=1
COLLECTIBLES_ENABLED=1 COLLECTIBLES_ENABLED=1
COMMANDS_ENABLED=1 COMMANDS_ENABLED=1
TWO_MINUTES_SYNCING=1 TWO_MINUTES_SYNCING=1
SWAP_ENABLED=1

View File

@ -230,7 +230,7 @@ PODS:
- React - React
- react-native-status (1.0.0): - react-native-status (1.0.0):
- React - React
- react-native-status-keycard (2.5.36): - react-native-status-keycard (2.5.37):
- Keycard - Keycard
- React - React
- react-native-webview (11.3.0): - react-native-webview (11.3.0):
@ -626,7 +626,7 @@ SPEC CHECKSUMS:
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
Folly: b73c3869541e86821df3c387eb0af5f65addfab4 Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 5bc68409594b19a3e5c5cbced7b1ecf61053b709 glog: 61334f8bdb4deea07543d4fbac3fb5948e78a7a5
Keycard: dd96182888da0aacf4de821b641103143bbb26cc Keycard: dd96182888da0aacf4de821b641103143bbb26cc
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b
@ -653,7 +653,7 @@ SPEC CHECKSUMS:
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4 react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-status: 45dbf1302ce3c258b459dfab137cd1c2c68c295d react-native-status: 45dbf1302ce3c258b459dfab137cd1c2c68c295d
react-native-status-keycard: eb84554a23315510948613a9467e7e3481be340c react-native-status-keycard: 961d01ca190889ddf220206822fd752f8f4f3f7a
react-native-webview: af9990b21a9aeafa8e8347746eb4116c0de086af react-native-webview: af9990b21a9aeafa8e8347746eb4116c0de086af
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

View File

@ -197,11 +197,13 @@
left-side-alignment icon-color icon-bg-color left-side-alignment icon-color icon-bg-color
title subtitle subtitle-secondary active on-press on-long-press chevron size text-size title subtitle subtitle-secondary active on-press on-long-press chevron size text-size
accessory-text accessibility-label title-accessibility-label accessory-style accessory-text accessibility-label title-accessibility-label accessory-style
haptic-feedback haptic-type error animated animated-accessory? title-text-weight container-style] haptic-feedback haptic-type error animated animated-accessory? title-text-weight container-style
active-background-enabled]
:or {subtitle-max-lines 1 :or {subtitle-max-lines 1
theme :main theme :main
haptic-feedback true haptic-feedback true
animated platform/ios? animated platform/ios?
active-background-enabled true
haptic-type :selection}}] haptic-type :selection}}]
(let [theme (if disabled :disabled theme) (let [theme (if disabled :disabled theme)
{:keys [text-color active-background passive-background]} {:keys [text-color active-background passive-background]}
@ -223,7 +225,7 @@
[component [component
(merge {:type :list-item (merge {:type :list-item
:disabled disabled :disabled disabled
:bg-color active-background :bg-color (when active-background-enabled active-background)
:accessibility-label accessibility-label} :accessibility-label accessibility-label}
(when on-press (when on-press
{:on-press (fn [] {:on-press (fn []

View File

@ -180,6 +180,12 @@
(reg-root-key-sub :wallet/fetching-collection-assets :wallet/fetching-collection-assets) (reg-root-key-sub :wallet/fetching-collection-assets :wallet/fetching-collection-assets)
(reg-root-key-sub :wallet/collectible-assets :wallet/collectible-assets) (reg-root-key-sub :wallet/collectible-assets :wallet/collectible-assets)
(reg-root-key-sub :wallet/selected-collectible :wallet/selected-collectible) (reg-root-key-sub :wallet/selected-collectible :wallet/selected-collectible)
(reg-root-key-sub :wallet/modal-selecting-source-token? :wallet/modal-selecting-source-token?)
(reg-root-key-sub :wallet/swap-from-token :wallet/swap-from-token)
(reg-root-key-sub :wallet/swap-to-token :wallet/swap-to-token)
(reg-root-key-sub :wallet/swap-from-token-amount :wallet/swap-from-token-amount)
(reg-root-key-sub :wallet/swap-to-token-amount :wallet/swap-to-token-amount)
(reg-root-key-sub :wallet/swap-advanced-mode? :wallet/swap-advanced-mode?)
;;commands ;;commands
(reg-root-key-sub :commands/select-account :commands/select-account) (reg-root-key-sub :commands/select-account :commands/select-account)

View File

@ -44,6 +44,17 @@
[status-im.ui.screens.currency-settings.views :as currency-settings] [status-im.ui.screens.currency-settings.views :as currency-settings]
[status-im.ui.screens.dapps-permissions.views :as dapps-permissions] [status-im.ui.screens.dapps-permissions.views :as dapps-permissions]
[status-im.ui.screens.default-sync-period-settings.view :as default-sync-period-settings] [status-im.ui.screens.default-sync-period-settings.view :as default-sync-period-settings]
[status-im.ui.screens.wallet.settings.views :as wallet-settings]
[status-im.ui.screens.wallet.transactions.views :as wallet-transactions]
[status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens]
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
[status-im.ui.screens.wallet.collectibles.views :as wallet.collectibles]
[status-im.ui.screens.wallet.account.views :as wallet.account]
[status-im.ui.screens.wallet.add-new.views :as add-account]
[status-im.ui.screens.wallet.account-settings.views :as account-settings]
[status-im.ui.screens.wallet.swap.views :as wallet.swap]
[status-im.ui.screens.status.views :as status.views]
[status-im.ui.screens.profile.user.views :as profile.user]
[status-im.ui.screens.ens.views :as ens] [status-im.ui.screens.ens.views :as ens]
[status-im.ui.screens.fleet-settings.views :as fleet-settings] [status-im.ui.screens.fleet-settings.views :as fleet-settings]
[status-im.ui.screens.glossary.view :as glossary] [status-im.ui.screens.glossary.view :as glossary]
@ -91,7 +102,6 @@
[status-im.ui.screens.profile.contact.views :as contact] [status-im.ui.screens.profile.contact.views :as contact]
[status-im.ui.screens.profile.group-chat.views :as profile.group-chat] [status-im.ui.screens.profile.group-chat.views :as profile.group-chat]
[status-im.ui.screens.profile.seed.views :as profile.seed] [status-im.ui.screens.profile.seed.views :as profile.seed]
[status-im.ui.screens.profile.user.views :as profile.user]
[status-im.ui.screens.progress.views :as progress] [status-im.ui.screens.progress.views :as progress]
[status-im.ui.screens.qr-scanner.views :as qr-scanner] [status-im.ui.screens.qr-scanner.views :as qr-scanner]
[status-im.ui.screens.referrals.public-chat :as referrals.public-chat] [status-im.ui.screens.referrals.public-chat :as referrals.public-chat]
@ -99,7 +109,6 @@
[status-im.ui.screens.reset-password.views :as reset-password] [status-im.ui.screens.reset-password.views :as reset-password]
[status-im.ui.screens.rpc-usage-info :as rpc-usage-info] [status-im.ui.screens.rpc-usage-info :as rpc-usage-info]
[status-im.ui.screens.status.new.views :as status.new] [status-im.ui.screens.status.new.views :as status.new]
[status-im.ui.screens.status.views :as status.views]
[status-im.ui.screens.stickers.views :as stickers] [status-im.ui.screens.stickers.views :as stickers]
[status-im.ui.screens.sync-settings.views :as sync-settings] [status-im.ui.screens.sync-settings.views :as sync-settings]
[status-im.ui.screens.terms-of-service.views :as terms-of-service] [status-im.ui.screens.terms-of-service.views :as terms-of-service]
@ -107,18 +116,10 @@
:as :as
edit-wakuv2-node] edit-wakuv2-node]
[status-im.ui.screens.wakuv2-settings.views :as wakuv2-settings] [status-im.ui.screens.wakuv2-settings.views :as wakuv2-settings]
[status-im.ui.screens.wallet.account-settings.views :as account-settings]
[status-im.ui.screens.wallet.account.views :as wallet.account]
[status-im.ui.screens.wallet.accounts-manage.views :as accounts-manage] [status-im.ui.screens.wallet.accounts-manage.views :as accounts-manage]
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
[status-im.ui.screens.wallet.add-new.views :as add-account]
[status-im.ui.screens.wallet.buy-crypto.views :as wallet.buy-crypto] [status-im.ui.screens.wallet.buy-crypto.views :as wallet.buy-crypto]
[status-im.ui.screens.wallet.collectibles.views :as wallet.collectibles]
[status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens]
[status-im.ui.screens.wallet.recipient.views :as recipient] [status-im.ui.screens.wallet.recipient.views :as recipient]
[status-im.ui.screens.wallet.send.views :as wallet.send] [status-im.ui.screens.wallet.send.views :as wallet.send]))
[status-im.ui.screens.wallet.settings.views :as wallet-settings]
[status-im.ui.screens.wallet.transactions.views :as wallet-transactions]))
(def components (def components
[{:name :chat-toolbar [{:name :chat-toolbar
@ -395,6 +396,32 @@
:options {:topBar {:title {:text (i18n/label :t/wallet-manage-accounts)}}} :options {:topBar {:title {:text (i18n/label :t/wallet-manage-accounts)}}}
:component accounts-manage/manage} :component accounts-manage/manage}
{:name :token-swap
;;TODO dynamic title
:options {:topBar {:visible false}}
:component wallet.swap/swap}
{:name :token-swap-advanced-nonce
:options {:topBar {:title {:text (i18n/label :t/nonce)}}}
:component wallet.swap/nonce-modal}
{:name :token-swap-advanced-approve-token
:options {:topBar {:title {:text (i18n/label :t/approve-token)}}}
:component wallet.swap/approve-token-modal}
{:name :token-swap-advanced-transaction-fee
:options {:topBar {:title {:text (i18n/label :t/transaction-fee)}}}
:component wallet.swap/transaction-fee-modal}
{:name :token-swap-advanced-swap-details
:options {:topBar {:title {:text (i18n/label :t/swap-details)}}}
:component wallet.swap/swap-details-modal}
{:name :swap-asset-selector
;;TODO dynamic title
:options {:topBar {:visible false}}
:component wallet.swap/asset-selector}
;;MY STATUS ;;MY STATUS
{:name :status {:name :status

View File

@ -42,3 +42,19 @@
:duration 200 :duration 200
:easing (.-ease ^js animation/easing) :easing (.-ease ^js animation/easing)
:useNativeDriver true})) :useNativeDriver true}))
(def round-action-button
{:background-color colors/blue
:height 44
:flex 1
:justify-content :center
:align-items :center
:width 44
:border-radius 44})
(def top-actions
{:flex 1
:flex-direction :row
:justify-content :space-between
:width "60%"
:align-self :center})

View File

@ -7,16 +7,17 @@
[quo.design-system.colors :as colors] [quo.design-system.colors :as colors]
[status-im.ui.components.icons.icons :as icons] [status-im.ui.components.icons.icons :as icons]
[quo.core :as quo] [quo.core :as quo]
[quo.design-system.spacing :as spacing]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.components.topbar :as topbar] [status-im.ui.components.topbar :as topbar]
[status-im.utils.config :as config] [status-im.utils.config :as config]
[status-im.ui.screens.wallet.account.styles :as styles] [status-im.ui.screens.wallet.account.styles :as styles]
[status-im.ui.screens.wallet.accounts.sheets :as sheets] [status-im.ui.screens.wallet.accounts.sheets :as sheets]
[status-im.ui.screens.wallet.accounts.views :as accounts] [status-im.ui.screens.wallet.accounts.views :as accounts]
[status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto]
[status-im.ui.screens.wallet.transactions.views :as history] [status-im.ui.screens.wallet.transactions.views :as history]
[status-im.ui.components.tabs :as tabs] [status-im.ui.components.tabs :as tabs]
[status-im.ui.screens.wallet.collectibles.views :as collectibles.views]) [status-im.ui.screens.wallet.collectibles.views :as collectibles.views]
[status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto])
(:require-macros [status-im.utils.views :as views])) (:require-macros [status-im.utils.views :as views]))
(def state (reagent/atom {:tab :assets})) (def state (reagent/atom {:tab :assets}))
@ -102,7 +103,6 @@
currency [:wallet/currency] currency [:wallet/currency]
opensea-enabled? [:opensea-enabled?] opensea-enabled? [:opensea-enabled?]
collectible-collection [:wallet/collectible-collection address] collectible-collection [:wallet/collectible-collection address]
mainnet? [:mainnet?]
ethereum-network? [:ethereum-network?]] ethereum-network? [:ethereum-network?]]
(let [{:keys [tab]} @state] (let [{:keys [tab]} @state]
[react/view {:flex 1} [react/view {:flex 1}
@ -111,11 +111,10 @@
(when ethereum-network? (when ethereum-network?
[tabs/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)]) [tabs/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)])
[tabs/tab-title state :history (i18n/label :t/history) (= tab :history)]] [tabs/tab-title state :history (i18n/label :t/history) (= tab :history)]]
[quo/separator {:style {:margin-top -8}}]
(cond (cond
(= tab :assets) (= tab :assets)
[:<> [:<>
(when mainnet?
[buy-crypto/banner])
(for [item tokens] (for [item tokens]
^{:key (:name item)} ^{:key (:name item)}
[accounts/render-asset item nil nil (:code currency)])] [accounts/render-asset item nil nil (:code currency)])]
@ -181,6 +180,27 @@
(styles/bottom-send-recv-buttons-lower anim-y button-group-height) (styles/bottom-send-recv-buttons-lower anim-y button-group-height)
#(reset! to-show false)))))))) #(reset! to-show false))))))))
(defn round-action-button [{:keys [icon title on-press]}]
[react/view {:style {:flex 1
:align-items :center
:margin-vertical (:large spacing/spacing)}}
[react/touchable-opacity {:style styles/round-action-button
:on-press on-press}
(icons/icon icon {:color colors/white})]
[quo/text {:color :secondary
:size :small
:style {:margin-top (:tiny spacing/spacing)}}
title]])
(defn top-actions []
[react/view {:style styles/top-actions}
[round-action-button {:icon :main-icons/add
:title (i18n/label :t/buy-crypto)
:on-press #(re-frame/dispatch [:buy-crypto.ui/open-screen])}]
[round-action-button {:icon :main-icons/change
:title (i18n/label :t/swap)
:on-press #(re-frame/dispatch [:open-modal :token-swap])}]])
(views/defview account [] (views/defview account []
(views/letsubs [{:keys [name address] :as account} [:multiaccount/current-account] (views/letsubs [{:keys [name address] :as account} [:multiaccount/current-account]
fetching-error [:wallet/fetching-error]] fetching-error [:wallet/fetching-error]]
@ -233,5 +253,8 @@
[react/scroll-view {:horizontal true} [react/scroll-view {:horizontal true}
[react/view {:flex-direction :row :padding-top 8 :padding-bottom 12} [react/view {:flex-direction :row :padding-top 8 :padding-bottom 12}
[account-card account]]]] [account-card account]]]]
(if config/swap-enabled?
[top-actions]
[buy-crypto/banner])
[assets-and-collections address]] [assets-and-collections address]]
[bottom-send-recv-buttons account anim-y]]))) [bottom-send-recv-buttons account anim-y]])))

View File

@ -0,0 +1,433 @@
(ns status-im.ui.screens.wallet.swap.views
(:require [quo.core :as quo]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.ethereum.tokens :as tokens]
[status-im.i18n.i18n :as i18n]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.keyboard-avoid-presentation
:as
kb-presentation]
[status-im.ui.components.react :as react]
[status-im.ui.components.search-input.view :as search-input]
[status-im.ui.components.slider :as slider]
[status-im.wallet.swap.core :as wallet.swap]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.wallet.components.views :as wallet.components]
[status-im.utils.handlers :refer [<sub]]
[status-im.wallet.utils :as wallet.utils]
[clojure.string :as str]))
(defn render-asset [{{:keys
[icon decimals amount color value]
:as token} :token
currency :currency
on-press :on-press}]
[quo/list-item
{:title [quo/text {:weight :medium}
[quo/text {:weight :inherit}
(str (if amount
(wallet.utils/format-amount amount decimals)
"...")
" ")]
[quo/text {:color :secondary
:weight :inherit}
(wallet.utils/display-symbol token)]]
:on-press on-press
:subtitle (str (if value value "...") " " currency)
:accessibility-label
(str (:symbol token) "-asset-value")
:icon (if icon
[wallet.components/token-icon icon]
[chat-icon/custom-icon-view-list (:name token) color])}])
(defn asset-selector []
(let [{:keys [address]} (<sub [:multiaccount/current-account])
{:keys [tokens]} (<sub [:wallet/visible-assets-with-values address])
source? (<sub [:wallet/modal-selecting-source-token?])
currency (<sub [:wallet/currency])]
[:<>
[topbar/topbar
{:title (if source?
(i18n/label :t/select-token-to-swap)
(i18n/label :t/select-token-to-receive))
:modal? true}]
[search-input/search-input
{:search-active? true}]
[react/scroll-view
(for [token tokens]
^{:key (:name token)}
[render-asset {:token token
:on-press #(re-frame/dispatch
[(if source?
::wallet.swap/set-from-token
::wallet.swap/set-to-token)
(:symbol token)])
:currency (:code currency)}])]]))
(defn pill-button [{:keys [on-press label margin-left]}]
[react/touchable-opacity {:on-press on-press
:style {:background-color colors/blue-light
:padding-horizontal 12
:padding-vertical 2
:border-radius 24
:margin-left (or margin-left 8)}}
[quo/text {:color :link
:weight :medium} label]])
(defn token-display
"Show token and act as an anchor to open selector."
[{:keys [token source?]}]
(let [token-icon-source (-> token :icon :source)]
[react/touchable-highlight
{:on-press #(re-frame/dispatch [::wallet.swap/open-asset-selector-modal source?])}
[react/view {:style {:flex-direction :row
:align-items :center
:border-width 1
:border-color colors/gray-lighter
:border-radius 8
:margin-left 16
:padding-horizontal 8
:padding-vertical 2}
:accessibility-label
:choose-asset-button}
[quo/text {:style {:margin-right 8}}
(-> token :symbol name)]
[react/image {:source (if (fn? token-icon-source)
(token-icon-source)
token-icon-source)}]]]))
(defn token-input
"Component to get the amount and type of tokens"
[{:keys [amount error label token max-from source?]}]
(let [window-width (<sub [:dimensions/window-width])]
[react/view {:style {:justify-content :space-between
:flex-direction :row
:align-items :center}}
[react/view {:flex 2}
[react/view {:flex-direction :row
:align-items :center}
[quo/text label]
(when max-from [pill-button {:on-press #()
:label "Max 0.043"}])]
[react/text-input
{:style {:font-size 38
:max-width (- (* (/ window-width 4) 3) 106)
:color (if error colors/red colors/black)}
:keyboard-type :decimal-pad
:auto-capitalize :words
:accessibility-label :amount-input
:default-value amount
:editable true
:auto-focus true
:on-change-text #(re-frame/dispatch [(when source?
::wallet.swap/set-from-token-amount)
%])
:placeholder "0.0"}]]
[token-display {:token token
:source? source?}]]))
(defn separator-with-icon []
[react/view
{:margin-vertical 8}
[quo/separator]
[react/touchable-opacity
{:on-press #(re-frame/dispatch [::wallet.swap/switch-from-token-with-to])}
[react/view {:style {:background-color colors/gray-lighter
:width 40
:height 40
:border-radius 40
:border-width 4
:border-color colors/white
:margin-top -20
:margin-bottom -20
:align-self :center
:align-items :center
:justify-content :center}}
[react/image {:source (icons/icon-source :main-icons/change)
:style {:tint-color colors/gray
:transform [{:rotate "90deg"}]}}]]]])
(defn floating-card [{:keys [icon title body on-press]}]
[react/view {:style {:border-width 1
:padding 2 ;; need a padding because border breaks otherwise
:border-radius 12
:margin-top 12
:border-color colors/gray-lighter}}
[quo/list-item {:title title
:subtitle body
:active-background-enabled
false
:on-press on-press
:theme :main
:chevron true
:icon [react/view {:style {:background-color colors/blue-light
:padding 8
:border-radius 4}}
(icons/icon icon {:color :dark})]}]])
(defn card-body-row [key value primary?]
[react/view {:flex-direction :row}
[quo/text {:color (when-not primary? :secondary)} key]
[quo/text {:style {:margin-right 4}
:color (when-not primary? :secondary)} ":"]
[quo/text {:ellipsize-mode :middle
:number-of-lines 1
:style {:width "50%"}
:color (when-not primary? :secondary)
:weight :semi-bold} value]])
(defn transaction-fee-card [{:keys [gas-amount price-limit tip-limit gas-in-eth gas-in-usd]}]
[floating-card {:title (i18n/label :t/transaction-fee)
:icon :main-icons/gas
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-transaction-fee])
:body [react/view
[card-body-row (i18n/label :t/gas-amount-limit) gas-amount]
[card-body-row (i18n/label :t/per-gas-price-limit) price-limit]
[card-body-row (i18n/label :t/per-gas-tip-limit) tip-limit]
[card-body-row (i18n/label :t/total-gas)
(str gas-in-eth " • $" gas-in-usd)
true]]}])
(defn swap-details-card [{:keys [slippage price-impact]}]
[floating-card {:title (i18n/label :t/swap-details)
:icon :main-icons/change
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-swap-details])
:body [react/view
[card-body-row (i18n/label :t/slippage) (str slippage " %")]
[card-body-row (i18n/label :t/price-impact) (str price-impact " %")]]}])
(defn nonce-card [{:keys [nonce]}]
[floating-card {:title (i18n/label :t/nonce)
:icon :main-icons/channel
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-nonce])
:body [react/view
[card-body-row (i18n/label :t/nonce) nonce]]}])
(defn approve-token-card [{:keys [token contract-address approve-limit]}]
[floating-card {:title (i18n/label :t/approve)
:icon :main-icons/check
:on-press #(re-frame/dispatch [:open-modal :token-swap-advanced-approve-token])
:body [react/view
[card-body-row (i18n/label :t/token) token]
[card-body-row (i18n/label :t/contract-address) contract-address]
[card-body-row (i18n/label :t/approve-limit) approve-limit]]}])
(defn advanced-input [{:keys [label label-help value on-change after]}]
[react/view {:style {:padding-horizontal 16
:margin-bottom 16}}
[react/view {:style {:flex-direction :row
:justify-content :space-between}}
[quo/text {} label]
label-help]
[quo/text-input {:default-value (str value)
:show-cancel false
:style {:margin-top 12
:border-radius 8}
:after {:component after}
:on-change-text on-change}]])
(defn help-label-kv [{:keys [key value]}]
[react/view {:style {:flex-direction :row}}
[quo/text {:color :secondary} key]
[quo/text {:color :secondary
:style {:margin-right 4}} ":"]
[quo/text {:color :secondary} value]])
(defn nonce-modal []
(let [last-txn-nonce 22
nonce 23]
[kb-presentation/keyboard-avoiding-view {:style {:flex 1
:margin-top 16}
:ignore-offset true}
[advanced-input {:label (i18n/label :t/nonce)
:label-help [help-label-kv {:key (i18n/label :t/last-transaction)
:value last-txn-nonce}]
:value nonce
:on-change #()
:on-save #()}]
[toolbar/toolbar
{:show-border? true
:left [quo/button {:type :secondary}
(i18n/label :t/cancel)]
:right [quo/button {:theme :accent}
(i18n/label :t/save)]}]]))
(defn approve-token-modal []
[quo/text "modal"])
(defn transaction-fee-modal []
(let [gas-amount-limit 21000
gas-amount 21000
per-gas-price-limit 7.3
current-avg-per-gas-price-limit 7.3
per-gas-tip-limit 150
current-avg-per-gas-tip-limit 150]
[kb-presentation/keyboard-avoiding-view {:style {:flex 1
:margin-top 16}
:ignore-offset true}
[react/view {:flex 1}
[advanced-input {:label (i18n/label :t/gas-amount-limit)
:label-help [help-label-kv {:key (i18n/label :t/limit)
:value gas-amount-limit}]
:value gas-amount
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
:on-change #()
:on-save #()}]
[advanced-input {:label (i18n/label :t/per-gas-price-limit)
:label-help [help-label-kv {:key (i18n/label :t/current-average)
:value current-avg-per-gas-price-limit}]
:value per-gas-price-limit
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
:on-change #()
:on-save #()}]
[advanced-input {:label (i18n/label :t/per-gas-price-limit)
:label-help [help-label-kv {:key (i18n/label :t/current-average)
:value current-avg-per-gas-tip-limit}]
:value per-gas-tip-limit
:after [quo/text {:color :secondary} (i18n/label :t/gwei)]
:on-change #()
:on-save #()}]
[quo/list-item {:title (i18n/label :t/maximum-fee)
:text-size :base
:title-text-weight :regular
:accessory :text
:accessory-text [quo/text "0.3 ETH"]
:container-style {:margin-top 16}}]
[quo/text {:color :secondary
:style {:padding-horizontal 16}}
(i18n/label :t/maximum-fee-desc)]]
[toolbar/toolbar
{:show-border? true
:left [quo/button {:type :secondary}
(i18n/label :t/cancel)]
:right [quo/button {:theme :accent}
(i18n/label :t/save)]}]]))
(defn swap-details-modal []
(let [slippage-limit 20
slippage 0.5
price-impact 4]
[kb-presentation/keyboard-avoiding-view {:style {:flex 1
:margin-top 16}
:ignore-offset true}
[react/view {:flex 1}
[advanced-input {:label (str (i18n/label :t/slippage) " %")
:label-help [help-label-kv {:key (i18n/label :t/limit)
:value (str slippage-limit "%")}]
:value slippage
:on-change #()
:on-save #()}]
[quo/list-item {:title (i18n/label :t/price-impact)
:text-size :base
:title-text-weight :regular
:accessory :text
:accessory-text (str price-impact "%")
:container-style {:margin-top 16}}]
[quo/text {:color :secondary
:style {:padding-horizontal 16}}
(i18n/label :t/price-impact-desc)]]
[toolbar/toolbar
{:show-border? true
:left [quo/button {:type :secondary}
(i18n/label :t/cancel)]
:right [quo/button {:theme :accent}
(i18n/label :t/save)]}]]))
(defn advanced-settings []
[react/view {:style {:flex 1
:padding-horizontal 16}}
[react/view {:align-self :flex-start}
[pill-button {:label (i18n/label :t/switch-to-simple-interface)
:margin-left 0
:on-press #(re-frame/dispatch [::wallet.swap/set-advanced-mode false])}]]
[transaction-fee-card {:gas-amount 21000
:price-limit 74
:tip-limit 21
:gas-in-eth 0.0031
:gas-in-usd 34.28}]
[swap-details-card {:slippage 0.5
:price-impact 4}]
[approve-token-card {:token "USDC"
:contract-address "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2"
:approve-limit "unlimited"}]
[nonce-card {:nonce 22}]])
(defn swap []
(let [{:keys [name]}
(<sub [:multiaccount/current-account])
all-tokens (<sub [:wallet/all-tokens])
from-symbol (<sub [:wallet/swap-from-token])
to-symbol (<sub [:wallet/swap-to-token])
advanced-mode? (<sub [:wallet/swap-advanced-mode?])
amount "0.02"
from-token (tokens/symbol->token all-tokens (or from-symbol :DGX))
to-token (tokens/symbol->token all-tokens (or to-symbol :SNT))]
[kb-presentation/keyboard-avoiding-view {:style (merge
{:flex 1})
:ignore-offset true}
[topbar/topbar
{:title name
:subtitle (str/upper-case (i18n/label :t/powered-by-paraswap))
:modal? true}]
[react/view (merge {:padding-horizontal 16
:margin-vertical 32}
(when-not advanced-mode?
{:flex 1}))
[token-input {:amount amount
:error nil
:label (i18n/label :t/amount)
:token from-token
:source? true
:max-from 67.28}]
[separator-with-icon]
[token-input {:amount "0.01"
:error nil
:label (i18n/label :t/minimum-received)
:source? false
:token to-token}]]
(when-not advanced-mode?
[react/view {:style {:flex-direction :row
:justify-content :space-between
:padding-horizontal 16
:align-items :center}}
[react/view {:style {:flex-direction :row}}
[quo/text {} (i18n/label :t/priority)]
[pill-button {:label (i18n/label :t/advanced)
:on-press #(re-frame/dispatch [::wallet.swap/set-advanced-mode true])}]]
[quo/text {:color :secondary} "0.0034 ETH/ $ 8.09"]])
(comment
(re-frame/dispatch [::wallet.swap/set-advanced-mode false]))
(when-not advanced-mode?
[react/view {:style {:padding-horizontal 16}}
[slider/animated-slider
{:minimum-value 0
:maximum-value 100
:style {:margin-vertical 8}}]])
(when advanced-mode?
[quo/text "here"]
[advanced-settings])
[toolbar/toolbar
{:show-border? true
:right [quo/button {:theme :accent}
(i18n/label :t/swap)]}]]))

View File

@ -53,6 +53,7 @@
(def collectibles-enabled? (enabled? (get-config :COLLECTIBLES_ENABLED "1"))) (def collectibles-enabled? (enabled? (get-config :COLLECTIBLES_ENABLED "1")))
(def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0"))) (def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0")))
(def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0"))) (def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0")))
(def swap-enabled? (enabled? (get-config :SWAP_ENABLED "0")))
;; CONFIG VALUES ;; CONFIG VALUES
(def log-level (def log-level

View File

@ -0,0 +1,51 @@
(ns status-im.wallet.swap.core
(:require [status-im.utils.fx :as fx]
[re-frame.db :as re-frame.db]
[status-im.navigation :as navigation]))
(fx/defn open-asset-selector-modal
"source? true signinfies we are selecting the source asset. false implies selection of sink asset"
{:events [::open-asset-selector-modal]}
[{:keys [db]} source?]
(fx/merge {:db (assoc db :wallet/modal-selecting-source-token? source?)}
(navigation/open-modal :swap-asset-selector {})))
(fx/defn set-from-token
{:events [::set-from-token]}
[{:keys [db]} from-symbol]
(fx/merge {:db (assoc db :wallet/swap-from-token from-symbol)}
(navigation/navigate-back)))
(fx/defn set-to-token
{:events [::set-to-token]}
[{:keys [db]} to-symbol]
(fx/merge {:db (assoc db :wallet/swap-to-token to-symbol)}
(navigation/navigate-back)))
(fx/defn set-from-token-amount
[{:keys [db]} from-amount]
{:db (assoc db :wallet/swap-from-token-amount from-amount)})
(fx/defn set-max-from-token-amount
[{:keys [db]} _]
{:db (assoc db :wallet/swap-from-token-amount 0)})
(fx/defn switch-from-token-with-to
{:events [::switch-from-token-with-to]}
[{:keys [db]}]
{:db (assoc db
:wallet/swap-from-token (:wallet/swap-to-token db)
:wallet/swap-to-token (:wallet/swap-from-token db))})
(fx/defn set-advanced-mode
{:events [::set-advanced-mode]}
[{:keys [db]} mode]
{:db (assoc db :wallet/swap-advanced-mode? mode)})
(comment
(->> re-frame.db/app-db
deref
:wallet/all-tokens
vals
(map #(str (:name %) "-" (:symbol %)))))

View File

@ -1704,5 +1704,30 @@
"status-always-online": "Always Online", "status-always-online": "Always Online",
"status-inactive": "Inactive", "status-inactive": "Inactive",
"status-inactive-subtitle": "Hides your online status", "status-inactive-subtitle": "Hides your online status",
"two-minutes": "two minutes" "two-minutes": "two minutes",
"swap": "Swap",
"select-token-to-swap": "Select token to Swap",
"select-token-to-receive": "Select token to receive",
"minimum-received": "Minimum received",
"powered-by-paraswap": "Powered by Paraswap",
"priority": "Priority",
"switch-to-simple-interface":"Switch to simple interface",
"transaction-fee": "Transaction fee",
"swap-details": "Swap details",
"slippage": "Slippage",
"price-impact": "Price impact",
"total-gas": "Total gas",
"token": "Token",
"approve-limit": "Approve limit",
"approve-token": "Approve token",
"approve-token-contract-desc": "Approving a token with a contract allows it to spend your token balance. If you feel that a project is untrustworthy, dont approve the token with them, or approve only the amount you will use with them.",
"unlimited": "Unlimited",
"approve": "Approve",
"limit": "Limit",
"last-transaction": "Last transaction",
"price-impact-desc": "Estimated price impact for this transaction. If the current block base fee exceeds this, your transaction will be included in a following block with a lower base fee.",
"safe-estimate": "Safe estimate",
"current-average": "Current average",
"current-base": "Current base",
"maximum-fee-desc": "Maximum overall price for the transaction. If the current block base fee exceeds this, your transaction will be included in a following block with a lower base fee."
} }