[#8348] [Multi-Account] Account overview + individual wallet UI
Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
parent
33840b7b84
commit
26bbac83bc
|
@ -299,8 +299,7 @@
|
|||
(let [props (merge props
|
||||
{:background-color
|
||||
(case current-view
|
||||
(:wallet
|
||||
:wallet-send-transaction
|
||||
(:wallet-send-transaction
|
||||
:wallet-request-transaction
|
||||
:wallet-send-assets
|
||||
:wallet-request-assets
|
||||
|
@ -308,8 +307,6 @@
|
|||
:recent-recipients
|
||||
:wallet-send-transaction-request
|
||||
:contact-code
|
||||
:wallet-modal
|
||||
:wallet-onboarding-setup-modal
|
||||
:wallet-settings-hook)
|
||||
colors/blue
|
||||
|
||||
|
@ -318,11 +315,9 @@
|
|||
"#2f3031"
|
||||
|
||||
colors/white)})
|
||||
bottom-background (when (#{:wallet
|
||||
:recent-recipients
|
||||
bottom-background (when (#{:recent-recipients
|
||||
:wallet-send-assets
|
||||
:wallet-request-assets
|
||||
:wallet-modal} current-view)
|
||||
:wallet-request-assets} current-view)
|
||||
[view {:background-color colors/white
|
||||
:position :absolute
|
||||
:bottom 0
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 13C11.4477 13 11 13.4477 11 14V16C11 16.5523 11.4477 17 12 17C12.5523 17 13 16.5523 13 16V14C13 13.4477 12.5523 13 12 13Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 3C9.79086 3 8 4.79086 8 7V9C6.34315 9 5 10.3431 5 12V18C5 19.6569 6.34315 21 8 21H16C17.6569 21 19 19.6569 19 18V12C19 10.3431 17.6569 9 16 9V7C16 4.79086 14.2091 3 12 3ZM14 7V9H10V7C10 5.89543 10.8954 5 12 5C13.1046 5 14 5.89543 14 7ZM7 12C7 11.4477 7.44772 11 8 11H16C16.5523 11 17 11.4477 17 12V18C17 18.5523 16.5523 19 16 19H8C7.44772 19 7 18.5523 7 18V12Z" fill="black"/>
|
||||
</svg>
|
||||
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="m12 22c5.5228 0 10-4.4772 10-10 0-5.52285-4.4772-10-10-10-5.52285 0-10 4.47715-10 10 0 5.5228 4.47715 10 10 10zm7.9381-11c-.3381-2.7113-2.0329-5.00126-4.3837-6.16901.065.13023.1276.26332.1878.39891.6898 1.55201 1.1314 3.56607 1.2345 5.7701zm0 2c-.3381 2.7113-2.0329 5.0013-4.3837 6.169.065-.1302.1276-.2633.1878-.3989.6898-1.552 1.1314-3.5661 1.2345-5.7701zm-4.9638-2c-.1017-1.96653-.4982-3.69454-1.0597-4.95782-.328-.73796-.6926-1.27326-1.047-1.61052-.3492-.33236-.6407-.43166-.8676-.43166s-.5184.0993-.8676.43166c-.3544.33726-.719.87256-1.047 1.61052-.56148 1.26328-.95804 2.99129-1.05973 4.95782zm-5.94863 2h5.94863c-.1017 1.9665-.4982 3.6945-1.0597 4.9578-.328.738-.6926 1.2733-1.047 1.6105-.3492.3324-.6407.4317-.8676.4317s-.5184-.0993-.8676-.4317c-.3544-.3372-.719-.8725-1.047-1.6105-.56148-1.2633-.95804-2.9913-1.05973-4.9578zm-2.00239-2c.10315-2.20403.5447-4.21809 1.23448-5.7701.06026-.13559.12288-.26868.18785-.39891-2.35076 1.16775-4.04562 3.45771-4.38372 6.16901zm-2.96139 2h2.96139c.10315 2.204.5447 4.2181 1.23448 5.7701.06026.1356.12288.2687.18785.3989-2.35076-1.1677-4.04562-3.4577-4.38372-6.169z" fill="#000" fill-rule="evenodd"/></svg>
|
Before Width: | Height: | Size: 684 B After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1 @@
|
|||
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="m12 22c-5.52295 0-10-4.4772-10-10 0-5.52283 4.47705-10 10-10 5.5229 0 10 4.47717 10 10 0 5.5228-4.4771 10-10 10zm0-2c4.4182 0 8-3.5817 8-8 0-4.41833-3.5818-8-8-8-4.41821 0-8 3.58167-8 8 0 4.4183 3.58179 8 8 8zm4-10h-3v6h-2v-6h-3v-2h8z" fill="#000" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 399 B |
|
@ -0,0 +1 @@
|
|||
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="m17.4225 9.99594c.9999.85526 1.7523 1.81106 2.2288 2.50406-.4765.693-1.2289 1.6488-2.2288 2.5041-1.3258 1.1339-2.97 1.9959-4.9225 1.9959-1.9526 0-3.5967-.862-4.9225-1.9959-.99999-.8553-1.75231-1.8111-2.22881-2.5041.4765-.693 1.22882-1.6488 2.22881-2.50406 1.3258-1.1339 2.9699-1.99594 4.9225-1.99594 1.9525 0 3.5967.86204 4.9225 1.99594zm4.3215 2.05736c.1681.2771.1681.6163 0 .8934-.8908 1.4684-4.0855 6.0533-9.244 6.0533-5.15858 0-8.35319-4.5849-9.24406-6.0533-.16808-.2771-.16808-.6163.00001-.8934.89086-1.4684 4.08547-6.0533 9.24405-6.0533 5.1585 0 8.3532 4.5849 9.244 6.0533zm-9.244 2.9467c1.3807 0 2.5-1.1193 2.5-2.5s-1.1193-2.5-2.5-2.5-2.5 1.1193-2.5 2.5 1.1193 2.5 2.5 2.5z" fill="#000" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 845 B |
|
@ -17,7 +17,7 @@
|
|||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.svgimage :as svgimage]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.platform :as platform]
|
||||
|
|
|
@ -535,6 +535,7 @@
|
|||
|
||||
:custom []})
|
||||
|
||||
;; TODO all these should be improved, we don't need to recalculate this each time, it can be done only once
|
||||
(defn tokens-for
|
||||
"makes sure all addresses are lower-case
|
||||
TODO: token list should be speced and not accept non-lower-cased addresses"
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
[status-im.stickers.core :as stickers]
|
||||
[status-im.transport.core :as transport]
|
||||
[status-im.transport.message.core :as transport.message]
|
||||
status-im.wallet.choose-recipient.core
|
||||
status-im.wallet.collectibles.core
|
||||
status-im.wallet.accounts.core
|
||||
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
|
||||
|
@ -61,7 +64,9 @@
|
|||
[status-im.wallet.custom-tokens.core :as custom-tokens]
|
||||
[status-im.wallet.db :as wallet.db]
|
||||
[status-im.web3.core :as web3]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.chat.commands.sending :as commands.sending]
|
||||
[status-im.utils.money :as money]))
|
||||
|
||||
;; init module
|
||||
|
||||
|
@ -1996,3 +2001,15 @@
|
|||
:dismiss-keyboard
|
||||
(fn []
|
||||
(react/dismiss-keyboard!)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet-send-request
|
||||
(fn [{:keys [db] :as cofx} [_ public-key amount symbol decimals]]
|
||||
(assert public-key)
|
||||
(let [request-command (get-in db [:id->command ["request" #{:personal-chats}]])]
|
||||
(fx/merge cofx
|
||||
(chat/start-chat public-key nil)
|
||||
(commands.sending/send public-key
|
||||
request-command
|
||||
{:asset (name symbol)
|
||||
:amount (str (money/internal->formatted amount symbol decimals))})))))
|
|
@ -31,7 +31,7 @@
|
|||
[status-im.ui.screens.mobile-network-settings.utils
|
||||
:as
|
||||
mobile-network-utils]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.build :as build]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
|
@ -1022,6 +1022,21 @@
|
|||
"0"))
|
||||
"...")))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/sorted-chain-tokens
|
||||
:<- [:wallet/all-tokens]
|
||||
:<- [:ethereum/chain-keyword]
|
||||
(fn [[all-tokens chain]]
|
||||
(tokens/sorted-tokens-for all-tokens chain)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/grouped-chain-tokens
|
||||
:<- [:wallet/sorted-chain-tokens]
|
||||
:<- [:wallet/visible-tokens-symbols]
|
||||
(fn [[all-tokens visible-tokens]]
|
||||
(let [vt-set (set visible-tokens)]
|
||||
(group-by :custom? (map #(assoc % :checked? (boolean (get vt-set (keyword (:symbol %))))) all-tokens)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/balance-loading?
|
||||
:<- [:wallet]
|
||||
|
@ -1059,6 +1074,30 @@
|
|||
(fn [[balance visible-assets]]
|
||||
(map #(assoc % :amount (get balance (:symbol %))) visible-assets)))
|
||||
|
||||
(defn update-value [balance prices currency]
|
||||
(fn [{:keys [symbol decimals] :as token}]
|
||||
(let [price (get-in prices [symbol (-> currency :code keyword) :price])]
|
||||
(assoc token
|
||||
:price price
|
||||
:value (when (and balance price)
|
||||
(-> (money/internal->formatted (get balance symbol) symbol decimals)
|
||||
(money/crypto->fiat price)
|
||||
(money/with-precision 2)
|
||||
str
|
||||
(i18n/format-currency (:code currency))))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/visible-assets-with-values
|
||||
:<- [:wallet/visible-assets-with-amount]
|
||||
:<- [:prices]
|
||||
:<- [:wallet/currency]
|
||||
:<- [:balance]
|
||||
(fn [[assets prices currency balance]]
|
||||
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
|
||||
tokens-with-values (map (update-value balance prices currency) tokens)]
|
||||
{:tokens tokens-with-values
|
||||
:nfts nfts})))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/transferrable-assets-with-amount
|
||||
:<- [:wallet/visible-assets-with-amount]
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
; theme - optional :default, :wallet
|
||||
|
||||
(defn list-item [{:keys [title subtitle accessories image image-path type theme on-press error] :or {type :default theme :default}}]
|
||||
(defn list-item [{:keys [title subtitle accessories image image-path type theme on-press error content] :or {type :default theme :default}}]
|
||||
(let [small? (= :small type)]
|
||||
[react/touchable-highlight {:on-press on-press :disabled (not on-press)}
|
||||
[react/view {:style (styles/container small?)}
|
||||
|
@ -27,38 +27,45 @@
|
|||
[react/image {:source (utils.image/source image-path)
|
||||
:style (styles/photo 40)}]])
|
||||
;;Title
|
||||
[react/view {:style {:margin-left 16 :margin-right 16}}
|
||||
[react/text {:style (styles/title small? subtitle)
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail}
|
||||
title]
|
||||
;;Subtitle
|
||||
(when subtitle
|
||||
[react/text {:style styles/subtitle
|
||||
(when title
|
||||
[react/view {:style {:margin-left 16 :margin-right 16}}
|
||||
[react/text {:style (styles/title small? subtitle)
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail}
|
||||
subtitle])]
|
||||
;;Accessories
|
||||
title]
|
||||
;;Subtitle
|
||||
(when subtitle
|
||||
[react/text {:style styles/subtitle
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail}
|
||||
subtitle])])
|
||||
;;Content
|
||||
(when content
|
||||
(if (vector? content)
|
||||
content
|
||||
[content]))
|
||||
[react/view {:flex 1}]
|
||||
;;Accessories
|
||||
(for [accessory accessories]
|
||||
(with-meta
|
||||
(cond
|
||||
(= :chevron accessory)
|
||||
[react/view
|
||||
[icons/icon :main-icons/next {:color colors/gray-transparent-40}]]
|
||||
(= :check accessory)
|
||||
[react/view
|
||||
[icons/icon :main-icons/check {:color colors/gray}]]
|
||||
:else
|
||||
[react/view {:padding-right 8 :flex-shrink 1}
|
||||
(cond
|
||||
(string? accessory)
|
||||
[react/text {:style styles/accessory-text}
|
||||
accessory]
|
||||
(vector? accessory)
|
||||
accessory
|
||||
:else
|
||||
[accessory])])
|
||||
{:key accessory}))
|
||||
(when-not (nil? accessory)
|
||||
(with-meta
|
||||
(cond
|
||||
(= :chevron accessory)
|
||||
[react/view
|
||||
[icons/icon :main-icons/next {:color colors/gray-transparent-40}]]
|
||||
(= :check accessory)
|
||||
[react/view
|
||||
[icons/icon :main-icons/check {:color colors/gray}]]
|
||||
:else
|
||||
[react/view {:margin-right 8 :flex-shrink 1}
|
||||
(cond
|
||||
(string? accessory)
|
||||
[react/text {:style styles/accessory-text :number-of-lines 1}
|
||||
accessory]
|
||||
(vector? accessory)
|
||||
accessory
|
||||
:else
|
||||
[accessory])])
|
||||
{:key accessory})))
|
||||
(when error
|
||||
[tooltip/tooltip error styles/error])]]))
|
||||
|
|
|
@ -53,26 +53,19 @@
|
|||
:stickers-pack-modal {:type :main}
|
||||
:tribute-learn-more {:type :main}
|
||||
:show-extension-modal {:type :main}
|
||||
:wallet {:type :wallet-tab}
|
||||
:wallet-stack {:type :wallet-tab}
|
||||
:wallet {:type :main}
|
||||
:wallet-stack {:type :main}
|
||||
:profile-qr-viewer {:type :modal-white}
|
||||
:recipient-qr-code {:type :transparent}
|
||||
:wallet-send-assets {:type :wallet}
|
||||
:wallet-request-assets {:type :wallet}
|
||||
:recent-recipients {:type :wallet}
|
||||
:contact-code {:type :wallet}
|
||||
:wallet-onboarding-setup {:type :wallet}
|
||||
:wallet-send-transaction-request {:type :wallet}
|
||||
:wallet-request-transaction {:type :wallet-tab}
|
||||
:wallet-send-transaction-chat {:type :wallet}
|
||||
:wallet-send-transaction {:type :wallet-tab}
|
||||
:sign-message-modal {:type :modal-wallet}
|
||||
:wallet-transaction-fee {:type :modal-wallet}
|
||||
:wallet-onboarding-setup-modal {:type :modal-wallet}
|
||||
:wallet-send-transaction-modal {:type :modal-wallet}
|
||||
:wallet-settings-assets {:type :wallet}
|
||||
:wallet-add-custom-token {:type :wallet}
|
||||
:wallet-sign-message-modal {:type :modal-wallet}
|
||||
:wallet-settings-assets {:type :main}
|
||||
:wallet-account {:type :main}
|
||||
:wallet-add-custom-token {:type :main}
|
||||
:wallet-settings-hook {:type :wallet}
|
||||
:wallet-transactions-filter {:type :modal-main}}
|
||||
view-id))
|
||||
|
|
|
@ -9,15 +9,6 @@
|
|||
status-im.web3.events
|
||||
status-im.ui.screens.add-new.new-chat.navigation
|
||||
status-im.ui.screens.profile.events
|
||||
status-im.ui.screens.wallet.collectibles.events
|
||||
status-im.ui.screens.wallet.send.events
|
||||
status-im.ui.screens.wallet.request.events
|
||||
status-im.ui.screens.wallet.choose-recipient.events
|
||||
status-im.ui.screens.wallet.collectibles.cryptokitties.events
|
||||
status-im.ui.screens.wallet.collectibles.cryptostrikers.events
|
||||
status-im.ui.screens.wallet.collectibles.etheremon.events
|
||||
status-im.ui.screens.wallet.collectibles.superrare.events
|
||||
status-im.ui.screens.wallet.collectibles.kudos.events
|
||||
status-im.ui.screens.wallet.navigation
|
||||
status-im.utils.keychain.events
|
||||
[re-frame.core :as re-frame]
|
||||
|
@ -31,7 +22,6 @@
|
|||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.http :as http]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.wallet.core :as wallet]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.biometric-auth.core :as biometric-auth]
|
||||
[status-im.constants :as const]))
|
||||
|
|
|
@ -104,19 +104,13 @@
|
|||
:value value}]))
|
||||
|
||||
(defn- my-profile-settings [{:keys [seed-backed-up? mnemonic]}
|
||||
{:keys [settings] :as account}
|
||||
currency
|
||||
{:keys [settings]}
|
||||
logged-in?
|
||||
extensions]
|
||||
(let [show-backup-seed? (and (not seed-backed-up?) (not (string/blank? mnemonic)))
|
||||
extensions-settings (vals (get extensions :settings))]
|
||||
[react/view
|
||||
[profile.components/settings-title (i18n/label :t/settings)]
|
||||
[profile.components/settings-item {:label-kw :t/main-currency
|
||||
:value (:code currency)
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :currency-settings])
|
||||
:accessibility-label :currency-button}]
|
||||
[profile.components/settings-item-separator]
|
||||
(when (and config/hardwallet-enabled?
|
||||
platform/android?)
|
||||
[profile.components/settings-item {:label-kw :t/status-keycard
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
:edit-network
|
||||
:log-level-settings
|
||||
:fleet-settings
|
||||
:currency-settings
|
||||
:mobile-network-settings
|
||||
:backup-seed
|
||||
:tribute-to-talk
|
||||
|
|
|
@ -55,13 +55,13 @@
|
|||
[status-im.ui.screens.stickers.views :as stickers]
|
||||
[status-im.ui.screens.wallet.collectibles.views :as collectibles]
|
||||
[status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[status-im.ui.screens.wallet.main.views :as wallet.main]
|
||||
[status-im.ui.screens.wallet.onboarding.views :as wallet.onboarding]
|
||||
[status-im.ui.screens.wallet.request.views :as request]
|
||||
[status-im.ui.screens.wallet.send.views :as send]
|
||||
[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.custom-tokens.views :as custom-tokens]
|
||||
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
|
||||
[status-im.ui.screens.wallet.account.views :as wallet.account]))
|
||||
|
||||
(def all-screens
|
||||
{:login login/login
|
||||
|
@ -103,10 +103,9 @@
|
|||
:tribute-learn-more [:modal tr-to-talk/learn-more]
|
||||
:chat-modal [:modal chat/chat-modal]
|
||||
:show-extension-modal [:modal extensions.module/show-extension-modal-view]
|
||||
:wallet-onboarding-setup-modal [:modal wallet.onboarding/modal]
|
||||
:wallet wallet.main/wallet
|
||||
:wallet wallet.accounts/accounts-overview
|
||||
:wallet-account wallet.account/account
|
||||
:collectibles-list collectibles/collectibles-list
|
||||
:wallet-onboarding-setup wallet.onboarding/screen
|
||||
:contact-code wallet.components/contact-code
|
||||
:wallet-send-transaction send/send-transaction
|
||||
:recent-recipients wallet.components/recent-recipients
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
(def wallet-stack
|
||||
{:name :wallet-stack
|
||||
:screens [:wallet
|
||||
:wallet-account
|
||||
:collectibles-list
|
||||
:wallet-onboarding-setup
|
||||
:contact-code
|
||||
|
@ -25,5 +26,6 @@
|
|||
:extension-screen-holder
|
||||
:wallet-settings-assets
|
||||
:wallet-add-custom-token
|
||||
:wallet-custom-token-details]
|
||||
:wallet-custom-token-details
|
||||
:currency-settings]
|
||||
:config {:initialRouteName :wallet}})
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
(views/defview fee-bottom-sheet [fee-display-symbol]
|
||||
(views/letsubs [{gas-edit :gas gas-price-edit :gasPrice max-fee :max-fee} [:signing/edit-fee]]
|
||||
[react/view
|
||||
[react/view {:style {:margin-horizontal 16 :margin-vertical 8}}
|
||||
[react/view {:style {:margin-horizontal 16 :margin-top 8}}
|
||||
[react/text {:style {:typography :title-bold}} (i18n/label :t/network-fee)]
|
||||
[react/view {:style {:flex-direction :row :margin-top 8}}
|
||||
[react/view {:flex 1}
|
||||
|
@ -35,7 +35,7 @@
|
|||
:auto-focus false}]]
|
||||
[react/view {:margin-top 58 :margin-left 10}
|
||||
[react/text (i18n/label :t/gwei)]]]
|
||||
[react/view {:margin-vertical 28 :align-items :center}
|
||||
[react/view {:margin-vertical 16 :align-items :center}
|
||||
[react/text {:style {:color colors/gray}} (i18n/label :t/wallet-transaction-total-fee)]
|
||||
[react/view {:height 8}]
|
||||
[react/nested-text {:style {:font-size 17}}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[reagent.core :as reagent]
|
||||
[status-im.ui.components.list-item.views :as list-item]
|
||||
[status-im.ui.components.button.view :as button]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
|
|
|
@ -14,7 +14,12 @@
|
|||
[status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings]
|
||||
[status-im.ui.screens.home.sheet.views :as home.sheet]
|
||||
[status-im.ui.screens.routing.core :as routing]
|
||||
[status-im.ui.screens.signing.views :as signing]))
|
||||
[status-im.ui.screens.signing.views :as signing]
|
||||
status-im.ui.screens.wallet.collectibles.etheremon.views
|
||||
status-im.ui.screens.wallet.collectibles.cryptostrikers.views
|
||||
status-im.ui.screens.wallet.collectibles.cryptokitties.views
|
||||
status-im.ui.screens.wallet.collectibles.superrare.views
|
||||
status-im.ui.screens.wallet.collectibles.kudos.views))
|
||||
|
||||
(defonce rand-label (when js/goog.DEBUG (rand/id)))
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
(ns status-im.ui.screens.wallet.account.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(defn card [window-width]
|
||||
{:width (- window-width 64) :height 161
|
||||
:background-color colors/blue
|
||||
:shadow-offset {:width 0 :height 2}
|
||||
:shadow-radius 8
|
||||
:shadow-opacity 1
|
||||
:shadow-color "rgba(0, 9, 26, 0.12)"
|
||||
:elevation 2
|
||||
:border-radius 8
|
||||
:justify-content :space-between})
|
||||
|
||||
(def divider
|
||||
{:height 52
|
||||
:width 1
|
||||
:background-color (colors/alpha colors/black 0.2)
|
||||
:shadow-offset {:width 0 :height 2}
|
||||
:shadow-radius 8
|
||||
:shadow-opacity 1
|
||||
:shadow-color "rgba(0, 9, 26, 0.12)"})
|
|
@ -0,0 +1,112 @@
|
|||
(ns status-im.ui.screens.wallet.account.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.screens.wallet.accounts.views :as accounts]
|
||||
[status-im.ui.screens.wallet.accounts.sheets :as sheets]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.components.bottom-bar.styles :as tabs.styles]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[status-im.ui.screens.wallet.account.styles :as styles]
|
||||
[status-im.ui.screens.wallet.transactions.views :as history]
|
||||
[status-im.ethereum.core :as ethereum]))
|
||||
|
||||
(def state (reagent/atom {:tab :assets}))
|
||||
|
||||
(defn toolbar-view [title]
|
||||
[react/view
|
||||
[status-bar/status-bar]
|
||||
[toolbar/toolbar {:transparent? true}
|
||||
toolbar/default-nav-back
|
||||
[toolbar/content-title title]
|
||||
[toolbar/actions
|
||||
[{:icon :main-icons/more
|
||||
:icon-opts {:color :black}
|
||||
:handler #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content sheets/account-settings
|
||||
:content-height 130}])}]]]])
|
||||
|
||||
(defn button [label icon handler]
|
||||
[react/touchable-highlight {:on-press handler :style {:flex 1}}
|
||||
[react/view {:flex 1 :align-items :center :justify-content :center}
|
||||
[react/view {:flex-direction :row :align-items :center}
|
||||
[icons/icon icon {:color colors/white}]
|
||||
[react/text {:style {:margin-left 8 :color colors/white}} label]]]])
|
||||
|
||||
(views/defview account-card []
|
||||
(views/letsubs [currency [:wallet/currency]
|
||||
portfolio-value [:portfolio-value]
|
||||
window-width [:dimensions/window-width]
|
||||
{:keys [address]} [:account/account]]
|
||||
[react/view {:style (styles/card window-width)}
|
||||
[react/view {:padding 16 :padding-bottom 12 :flex 1 :justify-content :space-between}
|
||||
[react/nested-text {:style {:color colors/white-transparent :line-height 38
|
||||
:font-weight "600" :font-size 32}}
|
||||
(accounts/total-tilde portfolio-value)
|
||||
[{:style {:color colors/white}} portfolio-value]
|
||||
" "
|
||||
(:code currency)]
|
||||
[react/text {:number-of-lines 1 :ellipsize-mode :middle
|
||||
:style {:width (/ window-width 3)
|
||||
:line-height 22 :font-size 13
|
||||
:font-family "monospace"
|
||||
:color (colors/alpha colors/white 0.7)}}
|
||||
(ethereum/normalized-address address)]]
|
||||
[react/view {:position :absolute :top 12 :right 12}
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.accounts/share])}
|
||||
[icons/icon :main-icons/share {:color colors/white}]]]
|
||||
[react/view {:height 52 :background-color (colors/alpha colors/black 0.2)
|
||||
:border-bottom-right-radius 8 :border-bottom-left-radius 8 :flex-direction :row}
|
||||
[button (i18n/label :t/wallet-send) :main-icons/send #(re-frame/dispatch [:navigate-to :wallet-send-transaction])]
|
||||
[react/view {:style styles/divider}]
|
||||
[button (i18n/label :t/receive) :main-icons/receive #(re-frame/dispatch [:navigate-to :wallet-request-transaction])]]]))
|
||||
|
||||
(views/defview transactions []
|
||||
(views/letsubs [{:keys [transaction-history-sections]}
|
||||
[:wallet.transactions.history/screen]]
|
||||
[history/history-list transaction-history-sections]))
|
||||
|
||||
(views/defview assets-and-collections []
|
||||
(views/letsubs [{:keys [tokens nfts]} [:wallet/visible-assets-with-values]
|
||||
currency [:wallet/currency]]
|
||||
(let [{:keys [tab]} @state]
|
||||
[react/view {:flex 1}
|
||||
[react/view {:flex-direction :row :margin-bottom 8 :padding-horizontal 4}
|
||||
[accounts/tab-title state :assets (i18n/label :t/wallet-assets) (= tab :assets)]
|
||||
(when (seq nfts)
|
||||
[accounts/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)])
|
||||
[accounts/tab-title state :history (i18n/label :t/history) (= tab :history)]]
|
||||
(cond
|
||||
(= tab :assets)
|
||||
[list/flat-list {:data tokens
|
||||
:default-separator? false
|
||||
:key-fn :name
|
||||
:footer [react/view
|
||||
{:style {:height tabs.styles/tabs-diff
|
||||
:align-self :stretch}}]
|
||||
:render-fn (accounts/render-asset (:code currency))}]
|
||||
(= tab :nft)
|
||||
[list/flat-list {:data nfts
|
||||
:default-separator? false
|
||||
:key-fn :name
|
||||
:footer [react/view
|
||||
{:style {:height tabs.styles/tabs-diff
|
||||
:align-self :stretch}}]
|
||||
:render-fn accounts/render-collectible}]
|
||||
(= tab :history)
|
||||
[transactions])])))
|
||||
|
||||
(defn account []
|
||||
[react/view {:flex 1 :background-color colors/white}
|
||||
[toolbar-view "Status account"]
|
||||
[react/scroll-view
|
||||
[react/view {:padding-left 16}
|
||||
[react/scroll-view {:horizontal true}
|
||||
[react/view {:flex-direction :row :padding-top 8 :padding-bottom 12}
|
||||
[account-card]]]]
|
||||
[assets-and-collections]]])
|
|
@ -0,0 +1,65 @@
|
|||
(ns status-im.ui.screens.wallet.accounts.sheets
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ui.components.action-button.action-button :as action-button]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.colors :as colors]))
|
||||
|
||||
(defn hide-sheet-and-dispatch [event]
|
||||
(re-frame/dispatch [:bottom-sheet/hide-sheet])
|
||||
(re-frame/dispatch event))
|
||||
|
||||
(defn accounts-options [seed-backed-up?]
|
||||
(fn []
|
||||
[react/view
|
||||
[action-button/action-button {:label (i18n/label :t/wallet-manage-assets)
|
||||
:icon :main-icons/token
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :wallet-settings-assets])}]
|
||||
[action-button/action-button {:label (i18n/label :t/set-currency)
|
||||
:icon :main-icons/language
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :currency-settings])}]
|
||||
[action-button/action-button-disabled {:label (i18n/label :t/view-signing)
|
||||
:icon :main-icons/info
|
||||
:icon-opts {:color :blue}}]
|
||||
(when-not seed-backed-up?
|
||||
[action-button/action-button {:label (i18n/label :t/wallet-backup-recovery-title)
|
||||
:icon :main-icons/security
|
||||
:icon-opts {:color colors/red}
|
||||
:label-style {:color colors/red}
|
||||
:cyrcle-color (colors/alpha colors/red 0.1)
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :backup-seed])}])]))
|
||||
|
||||
(defn send-receive []
|
||||
[react/view
|
||||
[action-button/action-button {:label (i18n/label :t/wallet-send)
|
||||
:icon :main-icons/send
|
||||
:accessibility-label :send-transaction-button
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :wallet-send-transaction])}]
|
||||
[action-button/action-button {:label (i18n/label :t/receive)
|
||||
:icon :main-icons/receive
|
||||
:accessibility-label :receive-transaction-button
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :wallet-request-transaction])}]])
|
||||
|
||||
(defn add-account []
|
||||
[react/view
|
||||
[action-button/action-button-disabled {:label (i18n/label :t/add-an-account)
|
||||
:icon :main-icons/add
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :wallet-send-transaction])}]
|
||||
[action-button/action-button-disabled {:label (i18n/label :t/add-a-watch-account)
|
||||
:icon :main-icons/watch
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(hide-sheet-and-dispatch [:navigate-to :wallet-request-transaction])}]])
|
||||
|
||||
(defn account-settings []
|
||||
[react/view
|
||||
[action-button/action-button-disabled {:label (i18n/label :t/account-settings)
|
||||
:icon :main-icons/info
|
||||
:icon-opts {:color :blue}}]
|
||||
[action-button/action-button-disabled {:label (i18n/label :t/export-account)
|
||||
:icon :main-icons/copy
|
||||
:icon-opts {:color :blue}}]])
|
|
@ -0,0 +1,35 @@
|
|||
(ns status-im.ui.screens.wallet.accounts.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def card
|
||||
{:width 156
|
||||
:height 145
|
||||
:background-color colors/blue
|
||||
:shadow-offset {:width 0 :height 2}
|
||||
:shadow-radius 8
|
||||
:shadow-opacity 1
|
||||
:shadow-color "rgba(0, 9, 26, 0.12)"
|
||||
:elevation 2
|
||||
:border-radius 8
|
||||
:justify-content :space-between
|
||||
:padding 12
|
||||
:padding-bottom 6
|
||||
:margin-top 5
|
||||
:margin-bottom 5})
|
||||
|
||||
(def add-card
|
||||
{:width 156
|
||||
:height 145
|
||||
:margin-left 16
|
||||
:margin-top 5
|
||||
:margin-right 5
|
||||
:margin-bottom 5
|
||||
:background-color colors/white
|
||||
:shadow-offset {:width 0 :height 2}
|
||||
:shadow-radius 8
|
||||
:shadow-opacity 1
|
||||
:shadow-color "rgba(0, 9, 26, 0.12)"
|
||||
:elevation 2
|
||||
:border-radius 8
|
||||
:justify-content :center
|
||||
:align-items :center})
|
|
@ -0,0 +1,167 @@
|
|||
(ns status-im.ui.screens.wallet.accounts.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[status-im.ui.components.toolbar.styles :as toolbar.styles]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.ui.components.list-item.views :as list-item]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.ui.components.bottom-bar.styles :as tabs.styles]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.utils.money :as money]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.screens.wallet.accounts.sheets :as sheets]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ui.screens.wallet.accounts.styles :as styles]))
|
||||
|
||||
(def state (reagent/atom {:tab :assets}))
|
||||
|
||||
(defn total-tilde [value]
|
||||
(when (and (not= "0" value) (not= "..." value)) "~"))
|
||||
|
||||
(views/defview account-card [name]
|
||||
(views/letsubs [currency [:wallet/currency]
|
||||
portfolio-value [:portfolio-value]
|
||||
{:keys [address]} [:account/account]]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :wallet-account])
|
||||
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content sheets/send-receive
|
||||
:content-height 130}])}
|
||||
[react/view {:style styles/card}
|
||||
[react/view {:flex-direction :row :align-items :center :justify-content :space-between}
|
||||
[react/nested-text {:style {:color colors/white-transparent :font-weight "500"}}
|
||||
(total-tilde portfolio-value)
|
||||
[{:style {:color colors/white}} portfolio-value]
|
||||
" "
|
||||
(:code currency)]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.accounts/share])}
|
||||
[icons/icon :main-icons/share {:color colors/white}]]]
|
||||
[react/view
|
||||
[react/text {:style {:color colors/white :font-weight "500" :line-height 22}} name]
|
||||
[react/text {:number-of-lines 1 :ellipsize-mode :middle
|
||||
:style {:line-height 22 :font-size 13
|
||||
:font-family "monospace"
|
||||
:color (colors/alpha colors/white 0.7)}}
|
||||
(ethereum/normalized-address address)]]]]))
|
||||
|
||||
(defn add-card []
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content sheets/add-account
|
||||
:content-height 130}])}
|
||||
[react/view {:style styles/add-card}
|
||||
[react/view {:width 40 :height 40 :justify-content :center :border-radius 20
|
||||
:align-items :center :background-color (colors/alpha colors/blue 0.1) :margin-bottom 8}
|
||||
[icons/icon :main-icons/add {:color colors/blue}]]
|
||||
[react/text {:style {:color colors/blue}} (i18n/label :t/add-account)]]])
|
||||
|
||||
(defn tab-title [state key label active?]
|
||||
[react/view {:align-items :center}
|
||||
[react/touchable-highlight {:on-press #(swap! state assoc :tab key)
|
||||
:underlay-color colors/gray-lighter
|
||||
:style {:border-radius 8}}
|
||||
[react/view {:padding-horizontal 12 :padding-vertical 9}
|
||||
[react/text {:style {:font-weight "500" :color (if active? colors/black colors/gray) :line-height 22}}
|
||||
label]]]
|
||||
(when active?
|
||||
[react/view {:width 24 :height 3 :border-radius 4 :background-color colors/blue}])])
|
||||
|
||||
(defn render-asset [currency]
|
||||
(fn [{:keys [icon decimals amount color value] :as token}]
|
||||
[list-item/list-item
|
||||
{:content [react/view {:style {:margin-horizontal 16 :justify-content :center :flex-shrink 1}}
|
||||
[react/view {:flex-direction :row}
|
||||
[react/text {:style {:font-weight "500" :flex-shrink 0.5} :number-of-lines 1 :ellipsize-mode :tail}
|
||||
(wallet.utils/format-amount amount decimals)]
|
||||
[react/text {:style {:font-weight "500" :color colors/gray :margin-left 6}
|
||||
:number-of-lines 1}
|
||||
(wallet.utils/display-symbol token)]]
|
||||
(when value
|
||||
[react/text {:style {:color colors/gray}} (str value " " currency)])]
|
||||
:image (if icon
|
||||
[list/item-image icon]
|
||||
[chat-icon/custom-icon-view-list (:name token) color])}]))
|
||||
|
||||
(defn render-collectible [{:keys [name icon amount] :as collectible}]
|
||||
(let [items-number (money/to-fixed amount)
|
||||
details? (pos? items-number)]
|
||||
[react/touchable-highlight
|
||||
(when details?
|
||||
{:on-press #(re-frame/dispatch [:show-collectibles-list collectible])})
|
||||
[list-item/list-item
|
||||
{:title (wallet.utils/display-symbol collectible)
|
||||
:subtitle name
|
||||
:image [list/item-image icon]
|
||||
:accessories [items-number :chevron]}]]))
|
||||
|
||||
(views/defview assets-and-collections []
|
||||
(views/letsubs [{:keys [tokens nfts]} [:wallet/visible-assets-with-values]
|
||||
currency [:wallet/currency]]
|
||||
(let [{:keys [tab]} @state]
|
||||
[react/view {:flex 1}
|
||||
[react/view {:flex-direction :row :margin-bottom 8 :margin-horizontal 4}
|
||||
[tab-title state :assets (i18n/label :t/wallet-assets) (= tab :assets)]
|
||||
[tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)]]
|
||||
(if (= tab :assets)
|
||||
[list/flat-list {:data tokens
|
||||
:default-separator? false
|
||||
:key-fn :name
|
||||
:footer [react/view
|
||||
{:style {:height tabs.styles/tabs-diff
|
||||
:align-self :stretch}}]
|
||||
:render-fn (render-asset (:code currency))}]
|
||||
(if (seq nfts)
|
||||
[list/flat-list {:data nfts
|
||||
:default-separator? false
|
||||
:key-fn :name
|
||||
:footer [react/view
|
||||
{:style {:height tabs.styles/tabs-diff
|
||||
:align-self :stretch}}]
|
||||
:render-fn render-collectible}]
|
||||
[react/view {:align-items :center :margin-top 32}
|
||||
[react/text {:style {:color colors/gray}}
|
||||
(i18n/label :t/no-collectibles)]]))])))
|
||||
|
||||
(views/defview total-value []
|
||||
(views/letsubs [currency [:wallet/currency]
|
||||
portfolio-value [:portfolio-value]]
|
||||
[react/view
|
||||
[react/nested-text {:style {:font-size 32 :color colors/gray :font-weight "600"}}
|
||||
(total-tilde portfolio-value)
|
||||
[{:style {:color colors/black}} portfolio-value]
|
||||
" "
|
||||
(:code currency)]
|
||||
[react/text {:style {:color colors/gray}} (i18n/label :t/wallet-total-value)]]))
|
||||
|
||||
(views/defview accounts-options []
|
||||
(views/letsubs [{:keys [seed-backed-up?]} [:account/account]]
|
||||
[react/view {:flex-direction :row :align-items :center}
|
||||
[react/view {:flex 1 :padding-left 16}
|
||||
(when-not seed-backed-up?
|
||||
[react/view {:flex-direction :row :align-items :center}
|
||||
[react/view {:width 14 :height 14 :background-color colors/gray :border-radius 7 :align-items :center
|
||||
:justify-content :center :margin-right 9}
|
||||
[react/text {:style {:color colors/white :font-size 13 :font-weight "700"}} "!"]]
|
||||
[react/text {:style {:color colors/gray}} (i18n/label :t/back-up-your-seed-phrase)]])]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (sheets/accounts-options seed-backed-up?)
|
||||
:content-height (if seed-backed-up? 190 250)}])}
|
||||
[react/view {:height toolbar.styles/toolbar-height :width toolbar.styles/toolbar-height :align-items :center
|
||||
:justify-content :center}
|
||||
[icons/icon :main-icons/more]]]]))
|
||||
|
||||
(defn accounts-overview []
|
||||
[react/view {:flex 1}
|
||||
[status-bar/status-bar]
|
||||
[react/scroll-view
|
||||
[accounts-options]
|
||||
[react/view {:margin-top 8 :padding-horizontal 16}
|
||||
[total-value]
|
||||
[react/scroll-view {:horizontal true}
|
||||
[react/view {:flex-direction :row :padding-top 11 :padding-bottom 12}
|
||||
[account-card "Status account"]
|
||||
[add-card]]]]
|
||||
[assets-and-collections]]])
|
|
@ -1,122 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.choose-recipient.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contact.db :as contact.db]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.eip55 :as eip55]
|
||||
[status-im.ethereum.eip681 :as eip681]
|
||||
[status-im.ethereum.ens :as ens]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.money :as money]))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet/toggle-flashlight
|
||||
(fn [{:keys [db]}]
|
||||
(let [flashlight-state (get-in db [:wallet :send-transaction :camera-flashlight])
|
||||
toggled-state (if (= :on flashlight-state) :off :on)]
|
||||
{:db (assoc-in db [:wallet :send-transaction :camera-flashlight] toggled-state)})))
|
||||
|
||||
(defn- find-address-name [db address]
|
||||
(:name (contact.db/find-contact-by-address (:contacts/contacts db) address)))
|
||||
|
||||
(defn- fill-request-details [db {:keys [address name value symbol gas gasPrice public-key from-chat?]} request?]
|
||||
{:pre [(not (nil? address))]}
|
||||
(let [name (or name (find-address-name db address))
|
||||
data-path (if request?
|
||||
[:wallet :request-transaction]
|
||||
[:wallet :send-transaction])]
|
||||
(update-in db data-path
|
||||
(fn [{old-symbol :symbol :as old-transaction}]
|
||||
(let [symbol-changed? (not= old-symbol symbol)]
|
||||
(cond-> (assoc old-transaction :to address :to-name name :public-key public-key)
|
||||
value (assoc :amount value)
|
||||
symbol (assoc :symbol symbol)
|
||||
(and gas symbol-changed?) (assoc :gas (money/bignumber gas))
|
||||
from-chat? (assoc :from-chat? from-chat?)
|
||||
(and gasPrice symbol-changed?)
|
||||
(assoc :gas-price (money/bignumber gasPrice))
|
||||
(and symbol (not gasPrice) symbol-changed?)
|
||||
(assoc :gas-price (ethereum/estimate-gas symbol))))))))
|
||||
|
||||
(defn- extract-details
|
||||
"First try to parse as EIP681 URI, if not assume this is an address directly.
|
||||
Returns a map containing at least the `address` and `chain-id` keys"
|
||||
[s chain-id all-tokens]
|
||||
(or (let [m (eip681/parse-uri s)]
|
||||
(merge m (eip681/extract-request-details m all-tokens)))
|
||||
(when (ethereum/address? s)
|
||||
{:address s :chain-id chain-id})))
|
||||
|
||||
;; NOTE(janherich) - whenever changing assets, we want to clear the previusly set amount/amount-text
|
||||
(defn changed-asset [{:keys [db] :as fx} old-symbol new-symbol]
|
||||
(-> fx
|
||||
(merge {:wallet/update-gas-price
|
||||
{:success-event :wallet/update-gas-price-success
|
||||
:edit? false}})
|
||||
(assoc-in [:db :wallet :send-transaction :amount] nil)
|
||||
(assoc-in [:db :wallet :send-transaction :amount-text] nil)
|
||||
(assoc-in [:db :wallet :send-transaction :asset-error]
|
||||
(i18n/label :t/changed-asset-warning {:old old-symbol :new new-symbol}))))
|
||||
|
||||
(defn changed-amount-warning [fx old-amount new-amount]
|
||||
(assoc-in fx [:db :wallet :send-transaction :amount-error]
|
||||
(i18n/label :t/changed-amount-warning {:old old-amount :new new-amount})))
|
||||
|
||||
(defn use-default-eth-gas [fx]
|
||||
(assoc-in fx [:db :wallet :send-transaction :gas]
|
||||
(ethereum/default-transaction-gas)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:resolve-address
|
||||
(fn [{:keys [registry ens-name cb]}]
|
||||
(ens/get-addr registry ens-name cb)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.send/set-recipient
|
||||
(fn [{:keys [db]} [_ recipient]]
|
||||
(let [chain (ethereum/chain-keyword db)]
|
||||
(if (ens/is-valid-eth-name? recipient)
|
||||
{:resolve-address {:registry (get ens/ens-registries chain)
|
||||
:ens-name recipient
|
||||
:cb #(re-frame/dispatch [:wallet.send/set-recipient %])}}
|
||||
(if (ethereum/address? recipient)
|
||||
(let [checksum (eip55/address->checksum recipient)]
|
||||
(if (eip55/valid-address-checksum? checksum)
|
||||
{:db (assoc-in db [:wallet :send-transaction :to] checksum)
|
||||
:dispatch [:navigate-back]}
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address-checksum {:data recipient})}))
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data recipient})})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet/fill-request-from-url
|
||||
(fn [{{:keys [network] :wallet/keys [all-tokens] :as db} :db} [_ data origin]]
|
||||
(let [current-chain-id (get-in constants/default-networks [network :config :NetworkId])
|
||||
{:keys [address chain-id] :as details} (extract-details data current-chain-id all-tokens)
|
||||
valid-network? (boolean (= current-chain-id chain-id))
|
||||
previous-state (get-in db [:wallet :send-transaction])
|
||||
old-symbol (:symbol previous-state)
|
||||
new-symbol (:symbol details)
|
||||
old-amount (:amount previous-state)
|
||||
new-amount (:value details)
|
||||
new-gas (:gas details)
|
||||
symbol-changed? (and old-symbol new-symbol (not= old-symbol new-symbol))]
|
||||
(cond-> {:db db}
|
||||
(not= :deep-link origin) (assoc :dispatch [:navigate-back]) ;; Only navigate-back when called from within wallet
|
||||
(and address valid-network?) (update :db #(fill-request-details % details false))
|
||||
symbol-changed? (changed-asset old-symbol new-symbol)
|
||||
(and old-amount new-amount (not= old-amount new-amount)) (changed-amount-warning old-amount new-amount)
|
||||
;; NOTE(goranjovic) - the next line is there is because QR code scanning switches the amount to ETH
|
||||
;; automatically, so we need to update the gas limit accordingly. The check for origin screen is there
|
||||
;; so that we wouldn't also switch gas limit to ETH specific if the user pastes address as text.
|
||||
;; We need to check if address is defined so that we wouldn't trigger this behavior when invalid QR is scanned
|
||||
;; (e.g. public-key)
|
||||
(and address (= origin :qr) (not new-gas) symbol-changed?) (use-default-eth-gas)
|
||||
(not address) (assoc :ui/show-error (i18n/label :t/wallet-invalid-address {:data data}))
|
||||
(and address (not valid-network?)) (assoc :ui/show-error (i18n/label :t/wallet-invalid-chain-id {:data data :chain current-chain-id}))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet/fill-request-from-contact
|
||||
(fn [{db :db} [_ {:keys [address name public-key]} request?]]
|
||||
{:db (fill-request-details db {:address address :name name :public-key public-key} request?)
|
||||
:dispatch [:navigate-back]}))
|
|
@ -9,7 +9,6 @@
|
|||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.screens.wallet.choose-recipient.styles :as styles]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.collectibles.cryptokitties.events
|
||||
(:require [status-im.utils.handlers :as handlers]
|
||||
[status-im.ui.screens.wallet.collectibles.events :as collectibles]
|
||||
[status-im.utils.http :as http]))
|
||||
|
||||
(def ck :CK)
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-kitties
|
||||
(fn [{db :db} [_ ids]]
|
||||
{:db db
|
||||
:http-get-n (mapv (fn [id]
|
||||
{:url (str "https://api.cryptokitties.co/kitties/" id)
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success ck {id (http/parse-payload o)}])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure ck {id (http/parse-payload o)}])})
|
||||
ids)}))
|
||||
|
||||
;; TODO(andrey) Each HTTP call will return up to 100 kitties. Maybe we need to implement some kind of paging later
|
||||
(defmethod collectibles/load-collectibles-fx ck [_ _ items-number address _]
|
||||
{:http-get {:url (str "https://api.cryptokitties.co/kitties?offset=0&limit="
|
||||
items-number
|
||||
"&owner_wallet_address="
|
||||
address
|
||||
"&parents=false")
|
||||
:success-event-creator (fn [o]
|
||||
[:load-kitties (map :id (:kitties (http/parse-payload o)))])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectibles-failure (http/parse-payload o)])
|
||||
:timeout-ms 10000}})
|
|
@ -1,12 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.collectibles.cryptostrikers.events
|
||||
(:require [status-im.ui.screens.wallet.collectibles.events :as collectibles]
|
||||
[status-im.utils.http :as http]))
|
||||
|
||||
(def strikers :STRK)
|
||||
|
||||
(defmethod collectibles/load-collectible-fx strikers [_ _ id]
|
||||
{:http-get {:url (str "https://us-central1-cryptostrikers-prod.cloudfunctions.net/cards/" id)
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success strikers {id (http/parse-payload o)}])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure strikers {id (http/parse-payload o)}])}})
|
|
@ -1,12 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.collectibles.etheremon.events
|
||||
(:require [status-im.ui.screens.wallet.collectibles.events :as collectibles]
|
||||
[status-im.utils.http :as http]))
|
||||
|
||||
(def emona :EMONA)
|
||||
|
||||
(defmethod collectibles/load-collectible-fx emona [_ _ id]
|
||||
{:http-get {:url (str "https://www.etheremon.com/api/monster/get_data?monster_ids=" id)
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success emona (:data (http/parse-payload o))])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure emona {id (http/parse-payload o)}])}})
|
|
@ -1,74 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.collectibles.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.browser.core :as browser]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.erc721 :as erc721]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.money :as money]))
|
||||
|
||||
(defmulti load-collectible-fx (fn [_ symbol _] symbol))
|
||||
|
||||
(defmethod load-collectible-fx :default [_ _ _] nil)
|
||||
|
||||
(defmulti load-collectibles-fx (fn [_ symbol _ _] symbol))
|
||||
|
||||
(defmethod load-collectibles-fx :default [all-tokens symbol items-number address chain-id]
|
||||
{:load-collectibles-fx [all-tokens symbol items-number address chain-id]})
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-collectibles-list
|
||||
(fn [{:keys [db]} [_ address {:keys [symbol amount] :as collectible}]]
|
||||
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
|
||||
all-tokens (:wallet/all-tokens db)
|
||||
items-number (money/to-number amount)
|
||||
loaded-items-number (count (get-in db [:collectibles symbol]))]
|
||||
(merge (when (not= items-number loaded-items-number)
|
||||
(load-collectibles-fx all-tokens symbol items-number address chain-id))
|
||||
{:dispatch [:navigate-to :collectibles-list collectible]}))))
|
||||
|
||||
(defn load-token [i items-number contract address symbol]
|
||||
(when (< i items-number)
|
||||
(erc721/token-of-owner-by-index contract address i
|
||||
(fn [response]
|
||||
(load-token (inc i) items-number contract address symbol)
|
||||
(re-frame/dispatch [:load-collectible symbol (.toNumber response)])))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:load-collectibles-fx
|
||||
(fn [[all-tokens symbol items-number address chain-id]]
|
||||
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
||||
contract (:address (tokens/symbol->token all-tokens chain symbol))]
|
||||
(load-token 0 items-number contract address symbol))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectible
|
||||
(fn [cofx [_ symbol token-id]]
|
||||
(load-collectible-fx cofx symbol token-id)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:store-collectibles
|
||||
(fn [{db :db} [_ symbol collectibles]]
|
||||
{:db (update-in db [:collectibles symbol] merge
|
||||
(reduce #(assoc %1 (:tokenId %2) %2) {} collectibles))}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectible-success
|
||||
(fn [{db :db} [_ symbol collectibles]]
|
||||
{:db (update-in db [:collectibles symbol] merge collectibles)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectibles-failure
|
||||
(fn [{db :db} [_ reason]]
|
||||
{:db (update-in db [:collectibles symbol :errors] merge reason)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectible-failure
|
||||
(fn [{db :db} [_]]
|
||||
{:db db}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:open-collectible-in-browser
|
||||
(fn [cofx [_ url]]
|
||||
(browser/open-url cofx url)))
|
|
@ -1,45 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.collectibles.kudos.events
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.erc721 :as erc721]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.ui.screens.wallet.collectibles.events :as collectibles]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.http :as http]))
|
||||
|
||||
(def kudos :KDO)
|
||||
|
||||
(defmethod collectibles/load-collectible-fx kudos [{db :db} symbol id]
|
||||
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
|
||||
all-tokens (:wallet/all-tokens db)]
|
||||
{:erc721-token-uri [all-tokens symbol id chain-id]}))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:erc721-token-uri
|
||||
(fn [[all-tokens symbol tokenId chain-id]]
|
||||
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
||||
contract (:address (tokens/symbol->token all-tokens chain symbol))]
|
||||
(erc721/token-uri contract
|
||||
tokenId
|
||||
#(re-frame/dispatch [:token-uri-success
|
||||
tokenId
|
||||
(when %
|
||||
(subs % (.indexOf % "http")))]))))) ;; extra chars in rinkeby
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:token-uri-success
|
||||
(fn [_ [_ tokenId token-uri]]
|
||||
{:http-get {:url
|
||||
token-uri
|
||||
:success-event-creator
|
||||
(fn [o]
|
||||
[:load-collectible-success kudos {tokenId (update (http/parse-payload o)
|
||||
:image
|
||||
string/replace
|
||||
#"http:"
|
||||
"https:")}]) ;; http in mainnet
|
||||
:failure-event-creator
|
||||
(fn [o]
|
||||
[:load-collectible-failure kudos {tokenId (http/parse-payload o)}])}}))
|
|
@ -1,41 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.collectibles.superrare.events
|
||||
(:require [status-im.ethereum.core :as ethereum]
|
||||
[status-im.ui.screens.wallet.collectibles.events :as collectibles]
|
||||
[status-im.utils.http :as http]
|
||||
[status-im.utils.types :as types]))
|
||||
|
||||
(def superrare :SUPR)
|
||||
|
||||
(defmethod collectibles/load-collectible-fx superrare [_ _ ids]
|
||||
{:http-get-n (mapv (fn [id]
|
||||
{:url id
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success superrare {id (http/parse-payload o)}])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure superrare {id (http/parse-payload o)}])})
|
||||
ids)})
|
||||
|
||||
(def graphql-url "https://api.pixura.io/graphql")
|
||||
|
||||
(defn graphql-query [address]
|
||||
(str "{
|
||||
collectiblesByOwner: allErc721Tokens(condition: {owner: \"" address "\"}) {
|
||||
collectibles: nodes {
|
||||
tokenId,
|
||||
metadata: erc721MetadatumByTokenId {
|
||||
metadataUri,
|
||||
description,
|
||||
name,
|
||||
imageUri
|
||||
}}}}"))
|
||||
|
||||
(defmethod collectibles/load-collectibles-fx superrare [_ _ _ address _]
|
||||
{:http-post {:url graphql-url
|
||||
:data (types/clj->json {:query (graphql-query (ethereum/naked-address address))})
|
||||
:opts {:headers {"Content-Type" "application/json"}}
|
||||
:success-event-creator (fn [{:keys [response-body]}]
|
||||
[:store-collectibles superrare
|
||||
(get-in (http/parse-payload response-body) [:data :collectiblesByOwner :collectibles])])
|
||||
:failure-event-creator (fn [{:keys [response-body]}]
|
||||
[:load-collectibles-failure (http/parse-payload response-body)])
|
||||
:timeout-ms 10000}})
|
|
@ -3,8 +3,6 @@
|
|||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.styles :as styles]))
|
||||
|
||||
;; Components
|
||||
|
||||
(def cartouche-container
|
||||
{:flex 1
|
||||
:margin-top 16
|
||||
|
@ -31,18 +29,6 @@
|
|||
:justify-content :space-between
|
||||
:align-items :center})
|
||||
|
||||
(def cartouche-text-wrapper
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 15
|
||||
:padding-vertical 15})
|
||||
|
||||
(def cartouche-primary-text
|
||||
{:color colors/white})
|
||||
|
||||
(def cartouche-secondary-text
|
||||
{:color colors/white-transparent})
|
||||
|
||||
(def text-content
|
||||
{:color colors/white})
|
||||
|
||||
|
@ -193,4 +179,4 @@
|
|||
:background-color colors/white-light-transparent})
|
||||
|
||||
(def button-text
|
||||
{:color colors/white})
|
||||
{:color colors/white})
|
|
@ -25,7 +25,7 @@
|
|||
:as
|
||||
choose-recipient]
|
||||
[status-im.ui.screens.wallet.components.styles :as styles]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.core :as utils.core]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.utils :as utils.utils])
|
||||
|
@ -90,19 +90,6 @@
|
|||
[vector-icons/icon icon (merge {:color :white} icon-opts)]]
|
||||
content)]]])])
|
||||
|
||||
(defn- cartouche-primary-text [s]
|
||||
[react/text {:style styles/cartouche-primary-text}
|
||||
s])
|
||||
|
||||
(defn cartouche-secondary-text [s]
|
||||
[react/text {:style styles/cartouche-secondary-text}
|
||||
s])
|
||||
|
||||
(defn cartouche-text-content [primary secondary]
|
||||
[react/view styles/cartouche-text-wrapper
|
||||
[cartouche-primary-text primary]
|
||||
[cartouche-secondary-text secondary]])
|
||||
|
||||
(defn view-asset [symbol]
|
||||
[react/view
|
||||
[react/i18n-text {:style styles/label :key :wallet-asset}]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
[status-im.ui.components.text-input.view :as text-input]
|
||||
[status-im.ui.components.common.common :as components.common]
|
||||
[clojure.string :as string]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.action-button.action-button :as action-button]))
|
||||
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.main.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
;; Main section
|
||||
|
||||
(defstyle main-section
|
||||
{:flex 1})
|
||||
|
||||
(defstyle scroll-bottom
|
||||
{:background-color colors/white
|
||||
:zIndex -1
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:android {:height 0}
|
||||
:ios {:height 9999}})
|
||||
|
||||
(def backup-seed-phrase-container
|
||||
{:flex-direction :row
|
||||
:background-color colors/black-transparent
|
||||
:margin 16
|
||||
:border-radius 8
|
||||
:padding-top 10
|
||||
:padding-bottom 10
|
||||
:padding-horizontal 16})
|
||||
|
||||
(def backup-seed-phrase-title
|
||||
{:color colors/white})
|
||||
|
||||
(def backup-seed-phrase-description
|
||||
{:color colors/white-transparent})
|
||||
|
||||
(def total-balance-text
|
||||
{:text-align :center
|
||||
:padding-top 49
|
||||
:padding-bottom 38
|
||||
:background-color colors/blue
|
||||
:color colors/white-transparent
|
||||
:font-size 32})
|
||||
|
||||
(def total-balance-value
|
||||
{:font-weight "700"
|
||||
:color colors/white})
|
||||
|
||||
(def total-balance-currency
|
||||
{:font-weight "700"})
|
||||
|
||||
(def snackbar-container
|
||||
{:background-color colors/gray})
|
||||
|
||||
(def snackbar-text
|
||||
{:color colors/white
|
||||
:margin-horizontal 50
|
||||
:margin-vertical 10
|
||||
:text-align :center})
|
||||
|
||||
;; Actions section
|
||||
|
||||
(def action
|
||||
{:background-color colors/white-transparent
|
||||
:width 40
|
||||
:height 40
|
||||
:border-radius 50})
|
||||
|
||||
(def action-label
|
||||
{:color :white})
|
||||
|
||||
(def action-separator
|
||||
{:height 1
|
||||
:background-color colors/white-light-transparent
|
||||
:margin-left 70})
|
||||
|
||||
;; Assets section
|
||||
|
||||
(def asset-section
|
||||
{:flex 1
|
||||
:padding-top 5
|
||||
:padding-bottom 20})
|
||||
|
||||
(def asset-section-header
|
||||
{:color colors/gray
|
||||
:margin-left 16
|
||||
:margin-top 7
|
||||
:margin-bottom 3})
|
||||
|
||||
(def asset-item-container
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between})
|
||||
|
||||
(def asset-item-value-container
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(def asset-item-value
|
||||
{:flex -1
|
||||
:font-size 16})
|
||||
|
||||
(def asset-item-currency
|
||||
{:font-size 16
|
||||
:color colors/gray
|
||||
:margin-left 6})
|
||||
|
||||
(def asset-item-price
|
||||
{:font-size 16
|
||||
:color colors/gray
|
||||
:margin-left 6})
|
||||
|
||||
(def wallet-address
|
||||
{:color colors/white
|
||||
:text-align :center})
|
||||
|
||||
(def address-section
|
||||
{:flex-grow 1
|
||||
:align-items :center
|
||||
:padding 20})
|
||||
|
||||
(def modal-history
|
||||
{:flex 1
|
||||
:background-color :white})
|
|
@ -1,201 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.main.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [reagent.core :as reagent]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.screens.wallet.onboarding.views :as onboarding.views]
|
||||
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
||||
[status-im.ui.screens.wallet.main.styles :as styles]
|
||||
[status-im.ui.screens.wallet.settings.views :as settings]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.ui.components.toolbar.actions :as action]
|
||||
status-im.ui.screens.wallet.collectibles.etheremon.views
|
||||
status-im.ui.screens.wallet.collectibles.cryptostrikers.views
|
||||
status-im.ui.screens.wallet.collectibles.cryptokitties.views
|
||||
status-im.ui.screens.wallet.collectibles.superrare.views
|
||||
status-im.ui.screens.wallet.collectibles.kudos.views
|
||||
[status-im.ui.components.status-bar.view :as status-bar.view]
|
||||
[status-im.ui.screens.wallet.transactions.views :as transactions.views]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]))
|
||||
|
||||
(defn toolbar-modal [modal-history?]
|
||||
[react/view
|
||||
[status-bar.view/status-bar {:type :modal-wallet}]
|
||||
[toolbar/toolbar {:transparent? true}
|
||||
[toolbar/nav-button (action/close-white action/default-handler)]
|
||||
[toolbar/content-wrapper]
|
||||
[toolbar/actions
|
||||
[{:icon (if modal-history? :main-icons/wallet :main-icons/two-arrows)
|
||||
:icon-opts {:color :white
|
||||
:accessibility-label (if modal-history? :wallet-modal-button :transaction-history-button)}
|
||||
:handler #(re-frame/dispatch [:set-in [:wallet :modal-history?] (not modal-history?)])}]]]])
|
||||
|
||||
(defn- total-section [value currency]
|
||||
[react/nested-text {:style styles/total-balance-text}
|
||||
(when (and
|
||||
(not= "0" value)
|
||||
(not= "..." value))
|
||||
"~")
|
||||
[{:style styles/total-balance-value
|
||||
:accessibility-label :total-amount-value-text}
|
||||
value]
|
||||
[{:style styles/total-balance-currency
|
||||
:accessibility-label :total-amount-currency-text}
|
||||
(str " " (:code currency))]])
|
||||
|
||||
(defn- backup-seed-phrase []
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :backup-seed])
|
||||
:style {:background-color colors/blue}
|
||||
:underlay-color colors/blue}
|
||||
[react/view {:style styles/backup-seed-phrase-container}
|
||||
[react/view
|
||||
[react/i18n-text {:style styles/backup-seed-phrase-title
|
||||
:key :wallet-backup-recovery-title}]
|
||||
[react/i18n-text {:style styles/backup-seed-phrase-description
|
||||
:key :wallet-backup-recovery-description}]]
|
||||
[react/view {:style {:flex 1}}]
|
||||
[react/view {:style {:align-items :center
|
||||
:justify-content :center}}
|
||||
[vector-icons/icon :main-icons/next {:color colors/white}]]]])
|
||||
|
||||
(def actions
|
||||
[{:label (i18n/label :t/wallet-send)
|
||||
:accessibility-label :send-transaction-button
|
||||
:icon :main-icons/send
|
||||
:action #(re-frame/dispatch [:navigate-to :wallet-send-transaction])}
|
||||
{:label (i18n/label :t/receive)
|
||||
:accessibility-label :receive-transaction-button
|
||||
:icon :main-icons/receive
|
||||
:action #(re-frame/dispatch [:navigate-to :wallet-request-transaction])}
|
||||
{:label (i18n/label :t/transaction-history)
|
||||
:accessibility-label :transaction-history-button
|
||||
:icon :main-icons/history
|
||||
:action #(re-frame/dispatch [:navigate-to :transactions-history])}])
|
||||
|
||||
(defn- render-asset [currency]
|
||||
(fn [{:keys [symbol icon decimals amount color] :as token}]
|
||||
(let [asset-value (re-frame/subscribe [:asset-value symbol decimals (-> currency :code keyword)])]
|
||||
[react/view {:style styles/asset-item-container}
|
||||
[list/item
|
||||
(if icon
|
||||
[list/item-image icon]
|
||||
[chat-icon/custom-icon-view-list (:name token) color])
|
||||
[react/view {:style styles/asset-item-value-container}
|
||||
[react/text {:style styles/asset-item-value
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:accessibility-label (str (-> symbol name clojure.string/lower-case) "-asset-value-text")}
|
||||
(wallet.utils/format-amount amount decimals)]
|
||||
[react/text {:style styles/asset-item-currency
|
||||
:number-of-lines 1}
|
||||
(wallet.utils/display-symbol token)]]
|
||||
[react/text {:style styles/asset-item-price
|
||||
:number-of-lines 1}
|
||||
(or @asset-value "...")]]])))
|
||||
|
||||
(def item-icon-forward
|
||||
[list/item-icon {:icon :main-icons/next
|
||||
:style {:width 12}
|
||||
:icon-opts {:color :gray}}])
|
||||
|
||||
(defn- render-collectible [address-hex {:keys [symbol name icon amount] :as collectible}]
|
||||
(let [items-number (money/to-fixed amount)
|
||||
details? (pos? items-number)]
|
||||
[react/touchable-highlight
|
||||
(when details?
|
||||
{:on-press #(re-frame/dispatch [:show-collectibles-list address-hex collectible])})
|
||||
[react/view {:style styles/asset-item-container}
|
||||
[list/item
|
||||
[list/item-image icon]
|
||||
[react/view {:style styles/asset-item-value-container}
|
||||
[react/text {:style styles/asset-item-value
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:accessibility-label (str (-> symbol clojure.core/name clojure.string/lower-case)
|
||||
"-collectible-value-text")}
|
||||
(or items-number "...")]
|
||||
[react/text {:style styles/asset-item-currency
|
||||
:number-of-lines 1}
|
||||
name]]
|
||||
(when details?
|
||||
item-icon-forward)]]]))
|
||||
|
||||
(defn group-assets [v]
|
||||
(group-by #(if (:nft? %) :nfts :tokens) v))
|
||||
|
||||
(defn- asset-section [assets currency address-hex]
|
||||
(let [{:keys [tokens nfts]} (group-assets assets)]
|
||||
[list/section-list
|
||||
{:scroll-enabled false
|
||||
:style styles/asset-section
|
||||
:key-fn (comp str :symbol)
|
||||
:render-section-header-fn (fn [{:keys [title data]}]
|
||||
(when (not-empty data)
|
||||
[react/text {:style styles/asset-section-header}
|
||||
title]))
|
||||
:sections [{:title (i18n/label :t/wallet-assets)
|
||||
:key :assets
|
||||
:data tokens
|
||||
:render-fn (render-asset currency)}
|
||||
{:title (i18n/label :t/wallet-collectibles)
|
||||
:key :collectibles
|
||||
:data nfts
|
||||
:render-fn #(render-collectible address-hex %)}]}]))
|
||||
|
||||
(defn snackbar [error-message]
|
||||
[react/view styles/snackbar-container
|
||||
[react/text {:style styles/snackbar-text}
|
||||
(i18n/label error-message)]])
|
||||
|
||||
(views/defview wallet-root [modal?]
|
||||
(views/letsubs [assets [:wallet/visible-assets-with-amount]
|
||||
currency [:wallet/currency]
|
||||
portfolio-value [:portfolio-value]
|
||||
{:keys [seed-backed-up?]} [:account/account]
|
||||
error-message [:wallet/error-message]
|
||||
address-hex [:account/hex-address]]
|
||||
[react/view styles/main-section
|
||||
[status-bar.view/status-bar {:type :wallet-tab}]
|
||||
[settings/toolbar-view]
|
||||
[react/scroll-view {:end-fill-color
|
||||
colors/white
|
||||
:refresh-control
|
||||
(reagent/as-element
|
||||
[(react/refresh-control) {:on-refresh #(re-frame/dispatch [:wallet.ui/pull-to-refresh])
|
||||
:tint-color :white
|
||||
:refreshing false}])}
|
||||
(if error-message
|
||||
[snackbar error-message]
|
||||
[total-section portfolio-value currency])
|
||||
;; this view is a hack to hide the 1px high white line gap on android
|
||||
(when platform/android?
|
||||
[react/view {:style {:background-color colors/blue
|
||||
:height 1
|
||||
:margin -1}}])
|
||||
(when (and (not modal?)
|
||||
(not seed-backed-up?)
|
||||
(some (fn [{:keys [amount]}]
|
||||
(and amount (not (.isZero amount))))
|
||||
assets))
|
||||
[backup-seed-phrase])
|
||||
[react/view {:style {:background-color colors/blue}}
|
||||
[list/flat-list
|
||||
{:data actions
|
||||
:key-fn (fn [_ i] (str i))
|
||||
:render-fn #(list/render-action % {:action-label-style {:font-size 17}})}]]
|
||||
[asset-section assets currency address-hex]
|
||||
(when platform/ios?
|
||||
[react/view {:style styles/scroll-bottom}])]]))
|
||||
|
||||
(views/defview wallet []
|
||||
(views/letsubs [{:keys [wallet-set-up-passed?]} [:account/account]]
|
||||
(if (not wallet-set-up-passed?)
|
||||
[onboarding.views/onboarding]
|
||||
[wallet-root])))
|
|
@ -1,93 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.onboarding.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def border-top-justify
|
||||
{:justify-content :space-between
|
||||
:flex 1})
|
||||
|
||||
(def signing-phrase
|
||||
{:background-color colors/white
|
||||
:border-radius 8
|
||||
:flex-direction :row})
|
||||
|
||||
(def signing-word
|
||||
{:flex 1
|
||||
:height 66
|
||||
:border-left-color "#ECECF0"
|
||||
:border-left-width 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def signing-word-text
|
||||
{:typography :main-semibold})
|
||||
|
||||
(def bottom-buttons
|
||||
{:background-color colors/blue
|
||||
:padding-vertical 8})
|
||||
|
||||
(def got-it-button-text
|
||||
{:padding-horizontal 0})
|
||||
|
||||
(def modal
|
||||
{:flex 1
|
||||
:background-color colors/blue})
|
||||
|
||||
(def bottom-button-container
|
||||
{:flex-direction :row,
|
||||
:border-top-width 1
|
||||
:background-color colors/blue
|
||||
:border-top-color colors/white-light-transparent})
|
||||
|
||||
(def explanation-container
|
||||
{:margin-top 40
|
||||
:margin-left 2
|
||||
:margin-right 2
|
||||
:align-items :center})
|
||||
|
||||
(def super-safe-text
|
||||
{:typography :header
|
||||
:color colors/white
|
||||
:margin-bottom 12})
|
||||
|
||||
(def super-safe-explainer-text
|
||||
{:color colors/white
|
||||
:text-align :center
|
||||
:margin-bottom 30})
|
||||
|
||||
;; onboarding screen styles
|
||||
|
||||
(def root
|
||||
{:flex 1
|
||||
:background-color colors/blue
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:padding-horizontal 30})
|
||||
|
||||
(def onboarding-image-container
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def onboarding-image
|
||||
{:width 285
|
||||
:height 312})
|
||||
|
||||
(def onboarding-title
|
||||
{:typography :header
|
||||
:text-align :center
|
||||
:color colors/white})
|
||||
|
||||
(def onboarding-text
|
||||
{:margin-top 8
|
||||
:margin-bottom 32
|
||||
:font-size 14
|
||||
:text-align :center
|
||||
:color colors/white-transparent})
|
||||
|
||||
(def set-up-button
|
||||
{:flex-direction :row
|
||||
:background-color (colors/alpha colors/black 0.1)
|
||||
:margin-bottom 32})
|
||||
|
||||
(def set-up-button-label
|
||||
{:color colors/white})
|
|
@ -1,132 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.onboarding.views
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.components.button.view :as button]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.common.common :as components.common]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[status-im.ui.screens.wallet.onboarding.styles :as styles]
|
||||
[status-im.utils.utils :as utils])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(defn display-confirmation [on-accept]
|
||||
(utils/show-confirmation
|
||||
{:title (i18n/label :t/wallet-set-up-confirm-title)
|
||||
:content (i18n/label :t/wallet-set-up-confirm-description)
|
||||
:cancel-button-text (i18n/label :t/see-it-again)
|
||||
:confirm-button-text (i18n/label :t/got-it)
|
||||
:on-accept on-accept}))
|
||||
|
||||
(defn info-bubble [text]
|
||||
;; keeping styles inline here as we are going to
|
||||
;; want to move this somewhere for reuse.
|
||||
[react/view {:style {:padding-top 10
|
||||
:align-items :center}}
|
||||
[react/view {:style {:align-items :center
|
||||
:position :absolute
|
||||
:top 0
|
||||
:width 34
|
||||
:zIndex 1
|
||||
:background-color colors/blue}}
|
||||
[vector-icons/icon :main-icons/info {:color colors/white}]]
|
||||
[react/view
|
||||
{:style {:border-color (colors/alpha colors/white 0.6)
|
||||
:border-width 1
|
||||
:border-radius 8
|
||||
:padding-top 15
|
||||
:padding-bottom 15
|
||||
:padding-left 20
|
||||
:padding-right 20
|
||||
:align-items :center}}
|
||||
[react/text
|
||||
{:style {:color (colors/alpha colors/white 0.6)
|
||||
:text-align :center}}
|
||||
text]]])
|
||||
|
||||
(defn toolbar []
|
||||
^{:key "toolbar"}
|
||||
[wallet.components/toolbar
|
||||
{:transparent? true}
|
||||
(actions/back-white #(re-frame/dispatch [:wallet.setup.ui/navigate-back-pressed]))
|
||||
(i18n/label :t/wallet-set-up-title)])
|
||||
|
||||
(defn main-panel [signing-phrase on-confirm]
|
||||
(let [signing-words (string/split signing-phrase #" ")]
|
||||
^{:key "main-panel-view"}
|
||||
[react/view {:style styles/border-top-justify}
|
||||
[react/view] ;; crappy way to vertically center things
|
||||
[react/view {:style {:padding-left 36 :padding-right 36}}
|
||||
[react/view {:style styles/signing-phrase
|
||||
:accessibility-label :signing-phrase}
|
||||
(map
|
||||
(fn [word container-style]
|
||||
^{:key (str "signing-word-" word)}
|
||||
[react/view container-style
|
||||
[react/text {:style styles/signing-word-text
|
||||
:number-of-lines 1}
|
||||
word]])
|
||||
signing-words
|
||||
(cons
|
||||
(dissoc styles/signing-word
|
||||
:border-left-color
|
||||
:border-left-width)
|
||||
(repeat styles/signing-word))
|
||||
(cons true (repeat false)))]
|
||||
[react/view {:style styles/explanation-container}
|
||||
[react/text {:style styles/super-safe-text}
|
||||
(i18n/label :t/wallet-set-up-safe-transactions-title)]
|
||||
[react/text
|
||||
{:style styles/super-safe-explainer-text}
|
||||
(i18n/label :t/wallet-set-up-signing-explainer)]
|
||||
(info-bubble
|
||||
(i18n/label :t/wallet-set-up-signing-explainer-warning))]]
|
||||
[react/view {:style styles/bottom-button-container}
|
||||
[button/button {:on-press on-confirm
|
||||
:text-style styles/got-it-button-text
|
||||
:style {:padding-vertical 9}
|
||||
:accessibility-label :done-button
|
||||
:fit-to-text? false}
|
||||
(i18n/label :t/got-it)
|
||||
nil]]]))
|
||||
|
||||
(views/defview screen []
|
||||
(views/letsubs [{:keys [signing-phrase]} [:account/account]]
|
||||
[wallet.components/simple-screen
|
||||
{:avoid-keyboard? true}
|
||||
(toolbar)
|
||||
(main-panel
|
||||
signing-phrase
|
||||
(partial display-confirmation #(re-frame/dispatch [:accounts.ui/wallet-set-up-confirmed false])))]))
|
||||
|
||||
(views/defview modal []
|
||||
(views/letsubs [{:keys [signing-phrase]} [:account/account]]
|
||||
[react/view styles/modal
|
||||
[status-bar/status-bar {:type :modal-wallet}]
|
||||
[react/view components.styles/flex
|
||||
(toolbar)
|
||||
(main-panel
|
||||
signing-phrase
|
||||
(partial display-confirmation #(re-frame/dispatch [:accounts.ui/wallet-set-up-confirmed true])))]]))
|
||||
|
||||
(defn onboarding []
|
||||
[react/view styles/root
|
||||
[react/view {:style styles/onboarding-image-container}
|
||||
[react/image {:source (resources/get-image :wallet-welcome)
|
||||
:style styles/onboarding-image}]]
|
||||
[react/text {:style styles/onboarding-title}
|
||||
(i18n/label :t/wallet-onboarding-title)]
|
||||
[react/text {:style styles/onboarding-text}
|
||||
(i18n/label :t/wallet-onboarding-description)]
|
||||
[components.common/button
|
||||
{:button-style styles/set-up-button
|
||||
:label-style styles/set-up-button-label
|
||||
:on-press #(re-frame/dispatch [:navigate-to :wallet-onboarding-setup])
|
||||
:label (i18n/label :t/wallet-onboarding-set-up)}]])
|
|
@ -1,34 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.request.events
|
||||
(:require [status-im.chat.commands.sending :as commands-sending]
|
||||
[status-im.chat.models :as chat-model]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.wallet.db :as wallet.db]))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet-send-request
|
||||
(fn [{:keys [db] :as cofx} [_ public-key amount symbol decimals]]
|
||||
(assert public-key)
|
||||
(let [request-command (get-in db [:id->command ["request" #{:personal-chats}]])]
|
||||
(fx/merge cofx
|
||||
(chat-model/start-chat public-key nil)
|
||||
(commands-sending/send public-key
|
||||
request-command
|
||||
{:asset (name symbol)
|
||||
:amount (str (money/internal->formatted amount symbol decimals))})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.request/set-and-validate-amount
|
||||
(fn [{:keys [db]} [_ amount symbol decimals]]
|
||||
(let [{:keys [value error]} (wallet.db/parse-amount amount decimals)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :request-transaction :amount] (money/formatted->internal value symbol decimals))
|
||||
(assoc-in [:wallet :request-transaction :amount-text] amount)
|
||||
(assoc-in [:wallet :request-transaction :amount-error] error))})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.request/set-symbol
|
||||
(fn [{:keys [db]} [_ symbol]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :request-transaction :symbol] symbol))}))
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.ui.screens.wallet.request.views
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.eip55 :as eip55]
|
||||
[status-im.ethereum.eip681 :as eip681]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
|
@ -16,16 +15,13 @@
|
|||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[status-im.ui.screens.wallet.request.styles :as styles]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.utils :as utils])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
;; Request screen
|
||||
|
||||
(views/defview send-transaction-request []
|
||||
;; TODO(jeluard) both send and request flows should be merged
|
||||
(views/letsubs [chain [:ethereum/chain-keyword]
|
||||
{:keys [to to-name public-key]} [:wallet.send/transaction]
|
||||
{:keys [amount amount-error amount-text symbol to
|
||||
to-name public-key]} [:wallet.request/transaction]
|
||||
network-status [:network-status]
|
||||
|
@ -65,8 +61,6 @@
|
|||
(i18n/label :t/send-request)
|
||||
[vector-icons/icon :main-icons/next {:color :white}]]]]])))
|
||||
|
||||
;; Main screen
|
||||
|
||||
(defn send-transaction-request-button [value]
|
||||
[button/primary-button {:on-press #(re-frame/dispatch [:navigate-to :wallet-send-transaction-request])
|
||||
:style styles/send-request
|
||||
|
@ -92,4 +86,4 @@
|
|||
:footer-button send-transaction-request-button
|
||||
:value (eip681/generate-uri address-hex {:chain-id chain-id})
|
||||
:hint (i18n/label :t/request-qr-legend)
|
||||
:legend (eip55/address->checksum address-hex)}]]]))
|
||||
:legend (eip55/address->checksum address-hex)}]]]))
|
|
@ -1,43 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.send.events
|
||||
(:require [status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.wallet.db :as wallet.db]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.ethereum.abi-spec :as abi-spec]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.signing.core :as signing]))
|
||||
|
||||
(defn set-and-validate-amount-db [db amount symbol decimals]
|
||||
(let [{:keys [value error]} (wallet.db/parse-amount amount decimals)]
|
||||
(-> db
|
||||
(assoc-in [:wallet :send-transaction :amount] (money/formatted->internal value symbol decimals))
|
||||
(assoc-in [:wallet :send-transaction :amount-text] amount)
|
||||
(assoc-in [:wallet :send-transaction :amount-error] error))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.send/set-and-validate-amount
|
||||
(fn [{:keys [db]} [_ amount symbol decimals]]
|
||||
{:db (set-and-validate-amount-db db amount symbol decimals)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.send/set-symbol
|
||||
(fn [{:keys [db]} [_ symbol]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :send-transaction :symbol] symbol)
|
||||
(assoc-in [:wallet :send-transaction :amount] nil)
|
||||
(assoc-in [:wallet :send-transaction :amount-text] nil)
|
||||
(assoc-in [:wallet :send-transaction :asset-error] nil))}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.ui/sign-transaction-button-clicked
|
||||
(fn [{:keys [db] :as cofx} _]
|
||||
(let [{:keys [to symbol amount]} (get-in cofx [:db :wallet :send-transaction])
|
||||
{:keys [symbol address]} (tokens/asset-for (:wallet/all-tokens db) (keyword (:chain db)) symbol)
|
||||
amount-hex (str "0x" (abi-spec/number-to-hex amount))
|
||||
to-norm (ethereum/normalized-address to)]
|
||||
(signing/sign cofx {:tx-obj (if (= symbol :ETH)
|
||||
{:to to-norm
|
||||
:value amount-hex}
|
||||
{:to (ethereum/normalized-address address)
|
||||
:data (abi-spec/encode "transfer(address,uint256)" [to-norm amount-hex])})
|
||||
:on-result [:navigate-back]}))))
|
|
@ -1,7 +1,6 @@
|
|||
(ns status-im.ui.screens.wallet.send.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
||||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.screens.wallet.components.styles :as wallet.components.styles]))
|
||||
|
||||
(def send-transaction-form
|
||||
|
@ -21,14 +20,6 @@
|
|||
:padding-top 12
|
||||
:padding-horizontal 12})
|
||||
|
||||
(def spinner-container
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:top 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:justify-content :center})
|
||||
|
||||
(def signing-phrase-container
|
||||
{:border-radius 8
|
||||
:height 36
|
||||
|
@ -69,48 +60,14 @@
|
|||
:padding 8
|
||||
:align-items :center})
|
||||
|
||||
(def advanced-button-wrapper
|
||||
{:align-items :center})
|
||||
|
||||
(def advanced-wrapper
|
||||
{:margin-top 24
|
||||
:margin-bottom 16})
|
||||
|
||||
(def gas-container-wrapper
|
||||
{:flex 1
|
||||
:flex-direction :row})
|
||||
|
||||
(def gas-input-wrapper
|
||||
{:align-items :center
|
||||
:justify-content :space-between
|
||||
:flex-direction :row})
|
||||
|
||||
(def advanced-options-text-wrapper
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-vertical 15})
|
||||
|
||||
(def advanced-label
|
||||
{:text-align-vertical :center
|
||||
:margin-left 4})
|
||||
|
||||
(def advanced-fees-text
|
||||
{:color colors/white})
|
||||
|
||||
(def advanced-fees-details-text
|
||||
{:color colors/white-transparent})
|
||||
|
||||
(def transaction-fee-block-wrapper
|
||||
{:flex-direction :row})
|
||||
|
||||
(def transaction-fee-info
|
||||
{:flex-direction :row
|
||||
:margin 15})
|
||||
|
||||
(def transaction-fee-info-text-wrapper
|
||||
{:flex-shrink 1})
|
||||
|
||||
(def transaction-fee-info-icon
|
||||
{:border-radius 25
|
||||
:width 25
|
||||
|
@ -136,12 +93,9 @@
|
|||
{:background-color colors/blue
|
||||
:padding-vertical 8})
|
||||
|
||||
(def fee-buttons
|
||||
{:background-color colors/blue})
|
||||
|
||||
(def password-error-tooltip
|
||||
{:bottom-value 15
|
||||
:color colors/red-light})
|
||||
|
||||
(defstyle gas-input-error-tooltip
|
||||
{:android {:bottom-value -38}})
|
||||
{:android {:bottom-value -38}})
|
|
@ -13,7 +13,6 @@
|
|||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.screens.wallet.components.views :as wallet.components]
|
||||
[status-im.ui.screens.wallet.main.views :as wallet.main.views]
|
||||
[status-im.ui.screens.wallet.send.styles :as styles]
|
||||
[status-im.ui.components.toolbar.actions :as actions]))
|
||||
|
||||
|
@ -51,8 +50,6 @@
|
|||
:ref #(reset! scroll %)
|
||||
:on-content-size-change #(when (and scroll @scroll)
|
||||
(.scrollToEnd @scroll))}
|
||||
(when-not online?
|
||||
[wallet.main.views/snackbar :t/error-cant-send-transaction-offline])
|
||||
[react/view styles/send-transaction-form
|
||||
[wallet.components/recipient-selector
|
||||
{:address to
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
:cyrcle-color (colors/alpha colors/red 0.1)
|
||||
:on-press #(hide-sheet-and-dispatch [:wallet.custom-token.ui/remove-pressed token])}])]))
|
||||
|
||||
(defn- render-token [{:keys [symbol name icon color custom?] :as token} visible-tokens]
|
||||
(defn- render-token [{:keys [symbol name icon color custom? checked?] :as token}]
|
||||
[list/list-item-with-checkbox
|
||||
{:checked? (contains? visible-tokens (keyword symbol))
|
||||
{:checked? checked?
|
||||
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet {:content (custom-token-actions-view token)
|
||||
:content-height (if custom? 128 68)}])
|
||||
:on-value-change #(re-frame/dispatch [:wallet.settings/toggle-visible-token (keyword symbol) %])}
|
||||
|
@ -57,31 +57,28 @@
|
|||
[list/item-secondary symbol]]]])
|
||||
|
||||
(defview manage-assets []
|
||||
(letsubs [chain [:ethereum/chain-keyword]
|
||||
visible-tokens [:wallet/visible-tokens-symbols]
|
||||
all-tokens [:wallet/all-tokens]]
|
||||
(let [{custom-tokens true default-tokens nil} (group-by :custom? (tokens/sorted-tokens-for all-tokens chain))]
|
||||
[react/view (merge components.styles/flex {:background-color :white})
|
||||
[status-bar/status-bar]
|
||||
[toolbar]
|
||||
[react/view {:style components.styles/flex}
|
||||
[list/section-list
|
||||
{:header [react/view {:margin-top 16}
|
||||
[action-button/action-button {:label (i18n/label :t/add-custom-token)
|
||||
:icon :main-icons/add
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(re-frame/dispatch [:navigate-to :wallet-add-custom-token])}]]
|
||||
:sections (concat
|
||||
(when (seq custom-tokens)
|
||||
[{:title (i18n/label :t/custom)
|
||||
:data custom-tokens}])
|
||||
[{:title (i18n/label :t/default)
|
||||
:data default-tokens}])
|
||||
:key-fn :address
|
||||
:stickySectionHeadersEnabled false
|
||||
:render-section-header-fn (fn [{:keys [title data]}]
|
||||
[list-header/list-header title])
|
||||
:render-fn #(render-token % visible-tokens)}]]])))
|
||||
(letsubs [{custom-tokens true default-tokens nil} [:wallet/grouped-chain-tokens]]
|
||||
[react/view (merge components.styles/flex {:background-color :white})
|
||||
[status-bar/status-bar]
|
||||
[toolbar]
|
||||
[react/view {:style components.styles/flex}
|
||||
[list/section-list
|
||||
{:header [react/view {:margin-top 16}
|
||||
[action-button/action-button {:label (i18n/label :t/add-custom-token)
|
||||
:icon :main-icons/add
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(re-frame/dispatch [:navigate-to :wallet-add-custom-token])}]]
|
||||
:sections (concat
|
||||
(when (seq custom-tokens)
|
||||
[{:title (i18n/label :t/custom)
|
||||
:data custom-tokens}])
|
||||
[{:title (i18n/label :t/default)
|
||||
:data default-tokens}])
|
||||
:key-fn :address
|
||||
:stickySectionHeadersEnabled false
|
||||
:render-section-header-fn (fn [{:keys [title data]}]
|
||||
[list-header/list-header title])
|
||||
:render-fn render-token}]]]))
|
||||
|
||||
(defn- create-payload [address]
|
||||
{:address (ethereum/normalized-address address)})
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
;; wallet
|
||||
|
||||
(defn button-container [enabled?]
|
||||
(merge {:flex-direction :row
|
||||
:align-items :center}
|
||||
(when-not enabled?
|
||||
{:opacity 0.4})))
|
||||
|
||||
(def wallet-modal-container
|
||||
{:flex 1
|
||||
:background-color colors/blue})
|
|
@ -1,102 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.transaction-fee.views
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.bottom-buttons.view :as bottom-buttons]
|
||||
[status-im.ui.components.button.view :as button]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.toolbar.actions :as act]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.tooltip.views :as tooltip]
|
||||
[status-im.ui.screens.wallet.components.views :as components]
|
||||
[status-im.ui.screens.wallet.send.styles :as styles]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.money :as money])
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
(defn- toolbar [title]
|
||||
[toolbar/toolbar
|
||||
{:style {:border-bottom-color colors/white-light-transparent}}
|
||||
[toolbar/nav-button (act/close-white act/default-handler)]
|
||||
[toolbar/content-title {:color :white} title]])
|
||||
|
||||
(defview transaction-fee []
|
||||
(letsubs [send-transaction [:wallet.send/transaction]
|
||||
chain [:ethereum/chain-keyword]
|
||||
{gas-edit :gas
|
||||
max-fee :max-fee
|
||||
gas-price-edit :gas-price} [:wallet/edit]
|
||||
all-tokens [:wallet/all-tokens]]
|
||||
(let [{:keys [amount symbol]} send-transaction
|
||||
gas (:value gas-edit)
|
||||
gas-price (:value gas-price-edit)
|
||||
native-currency (tokens/native-currency chain)
|
||||
{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)]
|
||||
[components/simple-screen {:status-bar-type :modal-wallet}
|
||||
[toolbar (i18n/label :t/wallet-transaction-fee)]
|
||||
[react/view components.styles/flex
|
||||
[react/view {:flex-direction :row}
|
||||
|
||||
[react/view styles/gas-container-wrapper
|
||||
[components/cartouche {}
|
||||
(i18n/label :t/gas-limit)
|
||||
[react/view styles/gas-input-wrapper
|
||||
[react/text-input (merge styles/transaction-fee-input
|
||||
{:on-change-text #(re-frame/dispatch [:wallet.send/edit-value :gas %])
|
||||
:default-value gas
|
||||
:accessibility-label :gas-limit-input})]]]
|
||||
(when (:invalid? gas-edit)
|
||||
[tooltip/tooltip (i18n/label :t/invalid-number) styles/gas-input-error-tooltip])]
|
||||
|
||||
[react/view styles/gas-container-wrapper
|
||||
[components/cartouche {}
|
||||
(i18n/label :t/gas-price)
|
||||
[react/view styles/gas-input-wrapper
|
||||
[react/text-input (merge styles/transaction-fee-input
|
||||
{:on-change-text #(re-frame/dispatch [:wallet.send/edit-value :gas-price %])
|
||||
:default-value gas-price
|
||||
:accessibility-label :gas-price-input})]
|
||||
[components/cartouche-secondary-text
|
||||
(i18n/label :t/gwei)]]]
|
||||
(when (:invalid? gas-price-edit)
|
||||
[tooltip/tooltip
|
||||
(i18n/label (if (= :invalid-number (:invalid? gas-price-edit))
|
||||
:t/invalid-number
|
||||
:t/wallet-send-min-wei))
|
||||
styles/gas-input-error-tooltip])]]
|
||||
|
||||
[react/view styles/transaction-fee-info
|
||||
[react/view styles/transaction-fee-info-icon
|
||||
[react/text {:style styles/transaction-fee-info-icon-text} "?"]]
|
||||
[react/view styles/transaction-fee-info-text-wrapper
|
||||
[react/i18n-text {:style styles/advanced-fees-text
|
||||
:key :wallet-transaction-fee-details}]]]
|
||||
[components/separator]
|
||||
[react/view styles/transaction-fee-block-wrapper
|
||||
[components/cartouche {:disabled? true}
|
||||
(i18n/label :t/amount)
|
||||
[react/view {:accessibility-label :amount-input}
|
||||
[components/cartouche-text-content
|
||||
(str (money/to-fixed (money/internal->formatted amount symbol decimals)))
|
||||
(wallet.utils/display-symbol token)]]]
|
||||
[components/cartouche {:disabled? true}
|
||||
(i18n/label :t/wallet-transaction-total-fee)
|
||||
[react/view {:accessibility-label :total-fee-input}
|
||||
[components/cartouche-text-content
|
||||
(str max-fee " " (wallet.utils/display-symbol native-currency))]]]]
|
||||
|
||||
[bottom-buttons/bottom-buttons styles/fee-buttons
|
||||
[button/button {:on-press #(re-frame/dispatch [:wallet.send/reset-gas-default])
|
||||
:accessibility-label :reset-to-default-button}
|
||||
(i18n/label :t/reset-default)]
|
||||
[button/button {:on-press #(do (re-frame/dispatch [:wallet.send/set-gas-details
|
||||
(:value-number gas-edit)
|
||||
(:value-number gas-price-edit)])
|
||||
(act/default-handler))
|
||||
:accessibility-label :done-button
|
||||
:disabled? (or (:invalid? gas-edit)
|
||||
(:invalid? gas-price-edit))}
|
||||
(i18n/label :t/done)]]]])))
|
|
@ -1,15 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.transaction-sent.styles
|
||||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(def transaction-sent
|
||||
{:typography :header
|
||||
:color colors/white
|
||||
:margin-bottom 8})
|
||||
|
||||
(def transaction-sent-description
|
||||
{:typography :title
|
||||
:color (colors/alpha colors/white 0.6)
|
||||
:text-align :center
|
||||
:padding-horizontal 30
|
||||
:margin-bottom 35})
|
|
@ -1,69 +0,0 @@
|
|||
(ns status-im.ui.screens.wallet.transaction-sent.views
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||
(:require [status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.icons.vector-icons :as vi]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.screens.wallet.transaction-sent.styles :as styles]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.ui.components.colors :as colors]))
|
||||
|
||||
(defn- ok-circle []
|
||||
[react/view {:background-color colors/black-transparent
|
||||
:width 160
|
||||
:height 160
|
||||
:border-radius 81
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[react/view {:background-color colors/white
|
||||
:width 80
|
||||
:height 80
|
||||
:border-radius 41
|
||||
:shadow-radius 4
|
||||
:shadow-offset {:width 0 :height 2}
|
||||
:shadow-opacity 0.8
|
||||
:shadow-color "rgba(43, 59, 71, 0.12)"
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[vi/tiny-icon :tiny-icons/tiny-check {:color colors/blue}]]])
|
||||
|
||||
(defn- transaction-sent-message []
|
||||
[react/view {:align-items :center}
|
||||
[react/text {:style styles/transaction-sent
|
||||
:accessibility-label :transaction-sent-text}
|
||||
(i18n/label :t/transaction-sent)]
|
||||
[react/i18n-text {:style styles/transaction-sent-description
|
||||
:key :transaction-description}]])
|
||||
|
||||
(defn- bottom-action-button [on-next]
|
||||
[react/touchable-highlight {:on-press on-next
|
||||
:style {:border-top-width 1
|
||||
:border-color colors/white-light-transparent}
|
||||
:accessibility-label :got-it-button}
|
||||
[react/view {:align-items :center
|
||||
:padding-vertical 18}
|
||||
[react/text {:style {:color colors/white}}
|
||||
(i18n/label :t/done)]]])
|
||||
|
||||
(defn- sent-screen [{:keys [on-next]}]
|
||||
{:pre [(fn? on-next)]}
|
||||
[react/view {:flex 1}
|
||||
[react/view {:flex 0.7}] ;; spacer
|
||||
[react/view {:align-items :center} (ok-circle)]
|
||||
[react/view {:flex 1}] ;; spacer
|
||||
(transaction-sent-message)
|
||||
(bottom-action-button on-next)])
|
||||
|
||||
(defview transaction-sent []
|
||||
(letsubs [chat-id [:chats/current-chat-id]]
|
||||
[react/view {:flex 1 :background-color colors/blue}
|
||||
[status-bar/status-bar {:type :transparent}]
|
||||
(sent-screen {:on-next #(re-frame/dispatch [:close-transaction-sent-screen chat-id])})]))
|
||||
|
||||
(defview transaction-sent-modal []
|
||||
(letsubs [chat-id [:chats/current-chat-id]]
|
||||
[react/view {:flex 1 :background-color colors/blue}
|
||||
[status-bar/status-bar {:type :modal-wallet}]
|
||||
(sent-screen {:on-next #(re-frame/dispatch [:close-transaction-sent-screen chat-id])})]))
|
|
@ -0,0 +1,16 @@
|
|||
(ns status-im.wallet.accounts.core
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.ethereum.eip55 :as eip55]
|
||||
[status-im.ui.components.list-selection :as list-selection]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:list.selection/open-share
|
||||
(fn [obj]
|
||||
(list-selection/open-share obj)))
|
||||
|
||||
(fx/defn set-symbol-request
|
||||
{:events [:wallet.accounts/share]}
|
||||
[{:keys [db]}]
|
||||
{:list.selection/open-share {:message (eip55/address->checksum (ethereum/current-address db))}})
|
|
@ -0,0 +1,122 @@
|
|||
(ns status-im.wallet.choose-recipient.core
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contact.db :as contact.db]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.eip55 :as eip55]
|
||||
[status-im.ethereum.eip681 :as eip681]
|
||||
[status-im.ethereum.ens :as ens]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
(fx/defn toggle-flashlight
|
||||
{:events [:wallet/toggle-flashlight]}
|
||||
[{:keys [db]}]
|
||||
(let [flashlight-state (get-in db [:wallet :send-transaction :camera-flashlight])
|
||||
toggled-state (if (= :on flashlight-state) :off :on)]
|
||||
{:db (assoc-in db [:wallet :send-transaction :camera-flashlight] toggled-state)}))
|
||||
|
||||
(defn- find-address-name [db address]
|
||||
(:name (contact.db/find-contact-by-address (:contacts/contacts db) address)))
|
||||
|
||||
(defn- fill-request-details [db {:keys [address name value symbol gas gasPrice public-key from-chat?]} request?]
|
||||
{:pre [(not (nil? address))]}
|
||||
(let [name (or name (find-address-name db address))
|
||||
data-path (if request?
|
||||
[:wallet :request-transaction]
|
||||
[:wallet :send-transaction])]
|
||||
(update-in db data-path
|
||||
(fn [{old-symbol :symbol :as old-transaction}]
|
||||
(let [symbol-changed? (not= old-symbol symbol)]
|
||||
(cond-> (assoc old-transaction :to address :to-name name :public-key public-key)
|
||||
value (assoc :amount value)
|
||||
symbol (assoc :symbol symbol)
|
||||
(and gas symbol-changed?) (assoc :gas (money/bignumber gas))
|
||||
from-chat? (assoc :from-chat? from-chat?)
|
||||
(and gasPrice symbol-changed?)
|
||||
(assoc :gas-price (money/bignumber gasPrice))
|
||||
(and symbol (not gasPrice) symbol-changed?)
|
||||
(assoc :gas-price (ethereum/estimate-gas symbol))))))))
|
||||
|
||||
(defn- extract-details
|
||||
"First try to parse as EIP681 URI, if not assume this is an address directly.
|
||||
Returns a map containing at least the `address` and `chain-id` keys"
|
||||
[s chain-id all-tokens]
|
||||
(or (let [m (eip681/parse-uri s)]
|
||||
(merge m (eip681/extract-request-details m all-tokens)))
|
||||
(when (ethereum/address? s)
|
||||
{:address s :chain-id chain-id})))
|
||||
|
||||
;; NOTE(janherich) - whenever changing assets, we want to clear the previusly set amount/amount-text
|
||||
(defn changed-asset [{:keys [db] :as fx} old-symbol new-symbol]
|
||||
(-> fx
|
||||
(merge {:wallet/update-gas-price
|
||||
{:success-event :wallet/update-gas-price-success
|
||||
:edit? false}})
|
||||
(assoc-in [:db :wallet :send-transaction :amount] nil)
|
||||
(assoc-in [:db :wallet :send-transaction :amount-text] nil)
|
||||
(assoc-in [:db :wallet :send-transaction :asset-error]
|
||||
(i18n/label :t/changed-asset-warning {:old old-symbol :new new-symbol}))))
|
||||
|
||||
(defn changed-amount-warning [fx old-amount new-amount]
|
||||
(assoc-in fx [:db :wallet :send-transaction :amount-error]
|
||||
(i18n/label :t/changed-amount-warning {:old old-amount :new new-amount})))
|
||||
|
||||
(defn use-default-eth-gas [fx]
|
||||
(assoc-in fx [:db :wallet :send-transaction :gas]
|
||||
(ethereum/default-transaction-gas)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:resolve-address
|
||||
(fn [{:keys [registry ens-name cb]}]
|
||||
(ens/get-addr registry ens-name cb)))
|
||||
|
||||
(fx/defn set-recipient
|
||||
{:events [:wallet.send/set-recipient]}
|
||||
[{:keys [db]} recipient]
|
||||
(let [chain (ethereum/chain-keyword db)]
|
||||
(if (ens/is-valid-eth-name? recipient)
|
||||
{:resolve-address {:registry (get ens/ens-registries chain)
|
||||
:ens-name recipient
|
||||
:cb #(re-frame/dispatch [:wallet.send/set-recipient %])}}
|
||||
(if (ethereum/address? recipient)
|
||||
(let [checksum (eip55/address->checksum recipient)]
|
||||
(if (eip55/valid-address-checksum? checksum)
|
||||
{:db (assoc-in db [:wallet :send-transaction :to] checksum)
|
||||
:dispatch [:navigate-back]}
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address-checksum {:data recipient})}))
|
||||
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data recipient})}))))
|
||||
|
||||
(fx/defn fill-request-from-url
|
||||
{:events [:wallet/fill-request-from-url]}
|
||||
[{{:keys [network] :wallet/keys [all-tokens] :as db} :db} data origin]
|
||||
(let [current-chain-id (get-in constants/default-networks [network :config :NetworkId])
|
||||
{:keys [address chain-id] :as details} (extract-details data current-chain-id all-tokens)
|
||||
valid-network? (boolean (= current-chain-id chain-id))
|
||||
previous-state (get-in db [:wallet :send-transaction])
|
||||
old-symbol (:symbol previous-state)
|
||||
new-symbol (:symbol details)
|
||||
old-amount (:amount previous-state)
|
||||
new-amount (:value details)
|
||||
new-gas (:gas details)
|
||||
symbol-changed? (and old-symbol new-symbol (not= old-symbol new-symbol))]
|
||||
(cond-> {:db db}
|
||||
(not= :deep-link origin) (assoc :dispatch [:navigate-back]) ;; Only navigate-back when called from within wallet
|
||||
(and address valid-network?) (update :db #(fill-request-details % details false))
|
||||
symbol-changed? (changed-asset old-symbol new-symbol)
|
||||
(and old-amount new-amount (not= old-amount new-amount)) (changed-amount-warning old-amount new-amount)
|
||||
;; NOTE(goranjovic) - the next line is there is because QR code scanning switches the amount to ETH
|
||||
;; automatically, so we need to update the gas limit accordingly. The check for origin screen is there
|
||||
;; so that we wouldn't also switch gas limit to ETH specific if the user pastes address as text.
|
||||
;; We need to check if address is defined so that we wouldn't trigger this behavior when invalid QR is scanned
|
||||
;; (e.g. public-key)
|
||||
(and address (= origin :qr) (not new-gas) symbol-changed?) (use-default-eth-gas)
|
||||
(not address) (assoc :ui/show-error (i18n/label :t/wallet-invalid-address {:data data}))
|
||||
(and address (not valid-network?)) (assoc :ui/show-error (i18n/label :t/wallet-invalid-chain-id {:data data :chain current-chain-id})))))
|
||||
|
||||
(fx/defn fill-request-from-contact
|
||||
{:events [:wallet/fill-request-from-contact]}
|
||||
[{db :db} {:keys [address name public-key]} request?]
|
||||
{:db (fill-request-details db {:address address :name name :public-key public-key} request?)
|
||||
:dispatch [:navigate-back]})
|
|
@ -0,0 +1,203 @@
|
|||
(ns status-im.wallet.collectibles.core
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.browser.core :as browser]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.erc721 :as erc721]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.http :as http]
|
||||
[clojure.string :as string]
|
||||
[status-im.utils.types :as types]))
|
||||
|
||||
;;TODO: REPLACE ALL HANDLERS BY FX/DEFN
|
||||
|
||||
(defmulti load-collectible-fx (fn [_ symbol _] symbol))
|
||||
|
||||
(defmethod load-collectible-fx :default [_ _ _] nil)
|
||||
|
||||
(defmulti load-collectibles-fx (fn [_ symbol _ _] symbol))
|
||||
|
||||
(defmethod load-collectibles-fx :default [all-tokens symbol items-number address chain-id]
|
||||
{:load-collectibles-fx [all-tokens symbol items-number address chain-id]})
|
||||
|
||||
(defn load-token [i items-number contract address symbol]
|
||||
(when (< i items-number)
|
||||
(erc721/token-of-owner-by-index contract address i
|
||||
(fn [response]
|
||||
(load-token (inc i) items-number contract address symbol)
|
||||
(re-frame/dispatch [:load-collectible symbol response])))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:load-collectibles-fx
|
||||
(fn [[all-tokens symbol items-number address chain-id]]
|
||||
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
||||
contract (:address (tokens/symbol->token all-tokens chain symbol))]
|
||||
(load-token 0 items-number contract address symbol))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-collectibles-list
|
||||
(fn [{:keys [db]} [_ {:keys [symbol amount] :as collectible}]]
|
||||
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
|
||||
all-tokens (:wallet/all-tokens db)
|
||||
items-number (money/to-number amount)
|
||||
loaded-items-number (count (get-in db [:collectibles symbol]))]
|
||||
(merge (when (not= items-number loaded-items-number)
|
||||
(load-collectibles-fx all-tokens symbol items-number (ethereum/current-address db) chain-id))
|
||||
{:dispatch [:navigate-to :collectibles-list collectible]}))))
|
||||
|
||||
;; Crypto Kitties
|
||||
(def ck :CK)
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-kitties
|
||||
(fn [{db :db} [_ ids]]
|
||||
{:db db
|
||||
:http-get-n (mapv (fn [id]
|
||||
{:url (str "https://api.cryptokitties.co/kitties/" id)
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success ck {id (http/parse-payload o)}])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure ck {id (http/parse-payload o)}])})
|
||||
ids)}))
|
||||
|
||||
;; TODO(andrey) Each HTTP call will return up to 100 kitties. Maybe we need to implement some kind of paging later
|
||||
(defmethod load-collectibles-fx ck [_ _ items-number address _]
|
||||
{:http-get {:url (str "https://api.cryptokitties.co/kitties?offset=0&limit="
|
||||
items-number
|
||||
"&owner_wallet_address="
|
||||
address
|
||||
"&parents=false")
|
||||
:success-event-creator (fn [o]
|
||||
[:load-kitties (map :id (:kitties (http/parse-payload o)))])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectibles-failure (http/parse-payload o)])
|
||||
:timeout-ms 10000}})
|
||||
|
||||
;; Crypto Strikers
|
||||
(def strikers :STRK)
|
||||
|
||||
(defmethod load-collectible-fx strikers [_ _ id]
|
||||
{:http-get {:url (str "https://us-central1-cryptostrikers-prod.cloudfunctions.net/cards/" id)
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success strikers {id (http/parse-payload o)}])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure strikers {id (http/parse-payload o)}])}})
|
||||
|
||||
;;Etheremona
|
||||
(def emona :EMONA)
|
||||
|
||||
(defmethod load-collectible-fx emona [_ _ id]
|
||||
{:http-get {:url (str "https://www.etheremon.com/api/monster/get_data?monster_ids=" id)
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success emona (:data (http/parse-payload o))])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure emona {id (http/parse-payload o)}])}})
|
||||
|
||||
;;Kudos
|
||||
(def kudos :KDO)
|
||||
|
||||
(defmethod load-collectible-fx kudos [{db :db} symbol id]
|
||||
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
|
||||
all-tokens (:wallet/all-tokens db)]
|
||||
{:erc721-token-uri [all-tokens symbol id chain-id]}))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:erc721-token-uri
|
||||
(fn [[all-tokens symbol tokenId chain-id]]
|
||||
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
||||
contract (:address (tokens/symbol->token all-tokens chain symbol))]
|
||||
(erc721/token-uri contract
|
||||
tokenId
|
||||
#(re-frame/dispatch [:token-uri-success
|
||||
tokenId
|
||||
(when %
|
||||
(subs % (.indexOf % "http")))]))))) ;; extra chars in rinkeby
|
||||
|
||||
;;Superrare
|
||||
(def superrare :SUPR)
|
||||
|
||||
(defmethod load-collectible-fx superrare [_ _ ids]
|
||||
{:http-get-n (mapv (fn [id]
|
||||
{:url id
|
||||
:success-event-creator (fn [o]
|
||||
[:load-collectible-success superrare {id (http/parse-payload o)}])
|
||||
:failure-event-creator (fn [o]
|
||||
[:load-collectible-failure superrare {id (http/parse-payload o)}])})
|
||||
ids)})
|
||||
|
||||
(def graphql-url "https://api.pixura.io/graphql")
|
||||
|
||||
(defn graphql-query [address]
|
||||
(str "{
|
||||
collectiblesByOwner: allErc721Tokens(condition: {owner: \"" address "\"}) {
|
||||
collectibles: nodes {
|
||||
tokenId,
|
||||
metadata: erc721MetadatumByTokenId {
|
||||
metadataUri,
|
||||
description,
|
||||
name,
|
||||
imageUri
|
||||
}}}}"))
|
||||
|
||||
(defmethod load-collectibles-fx superrare [_ _ _ address _]
|
||||
{:http-post {:url graphql-url
|
||||
:data (types/clj->json {:query (graphql-query (ethereum/naked-address address))})
|
||||
:opts {:headers {"Content-Type" "application/json"}}
|
||||
:success-event-creator (fn [{:keys [response-body]}]
|
||||
[:store-collectibles superrare
|
||||
(get-in (http/parse-payload response-body) [:data :collectiblesByOwner :collectibles])])
|
||||
:failure-event-creator (fn [{:keys [response-body]}]
|
||||
[:load-collectibles-failure (http/parse-payload response-body)])
|
||||
:timeout-ms 10000}})
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:token-uri-success
|
||||
(fn [_ [_ tokenId token-uri]]
|
||||
{:http-get {:url
|
||||
token-uri
|
||||
:success-event-creator
|
||||
(fn [o]
|
||||
[:load-collectible-success kudos {tokenId (update (http/parse-payload o)
|
||||
:image
|
||||
string/replace
|
||||
#"http:"
|
||||
"https:")}]) ;; http in mainnet
|
||||
:failure-event-creator
|
||||
(fn [o]
|
||||
[:load-collectible-failure kudos {tokenId (http/parse-payload o)}])}}))
|
||||
|
||||
;;
|
||||
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectible
|
||||
(fn [cofx [_ symbol token-id]]
|
||||
(load-collectible-fx cofx symbol token-id)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:store-collectibles
|
||||
(fn [{db :db} [_ symbol collectibles]]
|
||||
{:db (update-in db [:collectibles symbol] merge
|
||||
(reduce #(assoc %1 (:tokenId %2) %2) {} collectibles))}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectible-success
|
||||
(fn [{db :db} [_ symbol collectibles]]
|
||||
{:db (update-in db [:collectibles symbol] merge collectibles)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectibles-failure
|
||||
(fn [{db :db} [_ reason]]
|
||||
{:db (update-in db [:collectibles symbol :errors] merge reason)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-collectible-failure
|
||||
(fn [{db :db} [_]]
|
||||
{:db db}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:open-collectible-in-browser
|
||||
(fn [cofx [_ url]]
|
||||
(browser/open-url cofx url)))
|
|
@ -3,20 +3,43 @@
|
|||
[re-frame.core :as re-frame]
|
||||
[status-im.accounts.update.core :as accounts.update]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ethereum.abi-spec :as abi-spec]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.core :as utils.core]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.prices :as prices]
|
||||
[status-im.utils.utils :as utils.utils]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.wallet.db :as wallet.db]
|
||||
[status-im.ethereum.abi-spec :as abi-spec]
|
||||
[status-im.signing.core :as signing]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wallet/get-balance
|
||||
(fn [{:keys [account-id on-success on-error]}]
|
||||
(json-rpc/call
|
||||
{:method "eth_getBalance"
|
||||
:params [account-id "latest"]
|
||||
:on-success on-success
|
||||
:on-error on-error})))
|
||||
|
||||
;; TODO(oskarth): At some point we want to get list of relevant
|
||||
;; assets to get prices for
|
||||
(re-frame/reg-fx
|
||||
:wallet/get-prices
|
||||
(fn [{:keys [from to mainnet? success-event error-event chaos-mode?]}]
|
||||
(prices/get-prices from
|
||||
to
|
||||
mainnet?
|
||||
#(re-frame/dispatch [success-event %])
|
||||
#(re-frame/dispatch [error-event %])
|
||||
chaos-mode?)))
|
||||
|
||||
(defn assoc-error-message [db error-type err]
|
||||
(assoc-in db [:wallet :errors error-type] (or err :unknown-error)))
|
||||
|
@ -48,29 +71,6 @@
|
|||
{:db (assoc-in db [:wallet :current-transaction] hash)}
|
||||
(navigation/navigate-to-cofx :wallet-transaction-details nil)))
|
||||
|
||||
;; FX
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wallet/get-balance
|
||||
(fn [{:keys [account-id on-success on-error]}]
|
||||
(json-rpc/call
|
||||
{:method "eth_getBalance"
|
||||
:params [account-id "latest"]
|
||||
:on-success on-success
|
||||
:on-error on-error})))
|
||||
|
||||
;; TODO(oskarth): At some point we want to get list of relevant
|
||||
;; assets to get prices for
|
||||
(re-frame/reg-fx
|
||||
:wallet/get-prices
|
||||
(fn [{:keys [from to mainnet? success-event error-event chaos-mode?]}]
|
||||
(prices/get-prices from
|
||||
to
|
||||
mainnet?
|
||||
#(re-frame/dispatch [success-event %])
|
||||
#(re-frame/dispatch [error-event %])
|
||||
chaos-mode?)))
|
||||
|
||||
(defn- validate-token-name!
|
||||
[{:keys [address symbol name]}]
|
||||
(json-rpc/eth-call
|
||||
|
@ -161,6 +161,7 @@
|
|||
[{:keys [db] :as cofx}]
|
||||
(let [custom-tokens (get-in db [:account/account :settings :wallet :custom-tokens])
|
||||
chain (ethereum/chain-keyword db)
|
||||
;;TODO why do we need all tokens ? chain can be changed only through relogin
|
||||
all-tokens (merge-with
|
||||
merge
|
||||
(utils.core/map-values #(utils.core/index-by :address %)
|
||||
|
@ -300,4 +301,54 @@
|
|||
(fx/merge cofx
|
||||
(toggle-visible-token symbol true)
|
||||
;;TODO(goranjovic): move `update-token-balance-success` function to wallet models
|
||||
(update-token-balance symbol balance)))
|
||||
(update-token-balance symbol balance)))
|
||||
|
||||
(defn set-and-validate-amount-db [db amount symbol decimals]
|
||||
(let [{:keys [value error]} (wallet.db/parse-amount amount decimals)]
|
||||
(-> db
|
||||
(assoc-in [:wallet :send-transaction :amount] (money/formatted->internal value symbol decimals))
|
||||
(assoc-in [:wallet :send-transaction :amount-text] amount)
|
||||
(assoc-in [:wallet :send-transaction :amount-error] error))))
|
||||
|
||||
(fx/defn set-and-validate-amount
|
||||
{:events [:wallet.send/set-and-validate-amount]}
|
||||
[{:keys [db]} amount symbol decimals]
|
||||
{:db (set-and-validate-amount-db db amount symbol decimals)})
|
||||
|
||||
(fx/defn set-symbol
|
||||
{:events [:wallet.send/set-symbol]}
|
||||
[{:keys [db]} symbol]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :send-transaction :symbol] symbol)
|
||||
(assoc-in [:wallet :send-transaction :amount] nil)
|
||||
(assoc-in [:wallet :send-transaction :amount-text] nil)
|
||||
(assoc-in [:wallet :send-transaction :asset-error] nil))})
|
||||
|
||||
(fx/defn sign-transaction-button-clicked
|
||||
{:events [:wallet.ui/sign-transaction-button-clicked]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [to symbol amount]} (get-in cofx [:db :wallet :send-transaction])
|
||||
{:keys [symbol address]} (tokens/asset-for (:wallet/all-tokens db) (keyword (:chain db)) symbol)
|
||||
amount-hex (str "0x" (abi-spec/number-to-hex amount))
|
||||
to-norm (ethereum/normalized-address to)]
|
||||
(signing/sign cofx {:tx-obj (if (= symbol :ETH)
|
||||
{:to to-norm
|
||||
:value amount-hex}
|
||||
{:to (ethereum/normalized-address address)
|
||||
:data (abi-spec/encode "transfer(address,uint256)" [to-norm amount-hex])})
|
||||
:on-result [:navigate-back]})))
|
||||
|
||||
(fx/defn set-and-validate-amount-request
|
||||
{:events [:wallet.request/set-and-validate-amount]}
|
||||
[{:keys [db]} amount symbol decimals]
|
||||
(let [{:keys [value error]} (wallet.db/parse-amount amount decimals)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :request-transaction :amount] (money/formatted->internal value symbol decimals))
|
||||
(assoc-in [:wallet :request-transaction :amount-text] amount)
|
||||
(assoc-in [:wallet :request-transaction :amount-error] error))}))
|
||||
|
||||
(fx/defn set-symbol-request
|
||||
{:events [:wallet.request/set-symbol]}
|
||||
[{:keys [db]} symbol]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :request-transaction :symbol] symbol))})
|
|
@ -2,7 +2,6 @@
|
|||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.decode :as decode]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.ui.screens.wallet.utils
|
||||
(ns status-im.wallet.utils
|
||||
(:require [status-im.utils.money :as money]))
|
||||
|
||||
(defn format-amount [amount decimals]
|
|
@ -1137,5 +1137,15 @@
|
|||
"ens-your-usernames": "Your usernames",
|
||||
"ens-no-usernames": "You don't have any username connected",
|
||||
"ens-understand": "I understand that my wallet address will be publicly connected to my username.",
|
||||
"ens-transaction-pending": "Transaction pending..."
|
||||
"ens-transaction-pending": "Transaction pending...",
|
||||
"add-account" : "Add account",
|
||||
"add-an-account" : "Add an account",
|
||||
"back-up-your-seed-phrase" : "Back up your seed phrase",
|
||||
"add-a-watch-account" : "Add a watch-only account",
|
||||
"account-settings" : "Account settings",
|
||||
"export-account" : "Export account",
|
||||
"set-currency" : "Set currency",
|
||||
"view-signing" : "View signing phrase",
|
||||
"history" : "History",
|
||||
"no-collectibles" : "No collectibles available"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue