mirror of
https://github.com/status-im/status-react.git
synced 2025-02-20 22:58:33 +00:00
integrate status-go changes to move multiaccount settings to a table that can be migrated Signed-off-by: yenda <eric@status.im>
2073 lines
67 KiB
Clojure
2073 lines
67 KiB
Clojure
(ns status-im.subs
|
|
(:require [cljs.spec.alpha :as spec]
|
|
[clojure.string :as string]
|
|
[taoensso.timbre :as log]
|
|
[re-frame.core :as re-frame]
|
|
[status-im.browser.core :as browser]
|
|
[status-im.chat.constants :as chat.constants]
|
|
[status-im.chat.db :as chat.db]
|
|
[status-im.chat.models :as chat.models]
|
|
[status-im.chat.models.message-list :as models.message-list]
|
|
[status-im.constants :as constants]
|
|
[status-im.contact.db :as contact.db]
|
|
[status-im.ethereum.core :as ethereum]
|
|
[status-im.ethereum.stateofus :as stateofus]
|
|
[status-im.ethereum.tokens :as tokens]
|
|
[status-im.ethereum.transactions.core :as transactions]
|
|
[status-im.fleet.core :as fleet]
|
|
[status-im.group-chats.db :as group-chats.db]
|
|
[status-im.i18n :as i18n]
|
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
[status-im.multiaccounts.core :as multiaccounts]
|
|
[status-im.multiaccounts.db :as multiaccounts.db]
|
|
[status-im.multiaccounts.recover.core :as recover]
|
|
[status-im.pairing.core :as pairing]
|
|
[status-im.tribute-to-talk.core :as tribute-to-talk]
|
|
[status-im.tribute-to-talk.db :as tribute-to-talk.db]
|
|
[status-im.tribute-to-talk.whitelist :as whitelist]
|
|
[status-im.ui.components.tabbar.styles :as tabs.styles]
|
|
[status-im.ui.components.colors :as colors]
|
|
[status-im.ui.components.toolbar.styles :as toolbar.styles]
|
|
[status-im.ui.screens.add-new.new-public-chat.db :as db]
|
|
[status-im.ui.screens.chat.stickers.styles :as stickers.styles]
|
|
[status-im.ui.screens.mobile-network-settings.utils
|
|
:as
|
|
mobile-network-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]
|
|
[status-im.utils.hex :as utils.hex]
|
|
[status-im.utils.identicon :as identicon]
|
|
[status-im.utils.money :as money]
|
|
[status-im.utils.platform :as platform]
|
|
[status-im.utils.security :as security]
|
|
[status-im.utils.universal-links.core :as links]
|
|
[status-im.wallet.core :as wallet]
|
|
[status-im.wallet.db :as wallet.db]
|
|
[status-im.signing.gas :as signing.gas]
|
|
[status-im.utils.gfycat.core :as gfycat]
|
|
status-im.ui.screens.hardwallet.connect.subs
|
|
status-im.ui.screens.hardwallet.settings.subs
|
|
status-im.ui.screens.hardwallet.pin.subs
|
|
status-im.ui.screens.hardwallet.setup.subs
|
|
[status-im.ens.core :as ens]))
|
|
|
|
;; TOP LEVEL ===========================================================================================================
|
|
|
|
(defn reg-root-key-sub [sub-name db-key]
|
|
(re-frame/reg-sub sub-name (fn [db] (get db db-key))))
|
|
|
|
;;view
|
|
(reg-root-key-sub :view-id :view-id)
|
|
(reg-root-key-sub :navigation-stack :navigation-stack)
|
|
(reg-root-key-sub :screen-params :navigation/screen-params)
|
|
(reg-root-key-sub :two-pane-ui-enabled? :two-pane-ui-enabled?)
|
|
|
|
;;bottom sheet
|
|
(reg-root-key-sub :bottom-sheet/show? :bottom-sheet/show?)
|
|
(reg-root-key-sub :bottom-sheet/view :bottom-sheet/view)
|
|
(reg-root-key-sub :bottom-sheet/options :bottom-sheet/options)
|
|
|
|
;;general
|
|
(reg-root-key-sub :sync-state :sync-state)
|
|
(reg-root-key-sub :network-status :network-status)
|
|
(reg-root-key-sub :peers-count :peers-count)
|
|
(reg-root-key-sub :about-app/node-info :node-info)
|
|
(reg-root-key-sub :peers-summary :peers-summary)
|
|
(reg-root-key-sub :tab-bar-visible? :tab-bar-visible?)
|
|
(reg-root-key-sub :dimensions/window :dimensions/window)
|
|
(reg-root-key-sub :initial-props :initial-props)
|
|
(reg-root-key-sub :fleets/custom-fleets :custom-fleets)
|
|
(reg-root-key-sub :desktop/desktop :desktop/desktop)
|
|
(reg-root-key-sub :desktop :desktop)
|
|
(reg-root-key-sub :animations :animations)
|
|
(reg-root-key-sub :ui/search :ui/search)
|
|
(reg-root-key-sub :web3-node-version :web3-node-version)
|
|
(reg-root-key-sub :keyboard-height :keyboard-height)
|
|
(reg-root-key-sub :sync-data :sync-data)
|
|
(reg-root-key-sub :layout-height :layout-height)
|
|
(reg-root-key-sub :mobile-network/remember-choice? :mobile-network/remember-choice?)
|
|
(reg-root-key-sub :qr-modal :qr-modal)
|
|
(reg-root-key-sub :content-layout-height :content-layout-height)
|
|
(reg-root-key-sub :bootnodes/manage :bootnodes/manage)
|
|
(reg-root-key-sub :networks/current-network :networks/current-network)
|
|
(reg-root-key-sub :networks/networks :networks/networks)
|
|
(reg-root-key-sub :networks/manage :networks/manage)
|
|
(reg-root-key-sub :get-pairing-installations :pairing/installations)
|
|
(reg-root-key-sub :tooltips :tooltips)
|
|
(reg-root-key-sub :supported-biometric-auth :supported-biometric-auth)
|
|
|
|
;;NOTE this one is not related to ethereum network
|
|
;; it is about cellular network/ wifi network
|
|
(reg-root-key-sub :network/type :network/type)
|
|
|
|
;;profile
|
|
(reg-root-key-sub :my-profile/seed :my-profile/seed)
|
|
(reg-root-key-sub :my-profile/advanced? :my-profile/advanced?)
|
|
(reg-root-key-sub :my-profile/editing? :my-profile/editing?)
|
|
(reg-root-key-sub :my-profile/profile :my-profile/profile)
|
|
(reg-root-key-sub :profile/photo-added? :profile/photo-added?)
|
|
|
|
;;multiaccount
|
|
(reg-root-key-sub :multiaccounts/multiaccounts :multiaccounts/multiaccounts)
|
|
(reg-root-key-sub :multiaccounts/login :multiaccounts/login)
|
|
(reg-root-key-sub :multiaccount :multiaccount)
|
|
(reg-root-key-sub :multiaccount/accounts :multiaccount/accounts)
|
|
(reg-root-key-sub :get-recover-multiaccount :multiaccounts/recover)
|
|
;;chat
|
|
(reg-root-key-sub ::cooldown-enabled? :chat/cooldown-enabled?)
|
|
(reg-root-key-sub ::chats :chats)
|
|
(reg-root-key-sub ::chat-ui-props :chat-ui-props)
|
|
(reg-root-key-sub :chats/current-chat-id :current-chat-id)
|
|
(reg-root-key-sub :public-group-topic :public-group-topic)
|
|
(reg-root-key-sub :chats/loading? :chats/loading?)
|
|
(reg-root-key-sub :new-chat-name :new-chat-name)
|
|
(reg-root-key-sub :group-chat-profile/editing? :group-chat-profile/editing?)
|
|
(reg-root-key-sub :group-chat-profile/profile :group-chat-profile/profile)
|
|
(reg-root-key-sub :selected-participants :selected-participants)
|
|
|
|
;;browser
|
|
(reg-root-key-sub :browsers :browser/browsers)
|
|
(reg-root-key-sub :browser/options :browser/options)
|
|
(reg-root-key-sub :dapps/permissions :dapps/permissions)
|
|
|
|
;;stickers
|
|
(reg-root-key-sub :stickers/selected-pack :stickers/selected-pack)
|
|
(reg-root-key-sub :stickers/packs :stickers/packs)
|
|
(reg-root-key-sub :stickers/installed-packs :stickers/packs-installed)
|
|
(reg-root-key-sub :stickers/packs-owned :stickers/packs-owned)
|
|
(reg-root-key-sub :stickers/packs-pending :stickers/packs-pending)
|
|
|
|
;;mailserver
|
|
(reg-root-key-sub :mailserver/current-id :mailserver/current-id)
|
|
(reg-root-key-sub :mailserver/mailservers :mailserver/mailservers)
|
|
(reg-root-key-sub :mailserver.edit/mailserver :mailserver.edit/mailserver)
|
|
(reg-root-key-sub :mailserver/state :mailserver/state)
|
|
(reg-root-key-sub :mailserver/pending-requests :mailserver/pending-requests)
|
|
(reg-root-key-sub :mailserver/request-error? :mailserver/request-error)
|
|
(reg-root-key-sub :mailserver/fetching-gaps-in-progress :mailserver/fetching-gaps-in-progress)
|
|
(reg-root-key-sub :mailserver/gaps :mailserver/gaps)
|
|
(reg-root-key-sub :mailserver/ranges :mailserver/ranges)
|
|
|
|
;;contacts
|
|
(reg-root-key-sub ::contacts :contacts/contacts)
|
|
(reg-root-key-sub :contacts/current-contact-identity :contacts/identity)
|
|
(reg-root-key-sub :new-identity-error :contacts/new-identity-error)
|
|
(reg-root-key-sub :contacts/new-identity :contacts/new-identity)
|
|
(reg-root-key-sub :group/selected-contacts :group/selected-contacts)
|
|
;;wallet
|
|
(reg-root-key-sub :wallet :wallet)
|
|
(reg-root-key-sub :prices :prices)
|
|
(reg-root-key-sub :collectibles :collectibles)
|
|
(reg-root-key-sub :wallet/all-tokens :wallet/all-tokens)
|
|
(reg-root-key-sub :prices-loading? :prices-loading?)
|
|
(reg-root-key-sub :wallet.transactions :wallet.transactions)
|
|
(reg-root-key-sub :wallet/custom-token-screen :wallet/custom-token-screen)
|
|
(reg-root-key-sub :wallet/prepare-transaction :wallet/prepare-transaction)
|
|
|
|
;;ethereum
|
|
(reg-root-key-sub :ethereum/current-block :ethereum/current-block)
|
|
|
|
;;ens
|
|
(reg-root-key-sub :ens/registration :ens/registration)
|
|
(reg-root-key-sub :ens/names :ens/names)
|
|
|
|
;;signing
|
|
(reg-root-key-sub :signing/tx :signing/tx)
|
|
(reg-root-key-sub :signing/sign :signing/sign)
|
|
(reg-root-key-sub :signing/edit-fee :signing/edit-fee)
|
|
|
|
;;intro-wizard
|
|
(reg-root-key-sub :intro-wizard-state :intro-wizard)
|
|
|
|
(reg-root-key-sub :popover/popover :popover/popover)
|
|
(reg-root-key-sub :add-account :add-account)
|
|
|
|
(reg-root-key-sub :keycard :hardwallet)
|
|
|
|
(reg-root-key-sub :auth-method :auth-method)
|
|
|
|
;;GENERAL ==============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:connection-stats
|
|
:<- [:desktop/desktop]
|
|
(fn [desktop _]
|
|
(get desktop :debug-metrics)))
|
|
|
|
;; Intro wizard
|
|
(re-frame/reg-sub
|
|
:intro-wizard
|
|
:<- [:intro-wizard-state]
|
|
:<- [:dimensions/window]
|
|
(fn [[wizard-state
|
|
{:keys [width height] :as dimensions}
|
|
view-id]]
|
|
(assoc wizard-state
|
|
:view-height height :view-width width)))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/generate-key
|
|
:<- [:intro-wizard]
|
|
(fn [wizard-state]
|
|
(select-keys wizard-state [:processing? :view-height])))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/choose-key
|
|
:<- [:intro-wizard]
|
|
(fn [wizard-state]
|
|
(select-keys wizard-state [:multiaccounts :selected-id :view-height])))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/select-key-storage
|
|
:<- [:intro-wizard]
|
|
(fn [wizard-state]
|
|
(merge (select-keys wizard-state [:selected-storage-type :view-height :recovering?])
|
|
(if (:recovering? wizard-state)
|
|
{:forward-action :multiaccounts.recover/select-storage-next-pressed}
|
|
{:forward-action :intro-wizard/step-forward-pressed}))))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/create-code
|
|
:<- [:intro-wizard]
|
|
(fn [wizard-state]
|
|
(merge (select-keys wizard-state [:confirm-failure? :encrypt-with-password? :weak-password? :view-width])
|
|
(if (:recovering? wizard-state)
|
|
{:forward-action :multiaccounts.recover/enter-password-next-pressed}
|
|
{:forward-action :intro-wizard/step-forward-pressed}))))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/confirm-code
|
|
:<- [:intro-wizard]
|
|
(fn [wizard-state]
|
|
(merge (select-keys wizard-state [:confirm-failure? :encrypt-with-password? :processing? :view-width])
|
|
(if (:recovering? wizard-state)
|
|
{:forward-action :multiaccounts.recover/confirm-password-next-pressed}
|
|
{:forward-action :intro-wizard/step-forward-pressed}))))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/enter-phrase
|
|
:<- [:intro-wizard]
|
|
(fn [wizard-state]
|
|
(select-keys wizard-state [:processing?
|
|
:passphrase-word-count
|
|
:next-button-disabled?
|
|
:passphrase-error])))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/recovery-success
|
|
:<- [:intro-wizard]
|
|
(fn [wizard-state]
|
|
{:pubkey (get-in wizard-state [:derived constants/path-whisper-keyword :publicKey])
|
|
:name (get-in wizard-state [:derived constants/path-whisper-keyword :name])
|
|
:photo-path (get-in wizard-state [:derived constants/path-whisper-keyword :photo-path])
|
|
:processing? (:processing? wizard-state)}))
|
|
|
|
(re-frame/reg-sub
|
|
:intro-wizard/recover-existing-account?
|
|
:<- [:intro-wizard]
|
|
:<- [:multiaccounts/multiaccounts]
|
|
(fn [[intro-wizard multiaccounts]]
|
|
(recover/existing-account? (:root-key intro-wizard) multiaccounts)))
|
|
|
|
;;FIXME not needed until desktop enabled
|
|
#_(re-frame/reg-sub
|
|
:settings/logging-enabled
|
|
:<- [:desktop/desktop]
|
|
(fn [desktop _]
|
|
(get desktop :logging-enabled false)))
|
|
|
|
(re-frame/reg-sub
|
|
:current-network
|
|
:<- [:networks/networks]
|
|
:<- [:networks/current-network]
|
|
(fn [[networks current-network]]
|
|
(when-let [network (get networks current-network)]
|
|
(assoc network
|
|
:rpc-network? (get-in network [:config :UpstreamConfig :Enabled])))))
|
|
|
|
(re-frame/reg-sub
|
|
:chain-name
|
|
:<- [:current-network]
|
|
(fn [network]
|
|
(ethereum/network->chain-name network)))
|
|
|
|
(re-frame/reg-sub
|
|
:chain-id
|
|
:<- [:current-network]
|
|
(fn [network]
|
|
(ethereum/network->chain-id network)))
|
|
|
|
(re-frame/reg-sub
|
|
:mainnet?
|
|
:<- [:chain-id]
|
|
(fn [chain-id]
|
|
(= 1 chain-id)))
|
|
|
|
(re-frame/reg-sub
|
|
:network-name
|
|
:<- [:current-network]
|
|
(fn [network]
|
|
(:name network)))
|
|
|
|
(re-frame/reg-sub
|
|
:disconnected?
|
|
:<- [:peers-count]
|
|
(fn [peers-count]
|
|
(zero? peers-count)))
|
|
|
|
(re-frame/reg-sub
|
|
:offline?
|
|
:<- [:network-status]
|
|
:<- [:sync-state]
|
|
:<- [:disconnected?]
|
|
(fn [[network-status sync-state disconnected?]]
|
|
(or disconnected?
|
|
(= network-status :offline)
|
|
(= sync-state :offline))))
|
|
|
|
(re-frame/reg-sub
|
|
:syncing?
|
|
:<- [:sync-state]
|
|
(fn [sync-state]
|
|
(#{:pending :in-progress} sync-state)))
|
|
|
|
(re-frame/reg-sub
|
|
:dimensions/window-width
|
|
:<- [:dimensions/window]
|
|
:width)
|
|
|
|
(re-frame/reg-sub
|
|
:dimensions/window-height
|
|
:<- [:dimensions/window]
|
|
:height)
|
|
|
|
(re-frame/reg-sub
|
|
:dimensions/small-screen?
|
|
:<- [:dimensions/window-height]
|
|
(fn [height]
|
|
(< height 550)))
|
|
|
|
(re-frame/reg-sub
|
|
:get-screen-params
|
|
:<- [:screen-params]
|
|
:<- [:view-id]
|
|
(fn [[params view-id-db] [_ view-id]]
|
|
(get params (or view-id view-id-db))))
|
|
|
|
(re-frame/reg-sub
|
|
:can-navigate-back?
|
|
:<- [:navigation-stack]
|
|
(fn [stack]
|
|
(> (count stack) 1)))
|
|
|
|
(re-frame/reg-sub
|
|
:delete-swipe-position
|
|
:<- [:animations]
|
|
(fn [animations [_ type item-id]]
|
|
(get-in animations [type item-id :delete-swiped])))
|
|
|
|
(re-frame/reg-sub
|
|
:search/filter
|
|
:<- [:ui/search]
|
|
(fn [search]
|
|
(get search :filter)))
|
|
|
|
(defn- node-version [web3-node-version]
|
|
(or web3-node-version "N/A"))
|
|
|
|
(def app-short-version
|
|
(let [version (if platform/desktop? build/version build/build-no)]
|
|
(str build/version " (" version ")")))
|
|
|
|
(re-frame/reg-sub
|
|
:get-app-version
|
|
:<- [:web3-node-version]
|
|
(fn [web3-node-version]
|
|
(str app-short-version "; " (node-version web3-node-version))))
|
|
|
|
(re-frame/reg-sub
|
|
:get-app-short-version
|
|
(fn [db] app-short-version))
|
|
|
|
(re-frame/reg-sub
|
|
:get-app-node-version
|
|
:<- [:web3-node-version]
|
|
node-version)
|
|
|
|
(re-frame/reg-sub
|
|
:my-profile/recovery
|
|
:<- [:my-profile/seed]
|
|
(fn [seed]
|
|
(or seed {:step :intro})))
|
|
|
|
(re-frame/reg-sub
|
|
:bottom-sheet
|
|
:<- [:bottom-sheet/show?]
|
|
:<- [:bottom-sheet/view]
|
|
(fn [[show? view]]
|
|
{:show? show?
|
|
:view view}))
|
|
|
|
(re-frame/reg-sub
|
|
:is-contact-selected?
|
|
:<- [:group/selected-contacts]
|
|
(fn [selected-contacts [_ element]]
|
|
(-> selected-contacts
|
|
(contains? element))))
|
|
|
|
(re-frame/reg-sub
|
|
:is-participant-selected?
|
|
:<- [:selected-participants]
|
|
(fn [selected-participants [_ element]]
|
|
(-> selected-participants
|
|
(contains? element))))
|
|
|
|
(re-frame/reg-sub
|
|
:ethereum/chain-keyword
|
|
:<- [:current-network]
|
|
(fn [network]
|
|
(ethereum/network->chain-keyword network)))
|
|
|
|
(re-frame/reg-sub
|
|
:ethereum/native-currency
|
|
:<- [:ethereum/chain-keyword]
|
|
(fn [chain-keyword]
|
|
(tokens/native-currency chain-keyword)))
|
|
|
|
;;MULTIACCOUNT ==============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:multiaccount/public-key
|
|
:<- [:multiaccount]
|
|
(fn [{:keys [public-key]}]
|
|
public-key))
|
|
|
|
(re-frame/reg-sub
|
|
:multiaccount/default-account
|
|
:<- [:multiaccount/accounts]
|
|
(fn [accounts]
|
|
(ethereum/get-default-account accounts)))
|
|
|
|
(re-frame/reg-sub
|
|
:sign-in-enabled?
|
|
:<- [:multiaccounts/login]
|
|
(fn [{:keys [password]}]
|
|
(spec/valid? ::multiaccounts.db/password
|
|
(security/safe-unmask-data password))))
|
|
|
|
(re-frame/reg-sub
|
|
:fleets/current-fleet
|
|
:<- [:multiaccount]
|
|
(fn [multiaccount]
|
|
(fleet/current-fleet-sub multiaccount)))
|
|
|
|
(re-frame/reg-sub
|
|
:log-level/current-log-level
|
|
:<- [:multiaccount]
|
|
(fn [multiaccount]
|
|
(or (get multiaccount :log-level)
|
|
config/log-level-status-go)))
|
|
|
|
(re-frame/reg-sub
|
|
:dapps-address
|
|
:<- [:multiaccount]
|
|
(fn [acc]
|
|
(get acc :dapps-address)))
|
|
|
|
(re-frame/reg-sub
|
|
:dapps-account
|
|
:<- [:multiaccount/accounts]
|
|
:<- [:dapps-address]
|
|
(fn [[accounts address]]
|
|
(some #(when (= (:address %) address) %) accounts)))
|
|
|
|
(re-frame/reg-sub
|
|
:multiaccount/current-account
|
|
:<- [:multiaccount/accounts]
|
|
:<- [:get-screen-params :wallet-account]
|
|
(fn [[accounts acc]]
|
|
(some #(when (= (:address %) (:address acc)) %) accounts)))
|
|
|
|
(re-frame/reg-sub
|
|
:account-by-address
|
|
:<- [:multiaccount/accounts]
|
|
(fn [accounts [_ address]]
|
|
(some #(when (= (:address %) address) %) accounts)))
|
|
|
|
(re-frame/reg-sub
|
|
:multiple-multiaccounts?
|
|
:<- [:multiaccounts/multiaccounts]
|
|
(fn [multiaccounts]
|
|
(> (count multiaccounts) 1)))
|
|
|
|
(re-frame/reg-sub
|
|
:multiaccounts.login/keycard-account?
|
|
:<- [:multiaccounts/multiaccounts]
|
|
:<- [:multiaccounts/login]
|
|
(fn [[multiaccounts {:keys [key-uid]}]]
|
|
(get-in multiaccounts [key-uid :keycard-pairing])))
|
|
|
|
(re-frame/reg-sub
|
|
:accounts-without-watch-only
|
|
:<- [:multiaccount/accounts]
|
|
(fn [accounts]
|
|
(filter #(not= (:type %) :watch) accounts)))
|
|
|
|
(re-frame/reg-sub
|
|
:add-account-disabled?
|
|
:<- [:multiaccount/accounts]
|
|
:<- [:add-account]
|
|
(fn [[accounts {:keys [address]}]]
|
|
(or (not (ethereum/address? address))
|
|
(some #(when (= (:address %) address) %) accounts))))
|
|
|
|
;;CHAT ==============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:get-collectible-token
|
|
:<- [:collectibles]
|
|
(fn [collectibles [_ {:keys [symbol token]}]]
|
|
(get-in collectibles [(keyword symbol) (js/parseInt token)])))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/chat
|
|
:<- [:chats/active-chats]
|
|
(fn [chats [_ chat-id]]
|
|
(get chats chat-id)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/content-layout-height
|
|
:<- [:content-layout-height]
|
|
:<- [:chats/current-chat-ui-prop :input-height]
|
|
:<- [:chats/current-chat-ui-prop :input-focused?]
|
|
:<- [:keyboard-height]
|
|
:<- [:chats/current-chat-ui-prop :input-bottom-sheet]
|
|
(fn [[home-content-layout-height input-height input-focused? kheight stickers?]]
|
|
(- (+ home-content-layout-height tabs.styles/tabs-height)
|
|
(if platform/iphone-x?
|
|
(* 2 toolbar.styles/toolbar-height)
|
|
toolbar.styles/toolbar-height)
|
|
(if input-height input-height 0)
|
|
(if stickers?
|
|
(stickers.styles/stickers-panel-height)
|
|
kheight)
|
|
(if input-focused?
|
|
(cond
|
|
platform/iphone-x? 0
|
|
platform/ios? tabs.styles/tabs-diff
|
|
:else 0)
|
|
(cond
|
|
platform/iphone-x? (* 2 tabs.styles/minimized-tabs-height)
|
|
platform/ios? tabs.styles/tabs-height
|
|
:else tabs.styles/minimized-tabs-height)))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat-ui-props
|
|
:<- [::chat-ui-props]
|
|
:<- [:chats/current-chat-id]
|
|
(fn [[chat-ui-props id]]
|
|
(get chat-ui-props id)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat-ui-prop
|
|
:<- [:chats/current-chat-ui-props]
|
|
(fn [ui-props [_ prop]]
|
|
(get ui-props prop)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/input-margin
|
|
:<- [:keyboard-height]
|
|
(fn [kb-height]
|
|
(cond
|
|
(and platform/iphone-x? (> kb-height 0))
|
|
(- kb-height (* 2 tabs.styles/minimized-tabs-height))
|
|
|
|
platform/ios?
|
|
(+ kb-height (- (if (> kb-height 0)
|
|
tabs.styles/minimized-tabs-height
|
|
0)))
|
|
|
|
:default 0)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/active-chats
|
|
:<- [:contacts/contacts]
|
|
:<- [::chats]
|
|
:<- [:multiaccount]
|
|
(fn [[contacts chats multiaccount]]
|
|
(chat.db/active-chats contacts chats multiaccount)))
|
|
|
|
(defn enrich-current-one-to-one-chat
|
|
[{:keys [contact] :as current-chat} my-public-key ttt-settings
|
|
chain-keyword prices currency]
|
|
(let [{:keys [tribute-to-talk]} contact
|
|
{:keys [disabled? snt-amount message]} tribute-to-talk
|
|
whitelisted-by? (whitelist/whitelisted-by? contact)
|
|
loading? (and (not whitelisted-by?)
|
|
(not tribute-to-talk))
|
|
show-input? (or whitelisted-by?
|
|
disabled?)
|
|
token (case chain-keyword
|
|
:mainnet :SNT
|
|
:STT)
|
|
tribute-status (if loading?
|
|
:loading
|
|
(tribute-to-talk.db/tribute-status contact))
|
|
tribute-label (tribute-to-talk.db/status-label tribute-status snt-amount)]
|
|
|
|
(cond-> (assoc current-chat
|
|
:tribute-to-talk/tribute-status tribute-status
|
|
:tribute-to-talk/tribute-label tribute-label)
|
|
|
|
(#{:required :pending :paid} tribute-status)
|
|
(assoc :tribute-to-talk/snt-amount
|
|
(tribute-to-talk.db/from-wei snt-amount)
|
|
:tribute-to-talk/message
|
|
message
|
|
:tribute-to-talk/fiat-amount (if snt-amount
|
|
(money/fiat-amount-value
|
|
snt-amount
|
|
token
|
|
(-> currency :code keyword)
|
|
prices)
|
|
"0")
|
|
:tribute-to-talk/fiat-currency (:code currency)
|
|
:tribute-to-talk/token (str " " (name token)))
|
|
|
|
(tribute-to-talk.db/enabled? ttt-settings)
|
|
(assoc :tribute-to-talk/received? (tribute-to-talk.db/tribute-received?
|
|
contact))
|
|
|
|
(= tribute-status :required)
|
|
(assoc :tribute-to-talk/on-share-my-profile
|
|
#(re-frame/dispatch
|
|
[:profile/share-profile-link my-public-key]))
|
|
|
|
show-input?
|
|
(assoc :show-input? true))))
|
|
|
|
(defn enrich-current-chat
|
|
[{:keys [messages chat-id might-have-join-time-messages?] :as chat}
|
|
ranges height input-height]
|
|
(assoc chat
|
|
:height height
|
|
:input-height input-height
|
|
:range
|
|
(get ranges chat-id)
|
|
:intro-status
|
|
(if might-have-join-time-messages?
|
|
:loading
|
|
(if (empty? messages)
|
|
:empty
|
|
:messages))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-raw-chat
|
|
:<- [:chats/active-chats]
|
|
:<- [:chats/current-chat-id]
|
|
(fn [[chats current-chat-id]]
|
|
(get chats current-chat-id)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat-input-text
|
|
:<- [:chats/current-raw-chat]
|
|
(fn [chat]
|
|
(:input-text chat)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat
|
|
:<- [:chats/current-raw-chat]
|
|
:<- [:multiaccount/public-key]
|
|
:<- [:mailserver/ranges]
|
|
:<- [:chats/content-layout-height]
|
|
:<- [:chats/current-chat-ui-prop :input-height]
|
|
:<- [:tribute-to-talk/settings]
|
|
:<- [:ethereum/chain-keyword]
|
|
:<- [:prices]
|
|
:<- [:wallet/currency]
|
|
(fn [[{:keys [group-chat
|
|
chat-id
|
|
contact
|
|
messages]
|
|
:as current-chat} my-public-key ranges height
|
|
input-height ttt-settings chain-keyword prices currency]]
|
|
(when current-chat
|
|
(cond-> (enrich-current-chat current-chat ranges height input-height)
|
|
(empty? messages)
|
|
(assoc :universal-link
|
|
(links/generate-link :public-chat :external chat-id))
|
|
|
|
(chat.models/public-chat? current-chat)
|
|
(assoc :show-input? true)
|
|
|
|
(and (chat.models/group-chat? current-chat)
|
|
(group-chats.db/joined? my-public-key current-chat))
|
|
(assoc :show-input? true)
|
|
|
|
(not group-chat)
|
|
(enrich-current-one-to-one-chat my-public-key ttt-settings
|
|
chain-keyword prices currency)))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat-message
|
|
:<- [:chats/current-chat]
|
|
(fn [{:keys [messages]} [_ message-id]]
|
|
(get messages message-id)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat-messages
|
|
:<- [:chats/current-chat]
|
|
(fn [{:keys [messages]}]
|
|
(or messages {})))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/messages-gaps
|
|
:<- [:mailserver/gaps]
|
|
:<- [:chats/current-chat-id]
|
|
(fn [[gaps chat-id]]
|
|
(sort-by :from (vals (get gaps chat-id)))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/range
|
|
:<- [:mailserver/ranges]
|
|
:<- [:chats/current-chat-id]
|
|
(fn [[ranges chat-id]]
|
|
(get ranges chat-id)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/all-loaded?
|
|
:<- [:chats/current-chat]
|
|
(fn [chat]
|
|
(:all-loaded? chat)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/public?
|
|
:<- [:chats/current-chat]
|
|
(fn [chat]
|
|
(:public? chat)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/message-list
|
|
:<- [:chats/current-chat]
|
|
(fn [chat]
|
|
(:message-list chat)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/messages
|
|
:<- [:chats/current-chat]
|
|
(fn [chat]
|
|
(:messages chat)))
|
|
|
|
(defn hydrate-messages
|
|
"Pull data from messages and add it to the sorted list"
|
|
[message-list messages]
|
|
(keep #(if (= :message (% :type))
|
|
(when-let [message (messages (% :message-id))]
|
|
(merge message %))
|
|
%)
|
|
message-list))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat-messages-stream
|
|
:<- [:chats/message-list]
|
|
:<- [:chats/messages]
|
|
:<- [:chats/messages-gaps]
|
|
:<- [:chats/range]
|
|
:<- [:chats/all-loaded?]
|
|
:<- [:chats/public?]
|
|
(fn [[message-list messages messages-gaps range all-loaded? public?]]
|
|
(-> (models.message-list/->seq message-list)
|
|
(chat.db/add-datemarks)
|
|
(hydrate-messages messages)
|
|
(chat.db/add-gaps messages-gaps range all-loaded? public?))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/current-chat-intro-status
|
|
:<- [:chats/current-chat]
|
|
:<- [:chats/current-chat-messages]
|
|
(fn [[{:keys [might-have-join-time-messages?]} messages]]
|
|
(if might-have-join-time-messages?
|
|
:loading
|
|
(if (empty? messages)
|
|
:empty
|
|
:messages))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/unviewed-messages-count
|
|
(fn [[_ chat-id]]
|
|
(re-frame/subscribe [:chats/chat chat-id]))
|
|
(fn [{:keys [unviewed-messages-count]}]
|
|
unviewed-messages-count))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/photo-path
|
|
:<- [:contacts/contacts]
|
|
:<- [:multiaccount]
|
|
(fn [[contacts multiaccount] [_ id]]
|
|
(multiaccounts/displayed-photo (or (contacts id)
|
|
(when (= id (:public-key multiaccount))
|
|
multiaccount)
|
|
(contact.db/public-key->new-contact id)))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/unread-messages-number
|
|
:<- [:chats/active-chats]
|
|
(fn [chats _]
|
|
(apply + (map :unviewed-messages-count (vals chats)))))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/cooldown-enabled?
|
|
:<- [:chats/current-chat]
|
|
:<- [::cooldown-enabled?]
|
|
(fn [[{:keys [public?]} cooldown-enabled?]]
|
|
(and public?
|
|
cooldown-enabled?)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/reply-message
|
|
:<- [:chats/current-chat]
|
|
(fn [{:keys [metadata messages]}]
|
|
(get messages (get-in metadata [:responding-to-message :message-id]))))
|
|
|
|
(re-frame/reg-sub
|
|
:public-chat.new/topic-error-message
|
|
:<- [:public-group-topic]
|
|
(fn [topic]
|
|
(when-not (or (empty? topic)
|
|
(db/valid-topic? topic))
|
|
(i18n/label :topic-name-error))))
|
|
|
|
(defn filter-selected-contacts
|
|
[selected-contacts contacts]
|
|
(filter #(contact.db/added? (contacts %)) selected-contacts))
|
|
|
|
(re-frame/reg-sub
|
|
:selected-contacts-count
|
|
:<- [:group/selected-contacts]
|
|
:<- [:contacts/contacts]
|
|
(fn [[selected-contacts contacts]]
|
|
(count (filter-selected-contacts selected-contacts contacts))))
|
|
|
|
(re-frame/reg-sub
|
|
:selected-participants-count
|
|
:<- [:selected-participants]
|
|
(fn [selected-participants]
|
|
(count selected-participants)))
|
|
|
|
(defn filter-contacts [selected-contacts active-contacts]
|
|
(filter #(selected-contacts (:public-key %)) active-contacts))
|
|
|
|
(re-frame/reg-sub
|
|
:selected-group-contacts
|
|
:<- [:group/selected-contacts]
|
|
:<- [:contacts/active]
|
|
(fn [[selected-contacts active-contacts]]
|
|
(filter-contacts selected-contacts active-contacts)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/transaction-status
|
|
;;TODO address here for transactions
|
|
:<- [:wallet/transactions]
|
|
:<- [:ethereum/current-block]
|
|
(fn [[transactions current-block] [_ hash]]
|
|
(when-let [transaction (get transactions hash)]
|
|
{:exists? true
|
|
:confirmed?
|
|
(-> transaction
|
|
(wallet.db/get-confirmations current-block)
|
|
(>= transactions/confirmations-count-threshold))})))
|
|
|
|
;;BOOTNODES ============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:custom-bootnodes/enabled?
|
|
:<- [:multiaccount]
|
|
:<- [:networks/current-network]
|
|
(fn [[{:keys [custom-bootnodes-enabled?]} current-network]]
|
|
(get custom-bootnodes-enabled? current-network)))
|
|
|
|
(re-frame/reg-sub
|
|
:custom-bootnodes/network-bootnodes
|
|
:<- [:multiaccount]
|
|
:<- [:networks/current-network]
|
|
(fn [[multiaccount current-network]]
|
|
(get-in multiaccount [:custom-bootnodes current-network])))
|
|
|
|
(re-frame/reg-sub
|
|
:get-manage-bootnode
|
|
:<- [:bootnodes/manage]
|
|
(fn [manage]
|
|
manage))
|
|
|
|
(re-frame/reg-sub
|
|
:manage-bootnode-validation-errors
|
|
:<- [:get-manage-bootnode]
|
|
(fn [manage]
|
|
(set (keep
|
|
(fn [[k {:keys [error]}]]
|
|
(when error k))
|
|
manage))))
|
|
|
|
;;BROWSER ==============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:browser/browsers
|
|
:<- [:browsers]
|
|
(fn [browsers]
|
|
(reduce (fn [acc [k browser]]
|
|
(update acc k assoc :url (browser/get-current-url browser)))
|
|
browsers
|
|
browsers)))
|
|
|
|
(re-frame/reg-sub
|
|
:browser/browsers-vals
|
|
:<- [:browser/browsers]
|
|
(fn [browsers]
|
|
(sort-by :timestamp > (vals browsers))))
|
|
|
|
(re-frame/reg-sub
|
|
:get-current-browser
|
|
:<- [:browser/options]
|
|
:<- [:browser/browsers]
|
|
(fn [[options browsers]]
|
|
(let [browser (get browsers (:browser-id options))]
|
|
(assoc browser :secure? (browser/secure? browser options)))))
|
|
|
|
;;STICKERS =============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:stickers/installed-packs-vals
|
|
:<- [:stickers/installed-packs]
|
|
(fn [packs]
|
|
(vals packs)))
|
|
|
|
(re-frame/reg-sub
|
|
:stickers/all-packs
|
|
:<- [:stickers/packs]
|
|
:<- [:stickers/installed-packs]
|
|
:<- [:stickers/packs-owned]
|
|
:<- [:stickers/packs-pending]
|
|
(fn [[packs installed owned pending]]
|
|
(map (fn [{:keys [id] :as pack}]
|
|
(cond-> pack
|
|
(get installed id) (assoc :installed true)
|
|
(get owned id) (assoc :owned true)
|
|
(get pending id) (assoc :pending true)))
|
|
(vals packs))))
|
|
|
|
(re-frame/reg-sub
|
|
:stickers/get-current-pack
|
|
:<- [:get-screen-params]
|
|
:<- [:stickers/all-packs]
|
|
(fn [[{:keys [id]} packs]]
|
|
(first (filter #(= (:id %) id) packs))))
|
|
|
|
(defn find-pack-id-for-hash [sticker-uri packs]
|
|
(some (fn [{:keys [stickers id]}]
|
|
(when (some #(= sticker-uri (:hash %)) stickers)
|
|
id))
|
|
packs))
|
|
|
|
(re-frame/reg-sub
|
|
:stickers/recent
|
|
:<- [:multiaccount]
|
|
:<- [:stickers/installed-packs-vals]
|
|
(fn [[{:keys [:stickers/recent-stickers]} packs]]
|
|
(map (fn [hash] {:hash hash :pack (find-pack-id-for-hash hash packs)}) recent-stickers)))
|
|
|
|
(re-frame/reg-sub
|
|
:home-items
|
|
:<- [:chats/active-chats]
|
|
:<- [:search/filter]
|
|
:<- [:search/filtered-chats]
|
|
(fn [[chats search-filter filtered-chats]]
|
|
(if (or (nil? search-filter)
|
|
(and platform/desktop? (empty? search-filter)))
|
|
{:all-home-items
|
|
(sort-by #(-> % second :timestamp) > chats)}
|
|
{:search-filter search-filter
|
|
:chats filtered-chats})))
|
|
|
|
;;PAIRING ==============================================================================================================
|
|
|
|
|
|
(re-frame/reg-sub
|
|
:pairing/installations
|
|
:<- [:get-pairing-installations]
|
|
:<- [:pairing/installation-id]
|
|
(fn [[installations installation-id]]
|
|
(->> installations
|
|
vals
|
|
(pairing/sort-installations installation-id))))
|
|
|
|
(re-frame/reg-sub
|
|
:pairing/installation-id
|
|
:<- [:multiaccount]
|
|
:installation-id)
|
|
|
|
(re-frame/reg-sub
|
|
:pairing/installation-name
|
|
:<- [:multiaccount]
|
|
(fn [multiaccount] (:installation-name multiaccount)))
|
|
|
|
;;PROFILE ==============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:get-profile-unread-messages-number
|
|
:<- [:multiaccount]
|
|
(fn [{:keys [mnemonic]}]
|
|
(if mnemonic 1 0)))
|
|
|
|
;;WALLET ==============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:balance
|
|
:<- [:wallet]
|
|
(fn [wallet [_ address]]
|
|
(get-in wallet [:accounts address :balance])))
|
|
|
|
(re-frame/reg-sub
|
|
:balance-default
|
|
:<- [:wallet]
|
|
:<- [:multiaccount/accounts]
|
|
(fn [[wallet accounts]]
|
|
(get-in wallet [:accounts (:address (ethereum/get-default-account accounts)) :balance])))
|
|
|
|
(re-frame/reg-sub
|
|
:balances
|
|
:<- [:wallet]
|
|
(fn [wallet]
|
|
(map :balance (vals (:accounts wallet)))))
|
|
|
|
(re-frame/reg-sub
|
|
:empty-balances?
|
|
:<- [:balances]
|
|
(fn [balances]
|
|
(every?
|
|
(fn [balance]
|
|
(every?
|
|
(fn [asset]
|
|
(or (nil? asset) (.isZero asset)))
|
|
(vals balance)))
|
|
balances)))
|
|
|
|
(re-frame/reg-sub
|
|
:price
|
|
:<- [:prices]
|
|
(fn [prices [_ fsym tsym]]
|
|
(get-in prices [fsym tsym :price])))
|
|
|
|
(re-frame/reg-sub
|
|
:last-day
|
|
:<- [:prices]
|
|
(fn [prices [_ fsym tsym]]
|
|
(get-in prices [fsym tsym :last-day])))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.settings/currency
|
|
:<- [:multiaccount]
|
|
(fn [settings]
|
|
(or (get settings :currency) :usd)))
|
|
|
|
(defn- get-balance-total-value
|
|
[balance prices currency token->decimals]
|
|
(reduce-kv (fn [acc symbol value]
|
|
(if-let [price (get-in prices [symbol currency :price])]
|
|
(+ acc (or (some-> (money/internal->formatted value symbol (token->decimals symbol))
|
|
(money/crypto->fiat price)
|
|
.toNumber)
|
|
0))
|
|
acc)) 0 balance))
|
|
|
|
(re-frame/reg-sub
|
|
:portfolio-value
|
|
:<- [:balances]
|
|
:<- [:prices]
|
|
:<- [:wallet/currency]
|
|
:<- [:ethereum/chain-keyword]
|
|
:<- [:wallet/all-tokens]
|
|
(fn [[balances prices currency chain all-tokens]]
|
|
(if (and balances prices)
|
|
(let [assets (tokens/tokens-for all-tokens chain)
|
|
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
|
|
currency-key (-> currency :code keyword)
|
|
balance-total-value (apply + (map #(get-balance-total-value % prices currency-key token->decimals) balances))]
|
|
(if (pos? balance-total-value)
|
|
(-> balance-total-value
|
|
(money/with-precision 2)
|
|
str
|
|
(i18n/format-currency (:code currency) false))
|
|
"0"))
|
|
"...")))
|
|
|
|
(re-frame/reg-sub
|
|
:account-portfolio-value
|
|
(fn [[_ address] _]
|
|
[(re-frame/subscribe [:balance address])
|
|
(re-frame/subscribe [:prices])
|
|
(re-frame/subscribe [:wallet/currency])
|
|
(re-frame/subscribe [:ethereum/chain-keyword])
|
|
(re-frame/subscribe [:wallet/all-tokens])])
|
|
(fn [[balance prices currency chain all-tokens]]
|
|
(if (and balance prices)
|
|
(let [assets (tokens/tokens-for all-tokens chain)
|
|
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
|
|
currency-key (-> currency :code keyword)
|
|
balance-total-value (get-balance-total-value balance prices currency-key token->decimals)]
|
|
(if (pos? balance-total-value)
|
|
(-> balance-total-value
|
|
(money/with-precision 2)
|
|
str
|
|
(i18n/format-currency (:code currency) false))
|
|
"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/error-message
|
|
:<- [:wallet]
|
|
(fn [wallet]
|
|
(or (get-in wallet [:errors :balance-update])
|
|
(get-in wallet [:errors :prices-update]))))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/visible-tokens-symbols
|
|
:<- [:ethereum/chain-keyword]
|
|
:<- [:multiaccount]
|
|
(fn [[chain current-multiaccount]]
|
|
(get-in current-multiaccount [:wallet/visible-tokens chain])))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/visible-assets
|
|
:<- [:ethereum/chain-keyword]
|
|
:<- [:wallet/visible-tokens-symbols]
|
|
:<- [:wallet/all-tokens]
|
|
(fn [[chain visible-tokens-symbols all-tokens]]
|
|
(conj (filter #(contains? visible-tokens-symbols (:symbol %))
|
|
(tokens/sorted-tokens-for all-tokens chain))
|
|
(tokens/native-currency chain))))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/visible-assets-with-amount
|
|
(fn [[_ address] _]
|
|
[(re-frame/subscribe [:balance address])
|
|
(re-frame/subscribe [:wallet/visible-assets])])
|
|
(fn [[balance visible-assets]]
|
|
(map #(assoc % :amount (get balance (:symbol %))) visible-assets)))
|
|
|
|
(defn update-value [prices currency]
|
|
(fn [{:keys [symbol decimals amount] :as token}]
|
|
(let [price (get-in prices [symbol (-> currency :code keyword) :price])]
|
|
(assoc token
|
|
:price price
|
|
:value (when (and amount price)
|
|
(-> (money/internal->formatted amount 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
|
|
(fn [[_ address] _]
|
|
[(re-frame/subscribe [:wallet/visible-assets-with-amount address])
|
|
(re-frame/subscribe [:prices])
|
|
(re-frame/subscribe [:wallet/currency])])
|
|
(fn [[assets prices currency]]
|
|
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
|
|
tokens-with-values (map (update-value prices currency) tokens)]
|
|
{:tokens tokens-with-values
|
|
:nfts nfts})))
|
|
|
|
(defn get-asset-amount [balances sym]
|
|
(reduce #(if-let [bl (get %2 sym)]
|
|
(.plus %1 bl)
|
|
%1)
|
|
(money/bignumber 0)
|
|
balances))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/all-visible-assets-with-amount
|
|
:<- [:balances]
|
|
:<- [:wallet/visible-assets]
|
|
(fn [[balances visible-assets]]
|
|
(map #(assoc % :amount (get-asset-amount balances (:symbol %))) visible-assets)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/all-visible-assets-with-values
|
|
:<- [:wallet/all-visible-assets-with-amount]
|
|
:<- [:prices]
|
|
:<- [:wallet/currency]
|
|
(fn [[assets prices currency]]
|
|
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
|
|
tokens-with-values (map (update-value prices currency) tokens)]
|
|
{:tokens tokens-with-values
|
|
:nfts nfts})))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/transferrable-assets-with-amount
|
|
(fn [[_ address]]
|
|
(re-frame/subscribe [:wallet/visible-assets-with-amount address]))
|
|
(fn [all-assets]
|
|
(filter #(not (:nft? %)) all-assets)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/currency
|
|
:<- [:wallet.settings/currency]
|
|
(fn [currency-id]
|
|
(get constants/currencies currency-id)))
|
|
|
|
;;WALLET TRANSACTIONS ==================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/transactions
|
|
:<- [:wallet]
|
|
(fn [wallet [_ address]]
|
|
(get-in wallet [:accounts address :transactions])))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/filters
|
|
:<- [:wallet]
|
|
(fn [wallet]
|
|
(get wallet :filters)))
|
|
|
|
(defn enrich-transaction
|
|
[{:keys [type to from value token] :as transaction}
|
|
contacts native-currency]
|
|
(let [[contact-address key-contact key-wallet]
|
|
(if (= type :inbound)
|
|
[from :from-contact :to-wallet]
|
|
[to :to-contact :from-wallet])
|
|
wallet (i18n/label :main-wallet)
|
|
contact (get contacts contact-address)
|
|
{:keys [symbol-display symbol decimals] :as asset}
|
|
(or token native-currency)
|
|
amount-text (if value
|
|
(wallet.utils/format-amount value decimals)
|
|
"...")
|
|
currency-text (when asset
|
|
(clojure.core/name (or symbol-display symbol)))]
|
|
(cond-> transaction
|
|
contact (assoc key-contact (:name contact))
|
|
:always (assoc key-wallet wallet
|
|
:amount-text amount-text
|
|
:currency-text currency-text))))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.transactions/transactions
|
|
(fn [[_ address] _]
|
|
[(re-frame/subscribe [:wallet/transactions address])
|
|
(re-frame/subscribe [:contacts/contacts-by-address])
|
|
(re-frame/subscribe [:ethereum/native-currency])])
|
|
(fn [[transactions contacts native-currency]]
|
|
(reduce (fn [acc [hash transaction]]
|
|
(assoc acc
|
|
hash
|
|
(enrich-transaction transaction contacts native-currency))) ;;TODO this doesn't look good for performance, we need to calculate this only once for each transaction
|
|
{}
|
|
transactions)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.transactions/all-filters?
|
|
:<- [:wallet/filters]
|
|
(fn [filters]
|
|
(= wallet.db/default-wallet-filters
|
|
filters)))
|
|
|
|
(def filters-labels
|
|
{:inbound (i18n/label :t/incoming)
|
|
:outbound (i18n/label :t/outgoing)
|
|
:pending (i18n/label :t/pending)
|
|
:failed (i18n/label :t/failed)})
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.transactions/filters
|
|
:<- [:wallet/filters]
|
|
(fn [filters]
|
|
(map (fn [id]
|
|
(let [checked? (filters id)]
|
|
{:id id
|
|
:label (filters-labels id)
|
|
:checked? checked?
|
|
:on-touch #(if checked?
|
|
(re-frame/dispatch [:wallet.transactions/remove-filter id])
|
|
(re-frame/dispatch [:wallet.transactions/add-filter id]))}))
|
|
wallet.db/default-wallet-filters)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.transactions.filters/screen
|
|
:<- [:wallet.transactions/filters]
|
|
:<- [:wallet.transactions/all-filters?]
|
|
(fn [[filters all-filters?]]
|
|
{:all-filters? all-filters?
|
|
:filters filters
|
|
:on-touch-select-all (when-not all-filters?
|
|
#(re-frame/dispatch
|
|
[:wallet.transactions/add-all-filters]))}))
|
|
|
|
(defn- enrich-transaction-for-list
|
|
[filters
|
|
{:keys [type from-contact from to-contact to hash timestamp] :as transaction}
|
|
address]
|
|
(when (filters type)
|
|
(assoc (case type
|
|
:inbound
|
|
(assoc transaction
|
|
:label (i18n/label :t/from)
|
|
:contact-accessibility-label :sender-text
|
|
:address-accessibility-label :sender-address-text
|
|
:contact from-contact
|
|
:address from)
|
|
(assoc transaction
|
|
:label (i18n/label :t/to)
|
|
:contact-accessibility-label :recipient-name-text
|
|
:address-accessibility-label :recipient-address-text
|
|
:contact to-contact
|
|
:address to))
|
|
:time-formatted (datetime/timestamp->time timestamp)
|
|
:on-touch-fn #(re-frame/dispatch [:wallet.ui/show-transaction-details hash address]))))
|
|
|
|
(defn- group-transactions-by-date
|
|
[transactions]
|
|
(->> transactions
|
|
(group-by #(datetime/timestamp->date-key (:timestamp %)))
|
|
(sort-by key >)
|
|
(map (fn [[date-key transactions]]
|
|
{:title (datetime/timestamp->mini-date (:timestamp (first transactions)))
|
|
:key date-key
|
|
:data (sort-by :timestamp > transactions)}))))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.transactions.history/screen
|
|
(fn [[_ address] _]
|
|
[(re-frame/subscribe [:wallet.transactions/transactions address])
|
|
(re-frame/subscribe [:wallet/filters])
|
|
(re-frame/subscribe [:wallet.transactions/all-filters?])])
|
|
(fn [[transactions filters all-filters?] [_ address]]
|
|
{:all-filters? all-filters?
|
|
:transaction-history-sections
|
|
(->> transactions
|
|
vals
|
|
(keep #(enrich-transaction-for-list filters % address))
|
|
(group-transactions-by-date))}))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.transactions.details/current-transaction
|
|
(fn [[_ hash address] _]
|
|
[(re-frame/subscribe [:wallet.transactions/transactions address])
|
|
(re-frame/subscribe [:ethereum/native-currency])
|
|
(re-frame/subscribe [:ethereum/chain-keyword])])
|
|
(fn [[transactions native-currency chain-keyword] [_ hash _]]
|
|
(let [{:keys [gas-used gas-price hash timestamp type token value]
|
|
:as transaction}
|
|
(get transactions hash)
|
|
native-currency-text (name (or (:symbol-display native-currency)
|
|
(:symbol native-currency)))]
|
|
(when transaction
|
|
(merge transaction
|
|
{:gas-price-eth (if gas-price
|
|
(money/wei->str :eth
|
|
gas-price
|
|
native-currency-text)
|
|
"-")
|
|
:gas-price-gwei (if gas-price
|
|
(money/wei->str :gwei
|
|
gas-price)
|
|
"-")
|
|
:date (datetime/timestamp->long-date timestamp)}
|
|
(if (= type :unsigned)
|
|
{:block (i18n/label :not-applicable)
|
|
:cost (i18n/label :not-applicable)
|
|
:gas-limit (i18n/label :not-applicable)
|
|
:gas-used (i18n/label :not-applicable)
|
|
:nonce (i18n/label :not-applicable)
|
|
:hash (i18n/label :not-applicable)}
|
|
{:cost (when gas-used
|
|
(money/wei->str :eth
|
|
(money/fee-value gas-used gas-price)
|
|
native-currency-text))
|
|
:url (transactions/get-transaction-details-url
|
|
chain-keyword
|
|
hash)}))))))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.transactions.details/screen
|
|
(fn [[_ hash address] _]
|
|
[(re-frame/subscribe [:wallet.transactions.details/current-transaction hash address])
|
|
(re-frame/subscribe [:ethereum/current-block])])
|
|
(fn [[transaction current-block]]
|
|
(let [confirmations (wallet.db/get-confirmations transaction
|
|
current-block)]
|
|
(assoc transaction
|
|
:confirmations confirmations
|
|
:confirmations-progress
|
|
(if (>= confirmations transactions/confirmations-count-threshold)
|
|
100
|
|
(* 100 (/ confirmations transactions/confirmations-count-threshold)))))))
|
|
|
|
;;WALLET SEND ==========================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
::send-transaction
|
|
:<- [:wallet]
|
|
(fn [wallet]
|
|
(:send-transaction wallet)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.send/symbol
|
|
:<- [::send-transaction]
|
|
(fn [send-transaction]
|
|
(:symbol send-transaction)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.send/camera-flashlight
|
|
:<- [::send-transaction]
|
|
(fn [send-transaction]
|
|
(:camera-flashlight send-transaction)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet/settings
|
|
:<- [:wallet]
|
|
(fn [{:keys [settings]}]
|
|
(reduce-kv #(conj %1 %3) [] settings)))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.request/transaction
|
|
:<- [:wallet]
|
|
:request-transaction)
|
|
|
|
(re-frame/reg-sub
|
|
:screen-collectibles
|
|
:<- [:collectibles]
|
|
:<- [:get-screen-params]
|
|
(fn [[collectibles {:keys [symbol]}]]
|
|
(when-let [v (get collectibles symbol)]
|
|
(mapv #(assoc (second %) :id (first %)) v))))
|
|
|
|
;;UI ==============================================================================================================
|
|
|
|
;;TODO this subscription looks super weird huge and with dispatches?
|
|
(re-frame/reg-sub
|
|
:connectivity/status-properties
|
|
:<- [:offline?]
|
|
:<- [:disconnected?]
|
|
:<- [:mailserver/connecting?]
|
|
:<- [:mailserver/connection-error?]
|
|
:<- [:mailserver/request-error?]
|
|
:<- [:mailserver/fetching?]
|
|
:<- [:network/type]
|
|
:<- [:multiaccount]
|
|
(fn [[offline? disconnected? mailserver-connecting? mailserver-connection-error?
|
|
mailserver-request-error? mailserver-fetching? network-type multiaccount]]
|
|
(let [wallet-offline? (and offline?
|
|
;; There's no wallet of desktop
|
|
(not platform/desktop?))
|
|
error-label (cond
|
|
(and wallet-offline?
|
|
disconnected?)
|
|
:t/offline
|
|
|
|
wallet-offline?
|
|
:t/wallet-offline
|
|
|
|
disconnected?
|
|
:t/disconnected
|
|
|
|
mailserver-connecting?
|
|
:t/connecting
|
|
|
|
mailserver-connection-error?
|
|
:t/mailserver-reconnect
|
|
|
|
mailserver-request-error?
|
|
:t/mailserver-request-error-status
|
|
|
|
(and (mobile-network-utils/cellular? network-type)
|
|
(not (:syncing-on-mobile-network? multiaccount)))
|
|
:mobile-network
|
|
|
|
:else nil)]
|
|
{:message (or error-label :t/connected)
|
|
:connected? (and (nil? error-label) (not= :mobile-network error-label))
|
|
:connecting? (= error-label :t/connecting)
|
|
:loading-indicator? mailserver-fetching?
|
|
:on-press-fn #(cond
|
|
mailserver-connection-error?
|
|
(re-frame/dispatch [:mailserver.ui/reconnect-mailserver-pressed])
|
|
mailserver-request-error?
|
|
(re-frame/dispatch [:mailserver.ui/request-error-pressed])
|
|
|
|
(= :mobile-network error-label)
|
|
(re-frame/dispatch [:mobile-network/show-offline-sheet]))})))
|
|
|
|
;;CONTACT ==============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
::query-current-chat-contacts
|
|
:<- [:chats/current-chat]
|
|
:<- [:contacts/contacts]
|
|
(fn [[chat contacts] [_ query-fn]]
|
|
(contact.db/query-chat-contacts chat contacts query-fn)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/contacts
|
|
:<- [::contacts]
|
|
(fn [contacts]
|
|
(contact.db/enrich-contacts contacts)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/active
|
|
:<- [:contacts/contacts]
|
|
(fn [contacts]
|
|
(contact.db/get-active-contacts contacts)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/active-count
|
|
:<- [:contacts/active]
|
|
(fn [active-contacts]
|
|
(count active-contacts)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/blocked
|
|
:<- [:contacts/contacts]
|
|
(fn [contacts]
|
|
(->> contacts
|
|
(filter (fn [[_ contact]]
|
|
(contact.db/blocked? contact)))
|
|
(contact.db/sort-contacts))))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/blocked-count
|
|
:<- [:contacts/blocked]
|
|
(fn [blocked-contacts]
|
|
(count blocked-contacts)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/current-contact
|
|
:<- [:contacts/contacts]
|
|
:<- [:contacts/current-contact-identity]
|
|
(fn [[contacts identity]]
|
|
(or (contacts identity)
|
|
(-> identity
|
|
contact.db/public-key->new-contact
|
|
contact.db/enrich-contact))))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/contact-name-by-identity
|
|
:<- [:contacts/contacts]
|
|
:<- [:multiaccount]
|
|
(fn [[contacts current-multiaccount] [_ identity]]
|
|
(let [me? (= (:public-key current-multiaccount) identity)]
|
|
(if me?
|
|
{:ens-name (:preferred-name current-multiaccount)
|
|
:alias (gfycat/generate-gfy identity)}
|
|
(let [contact (or (contacts identity)
|
|
(contact.db/public-key->new-contact identity))]
|
|
{:ens-name (when (:ens-verified contact)
|
|
(:name contact))
|
|
:alias (or (:alias contact)
|
|
(gfycat/generate-gfy identity))})))))
|
|
|
|
(re-frame/reg-sub
|
|
:messages/quote-info
|
|
:<- [:chats/messages]
|
|
:<- [:contacts/contacts]
|
|
:<- [:multiaccount]
|
|
(fn [[messages contacts current-multiaccount] [_ message-id]]
|
|
(when-let [message (get messages message-id)]
|
|
(let [identity (:from message)
|
|
me? (= (:public-key current-multiaccount) identity)]
|
|
(if me?
|
|
{:quote {:from identity
|
|
:text (get-in message [:content :text])}
|
|
:ens-name (:preferred-name current-multiaccount)
|
|
:alias (gfycat/generate-gfy identity)}
|
|
(let [contact (or (contacts identity)
|
|
(contact.db/public-key->new-contact identity))]
|
|
{:quote {:from identity
|
|
:text (get-in message [:content :text])}
|
|
:ens-name (when (:ens-verified contact)
|
|
(:name contact))
|
|
:alias (or (:alias contact)
|
|
(gfycat/generate-gfy identity))}))))))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/all-contacts-not-in-current-chat
|
|
:<- [::query-current-chat-contacts remove]
|
|
(fn [contacts]
|
|
(sort-by (comp clojure.string/lower-case :name) contacts)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/current-chat-contacts
|
|
:<- [:chats/current-chat]
|
|
:<- [:contacts/contacts]
|
|
:<- [:multiaccount]
|
|
(fn [[{:keys [contacts admins]} all-contacts current-multiaccount]]
|
|
(map #(assoc % :name (multiaccounts/displayed-name %))
|
|
(contact.db/get-all-contacts-in-group-chat contacts admins all-contacts current-multiaccount))))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/contacts-by-chat
|
|
(fn [[_ _ chat-id] _]
|
|
[(re-frame/subscribe [:chats/chat chat-id])
|
|
(re-frame/subscribe [:contacts/contacts])])
|
|
(fn [[chat all-contacts] [_ query-fn]]
|
|
(contact.db/query-chat-contacts chat all-contacts query-fn)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/chat-photo
|
|
(fn [[_ chat-id] _]
|
|
[(re-frame/subscribe [:chats/chat chat-id])
|
|
(re-frame/subscribe [:contacts/contacts-by-chat filter chat-id])])
|
|
(fn [[chat contacts] [_ chat-id]]
|
|
(when (and chat (not (:group-chat chat)))
|
|
(if (pos? (count contacts))
|
|
(multiaccounts/displayed-photo (first contacts))
|
|
(multiaccounts/displayed-photo chat)))))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/contact-by-address
|
|
:<- [:contacts/contacts]
|
|
(fn [contacts [_ address]]
|
|
(contact.db/find-contact-by-address contacts address)))
|
|
|
|
(re-frame/reg-sub
|
|
:contacts/contacts-by-address
|
|
:<- [:contacts/contacts]
|
|
(fn [contacts]
|
|
(reduce (fn [acc [_ {:keys [address] :as contact}]]
|
|
(if address
|
|
(assoc acc address contact)
|
|
acc))
|
|
{}
|
|
contacts)))
|
|
|
|
;;MAILSERVER ===========================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver/connecting?
|
|
:<- [:mailserver/state]
|
|
(fn [state]
|
|
(#{:connecting :added} state)))
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver/connection-error?
|
|
:<- [:mailserver/state]
|
|
(fn [state]
|
|
(#{:error :disconnected} state)))
|
|
|
|
(re-frame/reg-sub
|
|
:chats/fetching-gap-in-progress?
|
|
:<- [:chats/current-chat-id]
|
|
:<- [:mailserver/fetching-gaps-in-progress]
|
|
(fn [[chat-id gaps] [_ ids]]
|
|
(seq (select-keys (get gaps chat-id) ids))))
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver/fetching?
|
|
:<- [:mailserver/state]
|
|
:<- [:mailserver/pending-requests]
|
|
:<- [:mailserver/connecting?]
|
|
:<- [:mailserver/connection-error?]
|
|
:<- [:mailserver/request-error?]
|
|
(fn [[state pending-requests connecting? connection-error? request-error?]]
|
|
(and pending-requests
|
|
(= state :connected)
|
|
(pos-int? pending-requests)
|
|
(not (or connecting? connection-error? request-error?)))))
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver/fleet-mailservers
|
|
:<- [:fleets/current-fleet]
|
|
:<- [:mailserver/mailservers]
|
|
(fn [[current-fleet mailservers]]
|
|
(current-fleet mailservers)))
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver.edit/connected?
|
|
:<- [:mailserver.edit/mailserver]
|
|
:<- [:mailserver/current-id]
|
|
(fn [[mailserver current-mailserver-id]]
|
|
(= (get-in mailserver [:id :value])
|
|
current-mailserver-id)))
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver.edit/validation-errors
|
|
:<- [:mailserver.edit/mailserver]
|
|
(fn [mailserver]
|
|
(set (keep
|
|
(fn [[k {:keys [error]}]]
|
|
(when error k))
|
|
mailserver))))
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver/connected?
|
|
:<- [:mailserver/state]
|
|
:<- [:disconnected?]
|
|
(fn [[mail-state disconnected?]]
|
|
(let [mailserver-connected? (= :connected mail-state)]
|
|
(and mailserver-connected?
|
|
(not disconnected?)))))
|
|
|
|
(re-frame/reg-sub
|
|
:mailserver/preferred-id
|
|
:<- [:multiaccount]
|
|
(fn [multiaccount]
|
|
(get-in multiaccount
|
|
[:pinned-mailservers (fleet/current-fleet-sub multiaccount)])))
|
|
|
|
;;SEARCH ==============================================================================================================
|
|
|
|
(defn extract-chat-attributes [chat]
|
|
(let [{:keys [name random-name tags]} (val chat)]
|
|
(into [name random-name] tags)))
|
|
|
|
(defn apply-filter
|
|
"extract-attributes-fn is a function that take an element from the collection
|
|
and returns a vector of attributes which are strings
|
|
apply-filter returns the elements for which at least one attribute includes
|
|
the search-filter
|
|
apply-filter returns nil if the search-filter is empty or if there is no element
|
|
that match the filter"
|
|
[search-filter coll extract-attributes-fn]
|
|
(when (not-empty search-filter)
|
|
(let [search-filter (string/lower-case search-filter)
|
|
results (filter (fn [element]
|
|
(some (fn [s]
|
|
(when (string? s)
|
|
(string/includes? (string/lower-case s)
|
|
search-filter)))
|
|
(extract-attributes-fn element)))
|
|
coll)]
|
|
(when (not-empty results)
|
|
(sort-by #(-> % second :timestamp) >
|
|
(into {} results))))))
|
|
|
|
(re-frame/reg-sub
|
|
:search/filtered-chats
|
|
:<- [:chats/active-chats]
|
|
:<- [:search/filter]
|
|
(fn [[chats search-filter]]
|
|
(apply-filter search-filter chats extract-chat-attributes)))
|
|
|
|
;; TRIBUTE TO TALK
|
|
(re-frame/reg-sub
|
|
:tribute-to-talk/settings
|
|
:<- [:multiaccount]
|
|
:<- [:ethereum/chain-keyword]
|
|
(fn [[multiaccount chain-keyword]]
|
|
(get-in multiaccount [:tribute-to-talk]) chain-keyword))
|
|
|
|
(re-frame/reg-sub
|
|
:tribute-to-talk/screen-params
|
|
:<- [:screen-params]
|
|
(fn [screen-params]
|
|
(get screen-params :tribute-to-talk)))
|
|
|
|
(re-frame/reg-sub
|
|
:tribute-to-talk/profile
|
|
:<- [:tribute-to-talk/settings]
|
|
:<- [:tribute-to-talk/screen-params]
|
|
(fn [[{:keys [seen? snt-amount]}
|
|
{:keys [state unavailable?]}]]
|
|
(let [state (or state (if snt-amount :completed :disabled))
|
|
snt-amount (tribute-to-talk.db/from-wei snt-amount)]
|
|
(when config/tr-to-talk-enabled?
|
|
(if unavailable?
|
|
{:subtext "Change network to enable Tribute to Talk"
|
|
:active? false
|
|
:icon :main-icons/tribute-to-talk
|
|
:icon-color colors/gray}
|
|
(cond-> {:new? (not seen?)}
|
|
(and (not (and seen?
|
|
snt-amount
|
|
(#{:signing :pending :transaction-failed :completed} state))))
|
|
(assoc :subtext (i18n/label :t/tribute-to-talk-desc))
|
|
|
|
(#{:signing :pending} state)
|
|
(assoc :activity-indicator {:animating true
|
|
:color colors/blue}
|
|
:subtext (case state
|
|
:pending (i18n/label :t/pending-confirmation)
|
|
:signing (i18n/label :t/waiting-to-sign)))
|
|
|
|
(= state :transaction-failed)
|
|
(assoc :icon :main-icons/warning
|
|
:icon-color colors/red
|
|
:subtext (i18n/label :t/transaction-failed))
|
|
|
|
(not (#{:signing :pending :transaction-failed} state))
|
|
(assoc :icon :main-icons/tribute-to-talk)
|
|
|
|
(and (= state :completed)
|
|
(not-empty snt-amount))
|
|
(assoc :accessory-value (str snt-amount " SNT"))))))))
|
|
|
|
(re-frame/reg-sub
|
|
:tribute-to-talk/enabled?
|
|
:<- [:tribute-to-talk/settings]
|
|
(fn [settings]
|
|
(tribute-to-talk.db/enabled? settings)))
|
|
|
|
(re-frame/reg-sub
|
|
:tribute-to-talk/settings-ui
|
|
:<- [:tribute-to-talk/settings]
|
|
:<- [:tribute-to-talk/screen-params]
|
|
:<- [:prices]
|
|
:<- [:wallet/currency]
|
|
(fn [[{:keys [seen? snt-amount message]
|
|
:as settings}
|
|
{:keys [step editing? state error]
|
|
:or {step :intro}
|
|
screen-snt-amount :snt-amount
|
|
screen-message :message} prices currency]]
|
|
(let [fiat-value (if snt-amount
|
|
(money/fiat-amount-value
|
|
snt-amount
|
|
:SNT
|
|
(-> currency :code keyword)
|
|
prices)
|
|
"0")]
|
|
(cond-> {:seen? seen?
|
|
:snt-amount (tribute-to-talk.db/from-wei snt-amount)
|
|
:message message
|
|
:enabled? (tribute-to-talk.db/enabled? settings)
|
|
:error error
|
|
:step step
|
|
:state (or state (if snt-amount :completed :disabled))
|
|
:editing? editing?
|
|
:fiat-value (str fiat-value " " (:code currency))}
|
|
|
|
(= step :set-snt-amount)
|
|
(assoc :snt-amount (str screen-snt-amount)
|
|
:disable-button?
|
|
(boolean (and (= step :set-snt-amount)
|
|
(or (string/blank? screen-snt-amount)
|
|
(#{"0" "0.0" "0.00"} screen-snt-amount)
|
|
(string/ends-with? screen-snt-amount ".")))))))))
|
|
|
|
;;ENS ==================================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:ens.stateofus/registrar
|
|
:<- [:current-network]
|
|
(fn [network]
|
|
(let [chain (ethereum/network->chain-keyword network)]
|
|
(get stateofus/registrars chain))))
|
|
|
|
(re-frame/reg-sub
|
|
:multiaccount/usernames
|
|
:<- [:multiaccount]
|
|
(fn [multiaccount]
|
|
(:usernames multiaccount)))
|
|
|
|
(re-frame/reg-sub
|
|
:ens/preferred-name
|
|
:<- [:multiaccount]
|
|
(fn [multiaccount]
|
|
(:preferred-name multiaccount)))
|
|
|
|
(re-frame/reg-sub
|
|
:ens/search-screen
|
|
:<- [:ens/registration]
|
|
(fn [{:keys [custom-domain? username state]}]
|
|
{:state state
|
|
:username username
|
|
:custom-domain? custom-domain?}))
|
|
|
|
(defn- ens-amount-label
|
|
[chain-id]
|
|
(str (ens/registration-cost chain-id)
|
|
(case chain-id
|
|
3 " STT"
|
|
1 " SNT"
|
|
"")))
|
|
|
|
(re-frame/reg-sub
|
|
:ens/checkout-screen
|
|
:<- [:ens/registration]
|
|
:<- [:ens.stateofus/registrar]
|
|
:<- [:multiaccount/default-account]
|
|
:<- [:multiaccount/public-key]
|
|
:<- [:chain-id]
|
|
(fn [[{:keys [custom-domain? username]}
|
|
registrar default-account public-key chain-id]]
|
|
{:address (ethereum/normalized-hex (:address default-account))
|
|
:username username
|
|
:public-key public-key
|
|
:custom-domain? custom-domain?
|
|
:contract registrar
|
|
:amount-label (ens-amount-label chain-id)}))
|
|
|
|
(re-frame/reg-sub
|
|
:ens/confirmation-screen
|
|
:<- [:ens/registration]
|
|
(fn [{:keys [username state] :as ens}]
|
|
{:state state
|
|
:username username}))
|
|
|
|
(re-frame/reg-sub
|
|
:ens.name/screen
|
|
:<- [:get-screen-params :ens-name-details]
|
|
:<- [:ens/names]
|
|
(fn [[name ens]]
|
|
(let [{:keys [address public-key]} (get ens name)
|
|
pending? (nil? address)]
|
|
(cond-> {:name name
|
|
:custom-domain? (not (string/ends-with? name ".stateofus.eth"))}
|
|
pending?
|
|
(assoc :pending? true)
|
|
(not pending?)
|
|
(assoc :address address
|
|
:public-key public-key)))))
|
|
|
|
(re-frame/reg-sub
|
|
:ens.main/screen
|
|
:<- [:multiaccount/usernames]
|
|
:<- [:multiaccount]
|
|
:<- [:ens/preferred-name]
|
|
(fn [[names multiaccount preferred-name]]
|
|
{:names names
|
|
:multiaccount multiaccount
|
|
:preferred-name preferred-name}))
|
|
|
|
;;SIGNING =============================================================================================================
|
|
|
|
(re-frame/reg-sub
|
|
:signing/fee
|
|
:<- [:signing/tx]
|
|
(fn [{:keys [gas gasPrice]}]
|
|
(signing.gas/calculate-max-fee gas gasPrice)))
|
|
|
|
(re-frame/reg-sub
|
|
:signing/phrase
|
|
:<- [:multiaccount]
|
|
(fn [{:keys [signing-phrase]}]
|
|
signing-phrase))
|
|
|
|
(defn- too-precise-amount?
|
|
"Checks if number has any extra digit beyond the allowed number of decimals.
|
|
It does so by checking the number against its rounded value."
|
|
[amount decimals]
|
|
(let [bn (money/bignumber amount)]
|
|
(not (.eq bn (.round bn decimals)))))
|
|
|
|
(defn get-amount-error [amount decimals]
|
|
(when (and (not (empty? amount)) decimals)
|
|
(let [normalized-amount (money/normalize amount)
|
|
value (money/bignumber normalized-amount)]
|
|
(cond
|
|
(not (money/valid? value))
|
|
{:amount-error (i18n/label :t/validation-amount-invalid-number)}
|
|
|
|
(too-precise-amount? normalized-amount decimals)
|
|
{:amount-error (i18n/label :t/validation-amount-is-too-precise {:decimals decimals})}
|
|
|
|
:else nil))))
|
|
|
|
(defn get-sufficient-funds-error
|
|
[balance symbol amount]
|
|
(when-not (money/sufficient-funds? amount (get balance symbol))
|
|
{:amount-error (i18n/label :t/wallet-insufficient-funds)}))
|
|
|
|
(defn get-sufficient-gas-error
|
|
[balance symbol amount gas gasPrice]
|
|
(if (and gas gasPrice)
|
|
(let [fee (.times gas gasPrice)
|
|
available-ether (money/bignumber (get balance :ETH 0))
|
|
available-for-gas (if (= :ETH symbol)
|
|
(.minus available-ether (money/bignumber amount))
|
|
available-ether)]
|
|
(when-not (money/sufficient-funds? fee (money/bignumber available-for-gas))
|
|
{:gas-error (i18n/label :t/wallet-insufficient-gas)}))
|
|
{:gas-error (i18n/label :t/invalid-number)}))
|
|
|
|
(re-frame/reg-sub
|
|
:signing/amount-errors
|
|
(fn [[_ address] _]
|
|
[(re-frame/subscribe [:signing/tx])
|
|
(re-frame/subscribe [:balance address])])
|
|
(fn [[{:keys [amount token gas gasPrice approve?]} balance]]
|
|
(if (and amount token (not approve?))
|
|
(let [amount-bn (money/formatted->internal (money/bignumber amount) (:symbol token) (:decimals token))
|
|
amount-error (or (get-amount-error amount (:decimals token))
|
|
(get-sufficient-funds-error balance (:symbol token) amount-bn))]
|
|
(or amount-error (get-sufficient-gas-error balance (:symbol token) amount-bn gas gasPrice)))
|
|
(get-sufficient-gas-error balance nil nil gas gasPrice))))
|
|
|
|
(re-frame/reg-sub
|
|
:wallet.send/prepare-transaction-with-balance
|
|
:<- [:wallet/prepare-transaction]
|
|
:<- [:wallet]
|
|
:<- [:offline?]
|
|
:<- [:wallet/all-tokens]
|
|
:<- [:ethereum/chain-keyword]
|
|
(fn [[{:keys [symbol from to amount-text] :as transaction}
|
|
wallet offline? all-tokens chain]]
|
|
(let [balance (get-in wallet [:accounts (:address from) :balance])
|
|
{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)
|
|
{:keys [value error]} (wallet.db/parse-amount amount-text decimals)
|
|
amount (money/formatted->internal value symbol decimals)
|
|
{:keys [amount-error] :as transaction-new}
|
|
(merge transaction
|
|
{:amount-error error}
|
|
(when amount
|
|
(get-sufficient-funds-error balance symbol amount)))]
|
|
(assoc transaction-new
|
|
:amount amount
|
|
:balance balance
|
|
:token (assoc token :amount (get balance (:symbol token)))
|
|
:sign-enabled? (and to
|
|
(nil? amount-error)
|
|
(not (nil? amount))
|
|
(not offline?))))))
|
|
|
|
;; NETWORK SETTINGS
|
|
|
|
(defn- filter-networks [network-type]
|
|
(fn [network]
|
|
(let [chain-id (ethereum/network->chain-id network)
|
|
testnet? (ethereum/testnet? chain-id)
|
|
custom? (:custom? network)]
|
|
(case network-type
|
|
:custom custom?
|
|
:mainnet (and (not custom?) (not testnet?))
|
|
:testnet (and (not custom?) testnet?)))))
|
|
|
|
(defn- label-networks [default-networks]
|
|
(fn [network]
|
|
(let [custom? (not (default-networks (:id network)))]
|
|
(assoc network :custom? custom?))))
|
|
|
|
(re-frame/reg-sub
|
|
:get-networks
|
|
:<- [:networks/networks]
|
|
(fn [networks]
|
|
(let [networks (map (label-networks (into #{} (map :id constants/default-networks))) (sort-by :name (vals networks)))
|
|
types [:mainnet :testnet :custom]]
|
|
(zipmap
|
|
types
|
|
(map #(filter (filter-networks %) networks) types)))))
|
|
|
|
(re-frame/reg-sub
|
|
:manage-network-valid?
|
|
:<- [:networks/manage]
|
|
(fn [manage]
|
|
(not-any? :error (vals manage))))
|