subs refactor (#14054)

This commit is contained in:
flexsurfer 2022-09-21 16:03:06 +02:00 committed by GitHub
parent 147958dd13
commit 2266d87ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 3125 additions and 3159 deletions

View File

@ -11,7 +11,7 @@
[status-im.native-module.core :as status]
status-im.navigation.core
[status-im.notifications.local :as notifications]
status-im.subs
status-im.subs.root
[status-im.ui.components.react :as react]
[status-im.utils.config :as config]
status-im.utils.db

View File

@ -7,7 +7,7 @@
[status-im.utils.security :as security]
[status-im.multiaccounts.logout.core :as logout]
[status-im.transport.core :as transport]
status-im.subs ;;so integration tests can run independently
status-im.subs.root ;;so integration tests can run independently
[status-im.ethereum.core :as ethereum]
[status-im.utils.test :as utils.test]
[taoensso.timbre :as log]))

View File

@ -1,6 +1,10 @@
(ns status-im.search.core-test
(:require [cljs.test :refer-macros [deftest testing is]]
[status-im.subs :as search.subs]))
[status-im.subs.search :as search.subs]))
(defn extract-chat-attributes [chat]
(let [{:keys [name alias tags]} (val chat)]
(into [name alias] tags)))
(deftest filter-chats
(let [chats {:chat-1 {:name "name1"
@ -19,35 +23,35 @@
(is (= (count chats)
(count (search.subs/apply-filter ""
chats
search.subs/extract-chat-attributes
extract-chat-attributes
false)))))
(testing "searching for a specific tag"
(is (= 1
(count (search.subs/apply-filter "tag2"
chats
search.subs/extract-chat-attributes
extract-chat-attributes
false)))))
(testing "searching for a partial tag"
(is (= 3
(count (search.subs/apply-filter "tag"
chats
search.subs/extract-chat-attributes
extract-chat-attributes
false)))))
(testing "searching for a specific alias"
(is (= 1
(count (search.subs/apply-filter "alias4"
chats
search.subs/extract-chat-attributes
extract-chat-attributes
false)))))
(testing "searching for a partial alias"
(is (= 4
(count (search.subs/apply-filter "alias"
chats
search.subs/extract-chat-attributes
extract-chat-attributes
false)))))
(testing "searching for a specific chat name"
(is (= 1
(count (search.subs/apply-filter "name4"
chats
search.subs/extract-chat-attributes
extract-chat-attributes
false)))))))

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
(ns status-im.subs.activity-center
(:require [re-frame.core :as re-frame]
[status-im.utils.datetime :as datetime]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.constants :as constants]
[clojure.string :as string]))
(re-frame/reg-sub
:activity-center/notifications-read
(fn [db]
(get-in db [:activity-center :notifications-read :data])))
(re-frame/reg-sub
:activity-center/notifications-unread
(fn [db]
(get-in db [:activity-center :notifications-unread :data])))
(re-frame/reg-sub
:activity-center/current-status-filter
(fn [db]
(get-in db [:activity-center :current-status-filter])))
(re-frame/reg-sub
:activity-center/notifications-per-read-status
:<- [:activity-center/notifications-read]
:<- [:activity-center/notifications-unread]
:<- [:activity-center/current-status-filter]
(fn [[notifications-read notifications-unread status-filter]]
(if (= status-filter :unread)
notifications-unread
notifications-read)))
(defn- group-notifications-by-date
[notifications]
(->> notifications
(group-by #(datetime/timestamp->date-key (:timestamp %)))
(sort-by key >)
(map (fn [[date-key notifications]]
(let [first-notification (first notifications)]
{:title (string/capitalize (datetime/day-relative (:timestamp first-notification)))
:key date-key
:data (sort-by :timestamp > notifications)})))))
(re-frame/reg-sub
:activity.center/notifications-grouped-by-date
:<- [:activity.center/notifications]
:<- [:contacts/contacts]
(fn [[{:keys [notifications]} contacts]]
(let [supported-notifications
(filter (fn [{:keys [type last-message message]}]
(or (and (= constants/activity-center-notification-type-one-to-one-chat type)
(not (nil? last-message)))
(and (= constants/activity-center-notification-type-contact-request type)
(not= constants/contact-request-message-state-none
(-> contacts
(multiaccounts/contact-by-identity (:from message))
:contact-request-state)))
(= constants/activity-center-notification-type-contact-request-retracted type)
(= constants/activity-center-notification-type-private-group-chat type)
(= constants/activity-center-notification-type-reply type)
(= constants/activity-center-notification-type-mention type)))
notifications)]
(group-notifications-by-date
(map #(assoc %
:timestamp (or (:timestamp %) (:timestamp (or (:message %) (:last-message %))))
:contact (multiaccounts/contact-by-identity contacts (get-in % [:message :from])))
supported-notifications)))))

View File

@ -0,0 +1,31 @@
(ns status-im.subs.bootnodes
(:require [re-frame.core :as re-frame]))
(re-frame/reg-sub
:custom-bootnodes/enabled?
:<- [:multiaccount]
:<- [:networks/current-network]
(fn [[{:keys [custom-bootnodes-enabled?]} current-network]]
(get custom-bootnodes-enabled? current-network)))
(re-frame/reg-sub
:custom-bootnodes/network-bootnodes
:<- [:multiaccount]
:<- [:networks/current-network]
(fn [[multiaccount current-network]]
(get-in multiaccount [:custom-bootnodes current-network])))
(re-frame/reg-sub
:get-manage-bootnode
:<- [:bootnodes/manage]
(fn [manage]
manage))
(re-frame/reg-sub
:wakuv2-nodes/validation-errors
:<- [:wakuv2-nodes/manage]
(fn [manage]
(set (keep
(fn [[k {:keys [error]}]]
(when error k))
manage))))

View File

@ -0,0 +1,32 @@
(ns status-im.subs.browser
(:require [re-frame.core :as re-frame]
[status-im.browser.core :as browser]))
(re-frame/reg-sub
:browser/browsers
:<- [:browsers]
(fn [browsers]
(reduce (fn [acc [k browser]]
(update acc k assoc :url (browser/get-current-url browser)))
browsers
browsers)))
(re-frame/reg-sub
:browser/browsers-vals
:<- [:browser/browsers]
(fn [browsers]
(reverse (vals browsers))))
(re-frame/reg-sub
:get-current-browser
:<- [:browser/options]
:<- [:browser/browsers]
(fn [[options browsers]]
(let [browser (get browsers (:browser-id options))]
(assoc browser :secure? (browser/secure? browser options)))))
(re-frame/reg-sub
:bookmarks/active
:<- [:bookmarks]
(fn [bookmarks]
(into {} (remove #(:removed (second %)) bookmarks))))

View File

@ -0,0 +1,413 @@
(ns status-im.subs.chat.chats
(:require [re-frame.core :as re-frame]
[clojure.string :as string]
[status-im.constants :as constants]
[quo.design-system.colors :as colors]
[status-im.chat.models :as chat.models]
[status-im.communities.core :as communities]
[status-im.utils.image-server :as image-server]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.group-chats.core :as group-chat]
[status-im.chat.models.mentions :as mentions]
[status-im.group-chats.db :as group-chats.db]
[status-im.utils.config :as config]
[status-im.add-new.db :as db]
[status-im.i18n.i18n :as i18n]))
(re-frame/reg-sub
:chats/chat
:<- [:chats/chats]
(fn [chats [_ chat-id]]
(get chats chat-id)))
(re-frame/reg-sub
:chats/by-community-id
:<- [:chats/chats]
(fn [chats [_ community-id]]
(->> chats
(keep (fn [[_ chat]]
(when (= (:community-id chat) community-id)
chat)))
(sort-by :timestamp >))))
(re-frame/reg-sub
:chats/with-empty-category-by-community-id
(fn [[_ community-id]]
[(re-frame/subscribe [:chats/by-community-id community-id])
(re-frame/subscribe [:communities/community-chats community-id])])
(fn [[chats comm-chats] [_ community-id]]
(filter #(string/blank? (get-in comm-chats [(string/replace (:chat-id %) community-id "") :categoryID])) chats)))
(re-frame/reg-sub
:chats/sorted-categories-by-community-id
(fn [[_ community-id]]
[(re-frame/subscribe [:chats/by-community-id community-id])
(re-frame/subscribe [:communities/community-chats community-id])])
(fn [[chats comm-chats] [_ community-id]]
(let [chat-cat (into {} (map (fn [{:keys [id categoryID position]}]
{(str community-id id) {:categoryID categoryID
:position position}})
(vals comm-chats)))]
(group-by :categoryID (sort-by :position
(map #(cond-> (merge % (chat-cat (:chat-id %)))
(= community-id constants/status-community-id)
(assoc :color colors/blue))
chats))))))
(re-frame/reg-sub
:chats/category-by-chat-id
(fn [[_ community-id _]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [chats categories]}] [_ community-id chat-id]]
(get categories (get-in chats [(string/replace chat-id community-id "") :categoryID]))))
(re-frame/reg-sub
:chats/community-chat-by-id
(fn [[_ community-id _]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [chats]}] [_ community-id chat-id]]
(get chats (string/replace chat-id community-id ""))))
(re-frame/reg-sub
:chats/home-list-chats
:<- [:chats/chats]
:<- [:chats-home-list]
(fn [[chats active-chats]]
(reduce #(if-let [item (get chats %2)]
(conj %1 item)
%1)
[]
active-chats)))
(re-frame/reg-sub
:chat-by-id
:<- [:chats/chats]
(fn [chats [_ chat-id]]
(get chats chat-id)))
(re-frame/reg-sub
:chats/synced-from
(fn [[_ chat-id] _]
(re-frame/subscribe [:chat-by-id chat-id]))
(fn [{:keys [synced-from]}]
synced-from))
(re-frame/reg-sub
:chats/muted
(fn [[_ chat-id] _]
(re-frame/subscribe [:chat-by-id chat-id]))
(fn [{:keys [muted]}]
muted))
(re-frame/reg-sub
:chats/chat-type
(fn [[_ chat-id] _]
(re-frame/subscribe [:chat-by-id chat-id]))
(fn [{:keys [chat-type]}]
chat-type))
(re-frame/reg-sub
:chats/joined
(fn [[_ chat-id] _]
(re-frame/subscribe [:chat-by-id chat-id]))
(fn [{:keys [joined]}]
joined))
(re-frame/reg-sub
:chats/synced-to-and-from
(fn [[_ chat-id] _]
(re-frame/subscribe [:chat-by-id chat-id]))
(fn [chat]
(select-keys chat [:synced-to :synced-from])))
(re-frame/reg-sub
:chats/current-raw-chat
:<- [:chats/chats]
:<- [:chats/current-chat-id]
(fn [[chats current-chat-id]]
(get chats current-chat-id)))
(re-frame/reg-sub
:chats/current-chat-inputs
:<- [:chats/current-chat-id]
:<- [:chat/inputs]
(fn [[chat-id inputs]]
(get inputs chat-id)))
(re-frame/reg-sub
:chats/timeline-chat-input
:<- [:chat/inputs]
:<- [:multiaccount/public-key]
(fn [[inputs public-key]]
(get inputs (chat.models/profile-chat-topic public-key))))
(re-frame/reg-sub
:chats/timeline-chat-input-text
:<- [:chats/timeline-chat-input]
(fn [input]
(:input-text input)))
(re-frame/reg-sub
:chats/current-chat-membership
:<- [:chats/current-chat-id]
:<- [:chat/memberships]
(fn [[chat-id memberships]]
(get memberships chat-id)))
(re-frame/reg-sub
:chats/current-chat
:<- [:chats/current-raw-chat]
:<- [:multiaccount/public-key]
:<- [:communities/current-community]
:<- [:contacts/blocked-set]
:<- [:contacts/contacts]
:<- [:chat/inputs]
:<- [:mutual-contact-requests/enabled?]
(fn [[{:keys [group-chat chat-id] :as current-chat} my-public-key community blocked-users-set contacts inputs mutual-contact-requests-enabled?]]
(when current-chat
(cond-> current-chat
(chat.models/public-chat? current-chat)
(assoc :show-input? true)
(and (chat.models/group-chat? current-chat)
(group-chats.db/member? my-public-key current-chat))
(assoc :show-input? true
:member? true)
(and (chat.models/community-chat? current-chat)
(communities/can-post? community my-public-key (:chat-id current-chat)))
(assoc :show-input? true)
(not group-chat)
(assoc :show-input?
(and
(or
(not mutual-contact-requests-enabled?)
(get-in inputs [chat-id :metadata :sending-contact-request])
(and mutual-contact-requests-enabled?
(= constants/contact-request-state-mutual
(get-in contacts [chat-id :contact-request-state]))))
(not (contains? blocked-users-set chat-id))))))))
(re-frame/reg-sub
:chats/current-chat-chat-view
:<- [:chats/current-chat]
(fn [current-chat]
(select-keys current-chat [:chat-id :show-input? :group-chat :admins :invitation-admin :public? :chat-type :color :chat-name :synced-to :synced-from :community-id :emoji])))
(re-frame/reg-sub
:current-chat/metadata
:<- [:chats/current-raw-chat]
(fn [current-chat]
(select-keys current-chat
[:community-id
:contacts
:public?
:group-chat
:chat-type
:chat-id
:chat-name
:color
:invitation-admin])))
(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)))))
(re-frame/reg-sub
:chats/current-profile-chat
:<- [:contacts/current-contact-identity]
(fn [identity]
(chat.models/profile-chat-topic identity)))
(re-frame/reg-sub
:chats/photo-path
:<- [:contacts/contacts]
:<- [:profile/multiaccount]
:<- [:mediaserver/port]
(fn [[contacts multiaccount port] [_ id]]
(let [contact (or (get contacts id)
(when (= id (:public-key multiaccount))
multiaccount))]
(if (nil? contact)
(image-server/get-identicons-uri port id)
(multiaccounts/displayed-photo contact)))))
(re-frame/reg-sub
:chats/unread-messages-number
:<- [:chats/home-list-chats]
(fn [chats _]
(reduce (fn [{:keys [public other]} {:keys [unviewed-messages-count public?] :as chat}]
(if (or public? (chat.models/community-chat? chat))
{:public (+ public unviewed-messages-count)
:other other}
{:other (+ other unviewed-messages-count)
:public public}))
{:public 0
:other 0}
chats)))
(re-frame/reg-sub
:chats/current-chat-cooldown-enabled?
:<- [:chats/current-chat]
:<- [:chats/cooldown-enabled?]
(fn [[{:keys [public?]} cooldown-enabled?]]
(and public?
cooldown-enabled?)))
(re-frame/reg-sub
:chats/reply-message
:<- [:chats/current-chat-inputs]
(fn [{:keys [metadata]}]
(:responding-to-message metadata)))
(re-frame/reg-sub
:chats/edit-message
:<- [:chats/current-chat-inputs]
(fn [{:keys [metadata]}]
(:editing-message metadata)))
(re-frame/reg-sub
:chats/sending-contact-request
:<- [:chats/current-chat-inputs]
(fn [{:keys [metadata]}]
(:sending-contact-request metadata)))
(re-frame/reg-sub
:chats/sending-image
:<- [:chats/current-chat-inputs]
(fn [{:keys [metadata]}]
(:sending-image metadata)))
(re-frame/reg-sub
:chats/timeline-sending-image
:<- [:chats/timeline-chat-input]
(fn [{:keys [metadata]}]
(:sending-image metadata)))
(re-frame/reg-sub
:chats/chat-toolbar
:<- [:multiaccounts/login]
:<- [:chats/sending-image]
:<- [:mainnet?]
:<- [:current-chat/one-to-one-chat?]
:<- [:current-chat/metadata]
:<- [:chats/reply-message]
:<- [:chats/edit-message]
:<- [:chats/sending-contact-request]
(fn [[{:keys [processing]} sending-image mainnet? one-to-one-chat? {:keys [public?]} reply edit sending-contact-request]]
(let [sending-image (seq sending-image)]
{:send (not processing)
:stickers (and (or config/stickers-test-enabled? mainnet?)
(not sending-image)
(not sending-contact-request)
(not reply))
:image (and (not reply)
(not edit)
(not sending-contact-request)
(not public?))
:extensions (and one-to-one-chat?
(or config/commands-enabled? mainnet?)
(not edit)
(not sending-contact-request)
(not reply))
:audio (and (not sending-image)
(not reply)
(not edit)
(not sending-contact-request)
(not public?))
:sending-image sending-image})))
(re-frame/reg-sub
:public-chat.new/topic-error-message
:<- [:public-group-topic]
(fn [topic]
(when-not (or (empty? topic)
(db/valid-topic? topic))
(i18n/label :topic-name-error))))
(defn filter-selected-contacts
[selected-contacts contacts]
(filter #(:added (contacts %)) selected-contacts))
(re-frame/reg-sub
:selected-contacts-count
:<- [:group/selected-contacts]
:<- [:contacts/contacts]
(fn [[selected-contacts contacts]]
(count (filter-selected-contacts selected-contacts contacts))))
(re-frame/reg-sub
:selected-participants-count
:<- [:selected-participants]
(fn [selected-participants]
(count selected-participants)))
(defn filter-contacts [selected-contacts active-contacts]
(filter #(selected-contacts (:public-key %)) active-contacts))
(re-frame/reg-sub
:selected-group-contacts
:<- [:group/selected-contacts]
:<- [:contacts/active]
(fn [[selected-contacts active-contacts]]
(filter-contacts selected-contacts active-contacts)))
(re-frame/reg-sub
:group-chat/inviter-info
(fn [[_ chat-id] _]
[(re-frame/subscribe [:chat-by-id chat-id])
(re-frame/subscribe [:multiaccount/public-key])])
(fn [[chat my-public-key]]
{:member? (group-chats.db/member? my-public-key chat)
:inviter-pk (group-chats.db/get-inviter-pk my-public-key chat)}))
(re-frame/reg-sub
:group-chat/invitations-by-chat-id
:<- [:group-chat/invitations]
(fn [invitations [_ chat-id]]
(filter #(= (:chat-id %) chat-id) (vals invitations))))
(re-frame/reg-sub
:group-chat/pending-invitations-by-chat-id
(fn [[_ chat-id] _]
[(re-frame/subscribe [:group-chat/invitations-by-chat-id chat-id])])
(fn [[invitations]]
(filter #(= constants/invitation-state-requested (:state %)) invitations)))
(re-frame/reg-sub
:group-chat/removed-from-current-chat?
:<- [:chats/current-raw-chat]
:<- [:multiaccount/public-key]
(fn [[current-chat pk]]
(group-chat/member-removed? current-chat pk)))
(re-frame/reg-sub
:chats/mentionable-users
:<- [:chats/current-chat]
:<- [:contacts/blocked-set]
:<- [:contacts/contacts]
:<- [:multiaccount]
(fn [[{:keys [users community-id] :as chat} blocked all-contacts
{:keys [public-key] :as current-multiaccount}]]
(let [community-members @(re-frame/subscribe [:communities/community-members community-id])
mentionable-users (mentions/get-mentionable-users chat all-contacts current-multiaccount community-members)
members-left (into #{} (filter #(group-chat/member-removed? chat %) (keys users)))]
(apply dissoc mentionable-users (conj (concat blocked members-left) public-key)))))
(re-frame/reg-sub
:chat/mention-suggestions
:<- [:chats/current-chat-id]
:<- [:chats/mention-suggestions]
(fn [[chat-id mentions]]
(take 15 (get mentions chat-id))))
(re-frame/reg-sub
:chat/input-with-mentions
:<- [:chats/current-chat-id]
:<- [:chat/inputs-with-mentions]
(fn [[chat-id cursor]]
(get cursor chat-id)))

View File

@ -0,0 +1,138 @@
(ns status-im.subs.chat.messages
(:require [re-frame.core :as re-frame]
[status-im.chat.models.reactions :as models.reactions]
[status-im.chat.models.message-list :as models.message-list]
[status-im.chat.db :as chat.db]
[status-im.utils.datetime :as datetime]
[status-im.constants :as constants]))
(re-frame/reg-sub
:chats/chat-messages
:<- [:messages/messages]
(fn [messages [_ chat-id]]
(get messages chat-id {})))
(re-frame/reg-sub
:chats/pinned
:<- [:messages/pin-messages]
(fn [pin-messages [_ chat-id]]
(get pin-messages chat-id {})))
(re-frame/reg-sub
:chats/pinned-sorted-list
:<- [:messages/pin-messages]
(fn [pin-messages [_ chat-id]]
(->>
(get pin-messages chat-id {})
vals
(sort-by :pinned-at <))))
(re-frame/reg-sub
:chats/message-reactions
:<- [:multiaccount/public-key]
:<- [:messages/reactions]
(fn [[current-public-key reactions] [_ message-id chat-id]]
(models.reactions/message-reactions
current-public-key
(get-in reactions [chat-id message-id]))))
(re-frame/reg-sub
:chats/all-loaded?
:<- [:messages/pagination-info]
(fn [pagination-info [_ chat-id]]
(get-in pagination-info [chat-id :all-loaded?])))
(re-frame/reg-sub
:chats/loading-messages?
:<- [:messages/pagination-info]
(fn [pagination-info [_ chat-id]]
(get-in pagination-info [chat-id :loading-messages?])))
(re-frame/reg-sub
:chats/loading-pin-messages?
:<- [:messages/pagination-info]
(fn [pagination-info [_ chat-id]]
(get-in pagination-info [chat-id :loading-pin-messages?])))
(re-frame/reg-sub
:chats/message-list
:<- [:messages/message-lists]
(fn [message-lists [_ chat-id]]
(get message-lists chat-id)))
(re-frame/reg-sub
:chats/pin-message-list
:<- [:messages/pin-message-lists]
(fn [pin-message-lists [_ chat-id]]
(get pin-message-lists chat-id)))
(defn hydrate-messages
"Pull data from messages and add it to the sorted list"
([message-list messages] (hydrate-messages message-list messages {}))
([message-list messages pinned-messages]
(keep #(if (= :message (% :type))
(when-let [message (messages (% :message-id))]
(let [pinned-message (get pinned-messages (% :message-id))
pinned (if pinned-message true (some? (message :pinned-by)))
pinned-by (when pinned (or (message :pinned-by) (pinned-message :pinned-by)))
message (assoc message :pinned pinned :pinned-by pinned-by)]
(merge message %)))
%)
message-list)))
(re-frame/reg-sub
:chats/chat-no-messages?
(fn [[_ chat-id] _]
(re-frame/subscribe [:chats/chat-messages chat-id]))
(fn [messages]
(empty? messages)))
(re-frame/reg-sub
:chats/raw-chat-messages-stream
(fn [[_ chat-id] _]
[(re-frame/subscribe [:chats/message-list chat-id])
(re-frame/subscribe [:chats/chat-messages chat-id])
(re-frame/subscribe [:chats/pinned chat-id])
(re-frame/subscribe [:chats/loading-messages? chat-id])
(re-frame/subscribe [:chats/synced-from chat-id])
(re-frame/subscribe [:chats/chat-type chat-id])
(re-frame/subscribe [:chats/joined chat-id])])
(fn [[message-list messages pin-messages loading-messages? synced-from chat-type joined] [_ chat-id]]
;;TODO (perf)
(let [message-list-seq (models.message-list/->seq message-list)]
; Don't show gaps if that's the case as we are still loading messages
(if (and (empty? message-list-seq) loading-messages?)
[]
(-> message-list-seq
(chat.db/add-datemarks)
(hydrate-messages messages pin-messages)
(chat.db/collapse-gaps chat-id synced-from (datetime/timestamp) chat-type joined loading-messages?))))))
;;we want to keep data unchanged so react doesn't change component when we leave screen
(def memo-profile-messages-stream (atom nil))
(re-frame/reg-sub
:chats/profile-messages-stream
(fn [[_ chat-id] _]
[(re-frame/subscribe [:chats/raw-chat-messages-stream chat-id])
(re-frame/subscribe [:chats/chat-no-messages? chat-id])
(re-frame/subscribe [:view-id])])
(fn [[messages empty view-id]]
(when (or (= view-id :profile) empty)
(reset! memo-profile-messages-stream messages))
@memo-profile-messages-stream))
(def memo-timeline-messages-stream (atom nil))
(re-frame/reg-sub
:chats/timeline-messages-stream
:<- [:chats/message-list constants/timeline-chat-id]
:<- [:chats/chat-messages constants/timeline-chat-id]
:<- [:view-id]
(fn [[message-list messages view-id]]
(if (= view-id :status)
(let [res (-> (models.message-list/->seq message-list)
(hydrate-messages messages))]
(reset! memo-timeline-messages-stream res)
res)
@memo-timeline-messages-stream)))

View File

@ -0,0 +1,162 @@
(ns status-im.subs.communities
(:require [re-frame.core :as re-frame]
[clojure.string :as string]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
[status-im.constants :as constants]))
(re-frame/reg-sub
:communities
:<- [:raw-communities]
:<- [:communities/enabled?]
(fn [[raw-communities communities-enabled?]]
(if communities-enabled?
raw-communities
[])))
(re-frame/reg-sub
:communities/fetching-community
:<- [:communities/resolve-community-info]
(fn [info [_ id]]
(get info id)))
(re-frame/reg-sub
:communities/section-list
:<- [:communities]
(fn [communities]
(->> (vals communities)
(group-by (comp (fnil string/upper-case "") first :name))
(sort-by (fn [[title]] title))
(map (fn [[title data]]
{:title title
:data data})))))
(re-frame/reg-sub
:communities/community
:<- [:communities]
(fn [communities [_ id]]
(get communities id)))
(re-frame/reg-sub
:communities/community-chats
:<- [:communities]
(fn [communities [_ id]]
(get-in communities [id :chats])))
(re-frame/reg-sub
:communities/community-members
:<- [:communities]
(fn [communities [_ id]]
(get-in communities [id :members])))
(re-frame/reg-sub
:communities/sorted-community-members
(fn [[_ community-id]]
(let [contacts (re-frame/subscribe [:contacts/contacts])
multiaccount (re-frame/subscribe [:multiaccount])
members (re-frame/subscribe [:communities/community-members community-id])]
[contacts multiaccount members]))
(fn [[contacts multiaccount members] _]
(let [names (reduce (fn [acc identity]
(let [me? (= (:public-key multiaccount) identity)
contact (when-not me?
(multiaccounts/contact-by-identity contacts identity))
name (first (multiaccounts/contact-two-names-by-identity contact multiaccount identity))]
(assoc acc identity name)))
{}
(keys members))]
(->> members
(sort-by #(get names (get % 0)))
(sort-by #(visibility-status-utils/visibility-status-order (get % 0)))))))
(re-frame/reg-sub
:communities/featured-communities
:<- [:communities/enabled?]
:<- [:search/home-filter]
:<- [:communities]
(fn [[communities-enabled? search-filter communities]]
(filterv
(fn [{:keys [name featured id]}]
(and (or featured (= name "Status")) ;; TO DO: remove once featured communities exist
(or communities-enabled?
(= id constants/status-community-id))
(or (empty? search-filter)
(string/includes? (string/lower-case (str name)) search-filter))))
(vals communities))))
(re-frame/reg-sub
:communities/communities
:<- [:communities/enabled?]
:<- [:search/home-filter]
:<- [:communities]
(fn [[communities-enabled? search-filter communities]]
(filterv
(fn [{:keys [name joined id]}]
(and joined
(or communities-enabled?
(= id constants/status-community-id))
(or (empty? search-filter)
(string/includes? (string/lower-case (str name)) search-filter))))
(vals communities))))
(re-frame/reg-sub
:communities/edited-community
:<- [:communities]
:<- [:communities/community-id-input]
(fn [[communities community-id]]
(get communities community-id)))
(re-frame/reg-sub
:communities/current-community
:<- [:communities]
:<- [:chats/current-raw-chat]
(fn [[communities {:keys [community-id]}]]
(get communities community-id)))
(re-frame/reg-sub
:communities/unviewed-count
(fn [[_ community-id]]
[(re-frame/subscribe [:chats/by-community-id community-id])])
(fn [[chats]]
(reduce (fn [acc {:keys [unviewed-messages-count]}]
(+ acc (or unviewed-messages-count 0)))
0
chats)))
(re-frame/reg-sub
:communities/unviewed-counts
(fn [[_ community-id]]
[(re-frame/subscribe [:chats/by-community-id community-id])])
(fn [[chats]]
(reduce (fn [acc {:keys [unviewed-mentions-count unviewed-messages-count]}]
{:unviewed-messages-count (+ (:unviewed-messages-count acc) (or unviewed-messages-count 0))
:unviewed-mentions-count (+ (:unviewed-mentions-count acc) (or unviewed-mentions-count 0))})
{:unviewed-messages-count 0
:unviewed-mentions-count 0}
chats)))
(re-frame/reg-sub
:communities/requests-to-join-for-community
:<- [:communities/requests-to-join]
(fn [requests [_ community-id]]
(->>
(get requests community-id {})
vals
(filter (fn [{:keys [state]}]
(= state constants/request-to-join-pending-state))))))
(re-frame/reg-sub
:community/categories
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [categories]}] _]
categories))
(re-frame/reg-sub
:communities/sorted-categories
:<- [:communities]
(fn [communities [_ id]]
(->> (get-in communities [id :categories])
(map #(assoc (get % 1) :community-id id))
(sort-by :position)
(into []))))

View File

@ -0,0 +1,239 @@
(ns status-im.subs.contact
(:require [re-frame.core :as re-frame]
[status-im.contact.db :as contact.db]
[status-im.utils.image-server :as image-server]
[status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
[clojure.string :as string]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.utils.gfycat.core :as gfycat]
[status-im.ethereum.core :as ethereum]))
(re-frame/reg-sub
::query-current-chat-contacts
:<- [:chats/current-chat]
:<- [:contacts/contacts]
(fn [[chat contacts] [_ query-fn]]
(contact.db/query-chat-contacts chat contacts query-fn)))
(re-frame/reg-sub
:multiaccount/profile-pictures-show-to
:<- [:multiaccount]
(fn [multiaccount]
(get multiaccount :profile-pictures-show-to)))
(re-frame/reg-sub
:mutual-contact-requests/enabled?
:<- [:multiaccount]
(fn [settings]
(boolean (:mutual-contact-enabled? settings))))
(re-frame/reg-sub
::profile-pictures-visibility
:<- [:multiaccount]
(fn [multiaccount]
(get multiaccount :profile-pictures-visibility)))
(defn- replace-contact-image-uri [contact port identity]
(let [identicon (image-server/get-identicons-uri port identity)
contact-images (:images contact)
contact-images (reduce (fn [acc image] (let [image-name (:type image)
; We pass the clock so that we reload the image if the image is updated
clock (:clock image)
uri (image-server/get-contact-image-uri port identity image-name clock)]
(assoc-in acc [(keyword image-name) :uri] uri)))
contact-images
(vals contact-images))]
(assoc contact :identicon identicon :images contact-images)))
(defn- reduce-contacts-image-uri [contacts port]
(reduce-kv (fn [acc public-key contact]
(let [contact (replace-contact-image-uri contact port public-key)]
(assoc acc public-key contact)))
{}
contacts))
(re-frame/reg-sub
:contacts/contacts
:<- [:contacts/contacts-raw]
:<- [::profile-pictures-visibility]
:<- [:multiaccount/public-key]
:<- [:mediaserver/port]
(fn [[contacts profile-pictures-visibility public-key port]]
(let [contacts (contact.db/enrich-contacts contacts profile-pictures-visibility public-key)]
(reduce-contacts-image-uri contacts port))))
(re-frame/reg-sub
:contacts/active
:<- [:contacts/contacts]
(fn [contacts]
(contact.db/get-active-contacts contacts)))
(re-frame/reg-sub
:contacts/sorted-contacts
:<- [:contacts/active]
(fn [active-contacts]
(->> active-contacts
(sort-by :alias)
(sort-by
#(visibility-status-utils/visibility-status-order (:public-key %))))))
(re-frame/reg-sub
:contacts/active-count
:<- [:contacts/active]
(fn [active-contacts]
(count active-contacts)))
(re-frame/reg-sub
:contacts/blocked
:<- [:contacts/contacts]
(fn [contacts]
(->> contacts
(filter (fn [[_ contact]]
(:blocked contact)))
(contact.db/sort-contacts))))
(re-frame/reg-sub
:contacts/blocked-count
:<- [:contacts/blocked]
(fn [blocked-contacts]
(count blocked-contacts)))
(defn filter-recipient-contacts
[search-filter {:keys [names]}]
(let [{:keys [nickname three-words-name ens-name]} names]
(or
(when ens-name
(string/includes? (string/lower-case (str ens-name)) search-filter))
(string/includes? (string/lower-case three-words-name) search-filter)
(when nickname
(string/includes? (string/lower-case nickname) search-filter)))))
(re-frame/reg-sub
:contacts/active-with-ens-names
:<- [:contacts/active]
:<- [:search/recipient-filter]
(fn [[contacts search-filter]]
(let [contacts (filter :ens-verified contacts)]
(if (string/blank? search-filter)
contacts
(filter (partial filter-recipient-contacts
(string/lower-case search-filter))
contacts)))))
(defn- enrich-contact [_ identity ens-name port]
(let [contact (contact.db/enrich-contact
(contact.db/public-key-and-ens-name->new-contact identity ens-name))]
(replace-contact-image-uri contact port identity)))
(re-frame/reg-sub
:contacts/current-contact
:<- [:contacts/contacts]
:<- [:contacts/current-contact-identity]
:<- [:contacts/current-contact-ens-name]
:<- [:mediaserver/port]
(fn [[contacts identity ens-name port]]
(let [contact (get contacts identity)]
(cond-> contact
(nil? contact)
(enrich-contact identity ens-name port)))))
(re-frame/reg-sub
:contacts/contact-by-identity
:<- [:contacts/contacts]
(fn [contacts [_ identity]]
(multiaccounts/contact-by-identity contacts identity)))
(re-frame/reg-sub
:contacts/contact-added?
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-by-identity identity])])
(fn [[contact] _]
(:added contact)))
(re-frame/reg-sub
:contacts/contact-blocked?
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-by-identity identity])])
(fn [[contact] _]
(:blocked contact)))
(re-frame/reg-sub
:contacts/contact-two-names-by-identity
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-by-identity identity])
(re-frame/subscribe [:multiaccount])])
(fn [[contact current-multiaccount] [_ identity]]
(multiaccounts/contact-two-names-by-identity contact current-multiaccount
identity)))
(re-frame/reg-sub
:contacts/contact-name-by-identity
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-two-names-by-identity identity])])
(fn [[names] _]
(first names)))
(re-frame/reg-sub
:messages/quote-info
:<- [:chats/messages]
:<- [:contacts/contacts]
:<- [:multiaccount]
(fn [[messages contacts current-multiaccount] [_ message-id]]
(when-let [message (get messages message-id)]
(let [identity (:from message)
me? (= (:public-key current-multiaccount) identity)]
(if me?
{:quote {:from identity
:text (get-in message [:content :text])}
:ens-name (:preferred-name current-multiaccount)
:alias (gfycat/generate-gfy identity)}
(let [contact (or (contacts identity)
(contact.db/public-key->new-contact identity))]
{:quote {:from identity
:text (get-in message [:content :text])}
:ens-name (when (:ens-verified contact)
(:name contact))
:alias (or (:alias contact)
(gfycat/generate-gfy identity))}))))))
(re-frame/reg-sub
:contacts/all-contacts-not-in-current-chat
:<- [::query-current-chat-contacts remove]
(fn [contacts]
(filter :added contacts)))
(re-frame/reg-sub
:contacts/current-chat-contacts
:<- [:chats/current-chat]
:<- [:contacts/contacts]
:<- [:multiaccount]
(fn [[{:keys [contacts admins]} all-contacts current-multiaccount]]
(contact.db/get-all-contacts-in-group-chat contacts admins all-contacts current-multiaccount)))
(re-frame/reg-sub
:contacts/contacts-by-chat
(fn [[_ _ chat-id] _]
[(re-frame/subscribe [:chats/chat chat-id])
(re-frame/subscribe [:contacts/contacts])])
(fn [[chat all-contacts] [_ query-fn]]
(contact.db/query-chat-contacts chat all-contacts query-fn)))
(re-frame/reg-sub
:contacts/contact-by-address
:<- [:contacts/contacts]
:<- [:multiaccount/contact]
(fn [[contacts multiaccount] [_ address]]
(if (ethereum/address= address (:public-key multiaccount))
multiaccount
(contact.db/find-contact-by-address contacts address))))
(re-frame/reg-sub
:contacts/contacts-by-address
:<- [:contacts/contacts]
(fn [contacts]
(reduce (fn [acc [_ {:keys [address] :as contact}]]
(if address
(assoc acc address contact)
acc))
{}
contacts)))

View File

@ -0,0 +1,92 @@
(ns status-im.subs.ens
(:require [re-frame.core :as re-frame]
[status-im.ens.core :as ens]
[status-im.ethereum.core :as ethereum]
[status-im.utils.money :as money]
[clojure.string :as string]))
(re-frame/reg-sub
:multiaccount/usernames
:<- [:multiaccount]
(fn [multiaccount]
(:usernames multiaccount)))
(re-frame/reg-sub
:ens/preferred-name
:<- [:multiaccount]
(fn [multiaccount]
(:preferred-name multiaccount)))
(re-frame/reg-sub
:ens/search-screen
:<- [:ens/registration]
(fn [{:keys [custom-domain? username state]}]
{:state state
:username username
:custom-domain? custom-domain?}))
(defn- ens-amount-label
[chain-id]
(str (ens/registration-cost chain-id)
(case chain-id
3 " STT"
1 " SNT"
"")))
(re-frame/reg-sub
:ens/checkout-screen
:<- [:ens/registration]
:<- [:chain-keyword]
:<- [:multiaccount/default-account]
:<- [:multiaccount/public-key]
:<- [:chain-id]
:<- [:wallet]
(fn [[{:keys [custom-domain? username address]}
chain default-account public-key chain-id wallet]]
(let [address (or address (ethereum/normalized-hex (:address default-account)))
balance (get-in wallet [:accounts address :balance])]
{:address address
:username username
:public-key public-key
:custom-domain? custom-domain?
:chain chain
:amount-label (ens-amount-label chain-id)
:sufficient-funds? (money/sufficient-funds?
(money/formatted->internal (money/bignumber 10) (ethereum/chain-keyword->snt-symbol chain) 18)
(get balance (ethereum/chain-keyword->snt-symbol chain)))})))
(re-frame/reg-sub
:ens/confirmation-screen
:<- [:ens/registration]
(fn [{:keys [username state]}]
{:state state
:username username}))
(re-frame/reg-sub
:ens.name/screen
:<- [:get-screen-params :ens-name-details]
:<- [:ens/names]
(fn [[name ens]]
(let [{:keys [address public-key expiration-date releasable?]} (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
:releasable? releasable?
:expiration-date expiration-date)))))
(re-frame/reg-sub
:ens.main/screen
:<- [:multiaccount/usernames]
:<- [:multiaccount]
:<- [:ens/preferred-name]
:<- [:ens/registrations]
(fn [[names multiaccount preferred-name registrations]]
{:names names
:multiaccount multiaccount
:preferred-name preferred-name
:registrations registrations}))

View File

@ -0,0 +1,298 @@
(ns status-im.subs.general
(:require [re-frame.core :as re-frame]
[status-im.utils.build :as build]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.tokens :as tokens]
[status-im.utils.mobile-sync :as mobile-network-utils]))
(re-frame/reg-sub
:visibility-status-updates/visibility-status-update
:<- [:visibility-status-updates]
(fn [visibility-status-updates [_ public-key]]
(get visibility-status-updates public-key)))
(re-frame/reg-sub
:multiaccount/logged-in?
(fn [db]
(multiaccounts.model/logged-in? {:db db})))
(re-frame/reg-sub
:hide-screen?
:<- [:app-state]
:<- [:multiaccount]
(fn [[state multiaccount]]
(and (= state "inactive") (:preview-privacy? multiaccount))))
(re-frame/reg-sub
:current-network
:<- [:networks/networks]
:<- [:networks/current-network]
(fn [[networks current-network]]
(when-let [network (get networks current-network)]
(assoc network :rpc-network? (get-in network [:config :UpstreamConfig :Enabled])))))
(re-frame/reg-sub
:custom-rpc-node
:<- [:current-network]
(fn [network]
(ethereum/custom-rpc-node? network)))
(re-frame/reg-sub
:chain-keyword
:<- [:current-network]
(fn [network]
(ethereum/network->chain-keyword network)))
(re-frame/reg-sub
:chain-name
:<- [:current-network]
(fn [network]
(ethereum/network->chain-name network)))
(re-frame/reg-sub
:chain-id
:<- [:current-network]
(fn [network]
(ethereum/network->chain-id network)))
(re-frame/reg-sub
:mainnet?
:<- [:chain-id]
(fn [chain-id]
(= 1 chain-id)))
(re-frame/reg-sub
:ethereum-network?
:<- [:chain-id]
(fn [chain-id]
(< chain-id 6)))
(re-frame/reg-sub
:network-name
:<- [:current-network]
(fn [network]
(:name network)))
(re-frame/reg-sub
:disconnected?
:<- [:peers-count]
:<- [:waku/v2-flag]
:<- [:waku/v2-peer-stats]
(fn [[peers-count wakuv2-flag peer-stats]]
;; If wakuv2 is enabled,
;; then fetch connectivity status from
;; peer-stats (populated from "wakuv2.peerstats" status-go signal)
;; Otherwise use peers-count fetched from "discovery.summary" signal
(if wakuv2-flag (not (:isOnline peer-stats)) (zero? peers-count))))
(re-frame/reg-sub
:offline?
:<- [:network-status]
:<- [:sync-state]
:<- [:disconnected?]
(fn [[network-status sync-state disconnected?]]
(or disconnected?
(= network-status :offline)
(= sync-state :offline))))
(re-frame/reg-sub
:syncing?
:<- [:sync-state]
(fn [sync-state]
(#{:pending :in-progress} sync-state)))
(re-frame/reg-sub
:dimensions/window-width
:<- [:dimensions/window]
:width)
(re-frame/reg-sub
:dimensions/window-height
:<- [:dimensions/window]
:height)
(re-frame/reg-sub
:dimensions/small-screen?
:<- [:dimensions/window-height]
(fn [height]
(< height 550)))
(re-frame/reg-sub
:get-screen-params
:<- [:screen-params]
:<- [:view-id]
(fn [[params view-id-db] [_ view-id]]
(get params (or view-id view-id-db))))
(re-frame/reg-sub
:delete-swipe-position
:<- [:animations]
(fn [animations [_ type item-id]]
(get-in animations [type item-id :delete-swiped])))
(re-frame/reg-sub
:search/home-filter
:<- [:ui/search]
(fn [search]
(get search :home-filter)))
(re-frame/reg-sub
:search/recipient-filter
:<- [:ui/search]
(fn [search]
(get search :recipient-filter)))
(re-frame/reg-sub
:search/currency-filter
:<- [:ui/search]
(fn [search]
(get search :currency-filter)))
(re-frame/reg-sub
:search/token-filter
:<- [:ui/search]
(fn [search]
(get search :token-filter)))
(defn- node-version [web3-node-version]
(or web3-node-version "N/A"))
(re-frame/reg-sub
:get-app-version
:<- [:web3-node-version]
(fn [web3-node-version]
(str build/app-short-version "; " (node-version web3-node-version))))
(re-frame/reg-sub
:get-app-short-version
build/app-short-version)
(re-frame/reg-sub
:get-commit-hash
(fn [_] build/commit-hash))
(re-frame/reg-sub
:get-app-node-version
:<- [:web3-node-version]
node-version)
(re-frame/reg-sub
:my-profile/recovery
:<- [:my-profile/seed]
(fn [seed]
(or seed {:step :intro})))
(re-frame/reg-sub
:bottom-sheet
:<- [:bottom-sheet/show?]
:<- [:bottom-sheet/view]
:<- [:bottom-sheet/options]
(fn [[show? view options]]
{:show? show?
:view view
:options options}))
(re-frame/reg-sub
:is-contact-selected?
:<- [:group/selected-contacts]
(fn [selected-contacts [_ element]]
(-> selected-contacts
(contains? element))))
(re-frame/reg-sub
:is-participant-selected?
:<- [:selected-participants]
(fn [selected-participants [_ element]]
(-> selected-participants
(contains? element))))
(re-frame/reg-sub
:ethereum/chain-keyword
:<- [:current-network]
(fn [network]
(ethereum/network->chain-keyword network)))
(re-frame/reg-sub
:ethereum/native-currency
:<- [:current-network]
(fn [network]
(tokens/native-currency network)))
(re-frame/reg-sub
:information-box-closed?
:<- [:information-box-states]
(fn [states [_ id]]
(get states id)))
(re-frame/reg-sub
:connectivity/state
:<- [:network-status]
:<- [:disconnected?]
:<- [:mailserver/connecting?]
:<- [:mailserver/connection-error?]
:<- [:mailserver/request-error?]
:<- [:network/type]
:<- [:multiaccount]
(fn [[network-status disconnected? mailserver-connecting? mailserver-connection-error?
mailserver-request-error? network-type {:keys [syncing-on-mobile-network? use-mailservers?]}]]
(merge {:mobile (mobile-network-utils/cellular? network-type)
:sync syncing-on-mobile-network?
:peers :online}
(cond (= network-status :offline)
{:peers :offline
:node :offline}
(not use-mailservers?)
{:node :disabled}
(or mailserver-connection-error? mailserver-connecting?)
{:node :connecting}
mailserver-request-error?
{:node :error}
disconnected?
{:peers :offline
:node :offline}
:else
{:peers :online
:node :online}))))
(re-frame/reg-sub
:mnemonic
:<- [:multiaccount]
(fn [{:keys [mnemonic]}]
mnemonic))
(re-frame/reg-sub
:get-profile-unread-messages-number
:<- [:multiaccount]
(fn [{:keys [mnemonic]}]
(if mnemonic 1 0)))
;; NAVIGATION2
(re-frame/reg-sub
:navigation2/switcher-cards
:<- [:navigation2/navigation2-stacks]
(fn [stacks [_ toggle-switcher-screen]]
(sort-by :clock >
(reduce (fn [acc stack-vector]
(let [{:keys [type clock id]} (get stack-vector 1)]
(conj acc {:type type
:clock clock
:id id
:toggle-switcher-screen toggle-switcher-screen})))
'() stacks))))
(re-frame/reg-sub
:mobile-network/syncing-allowed?
:<- [:network/type]
:<- [:multiaccount]
(fn [[network-type {:keys [syncing-on-mobile-network?]}]]
(or (= network-type "wifi")
(and
(= network-type "cellular")
syncing-on-mobile-network?))))

View File

@ -0,0 +1,39 @@
(ns status-im.subs.home
(:require [re-frame.core :as re-frame]
[status-im.utils.config :as config]))
(def memo-home-items (atom nil))
(re-frame/reg-sub
:home-items
:<- [:search/home-filter]
:<- [:search/filtered-chats]
:<- [:communities/communities]
:<- [:view-id]
:<- [:home-items-show-number]
(fn [[search-filter filtered-chats communities view-id home-items-show-number]]
(if (or (= view-id :home)
(and @config/new-ui-enabled? (= view-id :chat-stack)))
(let [communities-count (count communities)
chats-count (count filtered-chats)
;; If we have both communities & chats we want to display
;; a separator between them
communities-with-separator (if (and (pos? communities-count)
(pos? chats-count))
(update communities
(dec communities-count)
assoc :last? true)
communities)
res {:search-filter search-filter
:items (concat communities-with-separator (take home-items-show-number filtered-chats))}]
(reset! memo-home-items res)
res)
;;we want to keep data unchanged so react doesn't change component when we leave screen
@memo-home-items)))
(re-frame/reg-sub
:hide-home-tooltip?
:<- [:multiaccount]
(fn [multiaccount]
(:hide-home-tooltip? multiaccount)))

View File

@ -1,4 +1,4 @@
(ns status-im.ui.screens.keycard.subs
(ns status-im.subs.keycard
(:require [re-frame.core :as re-frame]
[status-im.keycard.common :as common]
[status-im.utils.datetime :as utils.datetime]
@ -204,4 +204,4 @@
:keycard/frozen-card?
(fn [db]
(and (common/keycard-multiaccount? db)
(zero? (get-in db [:keycard :application-info :pin-retry-counter])))))
(zero? (get-in db [:keycard :application-info :pin-retry-counter])))))

View File

@ -0,0 +1,88 @@
(ns status-im.subs.mailservers
(:require [re-frame.core :as re-frame]
[status-im.mailserver.core :as mailserver]
[status-im.fleet.core :as fleet]))
(re-frame/reg-sub
:mailserver/current-name
:<- [:mailserver/current-id]
:<- [:fleets/current-fleet]
:<- [:mailserver/mailservers]
(fn [[current-mailserver-id current-fleet mailservers]]
(get-in mailservers [current-fleet current-mailserver-id :name])))
(re-frame/reg-sub
:mailserver/connecting?
:<- [:mailserver/state]
(fn [state]
(#{:connecting :added} state)))
(re-frame/reg-sub
:mailserver/connection-error?
:<- [:mailserver/state]
(fn [state]
(#{:error :disconnected} state)))
(re-frame/reg-sub
:chats/fetching-gap-in-progress?
:<- [:mailserver/fetching-gaps-in-progress]
(fn [gaps [_ ids _]]
(seq (select-keys gaps ids))))
(re-frame/reg-sub
:mailserver/fetching?
:<- [:mailserver/state]
:<- [:mailserver/pending-requests]
:<- [:mailserver/connecting?]
:<- [:mailserver/connection-error?]
:<- [:mailserver/request-error?]
(fn [[state pending-requests connecting? connection-error? request-error?]]
(and pending-requests
(= state :connected)
(pos-int? pending-requests)
(not (or connecting? connection-error? request-error?)))))
(re-frame/reg-sub
:mailserver/fleet-mailservers
:<- [:fleets/current-fleet]
:<- [:mailserver/mailservers]
(fn [[current-fleet mailservers]]
(current-fleet mailservers)))
(re-frame/reg-sub
:mailserver.edit/connected?
:<- [:mailserver.edit/mailserver]
:<- [:mailserver/current-id]
(fn [[mailserver current-mailserver-id]]
(= (get-in mailserver [:id :value])
current-mailserver-id)))
(re-frame/reg-sub
:mailserver/use-status-nodes?
(fn [db _]
(boolean (mailserver/fetch-use-mailservers? {:db db}))))
(re-frame/reg-sub
:mailserver.edit/validation-errors
:<- [:mailserver.edit/mailserver]
(fn [mailserver]
(set (keep
(fn [[k {:keys [error]}]]
(when error k))
mailserver))))
(re-frame/reg-sub
:mailserver/connected?
:<- [:mailserver/state]
:<- [:disconnected?]
(fn [[mail-state disconnected?]]
(let [mailserver-connected? (= :connected mail-state)]
(and mailserver-connected?
(not disconnected?)))))
(re-frame/reg-sub
:mailserver/preferred-id
:<- [:multiaccount]
(fn [multiaccount]
(get-in multiaccount
[:pinned-mailservers (fleet/current-fleet-sub multiaccount)])))

View File

@ -0,0 +1,249 @@
(ns status-im.subs.multiaccount
(:require [re-frame.core :as re-frame]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ethereum.core :as ethereum]
[status-im.utils.security :as security]
[cljs.spec.alpha :as spec]
[status-im.fleet.core :as fleet]
[clojure.string :as string]
[status-im.utils.image-server :as image-server]
[clojure.set :as clojure.set]
[status-im.multiaccounts.db :as multiaccounts.db]))
(re-frame/reg-sub
:multiaccount/public-key
:<- [:multiaccount]
(fn [{:keys [public-key]}]
public-key))
(re-frame/reg-sub
:multiaccount/contact
:<- [:multiaccount]
(fn [current-account]
(some->
current-account
(select-keys [:name :preferred-name :public-key :identicon :image :images])
(clojure.set/rename-keys {:name :alias})
(multiaccounts/contact-with-names))))
(re-frame/reg-sub
:multiaccount/preferred-name
:<- [:multiaccount]
(fn [{:keys [preferred-name]}]
preferred-name))
(re-frame/reg-sub
:multiaccount/default-account
:<- [:multiaccount/accounts]
(fn [accounts]
(ethereum/get-default-account accounts)))
(re-frame/reg-sub
:multiaccount/visible-accounts
:<- [:multiaccount/accounts]
(fn [accounts]
(remove :hidden accounts)))
(re-frame/reg-sub
:sign-in-enabled?
:<- [:multiaccounts/login]
(fn [{:keys [password]}]
(spec/valid? ::multiaccounts.db/password
(security/safe-unmask-data password))))
(re-frame/reg-sub
:fleets/current-fleet
:<- [:multiaccount]
(fn [multiaccount]
(fleet/current-fleet-sub multiaccount)))
(re-frame/reg-sub
:opensea-enabled?
:<- [:multiaccount]
(fn [{:keys [opensea-enabled?]}]
(boolean opensea-enabled?)))
(re-frame/reg-sub
:log-level/current-log-level
:<- [:multiaccount]
(fn [multiaccount]
(get multiaccount :log-level)))
(re-frame/reg-sub
:waku/bloom-filter-mode
:<- [:multiaccount]
(fn [multiaccount]
(boolean (get multiaccount :waku-bloom-filter-mode))))
(re-frame/reg-sub
:waku/v2-flag
:<- [:fleets/current-fleet]
(fn [fleet]
(string/starts-with? (name fleet) "wakuv2")))
(re-frame/reg-sub
:dapps-address
:<- [:multiaccount]
(fn [acc]
(get acc :dapps-address)))
(re-frame/reg-sub
:dapps-account
:<- [:multiaccount/accounts]
:<- [:dapps-address]
(fn [[accounts address]]
(some #(when (= (:address %) address) %) accounts)))
(re-frame/reg-sub
:multiaccount/current-account
:<- [:multiaccount/accounts]
:<- [:get-screen-params :wallet-account]
(fn [[accounts acc]]
(some #(when (= (string/lower-case (:address %))
(string/lower-case (:address acc))) %) accounts)))
(re-frame/reg-sub
:account-by-address
:<- [:multiaccount/accounts]
(fn [accounts [_ address]]
(when (string? address)
(some #(when (= (string/lower-case (:address %))
(string/lower-case address)) %) accounts))))
(re-frame/reg-sub
:multiple-multiaccounts?
:<- [:multiaccounts/multiaccounts]
(fn [multiaccounts]
(> (count multiaccounts) 1)))
;; NOTE: this subscription only works on login
(re-frame/reg-sub
:multiaccounts.login/keycard-account?
:<- [:multiaccounts/multiaccounts]
:<- [:multiaccounts/login]
(fn [[multiaccounts {:keys [key-uid]}]]
(get-in multiaccounts [key-uid :keycard-pairing])))
(re-frame/reg-sub
:multiaccounts/keycard-account?
:<- [:multiaccount]
(fn [multiaccount]
(:keycard-pairing multiaccount)))
(re-frame/reg-sub
:accounts-without-watch-only
:<- [:multiaccount/accounts]
(fn [accounts]
(filter #(not= (:type %) :watch) accounts)))
(re-frame/reg-sub
:visible-accounts-without-watch-only
:<- [:multiaccount/accounts]
(fn [accounts]
(remove :hidden (filter #(not= (:type %) :watch) accounts))))
(defn filter-recipient-accounts
[search-filter {:keys [name]}]
(string/includes? (string/lower-case (str name)) search-filter))
(re-frame/reg-sub
:accounts-for-recipient
:<- [:multiaccount/visible-accounts]
:<- [:wallet/prepare-transaction]
:<- [:search/recipient-filter]
(fn [[accounts {:keys [from]} search-filter]]
(let [accounts (remove #(= (:address %) (:address from)) accounts)]
(if (string/blank? search-filter)
accounts
(filter (partial filter-recipient-accounts
(string/lower-case search-filter))
accounts)))))
(re-frame/reg-sub
:add-account-disabled?
:<- [:multiaccount/accounts]
:<- [:add-account]
(fn [[accounts {:keys [address type account seed private-key]}]]
(or (string/blank? (:name account))
(case type
:generate
false
:watch
(or (not (ethereum/address? address))
(some #(when (= (:address %) address) %) accounts))
:key
(string/blank? (security/safe-unmask-data private-key))
:seed
(string/blank? (security/safe-unmask-data seed))
false))))
(re-frame/reg-sub
:multiaccount/current-user-visibility-status
:<- [:multiaccount]
(fn [{:keys [current-user-visibility-status]}]
current-user-visibility-status))
(re-frame/reg-sub
:multiaccount/reset-password-form-vals-and-errors
:<- [:multiaccount/reset-password-form-vals]
:<- [:multiaccount/reset-password-errors]
:<- [:multiaccount/resetting-password?]
(fn [[form-vals errors resetting?]]
(let [{:keys [current-password new-password confirm-new-password]} form-vals]
{:form-vals form-vals
:errors errors
:resetting? resetting?
:next-enabled?
(and (pos? (count current-password))
(pos? (count new-password))
(pos? (count confirm-new-password))
(>= (count new-password) 6)
(>= (count current-password) 6)
(= new-password confirm-new-password))})))
(re-frame/reg-sub
:profile/has-picture
:<- [:multiaccount]
(fn [multiaccount]
(pos? (count (get multiaccount :images)))))
(defn- replace-multiaccount-image-uri [multiaccount port]
(let [public-key (:public-key multiaccount)
identicon (image-server/get-identicons-uri port public-key)
multiaccount (assoc multiaccount :identicon identicon)
images (:images multiaccount)
images (reduce (fn [acc current]
(let [key-uid (:keyUid current)
image-name (:type current)
uri (image-server/get-account-image-uri port public-key image-name key-uid)]
(conj acc (assoc current :uri uri))))
[]
images)]
(assoc multiaccount :images images)))
(re-frame/reg-sub
:profile/multiaccount
:<- [:multiaccount]
:<- [:mediaserver/port]
(fn [[multiaccount port]]
(replace-multiaccount-image-uri multiaccount port)))
;; LINK PREVIEW ========================================================================================================
(re-frame/reg-sub
:link-preview/cache
:<- [:multiaccount]
(fn [multiaccount]
(get multiaccount :link-previews-cache)))
(re-frame/reg-sub
:link-preview/enabled-sites
:<- [:multiaccount]
(fn [multiaccount]
(get multiaccount :link-previews-enabled-sites)))
(re-frame/reg-sub
:link-preview/link-preview-request-enabled
:<- [:multiaccount]
(fn [multiaccount]
(get multiaccount :link-preview-request-enabled)))

View File

@ -0,0 +1,35 @@
(ns status-im.subs.networks
(:require [status-im.ethereum.core :as ethereum]
[re-frame.core :as re-frame]
[status-im.utils.config :as config]))
(defn- filter-networks [network-type]
(fn [network]
(let [chain-id (ethereum/network->chain-id network)
testnet? (ethereum/testnet? chain-id)
custom? (:custom? network)]
(case network-type
:custom custom?
:mainnet (and (not custom?) (not testnet?))
:testnet (and (not custom?) testnet?)))))
(defn- label-networks [default-networks]
(fn [network]
(let [custom? (not (default-networks (:id network)))]
(assoc network :custom? custom?))))
(re-frame/reg-sub
:get-networks
:<- [:networks/networks]
(fn [networks]
(let [networks (map (label-networks (into #{} (map :id config/default-networks))) (sort-by :name (vals networks)))
types [:mainnet :testnet :custom]]
(zipmap
types
(map #(filter (filter-networks %) networks) types)))))
(re-frame/reg-sub
:manage-network-valid?
:<- [:networks/manage]
(fn [manage]
(not-any? :error (vals manage))))

View File

@ -0,0 +1,61 @@
(ns status-im.subs.onboarding
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.multiaccounts.recover.core :as recover]))
(re-frame/reg-sub
:intro-wizard
:<- [:intro-wizard-state]
:<- [:dimensions/window]
(fn [[wizard-state {:keys [width height]}]]
(assoc wizard-state :view-height height :view-width width)))
(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]
(select-keys wizard-state [:selected-storage-type :recovering?])))
(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 :public-key])
:name (get-in wizard-state [:derived constants/path-whisper-keyword :name])
:identicon (get-in wizard-state [:derived constants/path-whisper-keyword :identicon])
:processing? (:processing? wizard-state)}))
(re-frame/reg-sub
:intro-wizard/recover-existing-account?
:<- [:intro-wizard]
:<- [:multiaccounts/multiaccounts]
(fn [[intro-wizard multiaccounts]]
(recover/existing-account? (:root-key intro-wizard) multiaccounts)))
(defn login-ma-keycard-pairing
"Compute the keycard-pairing value of the multiaccount selected for login"
[db _]
(when-let [acc-to-login (-> db :multiaccounts/login)]
(-> db
:multiaccounts/multiaccounts
(get (:key-uid acc-to-login))
:keycard-pairing)))
(re-frame/reg-sub
:intro-wizard/acc-to-login-keycard-pairing
login-ma-keycard-pairing)

View File

@ -0,0 +1,22 @@
(ns status-im.subs.pairing
(:require [re-frame.core :as re-frame]
[status-im.pairing.core :as pairing]))
(re-frame/reg-sub
:pairing/installations
:<- [:get-pairing-installations]
:<- [:pairing/installation-id]
(fn [[installations installation-id]]
(->> installations
vals
(pairing/sort-installations installation-id))))
(re-frame/reg-sub
:pairing/installation-id
:<- [:multiaccount]
(fn [multiaccount] (:installation-id multiaccount)))
(re-frame/reg-sub
:pairing/installation-name
:<- [:multiaccount]
(fn [multiaccount] (:installation-name multiaccount)))

View File

@ -0,0 +1,254 @@
(ns status-im.subs.root
(:require [re-frame.core :as re-frame]
status-im.subs.activity-center
status-im.subs.bootnodes
status-im.subs.browser
status-im.subs.communities
status-im.subs.contact
status-im.subs.chat.chats
status-im.subs.chat.messages
status-im.subs.ens
status-im.subs.general
status-im.subs.home
status-im.subs.keycard
status-im.subs.mailservers
status-im.subs.multiaccount
status-im.subs.networks
status-im.subs.onboarding
status-im.subs.pairing
status-im.subs.search
status-im.subs.stickers
status-im.subs.wallet.signing
status-im.subs.wallet.transactions
status-im.subs.wallet.wallet))
(defn reg-root-key-sub [sub-name db-key]
(re-frame/reg-sub sub-name (fn [db] (get db db-key))))
;;view
(reg-root-key-sub :view-id :view-id)
(reg-root-key-sub :screen-params :navigation/screen-params)
;;bottom sheet
(reg-root-key-sub :bottom-sheet/show? :bottom-sheet/show?)
(reg-root-key-sub :bottom-sheet/view :bottom-sheet/view)
(reg-root-key-sub :bottom-sheet/options :bottom-sheet/options)
;;general
(reg-root-key-sub :sync-state :sync-state)
(reg-root-key-sub :network-status :network-status)
(reg-root-key-sub :peers-count :peers-count)
(reg-root-key-sub :about-app/node-info :node-info)
(reg-root-key-sub :peers-summary :peers-summary)
(reg-root-key-sub :dimensions/window :dimensions/window)
(reg-root-key-sub :fleets/custom-fleets :custom-fleets)
(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 :sync-data :sync-data)
(reg-root-key-sub :mobile-network/remember-choice? :mobile-network/remember-choice?)
(reg-root-key-sub :qr-modal :qr-modal)
(reg-root-key-sub :bootnodes/manage :bootnodes/manage)
(reg-root-key-sub :wakuv2-nodes/manage :wakuv2-nodes/manage)
(reg-root-key-sub :wakuv2-nodes/list :wakuv2-nodes/list)
(reg-root-key-sub :networks/current-network :networks/current-network)
(reg-root-key-sub :networks/networks :networks/networks)
(reg-root-key-sub :networks/manage :networks/manage)
(reg-root-key-sub :get-pairing-installations :pairing/installations)
(reg-root-key-sub :tooltips :tooltips)
(reg-root-key-sub :supported-biometric-auth :supported-biometric-auth)
(reg-root-key-sub :app-active-since :app-active-since)
(reg-root-key-sub :connectivity/ui-status-properties :connectivity/ui-status-properties)
(reg-root-key-sub :logged-in-since :logged-in-since)
(reg-root-key-sub :link-previews-whitelist :link-previews-whitelist)
(reg-root-key-sub :app-state :app-state)
(reg-root-key-sub :home-items-show-number :home-items-show-number)
(reg-root-key-sub :waku/v2-peer-stats :peer-stats)
(reg-root-key-sub :visibility-status-updates :visibility-status-updates)
(reg-root-key-sub :navigation2/navigation2-stacks :navigation2/navigation2-stacks)
;;NOTE this one is not related to ethereum network
;; it is about cellular network/ wifi network
(reg-root-key-sub :network/type :network/type)
;;profile
(reg-root-key-sub :my-profile/seed :my-profile/seed)
(reg-root-key-sub :my-profile/advanced? :my-profile/advanced?)
(reg-root-key-sub :my-profile/profile :my-profile/profile)
;;multiaccount
(reg-root-key-sub :multiaccounts/multiaccounts :multiaccounts/multiaccounts)
(reg-root-key-sub :multiaccounts/login :multiaccounts/login)
(reg-root-key-sub :multiaccount :multiaccount)
(reg-root-key-sub :multiaccount/accounts :multiaccount/accounts)
(reg-root-key-sub :get-recover-multiaccount :multiaccounts/recover)
(reg-root-key-sub :multiaccounts/key-storage :multiaccounts/key-storage)
(reg-root-key-sub :multiaccount/reset-password-form-vals :multiaccount/reset-password-form-vals)
(reg-root-key-sub :multiaccount/reset-password-errors :multiaccount/reset-password-errors)
(reg-root-key-sub :multiaccount/resetting-password? :multiaccount/resetting-password?)
;;chat
(reg-root-key-sub :chats/cooldown-enabled? :chat/cooldown-enabled?)
(reg-root-key-sub :chats/chats :chats)
(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)
(reg-root-key-sub :chat/inputs :chat/inputs)
(reg-root-key-sub :chat/memberships :chat/memberships)
(reg-root-key-sub :camera-roll-photos :camera-roll-photos)
(reg-root-key-sub :group-chat/invitations :group-chat/invitations)
(reg-root-key-sub :chats/mention-suggestions :chats/mention-suggestions)
(reg-root-key-sub :chat/inputs-with-mentions :chat/inputs-with-mentions)
(reg-root-key-sub :chats-home-list :chats-home-list)
;;messages
(reg-root-key-sub :messages/messages :messages)
(reg-root-key-sub :messages/reactions :reactions)
(reg-root-key-sub :messages/message-lists :message-lists)
(reg-root-key-sub :messages/pagination-info :pagination-info)
(reg-root-key-sub :messages/pin-message-lists :pin-message-lists)
(reg-root-key-sub :messages/pin-messages :pin-messages)
;;browser
(reg-root-key-sub :browsers :browser/browsers)
(reg-root-key-sub :browser/options :browser/options)
(reg-root-key-sub :dapps/permissions :dapps/permissions)
(reg-root-key-sub :bookmarks :bookmarks/bookmarks)
;;stickers
(reg-root-key-sub :stickers/selected-pack :stickers/selected-pack)
(reg-root-key-sub :stickers/packs :stickers/packs)
(reg-root-key-sub :stickers/recent-stickers :stickers/recent-stickers)
;;mailserver
(reg-root-key-sub :mailserver/current-id :mailserver/current-id)
(reg-root-key-sub :mailserver/mailservers :mailserver/mailservers)
(reg-root-key-sub :mailserver.edit/mailserver :mailserver.edit/mailserver)
(reg-root-key-sub :mailserver/state :mailserver/state)
(reg-root-key-sub :mailserver/pending-requests :mailserver/pending-requests)
(reg-root-key-sub :mailserver/request-error? :mailserver/request-error)
(reg-root-key-sub :mailserver/fetching-gaps-in-progress :mailserver/fetching-gaps-in-progress)
;;contacts
(reg-root-key-sub :contacts/contacts-raw :contacts/contacts)
(reg-root-key-sub :contacts/current-contact-identity :contacts/identity)
(reg-root-key-sub :contacts/current-contact-ens-name :contacts/ens-name)
(reg-root-key-sub :contacts/new-identity :contacts/new-identity)
(reg-root-key-sub :group/selected-contacts :group/selected-contacts)
(reg-root-key-sub :contacts/blocked-set :contacts/blocked)
;;wallet
(reg-root-key-sub :wallet :wallet)
(reg-root-key-sub :prices :prices)
(reg-root-key-sub :prices-loading? :prices-loading?)
(reg-root-key-sub :wallet.transactions :wallet.transactions)
(reg-root-key-sub :wallet/custom-token-screen :wallet/custom-token-screen)
(reg-root-key-sub :wallet/prepare-transaction :wallet/prepare-transaction)
(reg-root-key-sub :wallet-service/manual-setting :wallet-service/manual-setting)
(reg-root-key-sub :wallet/recipient :wallet/recipient)
(reg-root-key-sub :wallet/favourites :wallet/favourites)
(reg-root-key-sub :wallet/refreshing-history? :wallet/refreshing-history?)
(reg-root-key-sub :wallet/fetching-error :wallet/fetching-error)
(reg-root-key-sub :wallet/non-archival-node :wallet/non-archival-node)
(reg-root-key-sub :wallet/current-base-fee :wallet/current-base-fee)
(reg-root-key-sub :wallet/slow-base-fee :wallet/slow-base-fee)
(reg-root-key-sub :wallet/normal-base-fee :wallet/normal-base-fee)
(reg-root-key-sub :wallet/fast-base-fee :wallet/fast-base-fee)
(reg-root-key-sub :wallet/current-priority-fee :wallet/current-priority-fee)
(reg-root-key-sub :wallet/transactions-management-enabled? :wallet/transactions-management-enabled?)
(reg-root-key-sub :wallet/all-tokens :wallet/all-tokens)
(reg-root-key-sub :wallet/collectible-collections :wallet/collectible-collections)
(reg-root-key-sub :wallet/fetching-collection-assets :wallet/fetching-collection-assets)
(reg-root-key-sub :wallet/collectible-assets :wallet/collectible-assets)
(reg-root-key-sub :wallet/selected-collectible :wallet/selected-collectible)
(reg-root-key-sub :wallet/modal-selecting-source-token? :wallet/modal-selecting-source-token?)
(reg-root-key-sub :wallet/swap-from-token :wallet/swap-from-token)
(reg-root-key-sub :wallet/swap-to-token :wallet/swap-to-token)
(reg-root-key-sub :wallet/swap-from-token-amount :wallet/swap-from-token-amount)
(reg-root-key-sub :wallet/swap-to-token-amount :wallet/swap-to-token-amount)
(reg-root-key-sub :wallet/swap-advanced-mode? :wallet/swap-advanced-mode?)
;;commands
(reg-root-key-sub :commands/select-account :commands/select-account)
;;ethereum
(reg-root-key-sub :ethereum/current-block :ethereum/current-block)
;;ens
(reg-root-key-sub :ens/registration :ens/registration)
(reg-root-key-sub :ens/registrations :ens/registrations)
(reg-root-key-sub :ens/names :ens/names)
;;signing
(reg-root-key-sub :signing/sign :signing/sign)
(reg-root-key-sub :signing/tx :signing/tx)
(reg-root-key-sub :signing/edit-fee :signing/edit-fee)
;;intro-wizard
(reg-root-key-sub :intro-wizard-state :intro-wizard)
(reg-root-key-sub :popover/popover :popover/popover)
(reg-root-key-sub :visibility-status-popover/popover :visibility-status-popover/popover)
(reg-root-key-sub :add-account :add-account)
(reg-root-key-sub :keycard :keycard)
(reg-root-key-sub :auth-method :auth-method)
(reg-root-key-sub :multiaccounts/loading :multiaccounts/loading)
(reg-root-key-sub :tos-accept-next-root :tos-accept-next-root)
;; keycard
(reg-root-key-sub :keycard/banner-hidden :keycard/banner-hidden)
;; delete profile
(reg-root-key-sub :delete-profile/error :delete-profile/error)
(reg-root-key-sub :delete-profile/keep-keys-on-keycard? :delete-profile/keep-keys-on-keycard?)
;; push notifications
(reg-root-key-sub :push-notifications/servers :push-notifications/servers)
(reg-root-key-sub :push-notifications/preferences :push-notifications/preferences)
(reg-root-key-sub :buy-crypto/on-ramps :buy-crypto/on-ramps)
;; communities
(reg-root-key-sub :raw-communities :communities)
(reg-root-key-sub :communities/create :communities/create)
(reg-root-key-sub :communities/create-channel :communities/create-channel)
(reg-root-key-sub :communities/requests-to-join :communities/requests-to-join)
(reg-root-key-sub :communities/community-id-input :communities/community-id-input)
(reg-root-key-sub :communities/enabled? :communities/enabled?)
(reg-root-key-sub :communities/resolve-community-info :communities/resolve-community-info)
(reg-root-key-sub :activity.center/notifications :activity.center/notifications)
(reg-root-key-sub :activity.center/notifications-count :activity.center/notifications-count)
(reg-root-key-sub :bug-report/description-error :bug-report/description-error)
(reg-root-key-sub :bug-report/details :bug-report/details)
(reg-root-key-sub :backup/performing-backup :backup/performing-backup)
;; wallet connect
(reg-root-key-sub :wallet-connect/proposal-metadata :wallet-connect/proposal-metadata)
(reg-root-key-sub :wallet-connect/enabled? :wallet-connect/enabled?)
(reg-root-key-sub :wallet-connect/session-connected :wallet-connect/session-connected)
(reg-root-key-sub :wallet-connect/showing-app-management-sheet? :wallet-connect/showing-app-management-sheet?)
(reg-root-key-sub :wallet-connect/sessions :wallet-connect/sessions)
(reg-root-key-sub :wallet-connect-legacy/sessions :wallet-connect-legacy/sessions)
(reg-root-key-sub :wallet-connect/session-managed :wallet-connect/session-managed)
(reg-root-key-sub :contact-requests/pending :contact-requests/pending)
; media-server
(reg-root-key-sub :mediaserver/port :mediaserver/port)
; Testing
(reg-root-key-sub :messenger/started? :messenger/started?)
(reg-root-key-sub :information-box-states :information-box-states)

View File

@ -0,0 +1,95 @@
(ns status-im.subs.search
(:require [clojure.string :as string])
(:require [clojure.string :as string]
[status-im.utils.gfycat.core :as gfycat]
[re-frame.core :as re-frame]
[status-im.utils.currency :as currency]))
(defn sort-by-timestamp
[coll]
(when (not-empty coll)
(sort-by #(-> % second :timestamp) >
(into {} coll))))
(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 there is no element that match the filter
apply-filter returns full collection if the search-filter is empty"
[search-filter coll extract-attributes-fn sort?]
(let [results (if (not-empty search-filter)
(let [search-filter (string/lower-case search-filter)]
(filter (fn [element]
(some (fn [v]
(let [s (cond (string? v) v
(keyword? v) (name v))]
(when (string? s)
(string/includes? (string/lower-case s)
search-filter))))
(extract-attributes-fn element)))
coll))
coll)]
(if sort?
(sort-by-timestamp results)
results)))
(defn filter-chat
[contacts search-filter {:keys [group-chat alias name chat-id]}]
(let [alias (if-not group-chat
(string/lower-case (or alias
(get-in contacts [chat-id :alias])
(gfycat/generate-gfy chat-id)))
"")
nickname (get-in contacts [chat-id :nickname])]
(or
(string/includes? (string/lower-case (str name)) search-filter)
(string/includes? (string/lower-case alias) search-filter)
(when nickname
(string/includes? (string/lower-case nickname) search-filter))
(and
(get-in contacts [chat-id :ens-verified])
(string/includes? (string/lower-case
(str (get-in contacts [chat-id :name])))
search-filter)))))
(re-frame/reg-sub
:search/filtered-chats
:<- [:chats/home-list-chats]
:<- [:contacts/contacts]
:<- [:search/home-filter]
(fn [[chats contacts search-filter]]
;; Short-circuit if search-filter is empty
(let [filtered-chats (if (seq search-filter)
(filter
(partial filter-chat
contacts
(string/lower-case search-filter))
chats)
chats)]
(sort-by :timestamp > filtered-chats))))
(defn extract-currency-attributes [currency]
(let [{:keys [code display-name]} (val currency)]
[code display-name]))
(re-frame/reg-sub
:search/filtered-currencies
:<- [:search/currency-filter]
(fn [search-currency-filter]
{:search-filter search-currency-filter
:currencies (apply-filter search-currency-filter currency/currencies extract-currency-attributes false)}))
(defn extract-token-attributes [token]
(let [{:keys [symbol name]} token]
[symbol name]))
(re-frame/reg-sub
:wallet/filtered-grouped-chain-tokens
:<- [:wallet/grouped-chain-tokens]
:<- [:search/token-filter]
(fn [[{custom-tokens true default-tokens nil} search-token-filter]]
{:search-filter search-token-filter
:tokens {true (apply-filter search-token-filter custom-tokens extract-token-attributes false)
nil (apply-filter search-token-filter default-tokens extract-token-attributes false)}}))

View File

@ -0,0 +1,27 @@
(ns status-im.subs.stickers
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]))
(re-frame/reg-sub
:stickers/installed-packs
:<- [:stickers/packs]
(fn [packs]
(filter #(= (:status %) constants/sticker-pack-status-installed) (vals packs))))
(re-frame/reg-sub
:stickers/all-packs
:<- [:stickers/packs]
(fn [packs]
(map (fn [{:keys [status] :as pack}]
(-> pack
(assoc :installed (= status constants/sticker-pack-status-installed))
(assoc :pending (= status constants/sticker-pack-status-pending))
(assoc :owned (= status constants/sticker-pack-status-owned))))
(vals packs))))
(re-frame/reg-sub
:stickers/get-current-pack
:<- [:get-screen-params]
:<- [:stickers/all-packs]
(fn [[{:keys [id]} packs]]
(first (filter #(= (:id %) id) packs))))

View File

@ -1,6 +1,9 @@
(ns status-im.subs-test
(ns status-im.subs.subs-test
(:require [cljs.test :refer [deftest is testing]]
status-im.subs))
[status-im.subs.wallet.transactions :as wallet.transactions]
[status-im.subs.onboarding :as onboarding]
[status-im.utils.money :as money]
[status-im.subs.wallet.wallet :as wallet]))
(def transactions [{:timestamp "1505912551000"}
{:timestamp "1505764322000"}
@ -18,12 +21,12 @@
(deftest group-transactions-by-date
(testing "Check if transactions are sorted by date"
(is (= (#'status-im.subs/group-transactions-by-date transactions)
(is (= (wallet.transactions/group-transactions-by-date transactions)
grouped-transactions))))
(deftest login-ma-keycard-pairing
(testing "returns nil when no :multiaccounts/login"
(let [res (status-im.subs/login-ma-keycard-pairing
(let [res (onboarding/login-ma-keycard-pairing
{:multiaccounts/login nil
:multiaccounts/multiaccounts
{"0x1" {:keycard-pairing "keycard-pairing-code"}}}
@ -31,9 +34,23 @@
(is (nil? res))))
(testing "returns :keycard-pairing when :multiaccounts/login is present"
(let [res (status-im.subs/login-ma-keycard-pairing
(let [res (onboarding/login-ma-keycard-pairing
{:multiaccounts/login {:key-uid "0x1"}
:multiaccounts/multiaccounts
{"0x1" {:keycard-pairing "keycard-pairing-code"}}}
{})]
(is (= res "keycard-pairing-code")))))
(deftest test-balance-total-value
(is (= (wallet/get-balance-total-value
{:ETH (money/bignumber 1000000000000000000)
:SNT (money/bignumber 100000000000000000000)
:AST (money/bignumber 10000)}
{:ETH {:USD {:from "ETH", :to "USD", :price 677.91, :last-day 658.688}}
:SNT {:USD {:from "SNT", :to "USD", :price 0.1562, :last-day 0.15}}
:AST {:USD {:from "AST", :to "USD", :price 4, :last-day 3}}}
:USD
{:ETH 18
:SNT 18
:AST 4})
697.53)))

View File

@ -0,0 +1,220 @@
(ns status-im.subs.wallet.signing
(:require [re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.utils.money :as money]
[status-im.i18n.i18n :as i18n]
[status-im.ethereum.tokens :as tokens]
[clojure.string :as string]
[status-im.wallet.db :as wallet.db]
[status-im.signing.gas :as signing.gas]))
(re-frame/reg-sub
::send-transaction
:<- [:wallet]
(fn [wallet]
(:send-transaction wallet)))
(re-frame/reg-sub
:wallet.send/symbol
:<- [::send-transaction]
(fn [send-transaction]
(:symbol send-transaction)))
(re-frame/reg-sub
:wallet.send/camera-flashlight
:<- [::send-transaction]
(fn [send-transaction]
(:camera-flashlight send-transaction)))
(re-frame/reg-sub
:wallet/settings
:<- [:wallet]
(fn [{:keys [settings]}]
(reduce-kv #(conj %1 %3) [] settings)))
(re-frame/reg-sub
:wallet.request/transaction
:<- [:wallet]
:request-transaction)
(re-frame/reg-sub
:wallet/binance-chain?
:<- [:current-network]
(fn [network]
(ethereum/binance-chain-id? (get-in network [:config :NetworkId]))))
(re-frame/reg-sub
:signing/fee
:<- [:signing/tx]
(fn [{:keys [gas gasPrice maxFeePerGas]}]
(signing.gas/calculate-max-fee gas (or maxFeePerGas gasPrice))))
(re-frame/reg-sub
:signing/currencies
:<- [:prices]
:<- [:wallet/currency]
:<- [:ethereum/native-currency]
(fn [[prices {:keys [code]} {:keys [symbol]}]]
[(name symbol)
code
(get-in prices [symbol (keyword code) :price])]))
(re-frame/reg-sub
:signing/priority-fee-suggestions-range
:<- [:wallet/current-priority-fee]
:<- [:wallet/slow-base-fee]
:<- [:wallet/normal-base-fee]
:<- [:wallet/fast-base-fee]
(fn [[latest-tip slow normal fast]]
(reduce
(fn [acc [k fees]]
(assoc acc k (reduce
(fn [acc [k fee]]
(assoc acc k (-> fee
money/wei->gwei
(money/to-fixed 2))))
{}
fees)))
{}
(signing.gas/get-fee-options latest-tip slow normal fast))))
(re-frame/reg-sub
:signing/phrase
:<- [:multiaccount]
(fn [{:keys [signing-phrase]}]
signing-phrase))
(re-frame/reg-sub
:signing/sign-message
:<- [:signing/sign]
:<- [:multiaccount/accounts]
:<- [:prices]
(fn [[sign wallet-accounts prices]]
(if (= :pinless (:type sign))
(let [message (get-in sign [:formatted-data :message])
wallet-acc (some #(when (= (:address %) (:receiver message)) %) wallet-accounts)]
(cond-> sign
(and (:amount message) (:currency message))
(assoc :fiat-amount
(money/fiat-amount-value (:amount message)
(:currency message)
:USD prices)
:fiat-currency "USD")
(and (:receiver message) wallet-acc)
(assoc :account wallet-acc)))
sign)))
(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 [^js bn (money/bignumber amount)]
(not (.eq bn (.round bn decimals)))))
(defn get-amount-error [amount decimals]
(when (and (seq 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 gas-required-exceeds-allowance? [gas-error-message]
(and gas-error-message (string/starts-with?
gas-error-message
"gas required exceeds allowance")))
(defn get-sufficient-gas-error
[gas-error-message balance symbol amount ^js gas ^js gasPrice]
(if (and gas gasPrice)
(let [^js fee (.times gas gasPrice)
^js available-ether (money/bignumber (get balance :ETH 0))
^js available-for-gas (if (= :ETH symbol)
(.minus available-ether (money/bignumber amount))
available-ether)]
(merge {:gas-error-state (when gas-error-message :gas-is-set)}
(when-not (money/sufficient-funds? fee (money/bignumber available-for-gas))
{:gas-error (i18n/label :t/wallet-insufficient-gas)})))
(let [insufficient-balance? (gas-required-exceeds-allowance? gas-error-message)]
{:gas-error-state (when gas-error-message :gas-isnt-set)
:insufficient-balalce? insufficient-balance?
:gas-error (if insufficient-balance?
(i18n/label :t/insufficient-balance-to-cover-fee)
(or gas-error-message
(i18n/label :t/invalid-number)))})))
(re-frame/reg-sub
:signing/amount-errors
(fn [[_ address] _]
[(re-frame/subscribe [:signing/tx])
(re-frame/subscribe [:balance address])])
(fn [[{:keys [amount token gas gasPrice maxFeePerGas approve? gas-error-message]} balance]]
(let [gas-price (or maxFeePerGas gasPrice)]
(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))]
(merge amount-error (get-sufficient-gas-error gas-error-message balance (:symbol token) amount-bn gas gas-price)))
(get-sufficient-gas-error gas-error-message balance nil nil gas gas-price)))))
(re-frame/reg-sub
:wallet.send/prepare-transaction-with-balance
:<- [:wallet/prepare-transaction]
:<- [:wallet]
:<- [:offline?]
:<- [:wallet/all-tokens]
:<- [:current-network]
(fn [[{:keys [symbol from to amount-text] :as transaction}
wallet offline? all-tokens current-network]]
(let [balance (get-in wallet [:accounts (:address from) :balance])
{:keys [decimals] :as token} (tokens/asset-for all-tokens current-network symbol)
{:keys [value error]} (wallet.db/parse-amount amount-text decimals)
amount (money/formatted->internal value symbol decimals)
{:keys [amount-error] :as transaction-new}
(merge transaction
{:amount-error error}
(when amount
(get-sufficient-funds-error balance symbol amount)))]
(assoc transaction-new
:amount amount
:balance balance
:token (assoc token :amount (get balance (:symbol token)))
:sign-enabled? (and to
(nil? amount-error)
(not (nil? amount))
(not offline?))))))
(re-frame/reg-sub
:wallet.request/prepare-transaction-with-balance
:<- [:wallet/prepare-transaction]
:<- [:wallet]
:<- [:offline?]
:<- [:wallet/all-tokens]
:<- [:current-network]
(fn [[{:keys [symbol from to amount-text] :as transaction}
wallet offline? all-tokens current-network]]
(let [balance (get-in wallet [:accounts (:address from) :balance])
{:keys [decimals] :as token} (tokens/asset-for all-tokens current-network 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?))))))

View File

@ -0,0 +1,238 @@
(ns status-im.subs.wallet.transactions
(:require [re-frame.core :as re-frame]
[status-im.utils.money :as money]
[status-im.i18n.i18n :as i18n]
[status-im.ethereum.transactions.core :as transactions]
[status-im.wallet.db :as wallet.db]
[status-im.utils.datetime :as datetime]
[status-im.wallet.utils :as wallet.utils]
[status-im.notifications.core :as notifications]))
(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)))
(re-frame/reg-sub
:wallet/transactions
:<- [:wallet]
(fn [wallet [_ address]]
(get-in wallet [:accounts address :transactions])))
(re-frame/reg-sub
:wallet/filters
:<- [:wallet]
(fn [wallet]
(get wallet :filters)))
(defn enrich-transaction
[{:keys [type to from value token] :as transaction}
contacts native-currency]
(let [[contact-address key-contact key-wallet]
(if (= type :inbound)
[from :from-contact :to-wallet]
[to :to-contact :from-wallet])
wallet (i18n/label :main-wallet)
contact (get contacts contact-address)
{:keys [symbol-display symbol decimals] :as asset}
(or token native-currency)
amount-text (if value
(wallet.utils/format-amount value decimals)
"...")
currency-text (when asset
(clojure.core/name (or symbol-display symbol)))]
(cond-> transaction
contact (assoc key-contact (:name contact))
:always (assoc key-wallet wallet
:amount-text amount-text
:currency-text currency-text))))
(re-frame/reg-sub
:wallet.transactions/transactions
(fn [[_ address] _]
[(re-frame/subscribe [:wallet/transactions address])
(re-frame/subscribe [:contacts/contacts-by-address])
(re-frame/subscribe [:ethereum/native-currency])])
(fn [[transactions contacts native-currency]]
(reduce (fn [acc [hash transaction]]
(assoc acc
hash
(enrich-transaction transaction contacts native-currency))) ;;TODO this doesn't look good for performance, we need to calculate this only once for each transaction
{}
transactions)))
(re-frame/reg-sub
:wallet.transactions/all-filters?
:<- [:wallet/filters]
(fn [filters]
(= wallet.db/default-wallet-filters
filters)))
(def filters-labels
{:inbound (i18n/label :t/incoming)
:outbound (i18n/label :t/outgoing)
:pending (i18n/label :t/pending)
:failed (i18n/label :t/failed)})
(re-frame/reg-sub
:wallet.transactions/filters
:<- [:wallet/filters]
(fn [filters]
(map (fn [id]
(let [checked? (filters id)]
{:id id
:label (filters-labels id)
:checked? checked?
:on-touch #(if checked?
(re-frame/dispatch [:wallet.transactions/remove-filter id])
(re-frame/dispatch [:wallet.transactions/add-filter id]))}))
wallet.db/default-wallet-filters)))
(re-frame/reg-sub
:wallet.transactions.filters/screen
:<- [:wallet.transactions/filters]
:<- [:wallet.transactions/all-filters?]
(fn [[filters all-filters?]]
{:all-filters? all-filters?
:filters filters
:on-touch-select-all (when-not all-filters?
#(re-frame/dispatch
[:wallet.transactions/add-all-filters]))}))
(defn- enrich-transaction-for-list
[filters
{:keys [type from-contact from to-contact to hash timestamp] :as transaction}
address]
(when (filters type)
(assoc (case type
:inbound
(assoc transaction
:label (i18n/label :t/from)
:contact-accessibility-label :sender-text
:address-accessibility-label :sender-address-text
:contact from-contact
:address from)
(assoc transaction
:label (i18n/label :t/to)
:contact-accessibility-label :recipient-name-text
:address-accessibility-label :recipient-address-text
:contact to-contact
:address to))
:time-formatted (datetime/timestamp->time timestamp)
:on-touch-fn #(re-frame/dispatch [:wallet.ui/show-transaction-details hash address]))))
(defn group-transactions-by-date
[transactions]
(->> transactions
(group-by #(datetime/timestamp->date-key (:timestamp %)))
(sort-by key >)
(map (fn [[date-key transactions]]
{:title (datetime/timestamp->mini-date (:timestamp (first transactions)))
:key date-key
:data (sort-by :timestamp > transactions)}))))
(re-frame/reg-sub
:wallet.transactions.history/screen
(fn [[_ address] _]
[(re-frame/subscribe [:wallet.transactions/transactions address])
(re-frame/subscribe [:wallet/filters])
(re-frame/subscribe [:wallet.transactions/all-filters?])])
(fn [[transactions filters all-filters?] [_ address]]
{:all-filters? all-filters?
:total (count transactions)
:transaction-history-sections
(->> transactions
vals
(keep #(enrich-transaction-for-list filters % address))
(group-transactions-by-date))}))
(re-frame/reg-sub
:wallet/recipient-recent-txs
(fn [[_ address] _]
[(re-frame/subscribe [:wallet.transactions/transactions address])])
(fn [[transactions] _]
(->> transactions
vals
(sort-by :timestamp >)
(remove #(= (:type %) :pending))
(take 3))))
(re-frame/reg-sub
:wallet.transactions.details/current-transaction
(fn [[_ _ address] _]
[(re-frame/subscribe [:wallet.transactions/transactions address])
(re-frame/subscribe [:ethereum/native-currency])
(re-frame/subscribe [:chain-id])])
(fn [[transactions native-currency chain-id] [_ hash _]]
(let [{:keys [gas-used gas-price fee-cap tip-cap hash timestamp type]
:as transaction}
(get transactions hash)
native-currency-text (name (or (:symbol-display native-currency)
(:symbol native-currency)))]
(when transaction
(merge transaction
{:gas-price-eth (if gas-price
(money/wei->str :eth
gas-price
native-currency-text)
"-")
:gas-price-gwei (if gas-price
(money/wei->str :gwei
gas-price)
"-")
:fee-cap-gwei (if fee-cap
(money/wei->str :gwei
fee-cap)
"-")
:tip-cap-gwei (if tip-cap
(money/wei->str :gwei
tip-cap)
"-")
:date (datetime/timestamp->long-date timestamp)}
(if (= type :unsigned)
{:block (i18n/label :not-applicable)
:cost (i18n/label :not-applicable)
:gas-limit (i18n/label :not-applicable)
:gas-used (i18n/label :not-applicable)
:nonce (i18n/label :not-applicable)
:hash (i18n/label :not-applicable)}
{:cost (when gas-used
(money/wei->str :eth
(money/fee-value gas-used gas-price)
native-currency-text))
:url (transactions/get-transaction-details-url
chain-id
hash)}))))))
(re-frame/reg-sub
:wallet.transactions.details/screen
(fn [[_ hash address] _]
[(re-frame/subscribe [:wallet.transactions.details/current-transaction hash address])
(re-frame/subscribe [:ethereum/current-block])])
(fn [[transaction current-block]]
(let [confirmations (wallet.db/get-confirmations transaction
current-block)]
(assoc transaction
:confirmations confirmations
:confirmations-progress
(if (>= confirmations transactions/confirmations-count-threshold)
100
(* 100 (/ confirmations transactions/confirmations-count-threshold)))))))
(re-frame/reg-sub
:notifications/wallet-transactions
:<- [:push-notifications/preferences]
(fn [pref]
(first (filter #(notifications/preference= % {:service "wallet"
:event "transaction"
:identifier "all"}) pref))))

View File

@ -0,0 +1,283 @@
(ns status-im.subs.wallet.wallet
(:require [re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.utils.money :as money]
[status-im.i18n.i18n :as i18n]
[status-im.ethereum.tokens :as tokens]
[status-im.utils.config :as config]
[status-im.utils.currency :as currency]
[clojure.string :as string]))
(re-frame/reg-sub
:balance
:<- [:wallet]
(fn [wallet [_ address]]
(get-in wallet [:accounts address :balance])))
(re-frame/reg-sub
:balance-default
:<- [:wallet]
:<- [:multiaccount/accounts]
(fn [[wallet accounts]]
(get-in wallet [:accounts (:address (ethereum/get-default-account accounts)) :balance])))
(re-frame/reg-sub
:balances
:<- [:wallet]
:<- [:multiaccount/visible-accounts]
(fn [[wallet accounts]]
(let [accounts (map :address accounts)]
(map :balance (vals (select-keys (:accounts wallet) accounts))))))
(re-frame/reg-sub
:empty-balances?
:<- [:balances]
(fn [balances]
(every?
(fn [balance]
(every?
(fn [^js asset]
(or (nil? asset) (.isZero asset)))
(vals balance)))
balances)))
(re-frame/reg-sub
:price
:<- [:prices]
(fn [prices [_ fsym tsym]]
(get-in prices [fsym tsym :price])))
(re-frame/reg-sub
:last-day
:<- [:prices]
(fn [prices [_ fsym tsym]]
(get-in prices [fsym tsym :last-day])))
(re-frame/reg-sub
:wallet.settings/currency
:<- [:multiaccount]
(fn [settings]
(or (get settings :currency) :usd)))
(defn get-balance-total-value
[balance prices currency token->decimals]
(reduce-kv (fn [acc symbol value]
(if-let [price (get-in prices [symbol currency :price])]
(+ acc (or (some-> (money/internal->formatted value symbol (token->decimals symbol))
^js (money/crypto->fiat price)
.toNumber)
0))
acc)) 0 balance))
(re-frame/reg-sub
:wallet/token->decimals
:<- [:wallet/all-tokens]
(fn [all-tokens]
(into {} (map #(vector (:symbol %) (:decimals %)) (vals all-tokens)))))
(re-frame/reg-sub
:portfolio-value
:<- [:balances]
:<- [:prices]
:<- [:wallet/currency]
:<- [:wallet/token->decimals]
(fn [[balances prices currency token->decimals]]
(if (and balances prices)
(let [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)))
"0"))
"...")))
(re-frame/reg-sub
:account-portfolio-value
(fn [[_ address] _]
[(re-frame/subscribe [:balance address])
(re-frame/subscribe [:prices])
(re-frame/subscribe [:wallet/currency])
(re-frame/subscribe [:wallet/token->decimals])])
(fn [[balance prices currency token->decimals]]
(if (and balance prices)
(let [currency-key (-> currency :code keyword)
balance-total-value (get-balance-total-value balance prices currency-key token->decimals)]
(if (pos? balance-total-value)
(-> balance-total-value
(money/with-precision 2)
str
(i18n/format-currency (:code currency)))
"0"))
"...")))
(re-frame/reg-sub
:wallet/sorted-tokens
:<- [:wallet/all-tokens]
(fn [all-tokens]
(tokens/sorted-tokens-for all-tokens)))
(re-frame/reg-sub
:wallet/grouped-chain-tokens
:<- [:wallet/sorted-tokens]
:<- [:wallet/visible-tokens-symbols]
(fn [[all-tokens visible-tokens]]
(let [vt-set (set visible-tokens)]
(group-by :custom? (map #(assoc % :checked? (boolean (get vt-set (keyword (:symbol %))))) all-tokens)))))
(re-frame/reg-sub
:wallet/fetching-tx-history?
:<- [:wallet]
(fn [wallet [_ address]]
(get-in wallet [:fetching address :history?])))
(re-frame/reg-sub
:wallet/fetching-recent-tx-history?
:<- [:wallet]
(fn [wallet [_ address]]
(get-in wallet [:fetching address :recent?])))
(re-frame/reg-sub
:wallet/tx-history-fetched?
:<- [:wallet]
(fn [wallet [_ address]]
(get-in wallet [:fetching address :all-fetched?])))
(re-frame/reg-sub
:wallet/chain-explorer-link
(fn [db [_ address]]
(let [network (:networks/current-network db)
link (get-in config/default-networks-by-id
[network :chain-explorer-link])]
(when link
(str link address)))))
(re-frame/reg-sub
:wallet/error-message
:<- [:wallet]
(fn [wallet]
(or (get-in wallet [:errors :balance-update])
(get-in wallet [:errors :prices-update]))))
(re-frame/reg-sub
:wallet/visible-tokens-symbols
:<- [:ethereum/chain-keyword]
:<- [:multiaccount]
(fn [[chain current-multiaccount]]
(get-in current-multiaccount [:wallet/visible-tokens chain])))
(re-frame/reg-sub
:wallet/visible-assets
:<- [:current-network]
:<- [:wallet/visible-tokens-symbols]
:<- [:wallet/sorted-tokens]
(fn [[network visible-tokens-symbols all-tokens-sorted]]
(conj (filter #(contains? visible-tokens-symbols (:symbol %)) all-tokens-sorted)
(tokens/native-currency network))))
(re-frame/reg-sub
:wallet/visible-assets-with-amount
(fn [[_ address] _]
[(re-frame/subscribe [:balance address])
(re-frame/subscribe [:wallet/visible-assets])])
(fn [[balance visible-assets]]
(map #(assoc % :amount (get balance (:symbol %))) visible-assets)))
(defn update-value [prices currency]
(fn [{:keys [symbol decimals amount] :as token}]
(let [price (get-in prices [symbol (-> currency :code keyword) :price])]
(assoc token
:price price
:value (when (and amount price)
(-> (money/internal->formatted amount symbol decimals)
(money/crypto->fiat price)
(money/with-precision 2)
str
(i18n/format-currency (:code currency))))))))
(re-frame/reg-sub
:wallet/visible-assets-with-values
(fn [[_ address] _]
[(re-frame/subscribe [:wallet/visible-assets-with-amount address])
(re-frame/subscribe [:prices])
(re-frame/subscribe [:wallet/currency])])
(fn [[assets prices currency]]
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
tokens-with-values (map (update-value prices currency) tokens)]
{:tokens tokens-with-values
:nfts nfts})))
(defn get-asset-amount [balances sym]
(reduce #(if-let [^js bl (get %2 sym)]
(.plus ^js (or ^js %1 ^js (money/bignumber 0)) bl)
%1)
nil
balances))
(re-frame/reg-sub
:wallet/all-visible-assets-with-amount
:<- [:balances]
:<- [:wallet/visible-assets]
(fn [[balances visible-assets]]
(map #(assoc % :amount (get-asset-amount balances (:symbol %))) visible-assets)))
(re-frame/reg-sub
:wallet/all-visible-assets-with-values
:<- [:wallet/all-visible-assets-with-amount]
:<- [:prices]
:<- [:wallet/currency]
(fn [[assets prices currency]]
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
tokens-with-values (map (update-value prices currency) tokens)]
{:tokens tokens-with-values
:nfts nfts})))
(re-frame/reg-sub
:wallet/transferrable-assets-with-amount
(fn [[_ address]]
(re-frame/subscribe [:wallet/visible-assets-with-amount address]))
(fn [all-assets]
(filter #(not (:nft? %)) all-assets)))
(re-frame/reg-sub
:wallet/currency
:<- [:wallet.settings/currency]
(fn [currency-id]
(get currency/currencies currency-id)))
(defn filter-recipient-favs
[search-filter {:keys [name]}]
(string/includes? (string/lower-case (str name)) search-filter))
(re-frame/reg-sub
:wallet/favourites-filtered
:<- [:wallet/favourites]
:<- [:search/recipient-filter]
(fn [[favs search-filter]]
(let [favs (vals favs)]
(if (string/blank? search-filter)
favs
(filter (partial filter-recipient-favs
(string/lower-case search-filter))
favs)))))
(re-frame/reg-sub
:wallet/collectible-collection
:<- [:wallet/collectible-collections]
(fn [all-collections [_ address]]
(when address
(let [all-collections (get all-collections (string/lower-case address) [])]
(sort-by :name all-collections)))))
(re-frame/reg-sub
:wallet/collectible-assets-by-collection-and-address
:<- [:wallet/collectible-assets]
(fn [all-assets [_ address collectible-slug]]
(get-in all-assets [address collectible-slug] [])))
(re-frame/reg-sub
:wallet/fetching-assets-by-collectible-slug
:<- [:wallet/fetching-collection-assets]
(fn [fetching-collection-assets [_ collectible-slug]]
(get fetching-collection-assets collectible-slug false)))

View File

@ -255,7 +255,7 @@
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
(defn text-input-old [{:keys [set-active-panel refs chat-id sending-image]}]
(let [cooldown-enabled? @(re-frame/subscribe [:chats/cooldown-enabled?])
(let [cooldown-enabled? @(re-frame/subscribe [:chats/current-chat-cooldown-enabled?])
mentionable-users @(re-frame/subscribe [:chats/mentionable-users])
timeout-id (atom nil)
last-text-change (atom nil)
@ -294,7 +294,7 @@
(get @input-texts chat-id))]))
(defn text-input [{:keys [set-active-panel refs chat-id sending-image on-content-size-change]}]
(let [cooldown-enabled? @(re-frame/subscribe [:chats/cooldown-enabled?])
(let [cooldown-enabled? @(re-frame/subscribe [:chats/current-chat-cooldown-enabled?])
mentionable-users @(re-frame/subscribe [:chats/mentionable-users])
timeout-id (atom nil)
last-text-change (atom nil)

View File

@ -35,7 +35,7 @@
(re-frame/reg-fx
::get-stats
(fn []
(status-im.ethereum.json-rpc/call
(json-rpc/call
{:method "rpcstats_getStats"
:params []
:on-success #(re-frame/dispatch [::handle-stats %])})))
@ -43,7 +43,7 @@
(re-frame/reg-fx
::reset
(fn []
(status-im.ethereum.json-rpc/call
(json-rpc/call
{:method "rpcstats_reset"
:params []
:on-success #(log/debug "rpcstats_reset success")})))

View File

@ -989,7 +989,7 @@
{::async-storage/set! {:transactions-management-enabled? enabled?}
:db (assoc db :wallet/transactions-management-enabled? enabled?)})
(fx/defn update-curent-block
(fx/defn update-current-block
{:events [::update-current-block]}
[{:keys [db]} block]
{:db (assoc db :ethereum/current-block block)})

View File

@ -1,18 +0,0 @@
(ns status-im.wallet.subs-test
(:require [cljs.test :refer-macros [deftest is]]
[status-im.utils.money :as money]
[status-im.subs :as s]))
(deftest test-balance-total-value
(is (= (#'status-im.subs/get-balance-total-value
{:ETH (money/bignumber 1000000000000000000)
:SNT (money/bignumber 100000000000000000000)
:AST (money/bignumber 10000)}
{:ETH {:USD {:from "ETH", :to "USD", :price 677.91, :last-day 658.688}}
:SNT {:USD {:from "SNT", :to "USD", :price 0.1562, :last-day 0.15}}
:AST {:USD {:from "AST", :to "USD", :price 4, :last-day 3}}}
:USD
{:ETH 18
:SNT 18
:AST 4})
697.53)))