2019-04-26 12:09:58 +02:00
(ns status-im.subs
2019-05-09 01:33:19 +02:00
(:require [cljs.spec.alpha :as spec]
2019-04-26 12:09:58 +02:00
[clojure.string :as string]
2019-09-03 17:19:23 +03:00
[taoensso.timbre :as log]
2019-05-09 01:33:19 +02:00
[re-frame.core :as re-frame]
2019-04-26 12:09:58 +02:00
[status-im.browser.core :as browser]
2019-05-09 01:33:19 +02:00
[status-im.chat.constants :as chat.constants]
[status-im.chat.db :as chat.db]
2019-02-22 14:26:40 +02:00
[status-im.chat.models :as chat.models]
2019-11-06 13:45:45 +01:00
[status-im.chat.models.message-list :as models.message-list]
2019-04-26 12:09:58 +02:00
[status-im.constants :as constants]
2019-05-09 01:33:19 +02:00
[status-im.contact.db :as contact.db]
2019-06-03 09:42:29 +02:00
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.stateofus :as stateofus]
2019-05-22 17:00:34 +02:00
[status-im.ethereum.tokens :as tokens]
2019-05-09 21:51:41 +02:00
[status-im.ethereum.transactions.core :as transactions]
2019-05-09 01:33:19 +02:00
[status-im.fleet.core :as fleet]
2019-02-22 14:26:40 +02:00
[status-im.group-chats.db :as group-chats.db]
2019-05-09 01:33:19 +02:00
[status-im.i18n :as i18n]
2019-07-03 16:29:01 +02:00
[status-im.multiaccounts.model :as multiaccounts.model]
2019-09-12 11:41:25 +02:00
[status-im.multiaccounts.core :as multiaccounts]
2019-07-03 16:29:01 +02:00
[status-im.multiaccounts.db :as multiaccounts.db]
2019-11-20 16:41:21 +02:00
[status-im.multiaccounts.recover.core :as recover]
2019-07-03 16:29:01 +02:00
[status-im.pairing.core :as pairing]
2019-02-22 14:26:40 +02:00
[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]
2019-09-02 08:43:18 +02:00
[status-im.ui.components.tabbar.styles :as tabs.styles]
2019-02-22 14:26:40 +02:00
[status-im.ui.components.colors :as colors]
2019-05-09 01:33:19 +02:00
[status-im.ui.components.toolbar.styles :as toolbar.styles]
2019-04-26 12:09:58 +02:00
[status-im.ui.screens.add-new.new-public-chat.db :as db]
2019-05-09 01:33:19 +02:00
[status-im.ui.screens.chat.stickers.styles :as stickers.styles]
[status-im.ui.screens.mobile-network-settings.utils
:as
mobile-network-utils]
2019-06-17 11:41:37 +02:00
[status-im.wallet.utils :as wallet.utils]
2019-05-09 01:33:19 +02:00
[status-im.utils.build :as build]
2019-04-26 12:09:58 +02:00
[status-im.utils.config :as config]
2019-05-09 01:33:19 +02:00
[status-im.utils.datetime :as datetime]
2019-06-03 09:42:29 +02:00
[status-im.utils.hex :as utils.hex]
2019-05-09 01:33:19 +02:00
[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]
2019-05-18 13:06:42 +02:00
[status-im.wallet.core :as wallet]
[status-im.wallet.db :as wallet.db]
2019-06-05 13:11:47 +02:00
[status-im.signing.gas :as signing.gas]
2019-09-30 13:33:45 +02:00
[status-im.utils.gfycat.core :as gfycat]
2019-05-09 01:33:19 +02:00
status-im.ui.screens.hardwallet.connect.subs
status-im.ui.screens.hardwallet.settings.subs
status-im.ui.screens.hardwallet.pin.subs
2019-09-02 10:40:13 +02:00
status-im.ui.screens.hardwallet.setup.subs
[status-im.ens.core :as ens]))
2019-04-26 12:09:58 +02:00
;; TOP LEVEL ===========================================================================================================
2019-05-01 14:52:59 +02:00
(defn reg-root-key-sub [sub-name db-key]
(re-frame/reg-sub sub-name (fn [db] (get db db-key))))
2019-04-26 12:09:58 +02:00
;;view
2019-05-01 14:52:59 +02:00
(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)
2019-07-05 12:05:36 +03:00
(reg-root-key-sub :two-pane-ui-enabled? :two-pane-ui-enabled?)
2019-04-26 12:09:58 +02:00
;;bottom sheet
2019-05-01 14:52:59 +02:00
(reg-root-key-sub :bottom-sheet/show? :bottom-sheet/show?)
(reg-root-key-sub :bottom-sheet/view :bottom-sheet/view)
2019-05-15 02:24:40 +05:45
(reg-root-key-sub :bottom-sheet/options :bottom-sheet/options)
2019-04-26 12:09:58 +02:00
;;general
2019-05-01 14:52:59 +02:00
(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 :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)
2020-01-08 15:25:39 +03:00
(reg-root-key-sub :keyboard-max-height :keyboard-max-height)
2019-05-01 14:52:59 +02:00
(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)
2019-08-23 16:11:23 +02:00
(reg-root-key-sub :networks/current-network :networks/current-network)
2019-05-01 14:52:59 +02:00
(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)
2019-05-30 16:01:20 +02:00
(reg-root-key-sub :supported-biometric-auth :supported-biometric-auth)
2020-01-14 20:24:21 +01:00
(reg-root-key-sub :app-active-since :app-active-since)
(reg-root-key-sub :connectivity/ui-status-properties :connectivity/ui-status-properties)
2019-04-26 12:09:58 +02:00
2019-08-23 16:11:23 +02:00
;;NOTE this one is not related to ethereum network
;; it is about cellular network/ wifi network
(reg-root-key-sub :network/type :network/type)
2019-04-26 12:09:58 +02:00
;;profile
2019-05-01 14:52:59 +02:00
(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)
2019-10-22 20:36:25 -04:00
(reg-root-key-sub :profile/photo-added? :profile/photo-added?)
2019-07-03 16:29:01 +02:00
;;multiaccount
(reg-root-key-sub :multiaccounts/multiaccounts :multiaccounts/multiaccounts)
(reg-root-key-sub :multiaccounts/login :multiaccounts/login)
(reg-root-key-sub :multiaccount :multiaccount)
2019-12-16 12:18:40 +01:00
(reg-root-key-sub :multiaccount/accounts :multiaccount/accounts)
2019-07-03 16:29:01 +02:00
(reg-root-key-sub :get-recover-multiaccount :multiaccounts/recover)
2019-04-26 12:09:58 +02:00
;;chat
2019-05-01 14:52:59 +02:00
(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)
2019-04-26 12:09:58 +02:00
;;browser
2019-05-01 14:52:59 +02:00
(reg-root-key-sub :browsers :browser/browsers)
(reg-root-key-sub :browser/options :browser/options)
(reg-root-key-sub :dapps/permissions :dapps/permissions)
2019-04-26 12:09:58 +02:00
;;stickers
2019-05-01 14:52:59 +02:00
(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)
2019-05-20 02:21:38 +02:00
(reg-root-key-sub :stickers/packs-pending :stickers/packs-pending)
2019-04-26 12:09:58 +02:00
;;mailserver
2019-05-01 14:52:59 +02:00
(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)
2019-04-26 12:09:58 +02:00
;;contacts
2019-05-01 14:52:59 +02:00
(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)
2019-04-26 12:09:58 +02:00
;;wallet
2019-05-01 14:52:59 +02:00
(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)
2019-05-20 10:02:56 +02:00
(reg-root-key-sub :wallet/custom-token-screen :wallet/custom-token-screen)
2019-11-16 10:56:09 +01:00
(reg-root-key-sub :wallet/prepare-transaction :wallet/prepare-transaction)
2019-04-26 12:09:58 +02:00
2019-11-25 14:33:43 +01:00
;;commands
(reg-root-key-sub :commands/select-account :commands/select-account)
2019-05-09 01:33:19 +02:00
;;ethereum
(reg-root-key-sub :ethereum/current-block :ethereum/current-block)
2019-06-03 09:42:29 +02:00
;;ens
(reg-root-key-sub :ens/registration :ens/registration)
(reg-root-key-sub :ens/names :ens/names)
2019-06-05 13:11:47 +02:00
;;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)
2019-05-13 10:58:41 +03:00
;;intro-wizard
2019-09-03 17:19:23 +03:00
(reg-root-key-sub :intro-wizard-state :intro-wizard)
2019-05-13 10:58:41 +03:00
2019-07-08 13:38:47 +02:00
(reg-root-key-sub :popover/popover :popover/popover)
2019-11-18 10:29:30 +01:00
(reg-root-key-sub :add-account :add-account)
2019-07-08 13:38:47 +02:00
2019-08-15 17:44:25 +03:00
(reg-root-key-sub :keycard :hardwallet)
2019-09-15 17:20:10 +02:00
(reg-root-key-sub :auth-method :auth-method)
2019-04-26 12:09:58 +02:00
;;GENERAL ==============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:connection-stats
:<- [:desktop/desktop]
(fn [desktop _]
(get desktop :debug-metrics)))
2019-09-03 17:19:23 +03:00
;; 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])
2019-11-28 12:00:29 +02:00
:name (get-in wizard-state [:derived constants/path-whisper-keyword :name])
:photo-path (get-in wizard-state [:derived constants/path-whisper-keyword :photo-path])
2019-09-03 17:19:23 +03:00
:processing? (:processing? wizard-state)}))
2019-11-20 16:41:21 +02:00
(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)))
2019-12-10 12:31:22 +01:00
;;FIXME not needed until desktop enabled
#_(re-frame/reg-sub
:settings/logging-enabled
:<- [:desktop/desktop]
(fn [desktop _]
(get desktop :logging-enabled false)))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-08-23 16:11:23 +02:00
: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)))
2019-08-01 22:11:59 +02:00
(re-frame/reg-sub
:network-name
2019-08-23 16:11:23 +02:00
:<- [:current-network]
2019-08-01 22:11:59 +02:00
(fn [network]
2019-08-23 16:11:23 +02:00
(:name network)))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:disconnected?
:<- [:peers-count]
(fn [peers-count]
(zero? peers-count)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:offline?
:<- [:network-status]
:<- [:sync-state]
:<- [:disconnected?]
(fn [[network-status sync-state disconnected?]]
(or disconnected?
(= network-status :offline)
(= sync-state :offline))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:syncing?
:<- [:sync-state]
(fn [sync-state]
(#{:pending :in-progress} sync-state)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:dimensions/window-width
:<- [:dimensions/window]
:width)
2019-07-03 21:38:10 +03:00
(re-frame/reg-sub
:dimensions/window-height
:<- [:dimensions/window]
:height)
2019-09-26 19:49:26 +03:00
(re-frame/reg-sub
:dimensions/small-screen?
:<- [:dimensions/window-height]
(fn [height]
(< height 550)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:get-screen-params
:<- [:screen-params]
:<- [:view-id]
(fn [[params view-id-db] [_ view-id]]
(get params (or view-id view-id-db))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:can-navigate-back?
:<- [:navigation-stack]
(fn [stack]
(> (count stack) 1)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:delete-swipe-position
:<- [:animations]
(fn [animations [_ type item-id]]
(get-in animations [type item-id :delete-swiped])))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:search/filter
:<- [:ui/search]
(fn [search]
(get search :filter)))
(defn- node-version [web3-node-version]
2019-09-03 09:56:58 +02:00
(or web3-node-version "N/A"))
2019-04-26 12:09:58 +02:00
(def app-short-version
(let [version (if platform/desktop? build/version build/build-no)]
(str build/version " (" version ")")))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:get-app-version
:<- [:web3-node-version]
(fn [web3-node-version]
(str app-short-version "; " (node-version web3-node-version))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:get-app-short-version
(fn [db] app-short-version))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:get-app-node-version
:<- [:web3-node-version]
node-version)
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:my-profile/recovery
:<- [:my-profile/seed]
(fn [seed]
(or seed {:step :intro})))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:bottom-sheet
:<- [:bottom-sheet/show?]
:<- [:bottom-sheet/view]
(fn [[show? view]]
{:show? show?
:view view}))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:is-contact-selected?
:<- [:group/selected-contacts]
(fn [selected-contacts [_ element]]
(-> selected-contacts
(contains? element))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:is-participant-selected?
:<- [:selected-participants]
(fn [selected-participants [_ element]]
(-> selected-participants
(contains? element))))
2019-05-16 23:50:03 +02:00
(re-frame/reg-sub
:ethereum/chain-keyword
2019-08-23 16:11:23 +02:00
:<- [:current-network]
2019-05-16 23:50:03 +02:00
(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)))
2019-07-03 16:29:01 +02:00
;;MULTIACCOUNT ==============================================================================================================
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-07-03 16:29:01 +02:00
:multiaccount/public-key
:<- [:multiaccount]
2019-04-26 12:09:58 +02:00
(fn [{:keys [public-key]}]
public-key))
2019-09-02 10:40:13 +02:00
(re-frame/reg-sub
2019-12-12 16:18:04 +01:00
:multiaccount/default-account
2019-12-16 12:18:40 +01:00
:<- [:multiaccount/accounts]
(fn [accounts]
2019-12-12 16:18:04 +01:00
(ethereum/get-default-account accounts)))
2019-09-02 10:40:13 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:sign-in-enabled?
2019-07-03 16:29:01 +02:00
:<- [:multiaccounts/login]
2019-08-23 11:17:54 +02:00
(fn [{:keys [password]}]
(spec/valid? ::multiaccounts.db/password
(security/safe-unmask-data password))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-12-10 12:31:22 +01:00
:fleets/current-fleet
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2019-12-10 12:31:22 +01:00
(fn [multiaccount]
(fleet/current-fleet-sub multiaccount)))
2019-04-26 12:09:58 +02:00
2019-12-16 12:18:40 +01:00
(re-frame/reg-sub
2019-12-10 12:31:22 +01:00
:log-level/current-log-level
2019-12-16 12:18:40 +01:00
:<- [:multiaccount]
2019-12-10 12:31:22 +01:00
(fn [multiaccount]
(or (get multiaccount :log-level)
2019-04-26 12:09:58 +02:00
config/log-level-status-go)))
2019-10-04 13:52:33 +02:00
(re-frame/reg-sub
:dapps-address
:<- [:multiaccount]
(fn [acc]
(get acc :dapps-address)))
(re-frame/reg-sub
:dapps-account
2019-12-16 12:18:40 +01:00
:<- [:multiaccount/accounts]
2019-10-04 13:52:33 +02:00
:<- [:dapps-address]
2019-12-16 12:18:40 +01:00
(fn [[accounts address]]
(some #(when (= (:address %) address) %) accounts)))
2019-10-04 13:52:33 +02:00
2019-10-10 13:39:18 +02:00
(re-frame/reg-sub
2019-12-16 12:18:40 +01:00
:multiaccount/current-account
:<- [:multiaccount/accounts]
2019-10-10 13:39:18 +02:00
:<- [:get-screen-params :wallet-account]
2019-12-16 12:18:40 +01:00
(fn [[accounts acc]]
(some #(when (= (:address %) (:address acc)) %) accounts)))
2019-10-10 13:39:18 +02:00
2019-11-16 10:56:09 +01:00
(re-frame/reg-sub
:account-by-address
2019-12-16 12:18:40 +01:00
:<- [:multiaccount/accounts]
(fn [accounts [_ address]]
(some #(when (= (:address %) address) %) accounts)))
2019-11-16 10:56:09 +01:00
2019-11-07 10:53:46 +02:00
(re-frame/reg-sub
:multiple-multiaccounts?
:<- [:multiaccounts/multiaccounts]
(fn [multiaccounts]
(> (count multiaccounts) 1)))
2019-12-10 12:07:38 +02:00
(re-frame/reg-sub
:multiaccounts.login/keycard-account?
:<- [:multiaccounts/multiaccounts]
:<- [:multiaccounts/login]
(fn [[multiaccounts {:keys [key-uid]}]]
(get-in multiaccounts [key-uid :keycard-pairing])))
2019-11-18 10:29:30 +01:00
(re-frame/reg-sub
:accounts-without-watch-only
2019-12-16 12:18:40 +01:00
:<- [:multiaccount/accounts]
(fn [accounts]
(filter #(not= (:type %) :watch) accounts)))
2019-11-18 10:29:30 +01:00
2019-12-27 12:38:42 +01:00
(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))))
2019-04-26 12:09:58 +02:00
;;CHAT ==============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:get-collectible-token
:<- [:collectibles]
(fn [collectibles [_ {:keys [symbol token]}]]
(get-in collectibles [(keyword symbol) (js/parseInt token)])))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/chat
:<- [:chats/active-chats]
(fn [chats [_ chat-id]]
(get chats chat-id)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/content-layout-height
:<- [:content-layout-height]
:<- [:chats/current-chat-ui-prop :input-height]
:<- [:chats/current-chat-ui-prop :input-focused?]
:<- [:keyboard-height]
2019-11-16 10:56:09 +01:00
:<- [:chats/current-chat-ui-prop :input-bottom-sheet]
2019-04-26 12:09:58 +02:00
(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)))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/current-chat-ui-props
:<- [::chat-ui-props]
:<- [:chats/current-chat-id]
(fn [[chat-ui-props id]]
(get chat-ui-props id)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/current-chat-ui-prop
:<- [:chats/current-chat-ui-props]
(fn [ui-props [_ prop]]
(get ui-props prop)))
2020-01-08 15:25:39 +03:00
;; NOTE: The whole logic of stickers panel and input should be revised
(re-frame/reg-sub
:chats/chat-panel-height
:<- [:keyboard-max-height]
(fn [kb-height]
(cond
(and platform/iphone-x? (pos? kb-height))
(- kb-height tabs.styles/minimized-tabs-height 34)
(pos? kb-height)
(- kb-height tabs.styles/minimized-tabs-height)
platform/iphone-x? 299
platform/ios? 258
:else 272)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/input-margin
:<- [:keyboard-height]
2020-01-08 15:25:39 +03:00
:<- [:chats/current-chat-ui-prop :input-bottom-sheet]
(fn [[kb-height input-bottom-sheet]]
2019-04-26 12:09:58 +02:00
(cond
2020-01-08 15:25:39 +03:00
;; During the transition of bottom sheet and close of keyboard happens
;; The heights are summed up and input grows too much
(not (nil? input-bottom-sheet))
0
2019-04-26 12:09:58 +02:00
(and platform/iphone-x? (> kb-height 0))
2020-01-08 15:25:39 +03:00
(- kb-height tabs.styles/minimized-tabs-height 34)
2019-04-26 12:09:58 +02:00
platform/ios?
(+ kb-height (- (if (> kb-height 0)
tabs.styles/minimized-tabs-height
0)))
:default 0)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/active-chats
:<- [:contacts/contacts]
:<- [::chats]
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
(fn [[contacts chats multiaccount]]
(chat.db/active-chats contacts chats multiaccount)))
2019-04-26 12:09:58 +02:00
2019-11-25 14:33:43 +01:00
;; TODO: this is no useful without tribute to talk
#_(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))))
2019-02-22 14:26:40 +02:00
(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))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
Render markdown
Fixes: https://github.com/status-im/trailofbits-audit/issues/47
Fixes: https://github.com/status-im/trailofbits-audit/issues/46
Fixes: https://github.com/status-im/trailofbits-audit/issues/44
Fixes: https://github.com/status-im/security-reports/issues/13
Fixes: https://github.com/status-im/security-reports/issues/5
Fixes: https://github.com/status-im/status-react/issues/8995
This commits re-introduce rendering of markdown text and implent a few
changes:
1) Parsing of the message content is now in status-go, this includes
markdown, line-count, and rtl. Parsing is not nested, as there's some
rendering degradation involved as we nest components, unclear exactly if
it's react-native or clojure, haven't looked too deeply into it.
2) Emojii type messages are not parsed on the sending side, not the
receiving one, using the appropriate content-type
3) Fixes a few issues with chat input rendering, currrently we use
`chats/current-chat` subscription which is very heavy and should not be
used unless necessary, and means that
any change to chat will trigger a re-render, which caused re-rendering
of input container on each received message. Also to note that
input-container is fairly heavy to render, and it's rendered twice at
each keypress on input.
The inline markdow supported is:
*italic* or _italic_
**bold** or __bold__
`inline code`
http://test.com links
\#status-tag
The block markdown supported is:
\# Headers
```
code blocks
```
> Quotereply
The styling is very basic at the moment, but can be improved.
Adding other markdown (photo,mentions) is straightforward and should
come at little performance cost (unless the component to render is
heavy, i.e a photo for example).
There are some behavioral changes with this commit:
1) Links are only parsed if starting with http:// or https://, meaning that
blah.com won't be parsed, nor www.test.com. This behavior is consistent
with discord for example and allows faster parsing at little expense to
ser experience imo. Fixes a few security issues as well.
2) Content is not anymore capped (regression), that's due to the fact that
before we only rendered text and react-native allowed us easily to limit
the number of lines, but adding markdown support means that this
strategy is not viable anymore. Performance of rendering don't see to be
very much impacted by this, I would re-introduce it if necessary, but
I'd rather do that in a separate PR.
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-11-07 14:41:37 +01:00
:chats/current-raw-chat
2019-04-26 12:09:58 +02:00
:<- [:chats/active-chats]
:<- [:chats/current-chat-id]
Render markdown
Fixes: https://github.com/status-im/trailofbits-audit/issues/47
Fixes: https://github.com/status-im/trailofbits-audit/issues/46
Fixes: https://github.com/status-im/trailofbits-audit/issues/44
Fixes: https://github.com/status-im/security-reports/issues/13
Fixes: https://github.com/status-im/security-reports/issues/5
Fixes: https://github.com/status-im/status-react/issues/8995
This commits re-introduce rendering of markdown text and implent a few
changes:
1) Parsing of the message content is now in status-go, this includes
markdown, line-count, and rtl. Parsing is not nested, as there's some
rendering degradation involved as we nest components, unclear exactly if
it's react-native or clojure, haven't looked too deeply into it.
2) Emojii type messages are not parsed on the sending side, not the
receiving one, using the appropriate content-type
3) Fixes a few issues with chat input rendering, currrently we use
`chats/current-chat` subscription which is very heavy and should not be
used unless necessary, and means that
any change to chat will trigger a re-render, which caused re-rendering
of input container on each received message. Also to note that
input-container is fairly heavy to render, and it's rendered twice at
each keypress on input.
The inline markdow supported is:
*italic* or _italic_
**bold** or __bold__
`inline code`
http://test.com links
\#status-tag
The block markdown supported is:
\# Headers
```
code blocks
```
> Quotereply
The styling is very basic at the moment, but can be improved.
Adding other markdown (photo,mentions) is straightforward and should
come at little performance cost (unless the component to render is
heavy, i.e a photo for example).
There are some behavioral changes with this commit:
1) Links are only parsed if starting with http:// or https://, meaning that
blah.com won't be parsed, nor www.test.com. This behavior is consistent
with discord for example and allows faster parsing at little expense to
ser experience imo. Fixes a few security issues as well.
2) Content is not anymore capped (regression), that's due to the fact that
before we only rendered text and react-native allowed us easily to limit
the number of lines, but adding markdown support means that this
strategy is not viable anymore. Performance of rendering don't see to be
very much impacted by this, I would re-introduce it if necessary, but
I'd rather do that in a separate PR.
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-11-07 14:41:37 +01:00
(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]
2019-07-03 16:29:01 +02:00
:<- [:multiaccount/public-key]
2019-02-22 14:26:40 +02:00
:<- [:mailserver/ranges]
:<- [:chats/content-layout-height]
:<- [:chats/current-chat-ui-prop :input-height]
2019-11-25 14:33:43 +01:00
(fn [[{:keys [group-chat chat-id contact messages] :as current-chat}
my-public-key ranges height input-height]]
Render markdown
Fixes: https://github.com/status-im/trailofbits-audit/issues/47
Fixes: https://github.com/status-im/trailofbits-audit/issues/46
Fixes: https://github.com/status-im/trailofbits-audit/issues/44
Fixes: https://github.com/status-im/security-reports/issues/13
Fixes: https://github.com/status-im/security-reports/issues/5
Fixes: https://github.com/status-im/status-react/issues/8995
This commits re-introduce rendering of markdown text and implent a few
changes:
1) Parsing of the message content is now in status-go, this includes
markdown, line-count, and rtl. Parsing is not nested, as there's some
rendering degradation involved as we nest components, unclear exactly if
it's react-native or clojure, haven't looked too deeply into it.
2) Emojii type messages are not parsed on the sending side, not the
receiving one, using the appropriate content-type
3) Fixes a few issues with chat input rendering, currrently we use
`chats/current-chat` subscription which is very heavy and should not be
used unless necessary, and means that
any change to chat will trigger a re-render, which caused re-rendering
of input container on each received message. Also to note that
input-container is fairly heavy to render, and it's rendered twice at
each keypress on input.
The inline markdow supported is:
*italic* or _italic_
**bold** or __bold__
`inline code`
http://test.com links
\#status-tag
The block markdown supported is:
\# Headers
```
code blocks
```
> Quotereply
The styling is very basic at the moment, but can be improved.
Adding other markdown (photo,mentions) is straightforward and should
come at little performance cost (unless the component to render is
heavy, i.e a photo for example).
There are some behavioral changes with this commit:
1) Links are only parsed if starting with http:// or https://, meaning that
blah.com won't be parsed, nor www.test.com. This behavior is consistent
with discord for example and allows faster parsing at little expense to
ser experience imo. Fixes a few security issues as well.
2) Content is not anymore capped (regression), that's due to the fact that
before we only rendered text and react-native allowed us easily to limit
the number of lines, but adding markdown support means that this
strategy is not viable anymore. Performance of rendering don't see to be
very much impacted by this, I would re-introduce it if necessary, but
I'd rather do that in a separate PR.
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-11-07 14:41:37 +01:00
(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))
2019-02-22 14:26:40 +02:00
Render markdown
Fixes: https://github.com/status-im/trailofbits-audit/issues/47
Fixes: https://github.com/status-im/trailofbits-audit/issues/46
Fixes: https://github.com/status-im/trailofbits-audit/issues/44
Fixes: https://github.com/status-im/security-reports/issues/13
Fixes: https://github.com/status-im/security-reports/issues/5
Fixes: https://github.com/status-im/status-react/issues/8995
This commits re-introduce rendering of markdown text and implent a few
changes:
1) Parsing of the message content is now in status-go, this includes
markdown, line-count, and rtl. Parsing is not nested, as there's some
rendering degradation involved as we nest components, unclear exactly if
it's react-native or clojure, haven't looked too deeply into it.
2) Emojii type messages are not parsed on the sending side, not the
receiving one, using the appropriate content-type
3) Fixes a few issues with chat input rendering, currrently we use
`chats/current-chat` subscription which is very heavy and should not be
used unless necessary, and means that
any change to chat will trigger a re-render, which caused re-rendering
of input container on each received message. Also to note that
input-container is fairly heavy to render, and it's rendered twice at
each keypress on input.
The inline markdow supported is:
*italic* or _italic_
**bold** or __bold__
`inline code`
http://test.com links
\#status-tag
The block markdown supported is:
\# Headers
```
code blocks
```
> Quotereply
The styling is very basic at the moment, but can be improved.
Adding other markdown (photo,mentions) is straightforward and should
come at little performance cost (unless the component to render is
heavy, i.e a photo for example).
There are some behavioral changes with this commit:
1) Links are only parsed if starting with http:// or https://, meaning that
blah.com won't be parsed, nor www.test.com. This behavior is consistent
with discord for example and allows faster parsing at little expense to
ser experience imo. Fixes a few security issues as well.
2) Content is not anymore capped (regression), that's due to the fact that
before we only rendered text and react-native allowed us easily to limit
the number of lines, but adding markdown support means that this
strategy is not viable anymore. Performance of rendering don't see to be
very much impacted by this, I would re-introduce it if necessary, but
I'd rather do that in a separate PR.
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-11-07 14:41:37 +01:00
(chat.models/public-chat? current-chat)
(assoc :show-input? true)
2019-02-22 14:26:40 +02:00
Render markdown
Fixes: https://github.com/status-im/trailofbits-audit/issues/47
Fixes: https://github.com/status-im/trailofbits-audit/issues/46
Fixes: https://github.com/status-im/trailofbits-audit/issues/44
Fixes: https://github.com/status-im/security-reports/issues/13
Fixes: https://github.com/status-im/security-reports/issues/5
Fixes: https://github.com/status-im/status-react/issues/8995
This commits re-introduce rendering of markdown text and implent a few
changes:
1) Parsing of the message content is now in status-go, this includes
markdown, line-count, and rtl. Parsing is not nested, as there's some
rendering degradation involved as we nest components, unclear exactly if
it's react-native or clojure, haven't looked too deeply into it.
2) Emojii type messages are not parsed on the sending side, not the
receiving one, using the appropriate content-type
3) Fixes a few issues with chat input rendering, currrently we use
`chats/current-chat` subscription which is very heavy and should not be
used unless necessary, and means that
any change to chat will trigger a re-render, which caused re-rendering
of input container on each received message. Also to note that
input-container is fairly heavy to render, and it's rendered twice at
each keypress on input.
The inline markdow supported is:
*italic* or _italic_
**bold** or __bold__
`inline code`
http://test.com links
\#status-tag
The block markdown supported is:
\# Headers
```
code blocks
```
> Quotereply
The styling is very basic at the moment, but can be improved.
Adding other markdown (photo,mentions) is straightforward and should
come at little performance cost (unless the component to render is
heavy, i.e a photo for example).
There are some behavioral changes with this commit:
1) Links are only parsed if starting with http:// or https://, meaning that
blah.com won't be parsed, nor www.test.com. This behavior is consistent
with discord for example and allows faster parsing at little expense to
ser experience imo. Fixes a few security issues as well.
2) Content is not anymore capped (regression), that's due to the fact that
before we only rendered text and react-native allowed us easily to limit
the number of lines, but adding markdown support means that this
strategy is not viable anymore. Performance of rendering don't see to be
very much impacted by this, I would re-introduce it if necessary, but
I'd rather do that in a separate PR.
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-11-07 14:41:37 +01:00
(and (chat.models/group-chat? current-chat)
(group-chats.db/joined? my-public-key current-chat))
(assoc :show-input? true)
2019-02-22 14:26:40 +02:00
Render markdown
Fixes: https://github.com/status-im/trailofbits-audit/issues/47
Fixes: https://github.com/status-im/trailofbits-audit/issues/46
Fixes: https://github.com/status-im/trailofbits-audit/issues/44
Fixes: https://github.com/status-im/security-reports/issues/13
Fixes: https://github.com/status-im/security-reports/issues/5
Fixes: https://github.com/status-im/status-react/issues/8995
This commits re-introduce rendering of markdown text and implent a few
changes:
1) Parsing of the message content is now in status-go, this includes
markdown, line-count, and rtl. Parsing is not nested, as there's some
rendering degradation involved as we nest components, unclear exactly if
it's react-native or clojure, haven't looked too deeply into it.
2) Emojii type messages are not parsed on the sending side, not the
receiving one, using the appropriate content-type
3) Fixes a few issues with chat input rendering, currrently we use
`chats/current-chat` subscription which is very heavy and should not be
used unless necessary, and means that
any change to chat will trigger a re-render, which caused re-rendering
of input container on each received message. Also to note that
input-container is fairly heavy to render, and it's rendered twice at
each keypress on input.
The inline markdow supported is:
*italic* or _italic_
**bold** or __bold__
`inline code`
http://test.com links
\#status-tag
The block markdown supported is:
\# Headers
```
code blocks
```
> Quotereply
The styling is very basic at the moment, but can be improved.
Adding other markdown (photo,mentions) is straightforward and should
come at little performance cost (unless the component to render is
heavy, i.e a photo for example).
There are some behavioral changes with this commit:
1) Links are only parsed if starting with http:// or https://, meaning that
blah.com won't be parsed, nor www.test.com. This behavior is consistent
with discord for example and allows faster parsing at little expense to
ser experience imo. Fixes a few security issues as well.
2) Content is not anymore capped (regression), that's due to the fact that
before we only rendered text and react-native allowed us easily to limit
the number of lines, but adding markdown support means that this
strategy is not viable anymore. Performance of rendering don't see to be
very much impacted by this, I would re-introduce it if necessary, but
I'd rather do that in a separate PR.
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-11-07 14:41:37 +01:00
(not group-chat)
2019-11-25 14:33:43 +01:00
(assoc :show-input? true)))))
(re-frame/reg-sub
:current-chat/one-to-one-chat?
:<- [:chats/current-raw-chat]
(fn [current-chat]
(not (or (chat.models/group-chat? current-chat)
(chat.models/public-chat? current-chat)))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/current-chat-message
:<- [:chats/current-chat]
(fn [{:keys [messages]} [_ message-id]]
(get messages message-id)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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)))
Fix message ordering and improve performance rec. messages
This commit does a few things:
==== Ordering of messages ====
Change the ordering of messages from a mixture of timestamp/clock-value to use
only clock-value.
Datemarks are now not used for sorting anymore, which means that the
order of messages is always causally related (not the case before, as we
were breaking this property by sorting by datemark), but datemark
calculation is unreliable (a reply to a message might have a timestamp <
then the message that is replied to).
So for timestamp calculation we
naively group them ignoring "out-of-order timestamp" messages, although
there's much to improve.
It fixes an issue whereby the user would change their time and the
message will be displayed in the past, although it is still possible to
craft a message with a lower clock value and order it in the past
(there's no way we can prevent this to some extent, but there are ways
to mitigate, but outside the scope of this PR).
==== Performance of receiving messages ====
The app would freeze on pulling messages from a mailserver (100 or so).
This is due to the JS Thread being hogged by CPU calculation, coupled
with the fact that we always tried to process messages all in one go.
This strategy can't scale, and given x is big enough (200,300,1000) the
UI will freeze.
Instead, each message is now processed separately, and we leave a gap
between processing each message for the UI to respond to user input
(otherwise the app freezes again).
Pulling messages will be longer overall, but the app will be usuable
while this happen (albeit it might slow down).
Other strategies are possible (calculate off-db and do a big swap,
avoiding many re-renders etc), but this is the reccommended strategy by
re-frame author (Solving the CPU Hog problem), so sounds like a safe
base point.
The underlying data structure for holding messages was also changed, we
used an immutable Red and Black Tree, same as a sorted map for clojure, but we use
a js library as is twice as performing then clojure sorted map.
We also don't sort messages again each time we receive them O(nlogn), but we
insert them in order O(logn).
Other data structures considered but discarded:
1) Plain vector, but performance prepending/insertion in the middle
(both O(n)) were not great, as not really suited for these operations.
2) Linked list, appealing as append/prepend is O(1), while insertion is
O(n). This is probably acceptable as messages tend to come in order
(from the db, so adding N messages is O(n)), or the network (most of
them prepends, or close to the head), while mailserver would not follow this path.
An implementation of a linked list was built, which performed roughtly the
same as a clojure sorted-map (although faster append/prepend), but not
worth the complexity of having our own implementation.
3) Clojure sorted-map, probably the most versatile, performance were
acceptable, but nowhere near the javascript implementation we decided on
4) Priority map, much slower than a sorted map (twice as slow)
5) Mutable sorted map, js implementation, (bintrees), not explored this very much, but from
just a quick benchmark, performance were much worse that clojure
immutable sorted map
Given that each message is now processed separately, saving the chat /
messages is also debounced to avoid spamming status-go with network
requests. This is a temporary measure for now until that's done directly
in status-go, without having to ping-pong with status-react.
Next steps performance wise is to move stuff to status-go, parsing of
transit, validation, which is heavy, at which point we can re-consider
performance and how to handle messages.
Fixes also an issue with the last message in the chat, we were using the
last message in the chat list, which might not necessarely be the last
message the chat has seen, in case messages were not loaded and a more
recent message is the database (say you fetch historical messages for
1-to-1 A, you don't have any messages in 1-to-1 chat B loaded, you receive an
historical message for chat B, it sets it as last message).
Also use clj beans instead of js->clj for type conversion
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-10-24 16:23:20 +02:00
(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))
2019-04-26 12:09:58 +02:00
(re-frame/reg-sub
:chats/current-chat-messages-stream
Fix message ordering and improve performance rec. messages
This commit does a few things:
==== Ordering of messages ====
Change the ordering of messages from a mixture of timestamp/clock-value to use
only clock-value.
Datemarks are now not used for sorting anymore, which means that the
order of messages is always causally related (not the case before, as we
were breaking this property by sorting by datemark), but datemark
calculation is unreliable (a reply to a message might have a timestamp <
then the message that is replied to).
So for timestamp calculation we
naively group them ignoring "out-of-order timestamp" messages, although
there's much to improve.
It fixes an issue whereby the user would change their time and the
message will be displayed in the past, although it is still possible to
craft a message with a lower clock value and order it in the past
(there's no way we can prevent this to some extent, but there are ways
to mitigate, but outside the scope of this PR).
==== Performance of receiving messages ====
The app would freeze on pulling messages from a mailserver (100 or so).
This is due to the JS Thread being hogged by CPU calculation, coupled
with the fact that we always tried to process messages all in one go.
This strategy can't scale, and given x is big enough (200,300,1000) the
UI will freeze.
Instead, each message is now processed separately, and we leave a gap
between processing each message for the UI to respond to user input
(otherwise the app freezes again).
Pulling messages will be longer overall, but the app will be usuable
while this happen (albeit it might slow down).
Other strategies are possible (calculate off-db and do a big swap,
avoiding many re-renders etc), but this is the reccommended strategy by
re-frame author (Solving the CPU Hog problem), so sounds like a safe
base point.
The underlying data structure for holding messages was also changed, we
used an immutable Red and Black Tree, same as a sorted map for clojure, but we use
a js library as is twice as performing then clojure sorted map.
We also don't sort messages again each time we receive them O(nlogn), but we
insert them in order O(logn).
Other data structures considered but discarded:
1) Plain vector, but performance prepending/insertion in the middle
(both O(n)) were not great, as not really suited for these operations.
2) Linked list, appealing as append/prepend is O(1), while insertion is
O(n). This is probably acceptable as messages tend to come in order
(from the db, so adding N messages is O(n)), or the network (most of
them prepends, or close to the head), while mailserver would not follow this path.
An implementation of a linked list was built, which performed roughtly the
same as a clojure sorted-map (although faster append/prepend), but not
worth the complexity of having our own implementation.
3) Clojure sorted-map, probably the most versatile, performance were
acceptable, but nowhere near the javascript implementation we decided on
4) Priority map, much slower than a sorted map (twice as slow)
5) Mutable sorted map, js implementation, (bintrees), not explored this very much, but from
just a quick benchmark, performance were much worse that clojure
immutable sorted map
Given that each message is now processed separately, saving the chat /
messages is also debounced to avoid spamming status-go with network
requests. This is a temporary measure for now until that's done directly
in status-go, without having to ping-pong with status-react.
Next steps performance wise is to move stuff to status-go, parsing of
transit, validation, which is heavy, at which point we can re-consider
performance and how to handle messages.
Fixes also an issue with the last message in the chat, we were using the
last message in the chat list, which might not necessarely be the last
message the chat has seen, in case messages were not loaded and a more
recent message is the database (say you fetch historical messages for
1-to-1 A, you don't have any messages in 1-to-1 chat B loaded, you receive an
historical message for chat B, it sets it as last message).
Also use clj beans instead of js->clj for type conversion
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-10-24 16:23:20 +02:00
:<- [:chats/message-list]
:<- [:chats/messages]
2019-04-26 12:09:58 +02:00
:<- [:chats/messages-gaps]
:<- [:chats/range]
:<- [:chats/all-loaded?]
:<- [:chats/public?]
Fix message ordering and improve performance rec. messages
This commit does a few things:
==== Ordering of messages ====
Change the ordering of messages from a mixture of timestamp/clock-value to use
only clock-value.
Datemarks are now not used for sorting anymore, which means that the
order of messages is always causally related (not the case before, as we
were breaking this property by sorting by datemark), but datemark
calculation is unreliable (a reply to a message might have a timestamp <
then the message that is replied to).
So for timestamp calculation we
naively group them ignoring "out-of-order timestamp" messages, although
there's much to improve.
It fixes an issue whereby the user would change their time and the
message will be displayed in the past, although it is still possible to
craft a message with a lower clock value and order it in the past
(there's no way we can prevent this to some extent, but there are ways
to mitigate, but outside the scope of this PR).
==== Performance of receiving messages ====
The app would freeze on pulling messages from a mailserver (100 or so).
This is due to the JS Thread being hogged by CPU calculation, coupled
with the fact that we always tried to process messages all in one go.
This strategy can't scale, and given x is big enough (200,300,1000) the
UI will freeze.
Instead, each message is now processed separately, and we leave a gap
between processing each message for the UI to respond to user input
(otherwise the app freezes again).
Pulling messages will be longer overall, but the app will be usuable
while this happen (albeit it might slow down).
Other strategies are possible (calculate off-db and do a big swap,
avoiding many re-renders etc), but this is the reccommended strategy by
re-frame author (Solving the CPU Hog problem), so sounds like a safe
base point.
The underlying data structure for holding messages was also changed, we
used an immutable Red and Black Tree, same as a sorted map for clojure, but we use
a js library as is twice as performing then clojure sorted map.
We also don't sort messages again each time we receive them O(nlogn), but we
insert them in order O(logn).
Other data structures considered but discarded:
1) Plain vector, but performance prepending/insertion in the middle
(both O(n)) were not great, as not really suited for these operations.
2) Linked list, appealing as append/prepend is O(1), while insertion is
O(n). This is probably acceptable as messages tend to come in order
(from the db, so adding N messages is O(n)), or the network (most of
them prepends, or close to the head), while mailserver would not follow this path.
An implementation of a linked list was built, which performed roughtly the
same as a clojure sorted-map (although faster append/prepend), but not
worth the complexity of having our own implementation.
3) Clojure sorted-map, probably the most versatile, performance were
acceptable, but nowhere near the javascript implementation we decided on
4) Priority map, much slower than a sorted map (twice as slow)
5) Mutable sorted map, js implementation, (bintrees), not explored this very much, but from
just a quick benchmark, performance were much worse that clojure
immutable sorted map
Given that each message is now processed separately, saving the chat /
messages is also debounced to avoid spamming status-go with network
requests. This is a temporary measure for now until that's done directly
in status-go, without having to ping-pong with status-react.
Next steps performance wise is to move stuff to status-go, parsing of
transit, validation, which is heavy, at which point we can re-consider
performance and how to handle messages.
Fixes also an issue with the last message in the chat, we were using the
last message in the chat list, which might not necessarely be the last
message the chat has seen, in case messages were not loaded and a more
recent message is the database (say you fetch historical messages for
1-to-1 A, you don't have any messages in 1-to-1 chat B loaded, you receive an
historical message for chat B, it sets it as last message).
Also use clj beans instead of js->clj for type conversion
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-10-24 16:23:20 +02:00
(fn [[message-list messages messages-gaps range all-loaded? public?]]
2019-11-06 13:45:45 +01:00
(-> (models.message-list/->seq message-list)
Fix message ordering and improve performance rec. messages
This commit does a few things:
==== Ordering of messages ====
Change the ordering of messages from a mixture of timestamp/clock-value to use
only clock-value.
Datemarks are now not used for sorting anymore, which means that the
order of messages is always causally related (not the case before, as we
were breaking this property by sorting by datemark), but datemark
calculation is unreliable (a reply to a message might have a timestamp <
then the message that is replied to).
So for timestamp calculation we
naively group them ignoring "out-of-order timestamp" messages, although
there's much to improve.
It fixes an issue whereby the user would change their time and the
message will be displayed in the past, although it is still possible to
craft a message with a lower clock value and order it in the past
(there's no way we can prevent this to some extent, but there are ways
to mitigate, but outside the scope of this PR).
==== Performance of receiving messages ====
The app would freeze on pulling messages from a mailserver (100 or so).
This is due to the JS Thread being hogged by CPU calculation, coupled
with the fact that we always tried to process messages all in one go.
This strategy can't scale, and given x is big enough (200,300,1000) the
UI will freeze.
Instead, each message is now processed separately, and we leave a gap
between processing each message for the UI to respond to user input
(otherwise the app freezes again).
Pulling messages will be longer overall, but the app will be usuable
while this happen (albeit it might slow down).
Other strategies are possible (calculate off-db and do a big swap,
avoiding many re-renders etc), but this is the reccommended strategy by
re-frame author (Solving the CPU Hog problem), so sounds like a safe
base point.
The underlying data structure for holding messages was also changed, we
used an immutable Red and Black Tree, same as a sorted map for clojure, but we use
a js library as is twice as performing then clojure sorted map.
We also don't sort messages again each time we receive them O(nlogn), but we
insert them in order O(logn).
Other data structures considered but discarded:
1) Plain vector, but performance prepending/insertion in the middle
(both O(n)) were not great, as not really suited for these operations.
2) Linked list, appealing as append/prepend is O(1), while insertion is
O(n). This is probably acceptable as messages tend to come in order
(from the db, so adding N messages is O(n)), or the network (most of
them prepends, or close to the head), while mailserver would not follow this path.
An implementation of a linked list was built, which performed roughtly the
same as a clojure sorted-map (although faster append/prepend), but not
worth the complexity of having our own implementation.
3) Clojure sorted-map, probably the most versatile, performance were
acceptable, but nowhere near the javascript implementation we decided on
4) Priority map, much slower than a sorted map (twice as slow)
5) Mutable sorted map, js implementation, (bintrees), not explored this very much, but from
just a quick benchmark, performance were much worse that clojure
immutable sorted map
Given that each message is now processed separately, saving the chat /
messages is also debounced to avoid spamming status-go with network
requests. This is a temporary measure for now until that's done directly
in status-go, without having to ping-pong with status-react.
Next steps performance wise is to move stuff to status-go, parsing of
transit, validation, which is heavy, at which point we can re-consider
performance and how to handle messages.
Fixes also an issue with the last message in the chat, we were using the
last message in the chat list, which might not necessarely be the last
message the chat has seen, in case messages were not loaded and a more
recent message is the database (say you fetch historical messages for
1-to-1 A, you don't have any messages in 1-to-1 chat B loaded, you receive an
historical message for chat B, it sets it as last message).
Also use clj beans instead of js->clj for type conversion
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-10-24 16:23:20 +02:00
(chat.db/add-datemarks)
(hydrate-messages messages)
(chat.db/add-gaps messages-gaps range all-loaded? public?))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/unviewed-messages-count
(fn [[_ chat-id]]
2019-05-01 14:52:59 +02:00
(re-frame/subscribe [:chats/chat chat-id]))
2019-04-26 12:09:58 +02:00
(fn [{:keys [unviewed-messages-count]}]
unviewed-messages-count))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/photo-path
:<- [:contacts/contacts]
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
(fn [[contacts multiaccount] [_ id]]
2019-09-12 11:41:25 +02:00
(multiaccounts/displayed-photo (or (contacts id)
(when (= id (:public-key multiaccount))
multiaccount)
(contact.db/public-key->new-contact id)))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/unread-messages-number
:<- [:chats/active-chats]
(fn [chats _]
(apply + (map :unviewed-messages-count (vals chats)))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/cooldown-enabled?
:<- [:chats/current-chat]
:<- [::cooldown-enabled?]
(fn [[{:keys [public?]} cooldown-enabled?]]
(and public?
cooldown-enabled?)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:chats/reply-message
:<- [:chats/current-chat]
(fn [{:keys [metadata messages]}]
(get messages (get-in metadata [:responding-to-message :message-id]))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:selected-contacts-count
:<- [:group/selected-contacts]
:<- [:contacts/contacts]
(fn [[selected-contacts contacts]]
(count (filter-selected-contacts selected-contacts contacts))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:selected-group-contacts
:<- [:group/selected-contacts]
:<- [:contacts/active]
(fn [[selected-contacts active-contacts]]
(filter-contacts selected-contacts active-contacts)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-05-17 12:02:16 +02:00
:chats/transaction-status
2019-08-12 10:53:31 +02:00
;;TODO address here for transactions
2019-05-17 12:02:16 +02:00
:<- [: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))})))
2019-04-26 12:09:58 +02:00
;;BOOTNODES ============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-12-10 12:31:22 +01:00
:custom-bootnodes/enabled?
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2019-08-23 16:11:23 +02:00
:<- [:networks/current-network]
2019-12-10 12:31:22 +01:00
(fn [[{:keys [custom-bootnodes-enabled?]} current-network]]
(get custom-bootnodes-enabled? current-network)))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-12-10 12:31:22 +01:00
:custom-bootnodes/network-bootnodes
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2019-08-23 16:11:23 +02:00
:<- [:networks/current-network]
2019-09-11 13:22:47 +02:00
(fn [[multiaccount current-network]]
2019-12-10 12:31:22 +01:00
(get-in multiaccount [:custom-bootnodes current-network])))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:get-manage-bootnode
:<- [:bootnodes/manage]
(fn [manage]
manage))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:manage-bootnode-validation-errors
:<- [:get-manage-bootnode]
(fn [manage]
(set (keep
(fn [[k {:keys [error]}]]
(when error k))
manage))))
;;BROWSER ==============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:browser/browsers
:<- [:browsers]
(fn [browsers]
(reduce (fn [acc [k browser]]
(update acc k assoc :url (browser/get-current-url browser)))
browsers
browsers)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:browser/browsers-vals
:<- [:browser/browsers]
(fn [browsers]
(sort-by :timestamp > (vals browsers))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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 =============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:stickers/installed-packs-vals
:<- [:stickers/installed-packs]
(fn [packs]
(vals packs)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:stickers/all-packs
:<- [:stickers/packs]
:<- [:stickers/installed-packs]
:<- [:stickers/packs-owned]
2019-05-20 02:21:38 +02:00
:<- [:stickers/packs-pending]
2019-04-26 12:09:58 +02:00
(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))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:stickers/get-current-pack
:<- [:get-screen-params]
:<- [:stickers/all-packs]
(fn [[{:keys [id]} packs]]
(first (filter #(= (:id %) id) packs))))
2019-06-27 11:50:07 +02:00
(defn find-pack-id-for-hash [sticker-uri packs]
2019-04-26 12:09:58 +02:00
(some (fn [{:keys [stickers id]}]
2019-06-27 11:50:07 +02:00
(when (some #(= sticker-uri (:hash %)) stickers)
2019-04-26 12:09:58 +02:00
id))
packs))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:stickers/recent
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2019-04-26 12:09:58 +02:00
:<- [:stickers/installed-packs-vals]
2019-08-01 22:11:59 +02:00
(fn [[{:keys [:stickers/recent-stickers]} packs]]
2019-06-27 11:50:07 +02:00
(map (fn [hash] {:hash hash :pack (find-pack-id-for-hash hash packs)}) recent-stickers)))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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 ==============================================================================================================
2019-06-25 16:34:55 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:pairing/installations
:<- [:get-pairing-installations]
2019-06-25 16:34:55 +02:00
:<- [:pairing/installation-id]
(fn [[installations installation-id]]
2019-04-26 12:09:58 +02:00
(->> installations
vals
2019-06-25 16:34:55 +02:00
(pairing/sort-installations installation-id))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:pairing/installation-id
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2019-04-26 12:09:58 +02:00
:installation-id)
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:pairing/installation-name
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
(fn [multiaccount] (:installation-name multiaccount)))
2019-04-26 12:09:58 +02:00
;;PROFILE ==============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:get-profile-unread-messages-number
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2019-12-17 10:26:25 +01:00
(fn [{:keys [mnemonic]}]
(if mnemonic 1 0)))
2019-04-26 12:09:58 +02:00
;;WALLET ==============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:balance
:<- [:wallet]
2019-08-12 10:53:31 +02:00
(fn [wallet [_ address]]
(get-in wallet [:accounts address :balance])))
(re-frame/reg-sub
:balance-default
:<- [:wallet]
2019-12-16 12:18:40 +01:00
:<- [:multiaccount/accounts]
(fn [[wallet accounts]]
2019-08-12 10:53:31 +02:00
(get-in wallet [:accounts (:address (ethereum/get-default-account accounts)) :balance])))
(re-frame/reg-sub
:balances
:<- [:wallet]
2019-04-26 12:09:58 +02:00
(fn [wallet]
2019-08-12 10:53:31 +02:00
(map :balance (vals (:accounts wallet)))))
2019-04-26 12:09:58 +02:00
2019-10-21 10:15:06 +03:00
(re-frame/reg-sub
:empty-balances?
:<- [:balances]
(fn [balances]
(every?
(fn [balance]
(every?
(fn [asset]
(or (nil? asset) (.isZero asset)))
(vals balance)))
balances)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:price
:<- [:prices]
(fn [prices [_ fsym tsym]]
(get-in prices [fsym tsym :price])))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:last-day
:<- [:prices]
(fn [prices [_ fsym tsym]]
(get-in prices [fsym tsym :last-day])))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet.settings/currency
2019-12-10 12:31:22 +01:00
:<- [:multiaccount]
2019-05-16 23:50:03 +02:00
(fn [settings]
2019-12-10 12:31:22 +01:00
(or (get settings :currency) :usd)))
2019-04-26 12:09:58 +02:00
2019-05-16 23:50:03 +02:00
(defn- get-balance-total-value
[balance prices currency token->decimals]
2019-04-26 12:09:58 +02:00
(reduce-kv (fn [acc symbol value]
(if-let [price (get-in prices [symbol currency :price])]
2019-05-04 20:59:01 +03:00
(+ acc (or (some-> (money/internal->formatted value symbol (token->decimals symbol))
(money/crypto->fiat price)
.toNumber)
0))
2019-04-26 12:09:58 +02:00
acc)) 0 balance))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:portfolio-value
2019-08-12 10:53:31 +02:00
:<- [:balances]
2019-04-26 12:09:58 +02:00
:<- [:prices]
:<- [:wallet/currency]
2019-05-22 13:09:33 +02:00
:<- [:ethereum/chain-keyword]
2019-04-26 12:09:58 +02:00
:<- [:wallet/all-tokens]
2019-08-12 10:53:31 +02:00
(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] _]
2019-08-24 02:26:48 +02:00
[(re-frame/subscribe [:balance address])
2019-08-12 10:53:31 +02:00
(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]]
2019-04-26 12:09:58 +02:00
(if (and balance prices)
2019-08-12 10:53:31 +02:00
(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)]
2019-04-26 12:09:58 +02:00
(if (pos? balance-total-value)
(-> balance-total-value
(money/with-precision 2)
str
(i18n/format-currency (:code currency) false))
"0"))
"...")))
2019-11-25 14:33:43 +01:00
(re-frame/reg-sub
:wallet/chain-tokens
:<- [:wallet/all-tokens]
:<- [:ethereum/chain-keyword]
(fn [[all-tokens chain]]
(get all-tokens chain)))
2019-06-17 11:41:37 +02:00
(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)))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet/error-message
:<- [:wallet]
(fn [wallet]
(or (get-in wallet [:errors :balance-update])
(get-in wallet [:errors :prices-update]))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet/visible-tokens-symbols
2019-05-22 13:09:33 +02:00
:<- [:ethereum/chain-keyword]
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
(fn [[chain current-multiaccount]]
2019-12-10 12:31:22 +01:00
(get-in current-multiaccount [:wallet/visible-tokens chain])))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet/visible-assets
2019-05-22 13:09:33 +02:00
:<- [:ethereum/chain-keyword]
2019-04-26 12:09:58 +02:00
:<- [:wallet/visible-tokens-symbols]
:<- [:wallet/all-tokens]
2019-05-22 13:09:33 +02:00
(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))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet/visible-assets-with-amount
2019-08-12 10:53:31 +02:00
(fn [[_ address] _]
2019-08-24 02:26:48 +02:00
[(re-frame/subscribe [:balance address])
2019-08-12 10:53:31 +02:00
(re-frame/subscribe [:wallet/visible-assets])])
2019-04-26 12:09:58 +02:00
(fn [[balance visible-assets]]
(map #(assoc % :amount (get balance (:symbol %))) visible-assets)))
2019-08-12 10:53:31 +02:00
(defn update-value [prices currency]
(fn [{:keys [symbol decimals amount] :as token}]
2019-06-17 11:41:37 +02:00
(let [price (get-in prices [symbol (-> currency :code keyword) :price])]
(assoc token
:price price
2019-08-12 10:53:31 +02:00
:value (when (and amount price)
(-> (money/internal->formatted amount symbol decimals)
2019-06-17 11:41:37 +02:00
(money/crypto->fiat price)
(money/with-precision 2)
str
(i18n/format-currency (:code currency))))))))
(re-frame/reg-sub
:wallet/visible-assets-with-values
2019-08-12 10:53:31 +02:00
(fn [[_ address] _]
2019-08-24 02:26:48 +02:00
[(re-frame/subscribe [:wallet/visible-assets-with-amount address])
2019-08-12 10:53:31 +02:00
(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]
2019-06-17 11:41:37 +02:00
:<- [:prices]
:<- [:wallet/currency]
2019-08-12 10:53:31 +02:00
(fn [[assets prices currency]]
2019-06-17 11:41:37 +02:00
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
2019-08-12 10:53:31 +02:00
tokens-with-values (map (update-value prices currency) tokens)]
2019-06-17 11:41:37 +02:00
{:tokens tokens-with-values
:nfts nfts})))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet/transferrable-assets-with-amount
2019-08-12 10:53:31 +02:00
(fn [[_ address]]
2019-08-24 02:26:48 +02:00
(re-frame/subscribe [:wallet/visible-assets-with-amount address]))
2019-04-26 12:09:58 +02:00
(fn [all-assets]
(filter #(not (:nft? %)) all-assets)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet/currency
:<- [:wallet.settings/currency]
(fn [currency-id]
(get constants/currencies currency-id)))
;;WALLET TRANSACTIONS ==================================================================================================
2019-11-25 14:33:43 +01:00
(re-frame/reg-sub
:wallet/accounts
:<- [:wallet]
(fn [wallet]
(get wallet :accounts)))
(re-frame/reg-sub
:wallet/account-by-transaction-hash
:<- [:wallet/accounts]
(fn [accounts [_ hash]]
(some (fn [[address account]]
(when-let [transaction (get-in account [:transactions hash])]
(assoc transaction :address address)))
accounts)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-05-17 12:02:16 +02:00
:wallet/transactions
2019-04-26 12:09:58 +02:00
:<- [:wallet]
2019-08-12 10:53:31 +02:00
(fn [wallet [_ address]]
2019-08-24 02:26:48 +02:00
(get-in wallet [:accounts address :transactions])))
2019-04-26 12:09:58 +02:00
2019-05-16 23:50:03 +02:00
(re-frame/reg-sub
2019-05-17 12:02:16 +02:00
:wallet/filters
:<- [:wallet]
(fn [wallet]
(get wallet :filters)))
2019-05-16 23:50:03 +02:00
(defn enrich-transaction
2019-05-17 12:02:16 +02:00
[{: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])
2019-04-26 12:09:58 +02:00
wallet (i18n/label :main-wallet)
2019-05-17 12:02:16 +02:00
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)))]
2019-04-26 12:09:58 +02:00
(cond-> transaction
contact (assoc key-contact (:name contact))
:always (assoc key-wallet wallet
2019-05-17 12:02:16 +02:00
:amount-text amount-text
:currency-text currency-text))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet.transactions/transactions
2019-08-12 10:53:31 +02:00
(fn [[_ address] _]
[(re-frame/subscribe [:wallet/transactions address])
(re-frame/subscribe [:contacts/contacts-by-address])
(re-frame/subscribe [:ethereum/native-currency])])
2019-05-17 12:02:16 +02:00
(fn [[transactions contacts native-currency]]
2019-07-08 18:11:07 +02:00
(reduce (fn [acc [hash transaction]]
(assoc acc
hash
2019-08-12 10:53:31 +02:00
(enrich-transaction transaction contacts native-currency))) ;;TODO this doesn't look good for performance, we need to calculate this only once for each transaction
2019-07-08 18:11:07 +02:00
{}
transactions)))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-05-17 12:02:16 +02:00
:wallet.transactions/all-filters?
:<- [:wallet/filters]
(fn [filters]
(= wallet.db/default-wallet-filters
filters)))
2019-04-26 12:09:58 +02:00
2019-05-17 12:02:16 +02:00
(def filters-labels
{:inbound (i18n/label :t/incoming)
:outbound (i18n/label :t/outgoing)
:pending (i18n/label :t/pending)
:failed (i18n/label :t/failed)})
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-05-17 12:02:16 +02:00
: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
2019-08-12 10:53:31 +02:00
{:keys [type from-contact from to-contact to hash timestamp] :as transaction}
address]
2019-05-17 12:02:16 +02:00
(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)
2019-08-12 10:53:31 +02:00
:on-touch-fn #(re-frame/dispatch [:wallet.ui/show-transaction-details hash address]))))
2019-05-17 12:02:16 +02:00
(defn- group-transactions-by-date
[transactions]
2019-04-26 12:09:58 +02:00
(->> transactions
(group-by #(datetime/timestamp->date-key (:timestamp %)))
2019-05-17 12:02:16 +02:00
(sort-by key >)
2019-04-26 12:09:58 +02:00
(map (fn [[date-key transactions]]
{:title (datetime/timestamp->mini-date (:timestamp (first transactions)))
:key date-key
:data (sort-by :timestamp > transactions)}))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-05-17 12:02:16 +02:00
:wallet.transactions.history/screen
2019-08-12 10:53:31 +02:00
(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]]
2019-05-17 12:02:16 +02:00
{:all-filters? all-filters?
:transaction-history-sections
(->> transactions
vals
2019-08-12 10:53:31 +02:00
(keep #(enrich-transaction-for-list filters % address))
2019-05-17 12:02:16 +02:00
(group-transactions-by-date))}))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-05-16 23:50:03 +02:00
:wallet.transactions.details/current-transaction
2019-08-12 10:53:31 +02:00
(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 _]]
2019-05-16 23:50:03 +02:00
(let [{:keys [gas-used gas-price hash timestamp type token value]
:as transaction}
2019-08-12 10:53:31 +02:00
(get transactions hash)
2019-05-20 02:21:38 +02:00
native-currency-text (name (or (:symbol-display native-currency)
(:symbol native-currency)))]
2019-04-26 12:09:58 +02:00
(when transaction
2019-05-17 12:02:16 +02:00
(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))
2019-07-08 18:11:07 +02:00
:url (transactions/get-transaction-details-url
2019-05-17 12:02:16 +02:00
chain-keyword
hash)}))))))
2019-05-16 23:50:03 +02:00
(re-frame/reg-sub
:wallet.transactions.details/screen
2019-08-12 10:53:31 +02:00
(fn [[_ hash address] _]
[(re-frame/subscribe [:wallet.transactions.details/current-transaction hash address])
(re-frame/subscribe [:ethereum/current-block])])
2019-05-17 12:02:16 +02:00
(fn [[transaction current-block]]
(let [confirmations (wallet.db/get-confirmations transaction
current-block)]
2019-05-16 23:50:03 +02:00
(assoc transaction
:confirmations confirmations
:confirmations-progress
(if (>= confirmations transactions/confirmations-count-threshold)
100
(* 100 (/ confirmations transactions/confirmations-count-threshold)))))))
2019-04-26 12:09:58 +02:00
;;WALLET SEND ==========================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
::send-transaction
:<- [:wallet]
(fn [wallet]
(:send-transaction wallet)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-06-05 13:11:47 +02:00
:wallet.send/symbol
2019-04-26 12:09:58 +02:00
:<- [::send-transaction]
(fn [send-transaction]
2019-06-05 13:11:47 +02:00
(:symbol send-transaction)))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet.send/camera-flashlight
:<- [::send-transaction]
(fn [send-transaction]
(:camera-flashlight send-transaction)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet/settings
:<- [:wallet]
(fn [{:keys [settings]}]
(reduce-kv #(conj %1 %3) [] settings)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:wallet.request/transaction
:<- [:wallet]
:request-transaction)
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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?
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:connectivity/status-properties
2020-01-14 20:24:21 +01:00
:<- [:network-status]
2019-04-26 12:09:58 +02:00
:<- [:disconnected?]
:<- [:mailserver/connecting?]
:<- [:mailserver/connection-error?]
:<- [:mailserver/request-error?]
:<- [:mailserver/fetching?]
:<- [:network/type]
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2020-01-14 20:24:21 +01:00
(fn [[network-status disconnected? mailserver-connecting? mailserver-connection-error?
2019-07-03 16:29:01 +02:00
mailserver-request-error? mailserver-fetching? network-type multiaccount]]
2020-01-14 20:24:21 +01:00
(let [error-label (cond
(= network-status :offline)
2019-04-26 12:09:58 +02:00
:t/offline
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)
2019-07-03 16:29:01 +02:00
(not (:syncing-on-mobile-network? multiaccount)))
2019-04-26 12:09:58 +02:00
:mobile-network
2020-01-14 20:24:21 +01:00
disconnected?
:t/offline
2019-04-26 12:09:58 +02:00
: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?
2020-01-14 20:24:21 +01:00
:on-press-event (cond
mailserver-connection-error?
:mailserver.ui/reconnect-mailserver-pressed
mailserver-request-error?
:mailserver.ui/request-error-pressed
(= :mobile-network error-label)
:mobile-network/show-offline-sheet)})))
2019-04-26 12:09:58 +02:00
;;CONTACT ==============================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
::query-current-chat-contacts
:<- [:chats/current-chat]
:<- [:contacts/contacts]
(fn [[chat contacts] [_ query-fn]]
(contact.db/query-chat-contacts chat contacts query-fn)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/contacts
:<- [::contacts]
(fn [contacts]
(contact.db/enrich-contacts contacts)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/active
:<- [:contacts/contacts]
(fn [contacts]
(contact.db/get-active-contacts contacts)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/active-count
:<- [:contacts/active]
(fn [active-contacts]
(count active-contacts)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/blocked
:<- [:contacts/contacts]
(fn [contacts]
(->> contacts
(filter (fn [[_ contact]]
(contact.db/blocked? contact)))
(contact.db/sort-contacts))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/blocked-count
:<- [:contacts/blocked]
(fn [blocked-contacts]
(count blocked-contacts)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/contact-name-by-identity
:<- [:contacts/contacts]
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
(fn [[contacts current-multiaccount] [_ identity]]
(let [me? (= (:public-key current-multiaccount) identity)]
2019-04-26 12:09:58 +02:00
(if me?
Fix message ordering and improve performance rec. messages
This commit does a few things:
==== Ordering of messages ====
Change the ordering of messages from a mixture of timestamp/clock-value to use
only clock-value.
Datemarks are now not used for sorting anymore, which means that the
order of messages is always causally related (not the case before, as we
were breaking this property by sorting by datemark), but datemark
calculation is unreliable (a reply to a message might have a timestamp <
then the message that is replied to).
So for timestamp calculation we
naively group them ignoring "out-of-order timestamp" messages, although
there's much to improve.
It fixes an issue whereby the user would change their time and the
message will be displayed in the past, although it is still possible to
craft a message with a lower clock value and order it in the past
(there's no way we can prevent this to some extent, but there are ways
to mitigate, but outside the scope of this PR).
==== Performance of receiving messages ====
The app would freeze on pulling messages from a mailserver (100 or so).
This is due to the JS Thread being hogged by CPU calculation, coupled
with the fact that we always tried to process messages all in one go.
This strategy can't scale, and given x is big enough (200,300,1000) the
UI will freeze.
Instead, each message is now processed separately, and we leave a gap
between processing each message for the UI to respond to user input
(otherwise the app freezes again).
Pulling messages will be longer overall, but the app will be usuable
while this happen (albeit it might slow down).
Other strategies are possible (calculate off-db and do a big swap,
avoiding many re-renders etc), but this is the reccommended strategy by
re-frame author (Solving the CPU Hog problem), so sounds like a safe
base point.
The underlying data structure for holding messages was also changed, we
used an immutable Red and Black Tree, same as a sorted map for clojure, but we use
a js library as is twice as performing then clojure sorted map.
We also don't sort messages again each time we receive them O(nlogn), but we
insert them in order O(logn).
Other data structures considered but discarded:
1) Plain vector, but performance prepending/insertion in the middle
(both O(n)) were not great, as not really suited for these operations.
2) Linked list, appealing as append/prepend is O(1), while insertion is
O(n). This is probably acceptable as messages tend to come in order
(from the db, so adding N messages is O(n)), or the network (most of
them prepends, or close to the head), while mailserver would not follow this path.
An implementation of a linked list was built, which performed roughtly the
same as a clojure sorted-map (although faster append/prepend), but not
worth the complexity of having our own implementation.
3) Clojure sorted-map, probably the most versatile, performance were
acceptable, but nowhere near the javascript implementation we decided on
4) Priority map, much slower than a sorted map (twice as slow)
5) Mutable sorted map, js implementation, (bintrees), not explored this very much, but from
just a quick benchmark, performance were much worse that clojure
immutable sorted map
Given that each message is now processed separately, saving the chat /
messages is also debounced to avoid spamming status-go with network
requests. This is a temporary measure for now until that's done directly
in status-go, without having to ping-pong with status-react.
Next steps performance wise is to move stuff to status-go, parsing of
transit, validation, which is heavy, at which point we can re-consider
performance and how to handle messages.
Fixes also an issue with the last message in the chat, we were using the
last message in the chat list, which might not necessarely be the last
message the chat has seen, in case messages were not loaded and a more
recent message is the database (say you fetch historical messages for
1-to-1 A, you don't have any messages in 1-to-1 chat B loaded, you receive an
historical message for chat B, it sets it as last message).
Also use clj beans instead of js->clj for type conversion
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-10-24 16:23:20 +02:00
{:ens-name (:preferred-name current-multiaccount)
2019-09-30 13:33:45 +02:00
:alias (gfycat/generate-gfy identity)}
(let [contact (or (contacts identity)
(contact.db/public-key->new-contact identity))]
2019-10-11 13:33:34 +02:00
{:ens-name (when (:ens-verified contact)
(:name contact))
2019-09-30 13:33:45 +02:00
:alias (or (:alias contact)
(gfycat/generate-gfy identity))})))))
2019-04-26 12:09:58 +02:00
Fix message ordering and improve performance rec. messages
This commit does a few things:
==== Ordering of messages ====
Change the ordering of messages from a mixture of timestamp/clock-value to use
only clock-value.
Datemarks are now not used for sorting anymore, which means that the
order of messages is always causally related (not the case before, as we
were breaking this property by sorting by datemark), but datemark
calculation is unreliable (a reply to a message might have a timestamp <
then the message that is replied to).
So for timestamp calculation we
naively group them ignoring "out-of-order timestamp" messages, although
there's much to improve.
It fixes an issue whereby the user would change their time and the
message will be displayed in the past, although it is still possible to
craft a message with a lower clock value and order it in the past
(there's no way we can prevent this to some extent, but there are ways
to mitigate, but outside the scope of this PR).
==== Performance of receiving messages ====
The app would freeze on pulling messages from a mailserver (100 or so).
This is due to the JS Thread being hogged by CPU calculation, coupled
with the fact that we always tried to process messages all in one go.
This strategy can't scale, and given x is big enough (200,300,1000) the
UI will freeze.
Instead, each message is now processed separately, and we leave a gap
between processing each message for the UI to respond to user input
(otherwise the app freezes again).
Pulling messages will be longer overall, but the app will be usuable
while this happen (albeit it might slow down).
Other strategies are possible (calculate off-db and do a big swap,
avoiding many re-renders etc), but this is the reccommended strategy by
re-frame author (Solving the CPU Hog problem), so sounds like a safe
base point.
The underlying data structure for holding messages was also changed, we
used an immutable Red and Black Tree, same as a sorted map for clojure, but we use
a js library as is twice as performing then clojure sorted map.
We also don't sort messages again each time we receive them O(nlogn), but we
insert them in order O(logn).
Other data structures considered but discarded:
1) Plain vector, but performance prepending/insertion in the middle
(both O(n)) were not great, as not really suited for these operations.
2) Linked list, appealing as append/prepend is O(1), while insertion is
O(n). This is probably acceptable as messages tend to come in order
(from the db, so adding N messages is O(n)), or the network (most of
them prepends, or close to the head), while mailserver would not follow this path.
An implementation of a linked list was built, which performed roughtly the
same as a clojure sorted-map (although faster append/prepend), but not
worth the complexity of having our own implementation.
3) Clojure sorted-map, probably the most versatile, performance were
acceptable, but nowhere near the javascript implementation we decided on
4) Priority map, much slower than a sorted map (twice as slow)
5) Mutable sorted map, js implementation, (bintrees), not explored this very much, but from
just a quick benchmark, performance were much worse that clojure
immutable sorted map
Given that each message is now processed separately, saving the chat /
messages is also debounced to avoid spamming status-go with network
requests. This is a temporary measure for now until that's done directly
in status-go, without having to ping-pong with status-react.
Next steps performance wise is to move stuff to status-go, parsing of
transit, validation, which is heavy, at which point we can re-consider
performance and how to handle messages.
Fixes also an issue with the last message in the chat, we were using the
last message in the chat list, which might not necessarely be the last
message the chat has seen, in case messages were not loaded and a more
recent message is the database (say you fetch historical messages for
1-to-1 A, you don't have any messages in 1-to-1 chat B loaded, you receive an
historical message for chat B, it sets it as last message).
Also use clj beans instead of js->clj for type conversion
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
2019-10-24 16:23:20 +02:00
(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))}))))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/all-contacts-not-in-current-chat
:<- [::query-current-chat-contacts remove]
(fn [contacts]
2020-01-16 11:31:36 +01:00
(->> contacts
(filter contact.db/added?)
(sort-by (comp clojure.string/lower-case multiaccounts/displayed-name)))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/current-chat-contacts
:<- [:chats/current-chat]
:<- [:contacts/contacts]
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
(fn [[{:keys [contacts admins]} all-contacts current-multiaccount]]
2019-11-12 11:55:45 +01:00
(map #(assoc % :name (multiaccounts/displayed-name %))
(contact.db/get-all-contacts-in-group-chat contacts admins all-contacts current-multiaccount))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/contacts-by-chat
(fn [[_ _ chat-id] _]
2019-05-01 14:52:59 +02:00
[(re-frame/subscribe [:chats/chat chat-id])
(re-frame/subscribe [:contacts/contacts])])
2019-04-26 12:09:58 +02:00
(fn [[chat all-contacts] [_ query-fn]]
(contact.db/query-chat-contacts chat all-contacts query-fn)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/chat-photo
(fn [[_ chat-id] _]
2019-05-01 14:52:59 +02:00
[(re-frame/subscribe [:chats/chat chat-id])
(re-frame/subscribe [:contacts/contacts-by-chat filter chat-id])])
2019-04-26 12:09:58 +02:00
(fn [[chat contacts] [_ chat-id]]
(when (and chat (not (:group-chat chat)))
2019-09-12 11:41:25 +02:00
(if (pos? (count contacts))
(multiaccounts/displayed-photo (first contacts))
(multiaccounts/displayed-photo chat)))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/contact-by-address
:<- [:contacts/contacts]
(fn [contacts [_ address]]
(contact.db/find-contact-by-address contacts address)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:contacts/contacts-by-address
:<- [:contacts/contacts]
(fn [contacts]
(reduce (fn [acc [_ {:keys [address] :as contact}]]
(if address
(assoc acc address contact)
acc))
{}
contacts)))
;;MAILSERVER ===========================================================================================================
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:mailserver/connecting?
:<- [:mailserver/state]
(fn [state]
(#{:connecting :added} state)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:mailserver/connection-error?
:<- [:mailserver/state]
(fn [state]
(#{:error :disconnected} state)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
: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?)))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:mailserver/fleet-mailservers
2019-12-10 12:31:22 +01:00
:<- [:fleets/current-fleet]
2019-04-26 12:09:58 +02:00
:<- [:mailserver/mailservers]
(fn [[current-fleet mailservers]]
(current-fleet mailservers)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:mailserver.edit/connected?
:<- [:mailserver.edit/mailserver]
:<- [:mailserver/current-id]
(fn [[mailserver current-mailserver-id]]
(= (get-in mailserver [:id :value])
current-mailserver-id)))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:mailserver.edit/validation-errors
:<- [:mailserver.edit/mailserver]
(fn [mailserver]
(set (keep
(fn [[k {:keys [error]}]]
(when error k))
mailserver))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:mailserver/connected?
:<- [:mailserver/state]
2019-09-04 11:41:05 +02:00
:<- [:disconnected?]
(fn [[mail-state disconnected?]]
(let [mailserver-connected? (= :connected mail-state)]
(and mailserver-connected?
(not disconnected?)))))
2019-04-26 12:09:58 +02:00
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:mailserver/preferred-id
2019-12-10 12:31:22 +01:00
:<- [:multiaccount]
(fn [multiaccount]
(get-in multiaccount
[:pinned-mailservers (fleet/current-fleet-sub multiaccount)])))
2019-04-26 12:09:58 +02:00
;;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))))))
2019-05-01 14:52:59 +02:00
(re-frame/reg-sub
2019-04-26 12:09:58 +02:00
:search/filtered-chats
:<- [:chats/active-chats]
:<- [:search/filter]
(fn [[chats search-filter]]
2019-05-04 20:59:01 +03:00
(apply-filter search-filter chats extract-chat-attributes)))
2019-02-22 14:26:40 +02:00
;; TRIBUTE TO TALK
(re-frame/reg-sub
:tribute-to-talk/settings
2019-12-10 12:31:22 +01:00
:<- [:multiaccount]
2019-02-22 14:26:40 +02:00
:<- [:ethereum/chain-keyword]
2019-12-10 12:31:22 +01:00
(fn [[multiaccount chain-keyword]]
(get-in multiaccount [:tribute-to-talk]) chain-keyword))
2019-02-22 14:26:40 +02:00
(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?
2019-11-07 14:20:19 +01:00
:fiat-value (str fiat-value " " (:code currency))}
2019-02-22 14:26:40 +02:00
(= 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 ".")))))))))
2019-06-05 13:11:47 +02:00
2019-06-03 09:42:29 +02:00
;;ENS ==================================================================================================================
(re-frame/reg-sub
:ens.stateofus/registrar
2019-08-23 16:11:23 +02:00
:<- [:current-network]
2019-06-03 09:42:29 +02:00
(fn [network]
(let [chain (ethereum/network->chain-keyword network)]
(get stateofus/registrars chain))))
(re-frame/reg-sub
2019-07-03 16:29:01 +02:00
:multiaccount/usernames
:<- [:multiaccount]
(fn [multiaccount]
(:usernames multiaccount)))
2019-06-03 09:42:29 +02:00
2019-06-20 16:11:24 +02:00
(re-frame/reg-sub
:ens/preferred-name
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
(fn [multiaccount]
(:preferred-name multiaccount)))
2019-06-20 16:11:24 +02:00
2019-06-03 09:42:29 +02:00
(re-frame/reg-sub
2019-09-02 10:40:13 +02:00
: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
2019-06-03 09:42:29 +02:00
:<- [:ens/registration]
:<- [:ens.stateofus/registrar]
2019-12-12 16:18:04 +01:00
:<- [:multiaccount/default-account]
2019-09-02 10:40:13 +02:00
:<- [:multiaccount/public-key]
2019-08-24 17:43:18 +02:00
:<- [:chain-id]
2019-09-02 10:40:13 +02:00
(fn [[{:keys [custom-domain? username]}
2019-12-12 16:18:04 +01:00
registrar default-account public-key chain-id]]
{:address (ethereum/normalized-hex (:address default-account))
2019-09-02 10:40:13 +02:00
: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}))
2019-06-03 09:42:29 +02:00
(re-frame/reg-sub
:ens.name/screen
:<- [:get-screen-params :ens-name-details]
:<- [:ens/names]
2019-08-22 11:41:20 +02:00
(fn [[name ens]]
2019-09-02 10:40:13 +02:00
(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)))))
2019-06-03 09:42:29 +02:00
2019-06-20 16:11:24 +02:00
(re-frame/reg-sub
:ens.main/screen
2019-07-03 16:29:01 +02:00
:<- [:multiaccount/usernames]
:<- [:multiaccount]
2019-06-20 16:11:24 +02:00
:<- [:ens/preferred-name]
2019-12-17 12:17:48 +01:00
(fn [[names multiaccount preferred-name]]
2019-06-20 16:11:24 +02:00
{:names names
2019-07-03 16:29:01 +02:00
:multiaccount multiaccount
2019-12-17 12:17:48 +01:00
:preferred-name preferred-name}))
2019-06-20 16:11:24 +02:00
2019-06-05 13:11:47 +02:00
;;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
2019-07-03 16:29:01 +02:00
:<- [:multiaccount]
2019-06-05 13:11:47 +02:00
(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
2019-08-12 10:53:31 +02:00
(fn [[_ address] _]
[(re-frame/subscribe [:signing/tx])
(re-frame/subscribe [:balance address])])
2019-06-05 13:11:47 +02:00
(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))))
2019-08-23 16:11:23 +02:00
2019-08-24 02:26:48 +02:00
(re-frame/reg-sub
2019-11-16 10:56:09 +01:00
:wallet.send/prepare-transaction-with-balance
:<- [:wallet/prepare-transaction]
2019-08-24 02:26:48 +02:00
:<- [:wallet]
2019-08-24 18:51:05 +02:00
:<- [:offline?]
2019-08-24 02:26:48 +02:00
:<- [:wallet/all-tokens]
:<- [:ethereum/chain-keyword]
2019-11-16 10:56:09 +01:00
(fn [[{:keys [symbol from to amount-text] :as transaction}
2019-08-24 18:51:05 +02:00
wallet offline? all-tokens chain]]
2019-11-16 10:56:09 +01:00
(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
2019-08-24 02:26:48 +02:00
:balance balance
2019-11-16 10:56:09 +01:00
:token (assoc token :amount (get balance (:symbol token)))
2019-08-24 02:26:48 +02:00
:sign-enabled? (and to
(nil? amount-error)
(not (nil? amount))
2019-08-24 18:51:05 +02:00
(not offline?))))))
2019-11-25 14:33:43 +01:00
(re-frame/reg-sub
:wallet.request/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}
(assoc transaction
:amount-error error)]
(assoc transaction-new
:amount amount
:balance balance
:token (assoc token :amount (get balance (:symbol token)))
:sign-enabled? (and to
from
(nil? amount-error)
(not (nil? amount))
(not offline?))))))
2019-08-24 02:26:48 +02:00
2019-08-23 16:11:23 +02:00
;; 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]
2019-12-10 12:31:22 +01:00
(let [custom? (not (default-networks (:id network)))]
2019-08-23 16:11:23 +02:00
(assoc network :custom? custom?))))
(re-frame/reg-sub
:get-networks
:<- [:networks/networks]
(fn [networks]
2019-12-10 12:31:22 +01:00
(let [networks (map (label-networks (into #{} (map :id constants/default-networks))) (sort-by :name (vals networks)))
2019-08-23 16:11:23 +02:00
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))))