mirror of
https://github.com/status-im/status-react.git
synced 2025-02-22 23:58:30 +00:00
Refactoring chat events to shorten event chains
This commit is contained in:
parent
5a49926ad0
commit
d9db548e57
98
src/status_im/bots/events.cljs
Normal file
98
src/status_im/bots/events.cljs
Normal file
@ -0,0 +1,98 @@
|
||||
(ns status-im.bots.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.handlers :as handlers]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn- chats-with-bot [chats bot]
|
||||
(reduce (fn [acc [_ {:keys [chat-id contacts]}]]
|
||||
(let [contacts (map :identity contacts)]
|
||||
(if (some #{bot} contacts)
|
||||
(conj acc chat-id)
|
||||
acc)))
|
||||
[]
|
||||
chats))
|
||||
|
||||
(defn- subscription-values [subscriptions current-bot-db]
|
||||
(reduce (fn [sub-values [sub-name sub-path]]
|
||||
(assoc sub-values sub-name (get-in current-bot-db sub-path)))
|
||||
{}
|
||||
subscriptions))
|
||||
|
||||
;; TODO(janherich): optimze this, for sure we don't need to re-calculate all bot subscriptions every time something in bot db changes
|
||||
(defn- check-subscriptions-fx
|
||||
[db {:keys [bot path value]}]
|
||||
(let [{:keys [bot-db chats]} db
|
||||
subscriptions (get-in db [:bot-subscriptions path])]
|
||||
{:call-jail-function-n
|
||||
(for [{:keys [bot subscriptions name]} subscriptions
|
||||
:let [subs-values (subscription-values subscriptions (get bot-db bot))]]
|
||||
{:chat-id bot
|
||||
:function :subscription
|
||||
:parameters {:name name
|
||||
:subscriptions subs-values}
|
||||
:callback-events-creator (fn [jail-response]
|
||||
(into [[::calculated-subscription
|
||||
{:bot bot
|
||||
:path [name]
|
||||
:result jail-response}]]
|
||||
(map (fn [chat-id]
|
||||
[::calculated-subscription
|
||||
{:bot chat-id
|
||||
:path [name]
|
||||
:result jail-response}])
|
||||
(chats-with-bot chats bot))))})}))
|
||||
|
||||
(defn set-in-bot-db
|
||||
[{:keys [current-chat-id] :as app-db} {:keys [bot path value] :as params}]
|
||||
(let [bot (or bot current-chat-id)
|
||||
new-db (assoc-in app-db (concat [:bot-db bot] path) value)]
|
||||
(merge {:db new-db}
|
||||
(check-subscriptions-fx new-db params))))
|
||||
|
||||
(defn update-bot-db
|
||||
[{:keys [current-chat-id] :as app-db} {:keys [bot db]}]
|
||||
(let [bot (or bot current-chat-id)]
|
||||
(update-in app-db [:bot-db bot] merge db)))
|
||||
|
||||
(defn clear-bot-db
|
||||
[{:keys [current-chat-id] :as app-db}]
|
||||
(assoc-in app-db [:bot-db current-chat-id] nil))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:set-in-bot-db
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [params]]
|
||||
(set-in-bot-db db params)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:update-bot-db
|
||||
[re-frame/trim-v]
|
||||
(fn [db [params]]
|
||||
(update-bot-db db params)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:register-bot-subscription
|
||||
[re-frame/trim-v]
|
||||
(fn [db [{:keys [bot subscriptions] :as opts}]]
|
||||
(reduce
|
||||
(fn [db [sub-name sub-path]]
|
||||
(let [keywordized-sub-path (mapv keyword
|
||||
(if (coll? sub-path)
|
||||
sub-path
|
||||
[sub-path]))]
|
||||
(update-in db [:bot-subscriptions keywordized-sub-path] conj
|
||||
(assoc-in opts [:subscriptions sub-name] keywordized-sub-path))))
|
||||
db
|
||||
subscriptions)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
::calculated-subscription
|
||||
[re-frame/trim-v]
|
||||
(fn [db [{:keys [bot path]
|
||||
{:keys [error result]} :result}]]
|
||||
(if error
|
||||
db
|
||||
(assoc-in db (concat [:bot-db bot] path) (:returned result)))))
|
@ -1,77 +0,0 @@
|
||||
(ns status-im.bots.handlers
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.handlers :as u]))
|
||||
|
||||
(defn chats-with-bot [chats bot]
|
||||
(reduce (fn [acc [_ {:keys [chat-id contacts]}]]
|
||||
(let [contacts (map :identity contacts)]
|
||||
(if (some #{bot} contacts)
|
||||
(conj acc chat-id)
|
||||
acc)))
|
||||
[]
|
||||
chats))
|
||||
|
||||
(defn check-subscriptions
|
||||
[{:keys [bot-db chats] :as db} [handler {:keys [path key bot]}]]
|
||||
(let [path' (or path [key])
|
||||
subscriptions (get-in db [:bot-subscriptions path'])
|
||||
current-bot-db (get bot-db bot)]
|
||||
(doseq [{:keys [bot subscriptions name]} subscriptions]
|
||||
(let [subs-values (reduce (fn [res [sub-name sub-path]]
|
||||
(assoc res sub-name (get-in current-bot-db sub-path)))
|
||||
{} subscriptions)]
|
||||
(status/call-function!
|
||||
{:chat-id bot
|
||||
:function :subscription
|
||||
:parameters {:name name
|
||||
:subscriptions subs-values}
|
||||
:callback #(do
|
||||
(re-frame/dispatch
|
||||
[::calculated-subscription {:bot bot
|
||||
:path [name]
|
||||
:result %}])
|
||||
(doseq [chat-id (chats-with-bot chats bot)]
|
||||
(re-frame/dispatch
|
||||
[::calculated-subscription {:bot chat-id
|
||||
:path [name]
|
||||
:result %}])))})))))
|
||||
|
||||
(u/register-handler :set-in-bot-db
|
||||
(re-frame/after check-subscriptions)
|
||||
(fn [{:keys [current-chat-id] :as db} [_ {:keys [bot path value]}]]
|
||||
(let [bot (or bot current-chat-id)]
|
||||
(assoc-in db (concat [:bot-db bot] path) value))))
|
||||
|
||||
(u/register-handler :register-bot-subscription
|
||||
(fn [db [_ {:keys [bot subscriptions] :as opts}]]
|
||||
(reduce
|
||||
(fn [db [sub-name sub-path]]
|
||||
(let [sub-path' (if (coll? sub-path) sub-path [sub-path])
|
||||
sub-path'' (mapv keyword sub-path')]
|
||||
(update-in db [:bot-subscriptions sub-path''] conj
|
||||
(assoc-in opts [:subscriptions sub-name] sub-path''))))
|
||||
db
|
||||
subscriptions)))
|
||||
|
||||
(u/register-handler ::calculated-subscription
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [bot path]
|
||||
{:keys [error result]} :result
|
||||
:as data}]]
|
||||
(when-not error
|
||||
(let [returned (:returned result)
|
||||
opts {:bot bot
|
||||
:path path
|
||||
:value returned}]
|
||||
(re-frame/dispatch [:set-in-bot-db opts]))))))
|
||||
|
||||
(u/register-handler :update-bot-db
|
||||
(fn [{:keys [current-chat-id] :as app-db} [_ {:keys [bot db]}]]
|
||||
(let [bot (or bot current-chat-id)]
|
||||
(update-in app-db [:bot-db bot] merge db))))
|
||||
|
||||
(u/register-handler :clear-bot-db
|
||||
(fn [{:keys [current-chat-id] :as app-db} [_ {:keys [bot]}]]
|
||||
(let [bot (or bot current-chat-id)]
|
||||
(assoc-in app-db [:bot-db bot] nil))))
|
@ -0,0 +1,253 @@
|
||||
(ns status-im.chat.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.chat.models :as model]
|
||||
[status-im.chat.models.unviewed-messages :as unviewed-messages-model]
|
||||
[status-im.chat.sign-up :as sign-up]
|
||||
[status-im.chat.constants :as chat-const]
|
||||
[status-im.data-store.handler-data :as handler-data]
|
||||
[status-im.data-store.messages :as msg-store]
|
||||
[status-im.data-store.contacts :as contacts-store]
|
||||
[status-im.data-store.chats :as chats-store]
|
||||
[status-im.protocol.core :as protocol]
|
||||
[status-im.constants :as const]
|
||||
status-im.chat.events.input
|
||||
status-im.chat.events.commands
|
||||
status-im.chat.events.animation
|
||||
status-im.chat.events.receive-message
|
||||
status-im.chat.events.sign-up
|
||||
status-im.chat.events.console))
|
||||
|
||||
;;;; Coeffects
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:stored-unviewed-messages
|
||||
(fn [cofx _]
|
||||
(assoc cofx :stored-unviewed-messages (msg-store/get-unviewed))))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-stored-message
|
||||
(fn [cofx _]
|
||||
(assoc cofx :get-stored-message msg-store/get-by-id)))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-stored-messages
|
||||
(fn [cofx _]
|
||||
(assoc cofx :get-stored-messages msg-store/get-by-chat-id)))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-last-stored-message
|
||||
(fn [cofx _]
|
||||
(assoc cofx :get-last-stored-message msg-store/get-last-message)))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-message-previews
|
||||
(fn [cofx _]
|
||||
(assoc cofx :message-previews (msg-store/get-previews))))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:all-stored-chats
|
||||
(fn [cofx _]
|
||||
(assoc cofx :all-stored-chats (chats-store/get-all))))
|
||||
|
||||
;;;; Effects
|
||||
|
||||
(re-frame/reg-fx
|
||||
:update-message
|
||||
(fn [message]
|
||||
(msg-store/update message)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:save-message
|
||||
(fn [{:keys [chat-id] :as message}]
|
||||
(msg-store/save chat-id message)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:save-chat
|
||||
(fn [chat]
|
||||
(chats-store/save chat)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:save-all-contacts
|
||||
(fn [contacts]
|
||||
(contacts-store/save-all contacts)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:protocol-send-seen
|
||||
(fn [params]
|
||||
(protocol/send-seen! params)))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn init-console-chat
|
||||
[{:keys [chats] :accounts/keys [current-account-id] :as db} existing-account?]
|
||||
(if (chats const/console-chat-id)
|
||||
{:db db}
|
||||
(cond-> {:db (-> db
|
||||
(assoc :new-chat sign-up/console-chat)
|
||||
(update :chats assoc const/console-chat-id sign-up/console-chat)
|
||||
(assoc :current-chat-id const/console-chat-id))
|
||||
:dispatch-n [[:add-contacts [sign-up/console-contact]]]
|
||||
:save-chat sign-up/console-chat
|
||||
:save-all-contacts [sign-up/console-contact]}
|
||||
|
||||
(not current-account-id)
|
||||
(update :dispatch-n concat sign-up/intro-events)
|
||||
|
||||
existing-account?
|
||||
(update :dispatch-n concat sign-up/start-signup-events))))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
(handlers/register-handler-db
|
||||
:set-layout-height
|
||||
[re-frame/trim-v]
|
||||
(fn [db [height]]
|
||||
(assoc db :layout-height height)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:set-chat-ui-props
|
||||
[re-frame/trim-v]
|
||||
(fn [db [kvs]]
|
||||
(model/set-chat-ui-props db kvs)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:toggle-chat-ui-props
|
||||
[re-frame/trim-v]
|
||||
(fn [db [ui-element]]
|
||||
(model/toggle-chat-ui-prop db ui-element)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:show-message-details
|
||||
[re-frame/trim-v]
|
||||
(fn [db [details]]
|
||||
(model/set-chat-ui-props db {:show-bottom-info? true
|
||||
:show-emoji? false
|
||||
:bottom-info details})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-more-messages
|
||||
[(re-frame/inject-cofx :get-stored-messages)]
|
||||
(fn [{{:keys [current-chat-id loading-allowed] :as db} :db
|
||||
get-stored-messages :get-stored-messages} _]
|
||||
(let [all-loaded? (get-in db [:chats current-chat-id :all-loaded?])]
|
||||
(if (and loading-allowed (not all-loaded?))
|
||||
(let [messages-path [:chats current-chat-id :messages]
|
||||
messages (get-in db messages-path)
|
||||
chat-messages (filter #(= current-chat-id (:chat-id %)) messages)
|
||||
new-messages (get-stored-messages current-chat-id (count chat-messages))
|
||||
all-loaded? (> const/default-number-of-messages (count new-messages))]
|
||||
{:db (-> db
|
||||
(assoc :loading-allowed false)
|
||||
(update-in messages-path concat new-messages)
|
||||
(assoc-in [:chats current-chat-id :all-loaded?] all-loaded?))
|
||||
;; we permit loading more messages again after 400ms
|
||||
:dispatch-later [{:ms 400 :dispatch [:set :loading-allowed true]}]})
|
||||
{:db db}))))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:set-message-shown
|
||||
[re-frame/trim-v]
|
||||
(fn [db [{:keys [chat-id message-id]}]]
|
||||
(update-in db
|
||||
[:chats chat-id :messages]
|
||||
(fn [messages]
|
||||
(map (fn [message]
|
||||
(if (= message-id (:message-id message))
|
||||
(assoc message :new? false)
|
||||
message))
|
||||
messages)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:init-console-chat
|
||||
(fn [{:keys [db]} _]
|
||||
(init-console-chat db false)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:initialize-chats
|
||||
[(re-frame/inject-cofx :all-stored-chats)
|
||||
(re-frame/inject-cofx :stored-unviewed-messages)
|
||||
(re-frame/inject-cofx :get-last-stored-message)
|
||||
(re-frame/inject-cofx :get-message-previews)]
|
||||
(fn [{:keys [db all-stored-chats stored-unviewed-messages get-last-stored-message message-previews]} _]
|
||||
(let [{:accounts/keys [account-creation?]} db
|
||||
new-db (unviewed-messages-model/load-unviewed-messages db stored-unviewed-messages)
|
||||
event [:load-default-contacts!]]
|
||||
(if account-creation?
|
||||
{:db new-db
|
||||
:dispatch-n [event]}
|
||||
(let [chats (->> all-stored-chats
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
[chat-id (assoc chat :last-message (get-last-stored-message chat-id))]))
|
||||
(into {}))]
|
||||
(-> new-db
|
||||
(assoc-in [:message-data :preview] message-previews)
|
||||
(assoc :handler-data (handler-data/get-all))
|
||||
(assoc :chats chats)
|
||||
(init-console-chat true)
|
||||
(update :dispatch-n conj event)))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:reload-chats
|
||||
[(re-frame/inject-cofx :all-stored-chats) (re-frame/inject-cofx :get-last-stored-message)]
|
||||
(fn [{:keys [db all-stored-chats get-last-stored-message]} _]
|
||||
(let [updated-chats (->> all-stored-chats
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
(let [prev-chat (get (:chats db) chat-id)
|
||||
updated-chat (assoc chat :last-message (get-last-stored-message chat-id))]
|
||||
[chat-id (merge prev-chat updated-chat)])))
|
||||
(into {}))]
|
||||
(-> (assoc db :chats updated-chats)
|
||||
(init-console-chat true)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:send-seen!
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [{:keys [message-id chat-id from]}]]
|
||||
(let [{:keys [web3 current-public-key chats]
|
||||
:contacts/keys [contacts]} db
|
||||
{:keys [group-chat public?]} (get chats chat-id)]
|
||||
(cond-> {:db (unviewed-messages-model/remove-unviewed-messages db chat-id)
|
||||
:update-message {:message-id message-id
|
||||
:message-status :seen}}
|
||||
(and (not (get-in contacts [chat-id] :dapp?))
|
||||
(not public?))
|
||||
(assoc :protocol-send-seen
|
||||
{:web3 web3
|
||||
:message (cond-> {:from current-public-key
|
||||
:to from
|
||||
:message-id message-id}
|
||||
group-chat (assoc :group-id chat-id))})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-mnemonic
|
||||
[(re-frame/inject-cofx :get-stored-message) re-frame/trim-v]
|
||||
(fn [{:keys [get-stored-message]} [mnemonic signing-phrase]]
|
||||
(let [crazy-math-message? (get-stored-message chat-const/crazy-math-message-id)]
|
||||
{:dispatch-n (sign-up/passphrase-messages-events mnemonic
|
||||
signing-phrase
|
||||
crazy-math-message?)})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:account-generation-message
|
||||
[(re-frame/inject-cofx :get-stored-message)]
|
||||
(fn [{:keys [get-stored-message]} _]
|
||||
(when-not (get-stored-message chat-const/passphrase-message-id)
|
||||
{:dispatch sign-up/account-generation-event})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:move-to-internal-failure-message
|
||||
[(re-frame/inject-cofx :get-stored-message)]
|
||||
(fn [{:keys [get-stored-message]} _]
|
||||
(when-not (get-stored-message chat-const/move-to-internal-failure-message-id)
|
||||
{:dispatch sign-up/move-to-internal-failure-event})))
|
||||
(comment
|
||||
(handlers/register-handler-fx
|
||||
:init-chat
|
||||
[(re-frame/inject-cofx :get-stored-messages)]
|
||||
(fn [{:keys [db get-stored-messages]} _]
|
||||
(let [current-chat-id (:current-chat-id db)]
|
||||
{:db (assoc-in [:chats current-chat-id :messages] (get-stored-messages current-chat-id))
|
||||
;; TODO(janherich): make this dispatch into fn call once commands loading is refactored
|
||||
:dispatch [:load-commands! current-chat-id]}))))
|
75
src/status_im/chat/events/animation.cljs
Normal file
75
src/status_im/chat/events/animation.cljs
Normal file
@ -0,0 +1,75 @@
|
||||
(ns status-im.chat.events.animation
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.chat.views.input.utils :as input-utils]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.platform :as platform]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn set-expandable-height
|
||||
[{:keys [current-chat-id] :as db} key value]
|
||||
(-> db
|
||||
(assoc-in [:chat-animations current-chat-id key :height] value)
|
||||
(update-in [:chat-animations current-chat-id key :changes-counter] inc)))
|
||||
|
||||
(defn choose-predefined-expandable-height
|
||||
[{:keys [current-chat-id chat-ui-props layout-height] :as db} key preset]
|
||||
(if (= preset :max)
|
||||
(set-expandable-height db key :max)
|
||||
(let [input-height (get-in chat-ui-props [current-chat-id :input-height])
|
||||
chat-input-margin (if platform/ios?
|
||||
(get db :keyboard-height)
|
||||
0)
|
||||
bottom (+ input-height chat-input-margin)
|
||||
height (case preset
|
||||
:min input-utils/min-height
|
||||
(input-utils/default-container-area-height bottom layout-height))]
|
||||
(set-expandable-height db key height))))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
(handlers/register-handler-db
|
||||
:set-expandable-height
|
||||
[re-frame/trim-v]
|
||||
(fn [db [key value]]
|
||||
(set-expandable-height db key value)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:choose-predefined-expandable-height
|
||||
[re-frame/trim-v]
|
||||
(fn [db [key preset]]
|
||||
(choose-predefined-expandable-height db key preset)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:fix-expandable-height
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [current-chat-id chats chat-ui-props layout-height] :as db} [vy current key]]
|
||||
(let [input-height (get-in chat-ui-props [current-chat-id :input-height])
|
||||
chat-input-margin (if platform/ios?
|
||||
(get db :keyboard-height)
|
||||
0)
|
||||
bottom (+ input-height chat-input-margin)
|
||||
|
||||
min-height input-utils/min-height
|
||||
max-height (input-utils/max-container-area-height bottom layout-height)
|
||||
default-height (input-utils/default-container-area-height bottom layout-height)
|
||||
possible-values [min-height default-height max-height]
|
||||
|
||||
moving-down? (pos? vy)
|
||||
closest-index (->> possible-values
|
||||
(map-indexed vector)
|
||||
(sort-by (fn [[i v]] (Math/abs (- v current))))
|
||||
(ffirst))
|
||||
height (cond (and moving-down? (not= closest-index 0))
|
||||
(get possible-values (dec closest-index))
|
||||
|
||||
(and (not moving-down?) (not= closest-index 2))
|
||||
(get possible-values (inc closest-index))
|
||||
|
||||
moving-down?
|
||||
min-height
|
||||
|
||||
(not moving-down?)
|
||||
max-height)]
|
||||
(set-expandable-height db key height))))
|
@ -1,17 +1,15 @@
|
||||
(ns status-im.chat.events.commands
|
||||
(:require [cljs.reader :as reader]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :refer [reg-fx reg-cofx inject-cofx dispatch trim-v]]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.data-store.messages :as msg-store]
|
||||
[status-im.utils.handlers :refer [register-handler-fx]]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn generate-context
|
||||
(defn- generate-context
|
||||
"Generates context for jail call"
|
||||
[{:keys [chats] :accounts/keys [current-account-id]} chat-id to group-id]
|
||||
(merge {:platform platform/platform
|
||||
@ -22,55 +20,12 @@
|
||||
(not (nil? group-id)))}}
|
||||
i18n/delimeters))
|
||||
|
||||
;;;; Coeffects
|
||||
|
||||
(reg-cofx
|
||||
::get-persisted-message
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :get-persisted-message msg-store/get-by-id)))
|
||||
|
||||
;;;; Effects
|
||||
|
||||
(reg-fx
|
||||
::update-persisted-message
|
||||
(fn [message]
|
||||
(msg-store/update message)))
|
||||
|
||||
|
||||
(reg-fx
|
||||
:chat-fx/call-jail
|
||||
(fn [{:keys [callback-events-creator] :as opts}]
|
||||
(status/call-jail
|
||||
(-> opts
|
||||
(dissoc :callback-events-creator)
|
||||
(assoc :callback
|
||||
(fn [jail-response]
|
||||
(doseq [event (callback-events-creator jail-response)]
|
||||
(dispatch event))))))))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
(register-handler-fx
|
||||
::jail-command-data-response
|
||||
[trim-v]
|
||||
(fn [{:keys [db]} [{{:keys [returned]} :result} {:keys [message-id on-requested]} data-type]]
|
||||
(cond-> {}
|
||||
returned
|
||||
(assoc :db (assoc-in db [:message-data data-type message-id] returned))
|
||||
(and returned
|
||||
(= :preview data-type))
|
||||
(assoc ::update-persisted-message {:message-id message-id
|
||||
:preview (prn-str returned)})
|
||||
on-requested
|
||||
(assoc :dispatch (on-requested returned)))))
|
||||
|
||||
(register-handler-fx
|
||||
:request-command-data
|
||||
[trim-v]
|
||||
(fn [{:keys [db]}
|
||||
[{{:keys [command content-command params type]} :content
|
||||
:keys [chat-id jail-id group-id message-id handler-data] :as message}
|
||||
data-type]]
|
||||
(defn request-command-message-data
|
||||
"Requests command message data from jail"
|
||||
[db
|
||||
{{:keys [command content-command params type]} :content
|
||||
:keys [chat-id jail-id group-id message-id] :as message}
|
||||
data-type]
|
||||
(let [{:keys [chats]
|
||||
:accounts/keys [current-account-id]
|
||||
:contacts/keys [contacts]} db
|
||||
@ -85,38 +40,60 @@
|
||||
to (get-in contacts [chat-id :address])
|
||||
jail-params {:parameters params
|
||||
:context (generate-context db chat-id to group-id)}]
|
||||
{:chat-fx/call-jail {:jail-id jail-id
|
||||
{:call-jail {:jail-id jail-id
|
||||
:path path
|
||||
:params jail-params
|
||||
:callback-events-creator (fn [jail-response]
|
||||
[[::jail-command-data-response
|
||||
jail-response message data-type]])}})
|
||||
{:dispatch-n [[:add-commands-loading-callback jail-id
|
||||
#(dispatch [:request-command-data message data-type])]
|
||||
[:load-commands! jail-id]]}))))
|
||||
#(re-frame/dispatch [:request-command-message-data message data-type])]
|
||||
[:load-commands! jail-id]]})))
|
||||
|
||||
(register-handler-fx
|
||||
;;;; Handlers
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::jail-command-data-response
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [{{:keys [returned]} :result} {:keys [message-id on-requested]} data-type]]
|
||||
(cond-> {}
|
||||
returned
|
||||
(assoc :db (assoc-in db [:message-data data-type message-id] returned))
|
||||
(and returned
|
||||
(= :preview data-type))
|
||||
(assoc :update-message {:message-id message-id
|
||||
:preview (prn-str returned)})
|
||||
on-requested
|
||||
(assoc :dispatch (on-requested returned)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:request-command-message-data
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [message data-type]]
|
||||
(request-command-message-data db message data-type)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:execute-command-immediately
|
||||
[trim-v]
|
||||
[re-frame/trim-v]
|
||||
(fn [_ [{command-name :name :as command}]]
|
||||
(case (keyword command-name)
|
||||
:grant-permissions
|
||||
{:dispatch [:request-permissions
|
||||
[:read-external-storage]
|
||||
#(dispatch [:initialize-geth])]}
|
||||
#(re-frame/dispatch [:initialize-geth])]}
|
||||
(log/debug "ignoring command: " command))))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:request-command-preview
|
||||
[trim-v (inject-cofx ::get-persisted-message)]
|
||||
(fn [{:keys [db get-persisted-message]} [{:keys [message-id] :as message}]]
|
||||
[re-frame/trim-v (re-frame/inject-cofx :get-stored-message)]
|
||||
(fn [{:keys [db get-stored-message]} [{:keys [message-id] :as message}]]
|
||||
(let [previews (get-in db [:message-data :preview])]
|
||||
(when-not (contains? previews message-id)
|
||||
(let [{serialized-preview :preview} (get-persisted-message message-id)]
|
||||
(let [{serialized-preview :preview} (get-stored-message message-id)]
|
||||
;; if preview is already cached in db, do not request it from jail
|
||||
;; and write it directly to message-data path
|
||||
(if serialized-preview
|
||||
{:db (assoc-in db
|
||||
[:message-data :preview message-id]
|
||||
(reader/read-string serialized-preview))}
|
||||
{:dispatch [:request-command-data message :preview]}))))))
|
||||
(request-command-message-data db message :preview)))))))
|
||||
|
129
src/status_im/chat/events/console.cljs
Normal file
129
src/status_im/chat/events/console.cljs
Normal file
@ -0,0 +1,129 @@
|
||||
(ns status-im.chat.events.console
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.constants :as const]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.chat.events.sign-up :as sign-up-events]
|
||||
[status-im.ui.screens.accounts.events :as accounts-events]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.i18n :as i18n]
|
||||
[goog.string :as gstring]
|
||||
goog.string.format))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn console-respond-command-events
|
||||
[command random-id-seq]
|
||||
(let [{:keys [command handler-data]} command]
|
||||
(when command
|
||||
(let [{:keys [name]} command]
|
||||
(case name
|
||||
"js" (let [{:keys [err data messages]} handler-data
|
||||
content (or err data)
|
||||
message-events (mapv (fn [{:keys [message type]} id]
|
||||
[:received-message
|
||||
{:message-id id
|
||||
:content (str type ": " message)
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}])
|
||||
messages random-id-seq)]
|
||||
(conj message-events
|
||||
[:received-message
|
||||
{:message-id (first random-id-seq)
|
||||
:content (str content)
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]))
|
||||
(log/debug "ignoring command: " command))))))
|
||||
|
||||
(def faucet-base-url->url
|
||||
{"http://faucet.ropsten.be:3001" "http://faucet.ropsten.be:3001/donate/0x%s"
|
||||
"http://46.101.129.137:3001" "http://46.101.129.137:3001/donate/0x%s"})
|
||||
|
||||
(defn- faucet-response-event [message-id content]
|
||||
[:received-message
|
||||
{:message-id message-id
|
||||
:content content
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}])
|
||||
|
||||
(def console-commands->fx
|
||||
{"password"
|
||||
(fn [{:keys [db]} {:keys [params]}]
|
||||
(accounts-events/create-account db (:password params)))
|
||||
|
||||
"phone"
|
||||
(fn [{:keys [db]} {:keys [params id]}]
|
||||
(-> db
|
||||
(sign-up-events/sign-up (:phone params) id)
|
||||
(as-> fx
|
||||
(assoc fx :dispatch-n [(:dispatch fx)]))
|
||||
(dissoc :dispatch)))
|
||||
|
||||
"confirmation-code"
|
||||
(fn [{:keys [db]} {:keys [params id]}]
|
||||
(sign-up-events/sign-up-confirm db (:code params) id))
|
||||
|
||||
"faucet"
|
||||
(fn [{:keys [db random-id]} {:keys [params id]}]
|
||||
(let [{:accounts/keys [accounts current-account-id]} db
|
||||
current-address (get-in accounts [current-account-id :address])
|
||||
faucet-url (get faucet-base-url->url (:url params))]
|
||||
{:http-get {:url (gstring/format faucet-url current-address)
|
||||
:success-event-creator (fn [_]
|
||||
(faucet-response-event
|
||||
random-id
|
||||
(i18n/label :t/faucet-success)))
|
||||
:failure-event-creator (fn [_]
|
||||
(faucet-response-event
|
||||
random-id
|
||||
(i18n/label :t/faucet-error)))}}))
|
||||
|
||||
"debug"
|
||||
(fn [{:keys [random-id] :as cofx} {:keys [params id]}]
|
||||
(let [debug? (= "On" (:mode params))
|
||||
fx (accounts-events/account-update cofx {:debug? debug?})]
|
||||
(assoc fx :dispatch-n (if debug?
|
||||
[[:debug-server-start]
|
||||
[:received-message
|
||||
{:message-id random-id
|
||||
:content (i18n/label :t/debug-enabled)
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]]
|
||||
[[:debug-server-stop]]))))})
|
||||
|
||||
(def commands-names (set (keys console-commands->fx)))
|
||||
|
||||
(def commands-with-delivery-status
|
||||
(disj commands-names "password" "faucet" "debug"))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
;; TODO(janherich) remove this once send-message events are refactored
|
||||
(handlers/register-handler-fx
|
||||
:invoke-console-command-handler!
|
||||
[re-frame/trim-v (re-frame/inject-cofx :random-id) (re-frame/inject-cofx :now)]
|
||||
(fn [cofx [{:keys [chat-id command] :as command-params}]]
|
||||
(let [fx-fn (get console-commands->fx (-> command :command :name))]
|
||||
(-> cofx
|
||||
(fx-fn command)
|
||||
(update :dispatch-n (fnil conj []) [:prepare-command! chat-id command-params])))))
|
||||
|
||||
;; TODO(janherich) remove this once send-message events are refactored
|
||||
(handlers/register-handler-fx
|
||||
:console-respond-command
|
||||
[(re-frame/inject-cofx :random-id-seq) re-frame/trim-v]
|
||||
(fn [{:keys [random-id-seq]} [command]]
|
||||
(when-let [events (console-respond-command-events command random-id-seq)]
|
||||
{:dispatch-n events})))
|
@ -1,33 +1,24 @@
|
||||
(ns status-im.chat.events.input
|
||||
(:require [clojure.string :as str]
|
||||
[re-frame.core :refer [reg-fx reg-cofx inject-cofx dispatch trim-v]]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.chat.utils :as chat-utils]
|
||||
[status-im.chat.models :as model]
|
||||
[status-im.chat.models.input :as input-model]
|
||||
[status-im.chat.models.suggestions :as suggestions]
|
||||
[status-im.chat.models.suggestions :as suggestions-model]
|
||||
[status-im.chat.events.commands :as commands-events]
|
||||
[status-im.chat.events.animation :as animation-events]
|
||||
[status-im.bots.events :as bots-events]
|
||||
[status-im.components.react :as react-comp]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :refer [register-handler-db register-handler-fx]]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.i18n :as i18n]))
|
||||
|
||||
;;;; Coeffects
|
||||
|
||||
(reg-cofx
|
||||
:now
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :now (time/now-ms))))
|
||||
|
||||
(reg-cofx
|
||||
:random-id
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-id (random/id))))
|
||||
|
||||
;;;; Effects
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::focus-rn-component
|
||||
(fn [ref]
|
||||
(try
|
||||
@ -35,7 +26,7 @@
|
||||
(catch :default e
|
||||
(log/debug "Cannot focus the reference")))))
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::blur-rn-component
|
||||
(fn [ref]
|
||||
(try
|
||||
@ -43,169 +34,110 @@
|
||||
(catch :default e
|
||||
(log/debug "Cannot blur the reference")))))
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::dismiss-keyboard
|
||||
(fn [_]
|
||||
(react-comp/dismiss-keyboard!)))
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::set-native-props
|
||||
(fn [{:keys [ref props]}]
|
||||
(.setNativeProps ref (clj->js props))))
|
||||
|
||||
(reg-fx
|
||||
:chat-fx/call-jail-function
|
||||
(fn [{:keys [chat-id function callback-events-creator] :as opts}]
|
||||
(let [path [:functions function]
|
||||
params (select-keys opts [:parameters :context])]
|
||||
(status/call-jail
|
||||
{:jail-id chat-id
|
||||
:path path
|
||||
:params params
|
||||
:callback (fn [jail-response]
|
||||
(doseq [event (if callback-events-creator
|
||||
(callback-events-creator jail-response)
|
||||
[[:received-bot-response
|
||||
{:chat-id chat-id}
|
||||
jail-response]])
|
||||
:when event]
|
||||
(dispatch event)))}))))
|
||||
;;;; Helper functions
|
||||
|
||||
;;;; Handlers
|
||||
(defn update-suggestions
|
||||
"Update suggestions for current chat input, takes db as the only argument
|
||||
and returns map with keys :db (new db with up-to-date suggestions) and (optionally)
|
||||
:call-jail-function with jail function call params, if request to jail needs
|
||||
to be made as a result of suggestions update."
|
||||
[{:keys [chats current-chat-id current-account-id local-storage] :as db}]
|
||||
(let [chat-text (str/trim (or (get-in chats [current-chat-id :input-text]) ""))
|
||||
requests (->> (suggestions-model/get-request-suggestions db chat-text)
|
||||
(remove (fn [{:keys [type]}]
|
||||
(= type :grant-permissions))))
|
||||
commands (suggestions-model/get-command-suggestions db chat-text)
|
||||
global-commands (suggestions-model/get-global-command-suggestions db chat-text)
|
||||
all-commands (->> (into global-commands commands)
|
||||
(remove (fn [[k {:keys [hidden?]}]] hidden?))
|
||||
(into {}))
|
||||
{:keys [dapp?]} (get-in db [:contacts/contacts current-chat-id])
|
||||
new-db (cond-> db
|
||||
true (assoc-in [:chats current-chat-id :request-suggestions] requests)
|
||||
true (assoc-in [:chats current-chat-id :command-suggestions] all-commands)
|
||||
(and dapp?
|
||||
(str/blank? chat-text))
|
||||
(assoc-in [:chats current-chat-id :parameter-boxes :message] nil))]
|
||||
(cond-> {:db new-db}
|
||||
(and dapp?
|
||||
(not (str/blank? chat-text))
|
||||
(every? empty? [requests commands]))
|
||||
(assoc :call-jail-function {:chat-id current-chat-id
|
||||
:function :on-message-input-change
|
||||
:parameters {:message chat-text}
|
||||
:context {:data (get local-storage current-chat-id)
|
||||
:from current-account-id}}))))
|
||||
|
||||
(register-handler-db
|
||||
:update-input-data
|
||||
(fn [db]
|
||||
(input-model/modified-db-after-change db)))
|
||||
(defn set-chat-input-text
|
||||
"Set input text for current-chat and updates suggestions relevant to current input.
|
||||
Takes db, input text and `:append?` flag as arguments and returns new db.
|
||||
When `:append?` is false or not provided, resets the current chat input with input text,
|
||||
otherwise input text is appended to the current chat input."
|
||||
[{:keys [current-chat-id] :as db} new-input & {:keys [append?]}]
|
||||
(let [current-input (get-in db [:chats current-chat-id :input-text])]
|
||||
(assoc-in db
|
||||
[:chats current-chat-id :input-text]
|
||||
(input-model/text->emoji (if append?
|
||||
(str current-input new-input)
|
||||
new-input)))))
|
||||
|
||||
(register-handler-fx
|
||||
:set-chat-input-text
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id chats chat-ui-props] :as db} :db} [text chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)]
|
||||
{:db (assoc-in db
|
||||
[:chats chat-id :input-text]
|
||||
(input-model/text->emoji text))
|
||||
:dispatch [:update-suggestions chat-id text]})))
|
||||
(defn set-chat-input-metadata
|
||||
"Set input metadata for active chat. Takes db and metadata and returns updated db."
|
||||
[{:keys [current-chat-id] :as db} metadata]
|
||||
(assoc-in db [:chats current-chat-id :input-metadata] metadata))
|
||||
|
||||
(register-handler-fx
|
||||
:add-to-chat-input-text
|
||||
[trim-v]
|
||||
(fn [{{:keys [chats current-chat-id]} :db} [text-to-add]]
|
||||
(let [input-text (get-in chats [current-chat-id :input-text])]
|
||||
{:dispatch [:set-chat-input-text (str input-text text-to-add)]})))
|
||||
(defn set-chat-seq-arg-input-text
|
||||
"Sets input text for current sequential argument in active chat"
|
||||
[{:keys [current-chat-id] :as db} text]
|
||||
(assoc-in db [:chats current-chat-id :seq-argument-input-text] text))
|
||||
|
||||
(register-handler-fx
|
||||
:select-chat-input-command
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id chat-ui-props]} :db}
|
||||
[{:keys [prefill prefill-bot-db sequential-params name] :as command} metadata prevent-auto-focus?]]
|
||||
(cond-> {:dispatch-n [[:set-chat-input-text (str (chat-utils/command-name command)
|
||||
const/spacing-char
|
||||
(when-not sequential-params
|
||||
(input-model/join-command-args prefill)))]
|
||||
[:clear-bot-db]
|
||||
[:set-chat-input-metadata metadata]
|
||||
[:set-chat-ui-props {:show-suggestions? false
|
||||
:show-emoji? false
|
||||
:result-box nil
|
||||
:validation-messages nil
|
||||
:prev-command name}]
|
||||
[:load-chat-parameter-box command 0]]}
|
||||
(defn clear-seq-arguments
|
||||
"Clears sequential arguments for current-chat"
|
||||
[{:keys [current-chat-id chats] :as db}]
|
||||
(-> db
|
||||
(assoc-in [:chats current-chat-id :seq-arguments] [])
|
||||
(assoc-in [:chats current-chat-id :seq-argument-input-text] nil)))
|
||||
|
||||
prefill-bot-db
|
||||
(update :dispatch-n conj [:update-bot-db {:bot current-chat-id
|
||||
:db prefill-bot-db}])
|
||||
|
||||
(not (and sequential-params
|
||||
prevent-auto-focus?))
|
||||
(update :dispatch-n conj [:chat-input-focus :input-ref])
|
||||
|
||||
sequential-params
|
||||
(assoc :dispatch-later (cond-> [{:ms 100 :dispatch [:set-chat-seq-arg-input-text
|
||||
(str/join const/spacing-char prefill)]}]
|
||||
(not prevent-auto-focus?)
|
||||
(conj {:ms 100 :dispatch [:chat-input-focus :seq-input-ref]}))))))
|
||||
|
||||
(register-handler-db
|
||||
:set-chat-input-metadata
|
||||
[trim-v]
|
||||
(fn [{:keys [current-chat-id] :as db} [data chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)]
|
||||
(assoc-in db [:chats chat-id :input-metadata] data))))
|
||||
|
||||
(register-handler-fx
|
||||
:set-command-argument
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id] :as db} :db} [[index arg move-to-next?]]]
|
||||
(defn set-command-argument
|
||||
"Sets command argument in active chat"
|
||||
[{:keys [current-chat-id] :as db} index arg move-to-next?]
|
||||
(let [command (-> (get-in db [:chats current-chat-id :input-text])
|
||||
(input-model/split-command-args))
|
||||
seq-params? (-> (input-model/selected-chat-command db current-chat-id)
|
||||
(get-in [:command :sequential-params]))
|
||||
event-to-dispatch (if seq-params?
|
||||
[:set-chat-seq-arg-input-text arg]
|
||||
(get-in [:command :sequential-params]))]
|
||||
(if seq-params?
|
||||
{:db (set-chat-seq-arg-input-text db arg)}
|
||||
(let [arg (str/replace arg (re-pattern const/arg-wrapping-char) "")
|
||||
command-name (first command)
|
||||
command-args (into [] (rest command))
|
||||
command-args (if (< index (count command-args))
|
||||
(assoc command-args index arg)
|
||||
(conj command-args arg))]
|
||||
[:set-chat-input-text (str command-name
|
||||
(conj command-args arg))
|
||||
input-text (str command-name
|
||||
const/spacing-char
|
||||
(input-model/join-command-args command-args)
|
||||
(when (and move-to-next?
|
||||
(= index (dec (count command-args))))
|
||||
const/spacing-char))]))]
|
||||
{:dispatch event-to-dispatch})))
|
||||
const/spacing-char))]
|
||||
(-> db
|
||||
(set-chat-input-text input-text)
|
||||
update-suggestions)))))
|
||||
|
||||
(register-handler-fx
|
||||
:chat-input-focus
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id chat-ui-props]} :db} [ref]]
|
||||
(when-let [cmp-ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
{::focus-rn-component cmp-ref})))
|
||||
|
||||
(register-handler-fx
|
||||
:chat-input-blur
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id chat-ui-props]} :db} [ref]]
|
||||
(when-let [cmp-ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
{::blur-rn-component cmp-ref})))
|
||||
|
||||
(register-handler-fx
|
||||
:update-suggestions
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id] :as db} :db} [chat-id text]]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
chat-text (str/trim (or text (get-in db [:chats chat-id :input-text]) ""))
|
||||
requests (->> (suggestions/get-request-suggestions db chat-text)
|
||||
(remove (fn [{:keys [type]}]
|
||||
(= type :grant-permissions))))
|
||||
commands (suggestions/get-command-suggestions db chat-text)
|
||||
global-commands (suggestions/get-global-command-suggestions db chat-text)
|
||||
all-commands (->> (into global-commands commands)
|
||||
(remove (fn [[k {:keys [hidden?]}]] hidden?))
|
||||
(into {}))
|
||||
{:keys [dapp?]} (get-in db [:contacts/contacts chat-id])
|
||||
new-db (cond-> db
|
||||
true (assoc-in [:chats chat-id :request-suggestions] requests)
|
||||
true (assoc-in [:chats chat-id :command-suggestions] all-commands)
|
||||
(and dapp?
|
||||
(str/blank? chat-text))
|
||||
(assoc-in [:chats chat-id :parameter-boxes :message] nil))
|
||||
new-event (when (and dapp?
|
||||
(not (str/blank? chat-text))
|
||||
(every? empty? [requests commands]))
|
||||
[::check-dapp-suggestions chat-id chat-text])]
|
||||
(cond-> {:db new-db}
|
||||
new-event (assoc :dispatch new-event)))))
|
||||
|
||||
(register-handler-fx
|
||||
:load-chat-parameter-box
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id bot-db] :accounts/keys [current-account-id] :as db} :db}
|
||||
[{:keys [name type bot owner-id] :as command}]]
|
||||
(let [parameter-index (input-model/argument-position db current-chat-id)]
|
||||
(defn load-chat-parameter-box
|
||||
"Returns fx for loading chat parameter box for active chat"
|
||||
[{:keys [current-chat-id bot-db] :accounts/keys [current-account-id] :as db}
|
||||
{:keys [name type bot owner-id] :as command}]
|
||||
(let [parameter-index (input-model/argument-position db)]
|
||||
(when (and command (> parameter-index -1))
|
||||
(let [data (get-in db [:local-storage current-chat-id])
|
||||
bot-db (get bot-db (or bot current-chat-id))
|
||||
@ -215,8 +147,8 @@
|
||||
parameter-index
|
||||
:suggestions]
|
||||
args (-> (get-in db [:chats current-chat-id :input-text])
|
||||
(input-model/split-command-args)
|
||||
(rest))
|
||||
input-model/split-command-args
|
||||
rest)
|
||||
seq-arg (get-in db [:chats current-chat-id :seq-argument-input-text])
|
||||
to (get-in db [:contacts/contacts current-chat-id :address])
|
||||
params {:parameters {:args args
|
||||
@ -226,7 +158,7 @@
|
||||
:from current-account-id
|
||||
:to to}
|
||||
(input-model/command-dependent-context-params current-chat-id command))}]
|
||||
{:chat-fx/call-jail {:jail-id (or bot owner-id current-chat-id)
|
||||
{:call-jail {:jail-id (or bot owner-id current-chat-id)
|
||||
:path path
|
||||
:params params
|
||||
:callback-events-creator (fn [jail-response]
|
||||
@ -234,104 +166,100 @@
|
||||
{:chat-id current-chat-id
|
||||
:command command
|
||||
:parameter-index parameter-index}
|
||||
jail-response]])}})))))
|
||||
jail-response]])}}))))
|
||||
|
||||
(register-handler-fx
|
||||
::send-message
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-public-key] :accounts/keys [current-account-id] :as db} :db} [command chat-id]]
|
||||
(let [text (get-in db [:chats chat-id :input-text])
|
||||
data {:message text
|
||||
:command command
|
||||
:chat-id chat-id
|
||||
:identity current-public-key
|
||||
:address current-account-id}
|
||||
events [[:set-chat-input-text nil chat-id]
|
||||
[:set-chat-input-metadata nil chat-id]
|
||||
[:set-chat-ui-props {:sending-in-progress? false}]]]
|
||||
{:dispatch-n (if command
|
||||
(conj events [:check-commands-handlers! data])
|
||||
(if (str/blank? text)
|
||||
events
|
||||
(conj events [:prepare-message data])))})))
|
||||
(defn chat-input-focus
|
||||
"Returns fx for focusing on active chat input reference"
|
||||
[{:keys [current-chat-id chat-ui-props]} ref]
|
||||
(when-let [cmp-ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
{::focus-rn-component cmp-ref}))
|
||||
|
||||
(register-handler-fx
|
||||
:proceed-command
|
||||
[trim-v]
|
||||
(fn [_ [{{:keys [bot]} :command :as content} chat-id]]
|
||||
(let [params {:content content
|
||||
:chat-id chat-id
|
||||
:jail-id (or bot chat-id)}
|
||||
on-send-params (merge params
|
||||
{:data-type :on-send
|
||||
:event-after-creator (fn [_ jail-response]
|
||||
[::send-command jail-response content chat-id])})
|
||||
after-validation-events [[::request-command-data on-send-params]]
|
||||
validation-params (merge params
|
||||
{:data-type :validator
|
||||
:event-after-creator (fn [_ jail-response]
|
||||
[::proceed-validation
|
||||
jail-response
|
||||
after-validation-events])})]
|
||||
{:dispatch [::request-command-data validation-params]})))
|
||||
(defn update-text-selection
|
||||
"Updates text selection in active chat input"
|
||||
[{:keys [current-chat-id] :as db} selection]
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
command (input-model/selected-chat-command db current-chat-id input-text)
|
||||
new-db (model/set-chat-ui-props db {:selection selection})
|
||||
chat-parameter-box-fx (load-chat-parameter-box new-db (:command command))]
|
||||
(cond-> {:db new-db}
|
||||
|
||||
(register-handler-fx
|
||||
::proceed-validation
|
||||
[trim-v]
|
||||
(fn [_ [{:keys [markup validationHandler parameters]} proceed-events]]
|
||||
(let [error-events-creator (fn [validator-result]
|
||||
[[:set-chat-ui-props {:validation-messages validator-result
|
||||
:sending-in-progress? false}]])
|
||||
events (cond
|
||||
markup
|
||||
(error-events-creator markup)
|
||||
chat-parameter-box-fx
|
||||
(merge chat-parameter-box-fx)
|
||||
|
||||
validationHandler
|
||||
[[::execute-validation-handler
|
||||
validationHandler parameters error-events-creator proceed-events]
|
||||
[:set-chat-ui-props {:sending-in-progress? false}]]
|
||||
(and (= selection (+ (count const/command-char)
|
||||
(count (get-in command [:command :name]))
|
||||
(count const/spacing-char)))
|
||||
(get-in command [:command :sequential-params]))
|
||||
(merge (chat-input-focus new-db :seq-input-ref)))))
|
||||
|
||||
:default
|
||||
proceed-events)]
|
||||
{:dispatch-n events})))
|
||||
(defn select-chat-input-command
|
||||
"Selects command + (optional) arguments as input for active chat"
|
||||
[{:keys [current-chat-id chat-ui-props] :as db}
|
||||
{:keys [prefill prefill-bot-db sequential-params name] :as command} metadata prevent-auto-focus?]
|
||||
(let [fx (-> db
|
||||
bots-events/clear-bot-db
|
||||
clear-seq-arguments
|
||||
(model/set-chat-ui-props {:show-suggestions? false
|
||||
:show-emoji? false
|
||||
:result-box nil
|
||||
:validation-messages nil
|
||||
:prev-command name})
|
||||
(set-chat-input-metadata metadata)
|
||||
(set-chat-input-text (str (chat-utils/command-name command)
|
||||
const/spacing-char
|
||||
(when-not sequential-params
|
||||
(input-model/join-command-args prefill))))
|
||||
update-suggestions
|
||||
(as-> fx'
|
||||
(merge fx' (load-chat-parameter-box (:db fx') command))))]
|
||||
(cond-> fx
|
||||
prefill-bot-db (update :db bots-events/update-bot-db {:db prefill-bot-db})
|
||||
|
||||
(register-handler-fx
|
||||
::execute-validation-handler
|
||||
[trim-v]
|
||||
(fn [_ [validation-handler-name params error-events-creator proceed-events]]
|
||||
(let [error-events (when-let [validator (input-model/validation-handler validation-handler-name)]
|
||||
(validator params error-events-creator))]
|
||||
{:dispatch-n (or error-events proceed-events)})))
|
||||
(not (and sequential-params
|
||||
prevent-auto-focus?))
|
||||
(merge (chat-input-focus (:db fx) :input-ref))
|
||||
|
||||
(register-handler-fx
|
||||
::send-command
|
||||
[trim-v]
|
||||
(fn [_ [on-send {{:keys [fullscreen bot]} :command :as content} chat-id]]
|
||||
(if on-send
|
||||
{:dispatch-n (cond-> [[:set-chat-ui-props {:result-box on-send
|
||||
:sending-in-progress? false}]]
|
||||
fullscreen
|
||||
(conj [:choose-predefined-expandable-height :result-box :max]))
|
||||
::dismiss-keyboard nil}
|
||||
{:dispatch [::request-command-data
|
||||
{:content content
|
||||
:chat-id chat-id
|
||||
:jail-id (or bot chat-id)
|
||||
:data-type :preview
|
||||
:event-after-creator (fn [command-message _]
|
||||
[::send-message command-message chat-id])}]})))
|
||||
sequential-params
|
||||
(as-> fx'
|
||||
(cond-> (update fx' :db
|
||||
set-chat-seq-arg-input-text
|
||||
(str/join const/spacing-char prefill))
|
||||
(not prevent-auto-focus?)
|
||||
(merge fx' (chat-input-focus (:db fx') :seq-input-ref)))))))
|
||||
|
||||
(register-handler-fx
|
||||
::request-command-data
|
||||
[trim-v (inject-cofx :random-id) (inject-cofx :now)]
|
||||
(fn [{{:keys [bot-db] :contacts/keys [contacts]} :db
|
||||
message-id :random-id
|
||||
current-time :now}
|
||||
[{{:keys [command
|
||||
(defn set-contact-as-command-argument
|
||||
"Sets contact as command argument for active chat"
|
||||
[db {:keys [bot-db-key contact arg-index]}]
|
||||
(let [name (str/replace (:name contact) (re-pattern const/arg-wrapping-char) "")
|
||||
contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?])]
|
||||
(-> (set-command-argument db arg-index name true)
|
||||
(as-> fx
|
||||
(merge fx (bots-events/set-in-bot-db
|
||||
(:db fx)
|
||||
{:path [:public (keyword bot-db-key)]
|
||||
:value contact})))
|
||||
(as-> fx
|
||||
(let [{:keys [current-chat-id]
|
||||
:as new-db} (:db fx)
|
||||
arg-position (input-model/argument-position new-db)
|
||||
input-text (get-in new-db [:chats current-chat-id :input-text])
|
||||
command-args (cond-> (input-model/split-command-args input-text)
|
||||
(input-model/text-ends-with-space? input-text) (conj ""))
|
||||
new-selection (->> command-args
|
||||
(take (+ 3 arg-position))
|
||||
(input-model/join-command-args)
|
||||
count
|
||||
(min (count input-text)))]
|
||||
(merge fx (update-text-selection new-db new-selection)))))))
|
||||
|
||||
(defn- request-command-data
|
||||
"Requests command data from jail"
|
||||
[{:keys [bot-db] :contacts/keys [contacts] :as db}
|
||||
{{:keys [command
|
||||
metadata
|
||||
args]
|
||||
:as content} :content
|
||||
:keys [chat-id jail-id data-type event-after-creator]}]]
|
||||
:keys [chat-id jail-id data-type event-after-creator message-id current-time]}]
|
||||
(let [{:keys [dapp? dapp-url name]} (get contacts chat-id)
|
||||
metadata (merge metadata
|
||||
(when dapp?
|
||||
@ -359,53 +287,228 @@
|
||||
:type (:type command)}
|
||||
:on-requested (fn [jail-response]
|
||||
(event-after-creator command-message jail-response))}]
|
||||
{:dispatch [:request-command-data request-data data-type]})))
|
||||
(commands-events/request-command-message-data db request-data data-type)))
|
||||
|
||||
(register-handler-fx
|
||||
:send-current-message
|
||||
(fn [{{:keys [current-chat-id] :as db} :db} _]
|
||||
(let [chat-command (input-model/selected-chat-command db current-chat-id)
|
||||
seq-command? (get-in chat-command [:command :sequential-params])
|
||||
chat-command (if seq-command?
|
||||
(let [args (get-in db [:chats current-chat-id :seq-arguments])]
|
||||
(assoc chat-command :args args))
|
||||
(update chat-command :args #(remove str/blank? %)))
|
||||
set-chat-ui-props-event [:set-chat-ui-props {:sending-in-progress? true}]
|
||||
additional-events (if (:command chat-command)
|
||||
(if (= :complete (input-model/command-completion chat-command))
|
||||
[[:proceed-command chat-command current-chat-id]
|
||||
[:clear-seq-arguments current-chat-id]]
|
||||
(let [text (get-in db [:chats current-chat-id :input-text])]
|
||||
[[:set-chat-ui-props {:sending-in-progress? false}]
|
||||
(when-not (input-model/text-ends-with-space? text)
|
||||
[:set-chat-input-text (str text const/spacing-char)])]))
|
||||
[[::send-message nil current-chat-id]])]
|
||||
{:dispatch-n (into [set-chat-ui-props-event]
|
||||
(remove nil? additional-events))})))
|
||||
(defn proceed-command
|
||||
"Proceed with command processing by setting up execution chain of events:
|
||||
|
||||
(register-handler-fx
|
||||
::check-dapp-suggestions
|
||||
[trim-v]
|
||||
(fn [{{:accounts/keys [current-account-id] :as db} :db} [chat-id text]]
|
||||
(let [data (get-in db [:local-storage chat-id])]
|
||||
{:chat-fx/call-jail-function {:chat-id chat-id
|
||||
:function :on-message-input-change
|
||||
:parameters {:message text}
|
||||
:context {:data data
|
||||
:from current-account-id}}})))
|
||||
1. Command validation
|
||||
2. Checking if command defined `onSend`
|
||||
|
||||
(register-handler-db
|
||||
:clear-seq-arguments
|
||||
[trim-v]
|
||||
(fn [{:keys [current-chat-id chats] :as db} [chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)]
|
||||
Second check is important because commands defining `onSend` are actually not
|
||||
'sendable' and can't be treated as normal command messages, instead of actually
|
||||
sending them, returned markup is displayed in the chat result box and command processing
|
||||
ends there.
|
||||
If it's normal command instead (determined by nil response to `:on-send` jail request),
|
||||
processing continues by requesting command preview before actually sending the command
|
||||
message."
|
||||
[{:keys [current-chat-id] :as db} {{:keys [bot]} :command :as content} message-id current-time]
|
||||
(let [params-template {:content content
|
||||
:chat-id current-chat-id
|
||||
:jail-id (or bot current-chat-id)
|
||||
:message-id message-id
|
||||
:current-time current-time}
|
||||
on-send-params (merge params-template
|
||||
{:data-type :on-send
|
||||
:event-after-creator (fn [_ jail-response]
|
||||
[::check-command-type
|
||||
jail-response
|
||||
params-template])})
|
||||
after-validation-events [[::request-command-data on-send-params]]
|
||||
validation-params (merge params-template
|
||||
{:data-type :validator
|
||||
:event-after-creator (fn [_ jail-response]
|
||||
[::proceed-validation
|
||||
jail-response
|
||||
after-validation-events])})]
|
||||
(request-command-data db validation-params)))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
(handlers/register-handler-db
|
||||
:update-input-data
|
||||
(fn [db]
|
||||
(input-model/modified-db-after-change db)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:set-chat-input-text
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [text]]
|
||||
(-> db
|
||||
(assoc-in [:chats chat-id :seq-arguments] [])
|
||||
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
|
||||
(set-chat-input-text text)
|
||||
update-suggestions)))
|
||||
|
||||
(register-handler-db
|
||||
(handlers/register-handler-fx
|
||||
:add-to-chat-input-text
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [text-to-add]]
|
||||
(-> db
|
||||
(set-chat-input-text text-to-add :append? true)
|
||||
update-suggestions)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:select-chat-input-command
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [command metadata prevent-auto-focus?]]
|
||||
(select-chat-input-command db command metadata prevent-auto-focus?)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:set-chat-input-metadata
|
||||
[re-frame/trim-v]
|
||||
(fn [db [data]]
|
||||
(set-chat-input-metadata db data)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:set-command-argument
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [[index arg move-to-next?]]]
|
||||
(set-command-argument db index arg move-to-next?)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:chat-input-focus
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [ref]]
|
||||
(chat-input-focus db ref)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:chat-input-blur
|
||||
[re-frame/trim-v]
|
||||
(fn [{{:keys [current-chat-id chat-ui-props]} :db} [ref]]
|
||||
(when-let [cmp-ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
{::blur-rn-component cmp-ref})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:update-suggestions
|
||||
(fn [{:keys [db]} _]
|
||||
(update-suggestions db)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-chat-parameter-box
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [command]]
|
||||
(load-chat-parameter-box db command)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:proceed-command
|
||||
[re-frame/trim-v (re-frame/inject-cofx :random-id) (re-frame/inject-cofx :now)]
|
||||
(fn [{:keys [db random-id now]} [content]]
|
||||
(proceed-command db content random-id now)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::proceed-validation
|
||||
[re-frame/trim-v]
|
||||
(fn [_ [{:keys [markup validationHandler parameters]} proceed-events]]
|
||||
(let [error-events-creator (fn [validator-result]
|
||||
[[:set-chat-ui-props {:validation-messages validator-result
|
||||
:sending-in-progress? false}]])
|
||||
events (cond
|
||||
markup
|
||||
(error-events-creator markup)
|
||||
|
||||
validationHandler
|
||||
[[::execute-validation-handler
|
||||
validationHandler parameters error-events-creator proceed-events]
|
||||
[:set-chat-ui-props {:sending-in-progress? false}]]
|
||||
|
||||
:default
|
||||
proceed-events)]
|
||||
{:dispatch-n events})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::execute-validation-handler
|
||||
[re-frame/trim-v]
|
||||
(fn [_ [validation-handler-name params error-events-creator proceed-events]]
|
||||
(let [error-events (when-let [validator (input-model/validation-handler validation-handler-name)]
|
||||
(validator params error-events-creator))]
|
||||
{:dispatch-n (or error-events proceed-events)})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::request-command-data
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [command-params]]
|
||||
(request-command-data db command-params)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::send-command
|
||||
[re-frame/trim-v]
|
||||
(fn [{{:keys [current-public-key current-chat-id]
|
||||
:accounts/keys [current-account-id] :as db} :db} [{:keys [command] :as command-message}]]
|
||||
(-> db
|
||||
clear-seq-arguments
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
(model/set-chat-ui-props {:sending-in-progress? false})
|
||||
update-suggestions
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
(assoc :dispatch [:check-commands-handlers! {:message (get-in db [:chats current-chat-id :input-text])
|
||||
:command command-message
|
||||
:chat-id current-chat-id
|
||||
:identity current-public-key
|
||||
:address current-account-id}]))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::check-command-type
|
||||
[re-frame/trim-v]
|
||||
(fn [{{:keys [current-chat-id] :as db} :db} [on-send-jail-response params-template]]
|
||||
(if on-send-jail-response
|
||||
;; `onSend` is defined, we have non-sendable command here, like `@browse`
|
||||
{:db (-> db
|
||||
(model/set-chat-ui-props {:result-box on-send-jail-response
|
||||
:sending-in-progress? false})
|
||||
(animation-events/choose-predefined-expandable-height :result-box :max))
|
||||
::dismiss-keyboard nil}
|
||||
;; regular command message, we need to fetch preview before sending the command message
|
||||
(request-command-data db (merge params-template
|
||||
{:data-type :preview
|
||||
:event-after-creator (fn [command-message _]
|
||||
[::send-command command-message])})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:send-current-message
|
||||
[(re-frame/inject-cofx :random-id) (re-frame/inject-cofx :now)]
|
||||
(fn [{{:keys [current-chat-id current-public-key] :as db} :db message-id :random-id current-time :now} _]
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
chat-command (-> db
|
||||
(input-model/selected-chat-command current-chat-id input-text)
|
||||
(as-> selected-command
|
||||
(if (get-in selected-command [:command :sequential-params])
|
||||
(assoc selected-command :args
|
||||
(get-in db [:chats current-chat-id :seq-arguments]))
|
||||
(update selected-command :args (partial remove str/blank?)))))]
|
||||
(if (:command chat-command)
|
||||
;; current input contains command
|
||||
(if (= :complete (input-model/command-completion chat-command))
|
||||
;; command is complete, clear sequential arguments and proceed with command processing
|
||||
(-> db
|
||||
clear-seq-arguments
|
||||
(model/set-chat-ui-props {:sending-in-progress? true})
|
||||
(proceed-command chat-command message-id current-time))
|
||||
;; command is not complete, just add space after command if necessary
|
||||
{:db (cond-> db
|
||||
(not (input-model/text-ends-with-space? input-text))
|
||||
(set-chat-input-text const/spacing-char :append? true))})
|
||||
;; no command detected, when not empty, proceed by sending text message without command processing
|
||||
(if (str/blank? input-text)
|
||||
{:db db}
|
||||
(-> db
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
update-suggestions
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
(assoc :dispatch [:prepare-message {:message input-text
|
||||
:chat-id current-chat-id
|
||||
:identity current-public-key
|
||||
:address (:accounts/current-account-id db)}])))))))
|
||||
|
||||
;; TODO: remove this handler and leave only helper fn once all invocations are refactored
|
||||
(handlers/register-handler-db
|
||||
:clear-seq-arguments
|
||||
(fn [db]
|
||||
(clear-seq-arguments db)))
|
||||
|
||||
(handlers/register-handler-db
|
||||
::update-seq-arguments
|
||||
[trim-v]
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [current-chat-id chats] :as db} [chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
text (get-in chats [chat-id :seq-argument-input-text])]
|
||||
@ -413,58 +516,46 @@
|
||||
(update-in [:chats chat-id :seq-arguments] #(into [] (conj % text)))
|
||||
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:send-seq-argument
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id chats] :as db} :db} [chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
text (get-in chats [chat-id :seq-argument-input-text])
|
||||
seq-arguments (get-in chats [chat-id :seq-arguments])
|
||||
command (-> (input-model/selected-chat-command db chat-id)
|
||||
(fn [{{:keys [current-chat-id chats] :as db} :db} _]
|
||||
(let [text (get-in chats [current-chat-id :seq-argument-input-text])
|
||||
seq-arguments (get-in chats [current-chat-id :seq-arguments])
|
||||
command (-> (input-model/selected-chat-command db current-chat-id)
|
||||
(assoc :args (into [] (conj seq-arguments text))))]
|
||||
{:dispatch [::request-command-data
|
||||
{:content command
|
||||
:chat-id chat-id
|
||||
:jail-id (or (get-in command [:command :bot]) chat-id)
|
||||
(request-command-data db {:content command
|
||||
:chat-id current-chat-id
|
||||
:jail-id (or (get-in command [:command :bot]) current-chat-id)
|
||||
:data-type :validator
|
||||
:event-after-creator (fn [_ jail-response]
|
||||
[::proceed-validation
|
||||
jail-response
|
||||
[[::update-seq-arguments chat-id]
|
||||
[:send-current-message]]])}]})))
|
||||
[[::update-seq-arguments current-chat-id]
|
||||
[:send-current-message]]])}))))
|
||||
|
||||
(register-handler-db
|
||||
(handlers/register-handler-db
|
||||
:set-chat-seq-arg-input-text
|
||||
[trim-v]
|
||||
(fn [{:keys [current-chat-id] :as db} [text chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)]
|
||||
(assoc-in db [:chats chat-id :seq-argument-input-text] text))))
|
||||
[re-frame/trim-v]
|
||||
(fn [db [text]]
|
||||
(set-chat-seq-arg-input-text db text)))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:update-text-selection
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-chat-id] :as db} :db} [selection]]
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
command (input-model/selected-chat-command db current-chat-id input-text)]
|
||||
(cond-> {:dispatch-n [[:set-chat-ui-props {:selection selection}]
|
||||
[:load-chat-parameter-box (:command command)]]}
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [selection]]
|
||||
(update-text-selection db selection)))
|
||||
|
||||
(and (= selection (+ (count const/command-char)
|
||||
(count (get-in command [:command :name]))
|
||||
(count const/spacing-char)))
|
||||
(get-in command [:command :sequential-params]))
|
||||
(update :dispatch-n conj [:chat-input-focus :seq-input-ref])))))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:select-prev-argument
|
||||
(fn [{{:keys [chat-ui-props current-chat-id] :as db} :db} _]
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
command (input-model/selected-chat-command db current-chat-id input-text)]
|
||||
(if (get-in command [:command :sequential-params])
|
||||
{:dispatch-n [[:set-command-argument [0 "" false]]
|
||||
[:set-chat-seq-arg-input-text ""]
|
||||
[:load-chat-parameter-box (:command command)]]}
|
||||
(let [arg-pos (input-model/argument-position db current-chat-id)]
|
||||
(-> (set-command-argument db 0 "" false)
|
||||
(update :db set-chat-seq-arg-input-text "")
|
||||
(as-> fx
|
||||
(merge fx (load-chat-parameter-box (:db fx) (:command command)))))
|
||||
(let [arg-pos (input-model/argument-position db)]
|
||||
(when (pos? arg-pos)
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
new-sel (->> (input-model/split-command-args input-text)
|
||||
@ -472,23 +563,22 @@
|
||||
(input-model/join-command-args)
|
||||
(count))
|
||||
ref (get-in chat-ui-props [current-chat-id :input-ref])]
|
||||
{::set-native-props {:ref ref
|
||||
:props {:selection {:start new-sel :end new-sel}}}
|
||||
:dispatch [:update-text-selection new-sel]})))))))
|
||||
(-> db
|
||||
(update-text-selection new-sel)
|
||||
(assoc ::set-native-props
|
||||
{:ref ref
|
||||
:props {:selection {:start new-sel :end new-sel}}})))))))))
|
||||
|
||||
(register-handler-fx
|
||||
:select-next-argument
|
||||
(fn [{{:keys [chat-ui-props current-chat-id] :as db} :db} _]
|
||||
(let [arg-pos (input-model/argument-position db current-chat-id)]
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
command-args (cond-> (input-model/split-command-args input-text)
|
||||
(input-model/text-ends-with-space? input-text) (conj ""))
|
||||
new-sel (->> command-args
|
||||
(take (+ 3 arg-pos))
|
||||
(input-model/join-command-args)
|
||||
count
|
||||
(min (count input-text)))
|
||||
ref (get-in chat-ui-props [current-chat-id :input-ref])]
|
||||
{::set-native-props {:ref ref
|
||||
:props {:selection {:start new-sel :end new-sel}}}
|
||||
:dispatch [:update-text-selection new-sel]}))))
|
||||
(handlers/register-handler-fx
|
||||
:set-contact-as-command-argument
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [params]]
|
||||
(set-contact-as-command-argument db params)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-suggestions
|
||||
(fn [{:keys [db]} _]
|
||||
(-> db
|
||||
(model/toggle-chat-ui-prop :show-suggestions?)
|
||||
(model/set-chat-ui-props {:validation-messages nil})
|
||||
update-suggestions)))
|
||||
|
123
src/status_im/chat/events/receive_message.cljs
Normal file
123
src/status_im/chat/events/receive_message.cljs
Normal file
@ -0,0 +1,123 @@
|
||||
(ns status-im.chat.events.receive-message
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.utils.clocks :as clocks]
|
||||
[status-im.constants :as const]
|
||||
[status-im.chat.utils :as chat-utils]
|
||||
[status-im.chat.models.unviewed-messages :as unviewed-messages-model]
|
||||
[status-im.data-store.chats :as chat-store]
|
||||
[status-im.data-store.messages :as msg-store]))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:pop-up-chat?
|
||||
(fn [cofx]
|
||||
(assoc cofx :pop-up-chat? (fn [chat-id]
|
||||
(or (not (chat-store/exists? chat-id))
|
||||
(chat-store/is-active? chat-id))))))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-last-clock-value
|
||||
(fn [cofx]
|
||||
(assoc cofx :get-last-clock-value msg-store/get-last-clock-value)))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:current-timestamp
|
||||
(fn [cofx]
|
||||
;; TODO (janherich) why is actual timestmap generation in random namespace ?
|
||||
(assoc cofx :current-timestamp (random/timestamp))))
|
||||
|
||||
(defn- get-current-identity
|
||||
[{:accounts/keys [accounts current-account-id]}]
|
||||
(get-in accounts [current-account-id :public-key]))
|
||||
|
||||
(defn- wallet-message
|
||||
[{:keys [content-type] :as message}]
|
||||
(log/debug "Wallet msg")
|
||||
(let [wallet-ct (if (= content-type const/content-type-command)
|
||||
const/content-type-wallet-command
|
||||
const/content-type-wallet-request)]
|
||||
(-> message
|
||||
(assoc :clock-value 0
|
||||
:chat-id const/wallet-chat-id
|
||||
:content-type wallet-ct)
|
||||
(dissoc :group-id))))
|
||||
|
||||
(defn add-message
|
||||
[{:keys [db get-stored-message get-last-stored-message pop-up-chat?
|
||||
get-last-clock-value current-timestamp random-id]}
|
||||
{:keys [from group-id chat-id content-type
|
||||
message-id timestamp clock-value]
|
||||
:as message
|
||||
:or {clock-value 0}}]
|
||||
(let [chat-identifier (or group-id chat-id from)
|
||||
current-identity (get-current-identity db)]
|
||||
;; proceed with adding message if message is not already stored in realm,
|
||||
;; it's not from current user (outgoing message) and it's for relevant chat
|
||||
;; (either current active chat or new chat not existing yet)
|
||||
(if (and (not (get-stored-message chat-identifier))
|
||||
(not= from current-identity)
|
||||
(pop-up-chat? chat-identifier))
|
||||
(let [group-chat? (not (nil? group-id))
|
||||
enriched-message (assoc (chat-utils/check-author-direction
|
||||
(get-last-stored-message chat-identifier)
|
||||
message)
|
||||
:chat-id chat-identifier
|
||||
:timestamp (or timestamp current-timestamp)
|
||||
:clock-value (clocks/receive
|
||||
clock-value
|
||||
(get-last-clock-value chat-identifier)))]
|
||||
(cond-> {:db (-> db
|
||||
(chat-utils/add-message-to-db chat-identifier chat-identifier enriched-message
|
||||
(:new? enriched-message))
|
||||
(unviewed-messages-model/add-unviewed-message chat-identifier message-id)
|
||||
(assoc-in [:chats chat-identifier :last-message] message))
|
||||
:dispatch-n [[:upsert-chat! {:chat-id chat-identifier
|
||||
:group-chat group-chat?}]
|
||||
[:request-command-message-data enriched-message :short-preview]]
|
||||
:save-message (dissoc enriched-message :new?)}
|
||||
|
||||
(get-in enriched-message [:content :command])
|
||||
(update :dispatch-n conj [:request-command-preview enriched-message])
|
||||
|
||||
(= (:content-type enriched-message) const/content-type-command-request)
|
||||
(update :dispatch-n conj [:add-request chat-identifier enriched-message])
|
||||
;; TODO(janherich) refactor this ugly special treatment of wallet send commands for logged in user
|
||||
(and (= (get-in message [:content :params :bot-db :public :recipient :whisper-identity])
|
||||
current-identity)
|
||||
(= content-type const/content-type-command)
|
||||
(not= chat-identifier const/wallet-chat-id)
|
||||
(= "send" (get-in message [:content :command])))
|
||||
(update :dispatch-n conj [:received-message (wallet-message (assoc message :message-id random-id))])))
|
||||
{:db db})))
|
||||
|
||||
(def ^:private receive-interceptors
|
||||
[(re-frame/inject-cofx :get-stored-message) (re-frame/inject-cofx :get-last-stored-message)
|
||||
(re-frame/inject-cofx :pop-up-chat?) (re-frame/inject-cofx :get-last-clock-value)
|
||||
(re-frame/inject-cofx :current-timestamp) (re-frame/inject-cofx :random-id)
|
||||
re-frame/trim-v])
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:received-protocol-message!
|
||||
receive-interceptors
|
||||
(fn [cofx [{:keys [from to payload]}]]
|
||||
(add-message cofx (merge payload
|
||||
{:from from
|
||||
:to to
|
||||
:chat-id from}))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:received-message
|
||||
receive-interceptors
|
||||
(fn [cofx [message]]
|
||||
(add-message cofx message)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:received-message-when-commands-loaded
|
||||
receive-interceptors
|
||||
(fn [{:keys [db] :as cofx} [chat-id message]]
|
||||
(if (and (:status-node-started? db)
|
||||
(get-in db [:contacts/contacts chat-id :commands-loaded?]))
|
||||
(add-message cofx message)
|
||||
{:dispatch-later [{:ms 400 :dispatch [:received-message-when-commands-loaded chat-id message]}]})))
|
123
src/status_im/chat/events/sign_up.cljs
Normal file
123
src/status_im/chat/events/sign_up.cljs
Normal file
@ -0,0 +1,123 @@
|
||||
(ns status-im.chat.events.sign-up
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.phone-number :as phone-number-util]
|
||||
[status-im.constants :as const]
|
||||
[status-im.chat.sign-up :as sign-up]
|
||||
[status-im.ui.screens.accounts.events :as accounts-events]
|
||||
[status-im.ui.screens.contacts.events :as contacts-events]))
|
||||
|
||||
;;;; Helpers fns
|
||||
|
||||
(defn sign-up
|
||||
"Creates effects for signing up"
|
||||
[db phone-number message-id]
|
||||
(let [current-account-id (:accounts/current-account-id db)
|
||||
{:keys [public-key address]} (get-in db [:accounts/accounts current-account-id])]
|
||||
{:dispatch sign-up/start-listening-confirmation-code-sms-event
|
||||
:http-post {:action "sign-up"
|
||||
:data {:phone-number (phone-number-util/format-phone-number phone-number)
|
||||
:whisper-identity public-key
|
||||
:address address}
|
||||
:success-event-creator (fn [_]
|
||||
[::sign-up-success message-id])
|
||||
:failure-event-creator (fn [_]
|
||||
[::http-request-failure [::sign-up phone-number message-id]])}}))
|
||||
|
||||
(defn sign-up-confirm
|
||||
"Creates effects for sign-up confirmation"
|
||||
[db confirmation-code message-id]
|
||||
{:http-post {:action "sign-up-confirm"
|
||||
:data {:code confirmation-code}
|
||||
:success-event-creator (fn [body]
|
||||
[::sign-up-confirm-response body message-id])
|
||||
:failure-event-creator (fn [_]
|
||||
[::http-request-failure [::sign-up-confirm confirmation-code message-id]])}})
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::sign-up
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [phone-number message-id]]
|
||||
(sign-up db phone-number message-id)))
|
||||
|
||||
(defn- message-seen [{:keys [db] :as fx} message-id]
|
||||
(merge fx
|
||||
{:db (assoc-in db [:message-data :statuses message-id] {:status :seen})
|
||||
:update-message {:message-id message-id
|
||||
:message-status :seen}}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::sign-up-success
|
||||
[re-frame/trim-v (re-frame/inject-cofx :random-id)]
|
||||
(fn [{:keys [db random-id]} message-id]
|
||||
(-> {:db db
|
||||
:dispatch-n [;; create manual way for entering confirmation code
|
||||
(sign-up/enter-confirmation-code-event random-id)
|
||||
;; create automatic way for receiving confirmation code
|
||||
sign-up/start-listening-confirmation-code-sms-event]}
|
||||
(message-seen message-id))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:start-listening-confirmation-code-sms
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [sms-listener]]
|
||||
{:db (if-not (:confirmation-code-sms-listener db)
|
||||
(assoc db :confirmation-code-sms-listener sms-listener)
|
||||
db)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::sign-up-confirm
|
||||
(fn [{:keys [db]} [confirmation-code message-id]]
|
||||
(sign-up-confirm db confirmation-code message-id)))
|
||||
|
||||
(defn- sign-up-confirmed [{:keys [db] :as fx}]
|
||||
(cond-> (update fx :dispatch-n conj [:request-permissions
|
||||
[:read-contacts]
|
||||
#(re-frame/dispatch [:sync-contacts (fn [contacts]
|
||||
[::contacts-synced contacts])])])
|
||||
(:confirmation-code-sms-listener db)
|
||||
(merge {:db (dissoc db :confirmation-code-sms-listener)
|
||||
:remove-sms-listener (:confirmation-code-sms-listener db)})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::sign-up-confirm-response
|
||||
[re-frame/trim-v (re-frame/inject-cofx :random-id)]
|
||||
(fn [{:keys [db random-id]} [{:keys [message status]} message-id]]
|
||||
(cond-> {:db db
|
||||
:dispatch-n [[:received-message
|
||||
{:message-id random-id
|
||||
:content message
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]]}
|
||||
message-id
|
||||
(message-seen message-id)
|
||||
|
||||
(= "confirmed" status)
|
||||
sign-up-confirmed
|
||||
|
||||
(= "failed" status)
|
||||
(update :dispatch-n conj (sign-up/incorrect-confirmation-code-event random-id)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::contacts-synced
|
||||
[re-frame/trim-v (re-frame/inject-cofx :random-id) (re-frame/inject-cofx :now)]
|
||||
(fn [{:keys [db random-id] :as cofx} [contacts]]
|
||||
(-> db
|
||||
(contacts-events/add-contacts contacts)
|
||||
(as-> fx
|
||||
(merge fx
|
||||
(accounts-events/account-update (assoc cofx :db (:db fx)) {:signed-up? true})
|
||||
{:dispatch (sign-up/contacts-synchronised-event random-id)})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::http-request-failure
|
||||
[re-frame/trim-v]
|
||||
(fn [_ [original-event-vector]]
|
||||
;; TODO(janherich): in case of http request failure, we will try to hit http endpoint in loop forever,
|
||||
;; maybe it's better to cut it after N tries and display error message with explanation to user
|
||||
{:dispatch-later [{:ms 1000 :dispatch original-event-vector}]}))
|
@ -10,179 +10,29 @@
|
||||
[status-im.data-store.chats :as chats]
|
||||
[status-im.data-store.contacts :as contacts]
|
||||
[status-im.data-store.messages :as messages]
|
||||
[status-im.data-store.handler-data :as handler-data]
|
||||
[status-im.data-store.pending-messages :as pending-messages]
|
||||
[status-im.constants :refer [text-content-type
|
||||
content-type-command
|
||||
content-type-command-request
|
||||
default-number-of-messages
|
||||
console-chat-id
|
||||
wallet-chat-id]]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.chat.sign-up :as sign-up-service]
|
||||
[status-im.ui.screens.navigation :as nav]
|
||||
[status-im.utils.handlers :refer [register-handler register-handler-fx] :as u]
|
||||
[status-im.handlers.server :as server]
|
||||
[status-im.utils.phone-number :refer [format-phone-number
|
||||
valid-mobile-number?]]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.chat.utils :refer [console? not-console? safe-trim]]
|
||||
[status-im.utils.gfycat.core :refer [generate-gfy]]
|
||||
status-im.chat.events.input
|
||||
status-im.chat.events.commands
|
||||
status-im.chat.handlers.animation
|
||||
status-im.chat.events
|
||||
status-im.chat.handlers.requests
|
||||
status-im.chat.handlers.unviewed-messages
|
||||
status-im.chat.handlers.send-message
|
||||
status-im.chat.handlers.receive-message
|
||||
status-im.chat.handlers.faucet
|
||||
[cljs.core.async :as a]
|
||||
status-im.chat.handlers.webview-bridge
|
||||
status-im.chat.handlers.console
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(register-handler :set-layout-height
|
||||
(fn [db [_ height]]
|
||||
(assoc db :layout-height height)))
|
||||
|
||||
(register-handler :set-chat-ui-props
|
||||
(fn [{:keys [current-chat-id] :as db} [_ kvs]]
|
||||
(update-in db [:chat-ui-props current-chat-id] merge kvs)))
|
||||
|
||||
(register-handler :toggle-chat-ui-props
|
||||
(fn [{:keys [current-chat-id chat-ui-props] :as db} [_ ui-element chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)]
|
||||
(update-in db [:chat-ui-props chat-id ui-element] not))))
|
||||
|
||||
(register-handler :show-message-details
|
||||
(u/side-effect!
|
||||
(fn [_ [_ details]]
|
||||
(dispatch [:set-chat-ui-props {:show-bottom-info? true
|
||||
:show-emoji? false
|
||||
:bottom-info details}]))))
|
||||
|
||||
(register-handler :load-more-messages
|
||||
(fn [{:keys [current-chat-id loading-allowed] :as db} _]
|
||||
(let [all-loaded? (get-in db [:chats current-chat-id :all-loaded?])]
|
||||
(if loading-allowed
|
||||
(do (am/go
|
||||
(<! (a/timeout 400))
|
||||
(dispatch [:set :loading-allowed true]))
|
||||
(if all-loaded?
|
||||
db
|
||||
(let [messages-path [:chats current-chat-id :messages]
|
||||
messages (get-in db messages-path)
|
||||
chat-messages (filter #(= current-chat-id (:chat-id %)) messages)
|
||||
new-messages (messages/get-by-chat-id current-chat-id (count chat-messages))
|
||||
all-loaded? (> default-number-of-messages (count new-messages))]
|
||||
(-> db
|
||||
(assoc :loading-allowed false)
|
||||
(update-in messages-path concat new-messages)
|
||||
(assoc-in [:chats current-chat-id :all-loaded?] all-loaded?)))))
|
||||
db))))
|
||||
|
||||
(defn set-message-shown
|
||||
[db chat-id message-id]
|
||||
(update-in db
|
||||
[:chats chat-id :messages]
|
||||
(fn [messages]
|
||||
(map (fn [message]
|
||||
(if (= message-id (:message-id message))
|
||||
(assoc message :new? false)
|
||||
message))
|
||||
messages))))
|
||||
|
||||
(register-handler :set-message-shown
|
||||
(fn [db [_ {:keys [chat-id message-id]}]]
|
||||
(set-message-shown db chat-id message-id)))
|
||||
|
||||
(register-handler :cancel-command
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(-> db
|
||||
(assoc-in [:chats current-chat-id :command-input] {})
|
||||
(update-in [:chats current-chat-id :input-text] safe-trim))))
|
||||
|
||||
(defn init-console-chat
|
||||
([{:keys [chats] :accounts/keys [current-account-id] :as db} existing-account?]
|
||||
(let [new-chat sign-up-service/console-chat]
|
||||
(if (chats console-chat-id)
|
||||
db
|
||||
(do
|
||||
(dispatch [:add-contacts [sign-up-service/console-contact]])
|
||||
(chats/save new-chat)
|
||||
(contacts/save-all [sign-up-service/console-contact])
|
||||
(when-not current-account-id
|
||||
(sign-up-service/intro))
|
||||
(when existing-account?
|
||||
(sign-up-service/start-signup))
|
||||
(-> db
|
||||
(assoc :new-chat new-chat)
|
||||
(update :chats assoc console-chat-id new-chat)
|
||||
(assoc :current-chat-id console-chat-id)))))))
|
||||
|
||||
(register-handler :init-console-chat
|
||||
(fn [db _]
|
||||
(init-console-chat db false)))
|
||||
|
||||
(register-handler :account-generation-message
|
||||
(u/side-effect!
|
||||
(fn [_]
|
||||
(when-not (messages/get-by-id chat-consts/passphrase-message-id)
|
||||
(sign-up-service/account-generation-message)))))
|
||||
|
||||
(register-handler :move-to-internal-failure-message
|
||||
(u/side-effect!
|
||||
(fn [_]
|
||||
(when-not (messages/get-by-id chat-consts/move-to-internal-failure-message-id)
|
||||
(sign-up-service/move-to-internal-failure-message)))))
|
||||
|
||||
(register-handler :show-mnemonic
|
||||
(u/side-effect!
|
||||
(fn [_ [_ mnemonic signing-phrase]]
|
||||
(let [crazy-math-message? (messages/get-by-id chat-consts/crazy-math-message-id)]
|
||||
(sign-up-service/passphrase-messages mnemonic signing-phrase crazy-math-message?)))))
|
||||
|
||||
(defn- handle-sms [{body :body}]
|
||||
(when-let [matches (re-matches #"(\d{4})" body)]
|
||||
(dispatch [:sign-up-confirm (second matches)])))
|
||||
|
||||
(register-handler :sign-up
|
||||
(after (fn [_ [_ phone-number]]
|
||||
(dispatch [:account-update {:phone phone-number}])))
|
||||
(fn [db [_ phone-number message-id]]
|
||||
(sign-up-service/start-listening-confirmation-code-sms)
|
||||
(let [formatted (format-phone-number phone-number)]
|
||||
(server/sign-up db
|
||||
formatted
|
||||
message-id
|
||||
sign-up-service/on-sign-up-response))))
|
||||
|
||||
(register-handler :start-listening-confirmation-code-sms
|
||||
(fn [db [_ listener]]
|
||||
(if-not (:confirmation-code-sms-listener db)
|
||||
(assoc db :confirmation-code-sms-listener listener)
|
||||
db)))
|
||||
|
||||
(register-handler :stop-listening-confirmation-code-sms
|
||||
(fn [db]
|
||||
(if (:confirmation-code-sms-listener db)
|
||||
(sign-up-service/stop-listening-confirmation-code-sms db)
|
||||
db)))
|
||||
|
||||
(register-handler :sign-up-confirm
|
||||
(u/side-effect!
|
||||
(fn [_ [_ confirmation-code message-id]]
|
||||
(server/sign-up-confirm
|
||||
confirmation-code
|
||||
message-id
|
||||
sign-up-service/on-send-code-response))))
|
||||
|
||||
(register-handler :set-signed-up
|
||||
(u/side-effect!
|
||||
(fn [_ [_ signed-up]]
|
||||
(dispatch [:account-update {:signed-up? signed-up}]))))
|
||||
|
||||
(defn load-messages!
|
||||
([db] (load-messages! db nil))
|
||||
([{:keys [current-chat-id] :as db} _]
|
||||
@ -208,47 +58,6 @@
|
||||
init-chat
|
||||
load-commands!))
|
||||
|
||||
(defn initialize-chats
|
||||
[{:keys [loaded-chats chats] :accounts/keys [account-creation?] :as db} _]
|
||||
(let [chats' (if account-creation?
|
||||
chats
|
||||
(->> loaded-chats
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
(let [last-message (messages/get-last-message chat-id)]
|
||||
[chat-id (assoc chat :last-message last-message)])))
|
||||
(into {})))]
|
||||
|
||||
(-> db
|
||||
(assoc :chats chats')
|
||||
(assoc :handler-data (handler-data/get-all))
|
||||
(dissoc :loaded-chats)
|
||||
(init-console-chat true))))
|
||||
|
||||
(defn load-chats!
|
||||
[{:accounts/keys [account-creation?] :as db} _]
|
||||
(if account-creation?
|
||||
db
|
||||
(assoc db :loaded-chats (chats/get-all))))
|
||||
|
||||
(register-handler :initialize-chats
|
||||
[(after #(dispatch [:load-unviewed-messages!]))
|
||||
(after #(dispatch [:load-default-contacts!]))]
|
||||
(u/handlers->
|
||||
load-chats!
|
||||
initialize-chats))
|
||||
|
||||
(register-handler :reload-chats
|
||||
(fn [{:keys [chats] :as db} _]
|
||||
(let [chats' (->> (chats/get-all)
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
(let [last-message (messages/get-last-message chat-id)
|
||||
prev-chat (get chats chat-id)
|
||||
new-chat (assoc chat :last-message last-message)]
|
||||
[chat-id (merge prev-chat new-chat)])))
|
||||
(into {}))]
|
||||
(-> (assoc db :chats chats')
|
||||
(init-console-chat true)))))
|
||||
|
||||
(defmethod nav/preload-data! :chat
|
||||
[{:keys [current-chat-id] :accounts/keys [current-account-id] :as db} [_ _ id]]
|
||||
(let [chat-id (or id current-chat-id)
|
||||
@ -427,27 +236,6 @@
|
||||
remove-pending-messages!
|
||||
delete-chat!))
|
||||
|
||||
(defn send-seen!
|
||||
[{:keys [web3 current-public-key chats]
|
||||
:contacts/keys [contacts]}
|
||||
[_ {:keys [from chat-id message-id]}]]
|
||||
(when-not (get-in contacts [chat-id :dapp?])
|
||||
(let [{:keys [group-chat public?]} (chats chat-id)]
|
||||
(when-not public?
|
||||
(protocol/send-seen! {:web3 web3
|
||||
:message {:from current-public-key
|
||||
:to from
|
||||
:group-id (when group-chat chat-id)
|
||||
:message-id message-id}})))))
|
||||
|
||||
(register-handler :send-seen!
|
||||
[(after (fn [_ [_ {:keys [message-id]}]]
|
||||
(messages/update {:message-id message-id
|
||||
:message-status :seen})))
|
||||
(after (fn [_ [_ {:keys [chat-id]}]]
|
||||
(dispatch [:remove-unviewed-messages chat-id])))]
|
||||
(u/side-effect! send-seen!))
|
||||
|
||||
(register-handler :check-and-open-dapp!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-chat-id global-commands]
|
||||
|
@ -1,65 +0,0 @@
|
||||
(ns status-im.chat.handlers.animation
|
||||
(:require [re-frame.core :refer [after dispatch subscribe debug path]]
|
||||
[status-im.chat.views.input.utils :as input-utils]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.platform :as platform]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(handlers/register-handler :set-expandable-height
|
||||
(fn [{:keys [current-chat-id] :as db} [_ key value]]
|
||||
(-> db
|
||||
(assoc-in [:chat-animations current-chat-id key :height] value)
|
||||
(update-in [:chat-animations current-chat-id key :changes-counter] inc))))
|
||||
|
||||
(handlers/register-handler :hide-expandable
|
||||
(handlers/side-effect!
|
||||
(fn [_ [_ key]]
|
||||
(dispatch [:set-expandable-height key 1]))))
|
||||
|
||||
(handlers/register-handler :choose-predefined-expandable-height
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id chat-ui-props layout-height] :as db} [_ key preset]]
|
||||
(if (= preset :max)
|
||||
(dispatch [:set-expandable-height key :max])
|
||||
(let [input-height (get-in chat-ui-props [current-chat-id :input-height])
|
||||
chat-input-margin (if platform/ios?
|
||||
(get db :keyboard-height)
|
||||
0)
|
||||
bottom (+ input-height chat-input-margin)
|
||||
height (case preset
|
||||
:min input-utils/min-height
|
||||
(input-utils/default-container-area-height bottom layout-height))]
|
||||
(dispatch [:set-expandable-height key height]))))))
|
||||
|
||||
(handlers/register-handler :fix-expandable-height
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id chats chat-ui-props layout-height] :as db} [_ vy current key]]
|
||||
(let [input-height (get-in chat-ui-props [current-chat-id :input-height])
|
||||
chat-input-margin (if platform/ios?
|
||||
(get db :keyboard-height)
|
||||
0)
|
||||
bottom (+ input-height chat-input-margin)
|
||||
|
||||
min-height input-utils/min-height
|
||||
max-height (input-utils/max-container-area-height bottom layout-height)
|
||||
default-height (input-utils/default-container-area-height bottom layout-height)
|
||||
possible-values [min-height default-height max-height]
|
||||
|
||||
moving-down? (pos? vy)
|
||||
closest-index (->> possible-values
|
||||
(map-indexed vector)
|
||||
(sort-by (fn [[i v]] (Math/abs (- v current))))
|
||||
(ffirst))
|
||||
height (cond (and moving-down? (not= closest-index 0))
|
||||
(get possible-values (dec closest-index))
|
||||
|
||||
(and (not moving-down?) (not= closest-index 2))
|
||||
(get possible-values (inc closest-index))
|
||||
|
||||
moving-down?
|
||||
min-height
|
||||
|
||||
(not moving-down?)
|
||||
max-height)]
|
||||
(dispatch [:set-expandable-height key height])))))
|
||||
|
@ -1,100 +0,0 @@
|
||||
(ns status-im.chat.handlers.console
|
||||
(:require [re-frame.core :refer [dispatch dispatch-sync after]]
|
||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[status-im.constants :refer [console-chat-id
|
||||
text-content-type]]
|
||||
[status-im.data-store.messages :as messages]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.random :as random]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def console-commands
|
||||
{:password
|
||||
(fn [{:keys [password]} _]
|
||||
(dispatch [:create-account password]))
|
||||
|
||||
:phone
|
||||
(fn [{:keys [phone]} id]
|
||||
(dispatch [:sign-up phone id]))
|
||||
|
||||
:confirmation-code
|
||||
(fn [{:keys [code]} id]
|
||||
(dispatch [:sign-up-confirm code id]))
|
||||
|
||||
:faucet
|
||||
(fn [{:keys [url]} id]
|
||||
(dispatch [:open-faucet url id]))
|
||||
|
||||
:debug
|
||||
(fn [{:keys [mode]} id]
|
||||
(let [debug-on? (= mode "On")]
|
||||
(dispatch [:account-update {:debug? debug-on?}])
|
||||
(if debug-on?
|
||||
(do
|
||||
(dispatch [:debug-server-start])
|
||||
(dispatch [:received-message
|
||||
{:message-id (random/id)
|
||||
:content (label :t/debug-enabled)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}]))
|
||||
(dispatch [:debug-server-stop]))))})
|
||||
|
||||
(def commands-names (set (keys console-commands)))
|
||||
|
||||
(def commands-with-delivery-status
|
||||
(disj commands-names :password :faucet :debug))
|
||||
|
||||
(register-handler :invoke-console-command-handler!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {{:keys [command
|
||||
params
|
||||
id]
|
||||
:as content} :command
|
||||
chat-id :chat-id
|
||||
:as all-params}]]
|
||||
(let [{:keys [name]} command]
|
||||
(dispatch [:prepare-command! chat-id all-params])
|
||||
((console-commands (keyword name)) params id)))))
|
||||
|
||||
(register-handler :set-message-status
|
||||
(after
|
||||
(fn [_ [_ message-id status]]
|
||||
(messages/update {:message-id message-id
|
||||
:message-status status})))
|
||||
(fn [db [_ message-id status]]
|
||||
(assoc-in db [:message-data :statuses message-id] {:status status})))
|
||||
|
||||
(register-handler :console-respond-command
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [command]}]]
|
||||
(let [{:keys [command handler-data]} command]
|
||||
(when command
|
||||
(let [{:keys [name]} command]
|
||||
(case name
|
||||
"js" (let [{:keys [err data messages]} handler-data
|
||||
content (or err data)]
|
||||
(doseq [message messages]
|
||||
(let [{:keys [message type]} message]
|
||||
(dispatch [:received-message
|
||||
{:message-id (random/id)
|
||||
:content (str type ": " message)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])))
|
||||
(when content
|
||||
(dispatch [:received-message
|
||||
{:message-id (random/id)
|
||||
:content (str content)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])))
|
||||
(log/debug "ignoring command: " command))))))))
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
(ns status-im.chat.handlers.faucet
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[status-im.utils.utils :refer [http-get]]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.constants :refer [console-chat-id
|
||||
text-content-type]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[goog.string :as gstring]
|
||||
goog.string.format))
|
||||
|
||||
(def faucets
|
||||
[{:name "http://faucet.ropsten.be:3001"
|
||||
:type :api
|
||||
:api-url "http://faucet.ropsten.be:3001/donate/0x%s"}
|
||||
{:name "http://46.101.129.137:3001"
|
||||
:type :api
|
||||
:api-url "http://46.101.129.137:3001/donate/0x%s"}])
|
||||
|
||||
(defn faucet-by-name [faucet-name]
|
||||
(->> faucets
|
||||
(filter #(= (:name %) faucet-name))
|
||||
(first)))
|
||||
|
||||
(defn received-message [content]
|
||||
(dispatch [:received-message
|
||||
{:message-id (random/id)
|
||||
:content content
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}]))
|
||||
|
||||
(defmulti open-faucet (fn [_ _ {:keys [type]}] type))
|
||||
|
||||
(defmethod open-faucet :api
|
||||
[_ current-address {:keys [api-url]}]
|
||||
(let [api-url (gstring/format api-url current-address)]
|
||||
(http-get api-url
|
||||
#(received-message (label :t/faucet-success))
|
||||
#(received-message (label :t/faucet-error)))))
|
||||
|
||||
(register-handler :open-faucet
|
||||
(u/side-effect!
|
||||
(fn [{:accounts/keys [accounts current-account-id]} [_ faucet-name _]]
|
||||
(if-let [faucet (faucet-by-name faucet-name)]
|
||||
(let [current-address (get-in accounts [current-account-id :address])]
|
||||
(open-faucet faucet-name current-address faucet))))))
|
@ -1,112 +0,0 @@
|
||||
(ns status-im.chat.handlers.receive-message
|
||||
(:require [status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[re-frame.core :refer [enrich after debug dispatch path]]
|
||||
[status-im.data-store.messages :as messages]
|
||||
[status-im.chat.utils :as cu]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.constants :refer [wallet-chat-id
|
||||
content-type-command
|
||||
content-type-command-request]
|
||||
:as c]
|
||||
[cljs.reader :refer [read-string]]
|
||||
[status-im.data-store.chats :as chats]
|
||||
[status-im.utils.scheduler :as s]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.clocks :as clocks]))
|
||||
|
||||
(defn store-message [{chat-id :chat-id :as message}]
|
||||
(messages/save chat-id (dissoc message :new?)))
|
||||
|
||||
(defn get-current-identity
|
||||
[{:accounts/keys [accounts current-account-id]}]
|
||||
(get-in accounts [current-account-id :public-key]))
|
||||
|
||||
(declare add-message-to-wallet)
|
||||
|
||||
(defn add-message
|
||||
[db {:keys [from group-id chat-id
|
||||
message-id timestamp clock-value]
|
||||
:as message
|
||||
:or {clock-value 0}}]
|
||||
(let [same-message (messages/get-by-id message-id)
|
||||
current-identity (get-current-identity db)
|
||||
chat-id' (or group-id chat-id from)
|
||||
exists? (chats/exists? chat-id')
|
||||
active? (chats/is-active? chat-id')
|
||||
local-clock (messages/get-last-clock-value chat-id')
|
||||
clock-new (clocks/receive clock-value local-clock)
|
||||
recipient-pub-key (get-in message [:content :params :bot-db :public :recipient :whisper-identity])]
|
||||
(when (and (not same-message)
|
||||
(not= from current-identity)
|
||||
(or (not exists?) active?))
|
||||
(let [group-chat? (not (nil? group-id))
|
||||
previous-message (messages/get-last-message chat-id')
|
||||
message' (assoc (cu/check-author-direction previous-message message)
|
||||
:chat-id chat-id'
|
||||
:timestamp (or timestamp (random/timestamp))
|
||||
:clock-value clock-new)]
|
||||
(store-message message')
|
||||
(dispatch [:upsert-chat! {:chat-id chat-id'
|
||||
:group-chat group-chat?}])
|
||||
(when (get-in message [:content :command])
|
||||
(dispatch [:request-command-preview message]))
|
||||
(dispatch [::add-message chat-id' message'])
|
||||
(dispatch [::set-last-message message'])
|
||||
(when (= (:content-type message') content-type-command-request)
|
||||
(dispatch [:add-request chat-id' message']))
|
||||
(dispatch [:add-unviewed-message chat-id' message-id]))
|
||||
(if (and
|
||||
(= recipient-pub-key current-identity)
|
||||
(= (:content-type message) content-type-command)
|
||||
(not= chat-id' wallet-chat-id)
|
||||
(= "send" (get-in message [:content :command])))
|
||||
(add-message-to-wallet db message)))))
|
||||
|
||||
(defn add-message-to-wallet [db {:keys [content-type] :as message}]
|
||||
(let [ct (if (= content-type c/content-type-command)
|
||||
c/content-type-wallet-command
|
||||
c/content-type-wallet-request)
|
||||
message' (-> (assoc message :clock-value 0
|
||||
:message-id (random/id)
|
||||
:chat-id wallet-chat-id
|
||||
:content-type ct)
|
||||
(dissoc :group-id))]
|
||||
(add-message db message')))
|
||||
|
||||
(register-handler :received-protocol-message!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [from to payload]}]]
|
||||
(dispatch [:received-message (merge payload
|
||||
{:from from
|
||||
:to to
|
||||
:chat-id from})]))))
|
||||
|
||||
(register-handler :received-message
|
||||
(after #(dispatch [:update-suggestions]))
|
||||
(u/side-effect!
|
||||
(fn [db [_ message]]
|
||||
(add-message db message))))
|
||||
|
||||
(register-handler ::add-message
|
||||
(fn [db [_ add-to-chat-id {:keys [chat-id new?] :as message}]]
|
||||
(cu/add-message-to-db db add-to-chat-id chat-id message new?)))
|
||||
|
||||
(register-handler ::set-last-message
|
||||
(fn [{:keys [chats] :as db} [_ {:keys [chat-id] :as message}]]
|
||||
(dispatch [:request-command-data message :short-preview])
|
||||
(assoc-in db [:chats chat-id :last-message] message)))
|
||||
|
||||
(defn commands-loaded? [db chat-id]
|
||||
(get-in db [:contacts/contacts chat-id :commands-loaded?]))
|
||||
|
||||
(def timeout 400)
|
||||
|
||||
(register-handler :received-message-when-commands-loaded
|
||||
(u/side-effect!
|
||||
(fn [{:keys [status-node-started?] :as db} [_ chat-id message]]
|
||||
(if (and status-node-started? (commands-loaded? db chat-id))
|
||||
(dispatch [:received-message message])
|
||||
(s/execute-later
|
||||
#(dispatch [:received-message-when-commands-loaded chat-id message])
|
||||
timeout)))))
|
||||
|
@ -19,7 +19,7 @@
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.protocol.core :as protocol]
|
||||
[taoensso.timbre :refer-macros [debug] :as log]
|
||||
[status-im.chat.handlers.console :as console]
|
||||
[status-im.chat.events.console :as console]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.clocks :as clocks]))
|
||||
@ -60,7 +60,7 @@
|
||||
|
||||
(defn console-command? [chat-id command-name]
|
||||
(and (= console-chat-id chat-id)
|
||||
(console/commands-names (keyword command-name))))
|
||||
(console/commands-names command-name)))
|
||||
|
||||
(register-handler :check-commands-handlers!
|
||||
(u/side-effect!
|
||||
@ -124,10 +124,12 @@
|
||||
|
||||
(register-handler ::save-command!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ chat-id {:keys [command]} hidden-params]]
|
||||
(let [command (-> command
|
||||
(fn [db [_ chat-id {:keys [command]} hidden-params]]
|
||||
(let [preview (get-in db [:message-data :preview (:message-id command)])
|
||||
command (cond-> (-> command
|
||||
(update-in [:content :params] #(apply dissoc % hidden-params))
|
||||
(dissoc :to-message :has-handler))]
|
||||
(dissoc :to-message :has-handler :raw-input))
|
||||
preview (assoc :preview (pr-str preview)))]
|
||||
(messages/save chat-id command)))))
|
||||
|
||||
(register-handler ::dispatch-responded-requests!
|
||||
|
@ -1,37 +0,0 @@
|
||||
(ns status-im.chat.handlers.unviewed-messages
|
||||
(:require [re-frame.core :refer [after enrich path dispatch]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.data-store.messages :as messages]))
|
||||
|
||||
(defn set-unviewed-messages [db]
|
||||
(let [messages (->> (:raw-unviewed-messages db)
|
||||
(group-by :chat-id)
|
||||
(map (fn [[id messages]]
|
||||
[id {:messages-ids (map :message-id messages)
|
||||
:count (count messages)}]))
|
||||
(into {}))]
|
||||
(-> db
|
||||
(assoc :unviewed-messages messages)
|
||||
(dissoc :raw-unviewed-messages))))
|
||||
|
||||
(defn load-messages! [db]
|
||||
(let [messages (messages/get-unviewed)]
|
||||
(assoc db :raw-unviewed-messages messages)))
|
||||
|
||||
(register-handler ::set-unviewed-messages set-unviewed-messages)
|
||||
|
||||
(register-handler :load-unviewed-messages!
|
||||
(after #(dispatch [::set-unviewed-messages]))
|
||||
load-messages!)
|
||||
|
||||
(register-handler :add-unviewed-message
|
||||
(path :unviewed-messages)
|
||||
(fn [db [_ chat-id message-id]]
|
||||
(-> db
|
||||
(update-in [chat-id :messages-ids] conj message-id)
|
||||
(update-in [chat-id :count] inc))))
|
||||
|
||||
(register-handler :remove-unviewed-messages
|
||||
(path :unviewed-messages)
|
||||
(fn [db [_ chat-id]]
|
||||
(dissoc db chat-id)))
|
@ -68,8 +68,7 @@
|
||||
(dispatch [:proceed-command
|
||||
{:command command,
|
||||
:metadata nil,
|
||||
:args [(get contact :name) amount]}
|
||||
current-chat-id])))))
|
||||
:args [(get contact :name) amount]}])))))
|
||||
|
||||
(defn chat-with-command
|
||||
[_ [_ whisper-identity command-key params]]
|
||||
|
11
src/status_im/chat/models.cljs
Normal file
11
src/status_im/chat/models.cljs
Normal file
@ -0,0 +1,11 @@
|
||||
(ns status-im.chat.models)
|
||||
|
||||
(defn set-chat-ui-props
|
||||
"Updates ui-props in active chat by merging provided kvs into them"
|
||||
[{:keys [current-chat-id] :as db} kvs]
|
||||
(update-in db [:chat-ui-props current-chat-id] merge kvs))
|
||||
|
||||
(defn toggle-chat-ui-prop
|
||||
"Toggles chat ui prop in active chat"
|
||||
[{:keys [current-chat-id] :as db} ui-element]
|
||||
(update-in db [:chat-ui-props current-chat-id ui-element] not))
|
@ -95,7 +95,7 @@
|
||||
[[] false])
|
||||
(first)))))
|
||||
|
||||
(defn join-command-args [args]
|
||||
(defn join-command-args
|
||||
"Transforms a list of args to a string. The opposite of `split-command-args`.
|
||||
|
||||
Examples:
|
||||
@ -107,6 +107,7 @@
|
||||
|
||||
Input: ['/send' 'Complex name with space in between' '1.0']
|
||||
Output: '/send \"Complex name with space in between\" 1.0'"
|
||||
[args]
|
||||
(when args
|
||||
(->> args
|
||||
(map (fn [arg]
|
||||
@ -178,12 +179,11 @@
|
||||
-1 (`*no-argument-error*`) means error. It can happen if there is no command or selection.
|
||||
|
||||
This method is basically just another way of calling `current-chat-argument-position`."
|
||||
[{:keys [current-chat-id] :as db} chat-id]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
input-text (get-in db [:chats chat-id :input-text])
|
||||
seq-arguments (get-in db [:chats chat-id :seq-arguments])
|
||||
selection (get-in db [:chat-ui-props chat-id :selection])
|
||||
chat-command (selected-chat-command db chat-id)]
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
seq-arguments (get-in db [:chats current-chat-id :seq-arguments])
|
||||
selection (get-in db [:chat-ui-props current-chat-id :selection])
|
||||
chat-command (selected-chat-command db current-chat-id)]
|
||||
(current-chat-argument-position chat-command input-text selection seq-arguments)))
|
||||
|
||||
(defn command-completion
|
||||
|
18
src/status_im/chat/models/unviewed_messages.cljs
Normal file
18
src/status_im/chat/models/unviewed_messages.cljs
Normal file
@ -0,0 +1,18 @@
|
||||
(ns status-im.chat.models.unviewed-messages)
|
||||
|
||||
(defn load-unviewed-messages [db raw-unviewed-messages]
|
||||
(assoc db :unviewed-messages
|
||||
(->> raw-unviewed-messages
|
||||
(group-by :chat-id)
|
||||
(map (fn [[id messages]]
|
||||
[id {:messages-ids (map :message-id messages)
|
||||
:count (count messages)}]))
|
||||
(into {}))))
|
||||
|
||||
(defn add-unviewed-message [db chat-id message-id]
|
||||
(-> db
|
||||
(update-in [:unviewed-messages chat-id :messages-ids] conj message-id)
|
||||
(update-in [:unviewed-messages chat-id :count] inc)))
|
||||
|
||||
(defn remove-unviewed-messages [db chat-id]
|
||||
(update db :unviewed-messages dissoc chat-id))
|
@ -1,25 +1,20 @@
|
||||
(ns status-im.chat.sign-up
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[status-im.components.styles :refer [default-chat-color]]
|
||||
[status-im.utils.utils :refer [http-post]]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.utils.sms-listener :refer [add-sms-listener
|
||||
remove-sms-listener]]
|
||||
[status-im.constants :refer [console-chat-id
|
||||
text-content-type
|
||||
content-type-command
|
||||
content-type-command-request
|
||||
content-type-status]]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.constants :as const]
|
||||
[status-im.chat.constants :as chat-const]
|
||||
[status-im.i18n :refer [label]]
|
||||
[clojure.string :as s]))
|
||||
|
||||
(defn send-console-message [text]
|
||||
{:message-id (random/id)
|
||||
:from "me"
|
||||
:to console-chat-id
|
||||
:to const/console-chat-id
|
||||
:content text
|
||||
:content-type text-content-type
|
||||
:content-type const/text-content-type
|
||||
:outgoing true})
|
||||
|
||||
;; todo fn name is not too smart, but...
|
||||
@ -29,192 +24,165 @@
|
||||
:content content})
|
||||
|
||||
;; -- Send phone number ----------------------------------------
|
||||
(defn on-sign-up-response [& [message]]
|
||||
(let [message-id (random/id)]
|
||||
(dispatch [:received-message
|
||||
(defn- confirmation-code-event [correct? message-id]
|
||||
[:received-message
|
||||
{:message-id message-id
|
||||
:content (command-content
|
||||
:confirmation-code
|
||||
(or message (label :t/confirmation-code)))
|
||||
:content-type content-type-command-request
|
||||
(if correct?
|
||||
(label :t/confirmation-code)
|
||||
(label :t/incorrect-code)))
|
||||
:content-type const/content-type-command-request
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])))
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}])
|
||||
|
||||
(defn start-listening-confirmation-code-sms []
|
||||
(dispatch [:request-permissions
|
||||
(def enter-confirmation-code-event (partial confirmation-code-event true))
|
||||
(def incorrect-confirmation-code-event (partial confirmation-code-event false))
|
||||
|
||||
(defn- sms-receive-handler [{confirmation-code :body}]
|
||||
(when-let [matches (re-matches #"(\d{4})" confirmation-code)]
|
||||
(dispatch [:sign-up-confirm (second matches)])))
|
||||
|
||||
(def start-listening-confirmation-code-sms-event
|
||||
[:request-permissions
|
||||
[:receive-sms]
|
||||
(fn []
|
||||
(let [listener (add-sms-listener
|
||||
(fn [{body :body}]
|
||||
(when-let [matches (re-matches #"(\d{4})" body)]
|
||||
(dispatch [:sign-up-confirm (second matches)]))))]
|
||||
(dispatch [:start-listening-confirmation-code-sms listener])))]))
|
||||
|
||||
(defn stop-listening-confirmation-code-sms [db]
|
||||
(when-let [listener (:confirmation-code-sms-listener db)]
|
||||
(remove-sms-listener listener)
|
||||
(dissoc db :confirmation-code-sms-listener)))
|
||||
(let [listener (add-sms-listener sms-receive-handler)]
|
||||
(dispatch [:start-listening-confirmation-code-sms listener])))])
|
||||
|
||||
;; -- Send confirmation code and synchronize contacts---------------------------
|
||||
(defn on-sync-contacts []
|
||||
(dispatch [:received-message
|
||||
{:message-id (random/id)
|
||||
:content (label :t/contacts-syncronized)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])
|
||||
(dispatch [:set-signed-up true]))
|
||||
|
||||
(defn sync-contacts []
|
||||
;; TODO 'on-sync-contacts' is never called
|
||||
(dispatch [:request-permissions
|
||||
[:read-contacts]
|
||||
#(dispatch [:sync-contacts on-sync-contacts])]))
|
||||
|
||||
(defn on-send-code-response [body]
|
||||
(dispatch [:received-message
|
||||
{:message-id (random/id)
|
||||
:content (:message body)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])
|
||||
(let [status (keyword (:status body))]
|
||||
(when (= :confirmed status)
|
||||
(dispatch [:stop-listening-confirmation-code-sms])
|
||||
(sync-contacts)
|
||||
;; TODO should be called after sync-contacts?
|
||||
(dispatch [:set-signed-up true]))
|
||||
(when (= :failed status)
|
||||
(on-sign-up-response (label :t/incorrect-code)))))
|
||||
|
||||
(defn start-signup []
|
||||
(let [message-id (random/id)]
|
||||
(dispatch [:received-message
|
||||
(defn contacts-synchronised-event [message-id]
|
||||
[:received-message
|
||||
{:message-id message-id
|
||||
:content (label :t/contacts-syncronized)
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}])
|
||||
|
||||
(def start-signup-events
|
||||
[[:received-message
|
||||
{:message-id (random/id)
|
||||
:content (command-content
|
||||
:phone
|
||||
(label :t/phone-number-required))
|
||||
:content-type content-type-command-request
|
||||
:content-type const/content-type-command-request
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}]))
|
||||
(dispatch [:received-message
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id (random/id)
|
||||
:content (label :t/shake-your-phone)
|
||||
:content-type text-content-type
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}]))
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]])
|
||||
|
||||
;; -- Saving password ----------------------------------------
|
||||
(defn account-generation-message []
|
||||
(dispatch [:received-message
|
||||
{:message-id const/crazy-math-message-id
|
||||
(def account-generation-event
|
||||
[:received-message
|
||||
{:message-id chat-const/crazy-math-message-id
|
||||
:content (label :t/account-generation-message)
|
||||
:content-type text-content-type
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}]))
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}])
|
||||
|
||||
(defn move-to-internal-failure-message []
|
||||
(dispatch [:received-message
|
||||
{:message-id const/move-to-internal-failure-message-id
|
||||
(def move-to-internal-failure-event
|
||||
[:received-message
|
||||
{:message-id chat-const/move-to-internal-failure-message-id
|
||||
:content (command-content
|
||||
:grant-permissions
|
||||
(label :t/move-to-internal-failure-message))
|
||||
:content-type content-type-command-request
|
||||
:content-type const/content-type-command-request
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}]))
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}])
|
||||
|
||||
|
||||
(defn passphrase-messages [mnemonic signing-phrase crazy-math-message?]
|
||||
(dispatch [:received-message
|
||||
{:message-id const/passphrase-message-id
|
||||
(defn passphrase-messages-events [mnemonic signing-phrase crazy-math-message?]
|
||||
(into [[:received-message
|
||||
{:message-id chat-const/passphrase-message-id
|
||||
:content (if crazy-math-message?
|
||||
(label :t/phew-here-is-your-passphrase)
|
||||
(label :t/here-is-your-passphrase))
|
||||
:content-type text-content-type
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])
|
||||
(dispatch [:received-message
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id (random/id)
|
||||
:content mnemonic
|
||||
:content-type text-content-type
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])
|
||||
(dispatch [:received-message
|
||||
{:message-id const/signing-phrase-message-id
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id chat-const/signing-phrase-message-id
|
||||
:content (label :t/here-is-your-signing-phrase)
|
||||
:content-type text-content-type
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])
|
||||
(dispatch [:received-message
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id (random/id)
|
||||
:content signing-phrase
|
||||
:content-type text-content-type
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id console-chat-id
|
||||
:from console-chat-id
|
||||
:to "me"}])
|
||||
(start-signup))
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]]
|
||||
start-signup-events))
|
||||
|
||||
(def intro-status
|
||||
{:message-id const/intro-status-message-id
|
||||
{:message-id chat-const/intro-status-message-id
|
||||
:content (label :t/intro-status)
|
||||
:from console-chat-id
|
||||
:chat-id console-chat-id
|
||||
:content-type content-type-status
|
||||
:from const/console-chat-id
|
||||
:chat-id const/console-chat-id
|
||||
:content-type const/content-type-status
|
||||
:outgoing false
|
||||
:to "me"})
|
||||
|
||||
(defn intro []
|
||||
(dispatch [:received-message intro-status])
|
||||
(dispatch [:received-message-when-commands-loaded
|
||||
console-chat-id
|
||||
{:chat-id console-chat-id
|
||||
:message-id const/intro-message1-id
|
||||
(def intro-events
|
||||
[[:received-message intro-status]
|
||||
[:received-message-when-commands-loaded
|
||||
const/console-chat-id
|
||||
{:chat-id const/console-chat-id
|
||||
:message-id chat-const/intro-message1-id
|
||||
:content (command-content
|
||||
:password
|
||||
(label :t/intro-message1))
|
||||
:content-type content-type-command-request
|
||||
:content-type const/content-type-command-request
|
||||
:outgoing false
|
||||
:from console-chat-id
|
||||
:to "me"}]))
|
||||
:from const/console-chat-id
|
||||
:to "me"}]])
|
||||
|
||||
(def console-chat
|
||||
{:chat-id console-chat-id
|
||||
:name (s/capitalize console-chat-id)
|
||||
{:chat-id const/console-chat-id
|
||||
:name (s/capitalize const/console-chat-id)
|
||||
:color default-chat-color
|
||||
:group-chat false
|
||||
:is-active true
|
||||
:unremovable? true
|
||||
:timestamp (.getTime (js/Date.))
|
||||
:photo-path console-chat-id
|
||||
:contacts [{:identity console-chat-id
|
||||
:photo-path const/console-chat-id
|
||||
:contacts [{:identity const/console-chat-id
|
||||
:text-color "#FFFFFF"
|
||||
:background-color "#AB7967"}]})
|
||||
|
||||
(def console-contact
|
||||
{:whisper-identity console-chat-id
|
||||
:name (s/capitalize console-chat-id)
|
||||
:photo-path console-chat-id
|
||||
{:whisper-identity const/console-chat-id
|
||||
:name (s/capitalize const/console-chat-id)
|
||||
:photo-path const/console-chat-id
|
||||
:dapp? true
|
||||
:unremovable? true
|
||||
:bot-url "local://console-bot"
|
||||
|
@ -2,8 +2,6 @@
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [reagent.core :as r]
|
||||
[re-frame.core :refer [dispatch subscribe]]
|
||||
[clojure.string :as str]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
list-view
|
||||
@ -12,20 +10,15 @@
|
||||
[status-im.components.renderers.renderers :as renderers]
|
||||
[status-im.utils.listview :as lw]))
|
||||
|
||||
(defn- select-contact [arg-index bot-db-key {:keys [name] :as contact}]
|
||||
(let [contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?])
|
||||
name (str/replace name (re-pattern const/arg-wrapping-char) "")]
|
||||
(dispatch [:set-command-argument [arg-index name true]])
|
||||
(dispatch [:set-in-bot-db {:path [:public (keyword bot-db-key)]
|
||||
:value contact}])
|
||||
(dispatch [:select-next-argument])))
|
||||
|
||||
(defn render-row [arg-index bot-db-key]
|
||||
(fn [contact _ _]
|
||||
(list-item
|
||||
^{:key contact}
|
||||
[contact-view {:contact contact
|
||||
:on-press #(select-contact arg-index bot-db-key contact)}])))
|
||||
:on-press #(dispatch
|
||||
[:set-contact-as-command-argument {:arg-index arg-index
|
||||
:bot-db-key bot-db-key
|
||||
:contact contact}])}])))
|
||||
|
||||
(defview choose-contact-view [{title :title
|
||||
arg-index :index
|
||||
|
@ -41,9 +41,7 @@
|
||||
show-suggestions? [:show-suggestions?]]
|
||||
[view style/commands-root
|
||||
[view style/command-list-icon-container
|
||||
[touchable-highlight {:on-press #(do (dispatch [:toggle-chat-ui-props :show-suggestions?])
|
||||
(dispatch [:set-chat-ui-props {:validation-messages nil}])
|
||||
(dispatch [:update-suggestions]))}
|
||||
[touchable-highlight {:on-press #(dispatch [:show-suggestions])}
|
||||
[view style/commands-list-icon
|
||||
(if show-suggestions?
|
||||
[vi/icon :icons/close]
|
||||
|
@ -39,7 +39,7 @@
|
||||
get-contact-translated]]
|
||||
[status-im.chat.utils :as cu]
|
||||
[clojure.string :as str]
|
||||
[status-im.chat.handlers.console :as console]
|
||||
[status-im.chat.events.console :as console]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def window-width (:width (get-dimensions "window")))
|
||||
@ -300,8 +300,7 @@
|
||||
[{:keys [message-id chat-id message-status user-statuses content]}]
|
||||
[app-db-message-status-value [:get-in [:message-data :statuses message-id :status]]]
|
||||
(let [delivery-status (get-in user-statuses [chat-id :status])
|
||||
command-name (keyword (:command content))
|
||||
status (cond (and (not (console/commands-with-delivery-status command-name))
|
||||
status (cond (and (not (console/commands-with-delivery-status (:command content)))
|
||||
(cu/console? chat-id))
|
||||
:seen
|
||||
|
||||
|
@ -97,6 +97,14 @@
|
||||
[]
|
||||
(data-store/get-unviewed))
|
||||
|
||||
(defn get-previews
|
||||
[]
|
||||
(->> (data-store/get-all-as-list)
|
||||
(filter :preview)
|
||||
(reduce (fn [acc {:keys [message-id preview]}]
|
||||
(assoc acc message-id (read-string preview)))
|
||||
{})))
|
||||
|
||||
(defn save
|
||||
;; todo remove chat-id parameter
|
||||
[chat-id {:keys [message-id content]
|
||||
@ -120,4 +128,3 @@
|
||||
|
||||
(defn delete-by-chat-id [chat-id]
|
||||
(data-store/delete-by-chat-id chat-id))
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
status-im.ui.screens.accounts.recover.events
|
||||
|
||||
[status-im.data-store.accounts :as accounts-store]
|
||||
[re-frame.core :refer [reg-cofx reg-fx dispatch inject-cofx]]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.protocol.core :as protocol]
|
||||
[status-im.native-module.core :as status]
|
||||
@ -13,26 +13,35 @@
|
||||
[status-im.utils.random :as random]
|
||||
[clojure.string :as str]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :refer [register-handler-db register-handler-fx get-hashtags] :as handlers]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.ui.screens.accounts.statuses :as statuses]
|
||||
[status-im.utils.signing-phrase.core :as signing-phrase]
|
||||
[status-im.utils.gfycat.core :refer [generate-gfy]]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn create-account
|
||||
"Takes db and password, creates map of effects describing account creation"
|
||||
[db password]
|
||||
{:db (assoc db :accounts/creating-account? true)
|
||||
::create-account password
|
||||
:dispatch-later [{:ms 400 :dispatch [:account-generation-message]}]})
|
||||
|
||||
;;;; COFX
|
||||
|
||||
(reg-cofx
|
||||
(re-frame/reg-cofx
|
||||
:get-new-keypair!
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :keypair (protocol/new-keypair!))))
|
||||
|
||||
(reg-cofx
|
||||
(re-frame/reg-cofx
|
||||
::get-all-accounts
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :all-accounts (accounts-store/get-all))))
|
||||
|
||||
;;;; FX
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::save-account
|
||||
(fn [account]
|
||||
(accounts-store/save account true)))
|
||||
@ -55,17 +64,17 @@
|
||||
:signing-phrase phrase}]
|
||||
(log/debug "account-created")
|
||||
(when-not (str/blank? public-key)
|
||||
(dispatch [:show-mnemonic mnemonic phrase])
|
||||
(dispatch [:add-account account password]))))
|
||||
(re-frame/dispatch [:show-mnemonic mnemonic phrase])
|
||||
(re-frame/dispatch [:add-account account password]))))
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::create-account
|
||||
(fn [password]
|
||||
(status/create-account
|
||||
password
|
||||
#(account-created % password))))
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::broadcast-account-update
|
||||
(fn [{:keys [current-public-key web3 name photo-path status
|
||||
updates-public-key updates-private-key]}]
|
||||
@ -80,7 +89,7 @@
|
||||
:status status
|
||||
:profile-image photo-path}}}}))))
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
::send-keys-update
|
||||
(fn [{:keys [web3 current-public-key contacts
|
||||
updates-public-key updates-private-key]}]
|
||||
@ -94,7 +103,7 @@
|
||||
:private updates-private-key}}}}))))
|
||||
;;;; Handlers
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:add-account
|
||||
(fn [{{:keys [network]
|
||||
:networks/keys [networks]
|
||||
@ -107,23 +116,16 @@
|
||||
(when password
|
||||
{:dispatch-later [{:ms 400 :dispatch [:login-account address password true]}]})))))
|
||||
|
||||
(register-handler-fx
|
||||
:create-account
|
||||
(fn [{db :db} [_ password]]
|
||||
{:db (assoc db :accounts/creating-account? true)
|
||||
::create-account password
|
||||
:dispatch-later [{:ms 400 :dispatch [:account-generation-message]}]}))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:create-new-account-handler
|
||||
(fn [_ _]
|
||||
{:dispatch-n [[:initialize-db]
|
||||
[:load-accounts]
|
||||
[:check-console-chat true]]}))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:load-accounts
|
||||
[(inject-cofx ::get-all-accounts)]
|
||||
[(re-frame/inject-cofx ::get-all-accounts)]
|
||||
(fn [{:keys [db all-accounts]} _]
|
||||
(let [accounts (->> all-accounts
|
||||
(map (fn [{:keys [address] :as account}]
|
||||
@ -136,7 +138,7 @@
|
||||
(when-not (empty? events)
|
||||
{:dispatch-n events})))))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:account-update-networks
|
||||
(fn [{{:accounts/keys [accounts] :networks/keys [networks] :as db} :db} [_ id]]
|
||||
(let [current-account (get accounts id)
|
||||
@ -144,41 +146,51 @@
|
||||
{:db (assoc-in db [:accounts/accounts id] new-account)
|
||||
::save-account new-account})))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:check-status-change
|
||||
(fn [{{:accounts/keys [accounts current-account-id]} :db} [_ status]]
|
||||
(let [{old-status :status} (get accounts current-account-id)
|
||||
status-updated? (and (not= status nil)
|
||||
(not= status old-status))]
|
||||
(when status-updated?
|
||||
(let [hashtags (get-hashtags status)]
|
||||
(let [hashtags (handlers/get-hashtags status)]
|
||||
(when (seq hashtags)
|
||||
{:dispatch [:broadcast-status status hashtags]}))))))
|
||||
|
||||
(defn update-account [current-account new-fields]
|
||||
(merge current-account (assoc new-fields :last-updated (time/now-ms))))
|
||||
(defn- update-account [current-account new-fields now]
|
||||
(merge current-account (assoc new-fields :last-updated now)))
|
||||
|
||||
(register-handler-fx
|
||||
:account-update
|
||||
(fn [{{:accounts/keys [accounts current-account-id] :as db} :db} [_ new-account-fields]]
|
||||
(defn account-update
|
||||
"Takes map of coeffects containing `:db` and `:now` keys + new account fields,
|
||||
returns all effects necessary for account update."
|
||||
[{{:keys [network]
|
||||
:accounts/keys [accounts current-account-id] :as db} :db now :now} new-account-fields]
|
||||
(let [current-account (get accounts current-account-id)
|
||||
new-account (update-account current-account new-account-fields)]
|
||||
new-account (update-account current-account new-account-fields now)]
|
||||
{:db (assoc-in db [:accounts/accounts current-account-id] new-account)
|
||||
::save-account new-account
|
||||
::broadcast-account-update (merge
|
||||
(select-keys db [:current-public-key :web3])
|
||||
(select-keys new-account [:name :photo-path :status
|
||||
:updates-public-key :updates-private-key]))})))
|
||||
:updates-public-key :updates-private-key]))}))
|
||||
|
||||
(register-handler-fx
|
||||
;; TODO(janherich): remove this event once it's not used anymore
|
||||
(handlers/register-handler-fx
|
||||
:account-update
|
||||
[(re-frame/inject-cofx :now) re-frame/trim-v]
|
||||
(fn [cofx [new-account-fields]]
|
||||
(account-update cofx new-account-fields)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:account-update-keys
|
||||
[(inject-cofx :get-new-keypair!)]
|
||||
(fn [{:keys [db keypair]} _]
|
||||
[(re-frame/inject-cofx :get-new-keypair!) (re-frame/inject-cofx :now)]
|
||||
(fn [{:keys [db keypair now]} _]
|
||||
(let [{:accounts/keys [accounts current-account-id]} db
|
||||
{:keys [public private]} keypair
|
||||
current-account (get accounts current-account-id)
|
||||
new-account (update-account current-account {:updates-public-key public
|
||||
:updates-private-key private})]
|
||||
:updates-private-key private}
|
||||
now)]
|
||||
{:db (assoc-in db [:accounts/accounts current-account-id] new-account)
|
||||
::save-account new-account
|
||||
::send-keys-update (merge
|
||||
@ -186,17 +198,19 @@
|
||||
(select-keys new-account [:updates-public-key
|
||||
:updates-private-key]))})))
|
||||
|
||||
(register-handler-fx
|
||||
(handlers/register-handler-fx
|
||||
:send-account-update-if-needed
|
||||
(fn [{{:accounts/keys [accounts current-account-id]} :db} _]
|
||||
[(re-frame/inject-cofx :now)]
|
||||
(fn [{{:accounts/keys [accounts current-account-id]} :db now :now :as cofx} _]
|
||||
(let [{:keys [last-updated]} (get accounts current-account-id)
|
||||
now (time/now-ms)
|
||||
needs-update? (> (- now last-updated) time/week)]
|
||||
(log/info "Need to send account-update: " needs-update?)
|
||||
(when needs-update?
|
||||
(dispatch [:account-update])))))
|
||||
;; TODO(janherich): this is very strange and misleading, need to figure out why it'd necessary to update
|
||||
;; account with network update when last update was more then week ago
|
||||
(account-update cofx nil)))))
|
||||
|
||||
(register-handler-db
|
||||
(handlers/register-handler-db
|
||||
:set-current-account
|
||||
(fn [{:accounts/keys [accounts] :as db} [_ address]]
|
||||
(let [key (:public-key (accounts address))]
|
||||
|
@ -27,7 +27,7 @@
|
||||
(fn []
|
||||
(when (and (get-in @message [:content :command])
|
||||
(not @preview))
|
||||
(dispatch [:request-command-data @message :short-preview])))
|
||||
(dispatch [:request-command-message-data @message :short-preview])))
|
||||
|
||||
:reagent-render
|
||||
(fn [_]
|
||||
|
@ -1,5 +1,5 @@
|
||||
(ns status-im.ui.screens.contacts.events
|
||||
(:require [re-frame.core :refer [dispatch reg-fx reg-cofx inject-cofx]]
|
||||
(:require [re-frame.core :refer [dispatch trim-v reg-fx reg-cofx inject-cofx]]
|
||||
[status-im.utils.handlers :refer [register-handler-db register-handler-fx]]
|
||||
[status-im.data-store.contacts :as contacts]
|
||||
[status-im.utils.crypt :refer [encrypt]]
|
||||
@ -102,13 +102,13 @@
|
||||
|
||||
(reg-fx
|
||||
::fetch-contacts-from-phone!
|
||||
(fn [_]
|
||||
(fn [on-contacts-event-creator]
|
||||
(.getAll rn-dependencies/contacts
|
||||
(fn [error contacts]
|
||||
(if error
|
||||
(log/debug :error-on-fetching-loading error)
|
||||
(let [contacts' (normalize-phone-contacts contacts)]
|
||||
(dispatch [::get-contacts-identities contacts'])))))))
|
||||
(dispatch [::get-contacts-identities contacts' on-contacts-event-creator])))))))
|
||||
|
||||
(defn- get-contacts-by-hash [contacts]
|
||||
(->> contacts
|
||||
@ -131,13 +131,12 @@
|
||||
|
||||
(reg-fx
|
||||
::request-stored-contacts
|
||||
(fn [contacts]
|
||||
(fn [{:keys [contacts on-contacts-event-creator]}]
|
||||
(let [contacts-by-hash (get-contacts-by-hash contacts)
|
||||
data (or (keys contacts-by-hash) '())]
|
||||
(http-post "get-contacts" {:phone-number-hashes data}
|
||||
(fn [{:keys [contacts]}]
|
||||
(let [contacts' (add-identity contacts-by-hash contacts)]
|
||||
(dispatch [:add-contacts contacts'])))))))
|
||||
(dispatch (on-contacts-event-creator (add-identity contacts-by-hash contacts))))))))
|
||||
|
||||
(reg-fx
|
||||
::request-contacts-by-address
|
||||
@ -159,8 +158,16 @@
|
||||
|
||||
(register-handler-fx
|
||||
::get-contacts-identities
|
||||
(fn [_ [_ contacts]]
|
||||
{::request-stored-contacts contacts}))
|
||||
[trim-v]
|
||||
(fn [_ [contacts on-contacts-event-creator]]
|
||||
{::request-stored-contacts {:contacts contacts
|
||||
:on-contacts-event-creator on-contacts-event-creator}}))
|
||||
|
||||
(register-handler-fx
|
||||
:sync-contacts
|
||||
[trim-v]
|
||||
(fn [_ [on-contacts-event-creator]]
|
||||
{::fetch-contacts-from-phone! on-contacts-event-creator}))
|
||||
|
||||
(register-handler-fx
|
||||
:watch-contact
|
||||
@ -177,11 +184,6 @@
|
||||
{:db (update-in db [:contacts/contacts whisper-identity] merge contact)
|
||||
::save-contact contact})))
|
||||
|
||||
(register-handler-fx
|
||||
:sync-contacts
|
||||
(fn [_ _]
|
||||
{::fetch-contacts-from-phone! nil}))
|
||||
|
||||
(defn- update-pending-status [old-contacts {:keys [whisper-identity pending?] :as contact}]
|
||||
(let [{old-pending :pending?
|
||||
:as old-contact} (get old-contacts whisper-identity)
|
||||
@ -281,9 +283,9 @@
|
||||
:global-commands global-commands)
|
||||
:dispatch-n (mapv (fn [_ contact] [:watch-contact contact]) contacts)})))
|
||||
|
||||
(register-handler-fx
|
||||
:add-contacts
|
||||
(fn [{:keys [db]} [_ new-contacts]]
|
||||
(defn add-contacts
|
||||
"Creates effects map for adding contacts"
|
||||
[db new-contacts]
|
||||
(let [{:contacts/keys [contacts]} db
|
||||
identities (set (keys contacts))
|
||||
new-contacts' (->> new-contacts
|
||||
@ -301,7 +303,13 @@
|
||||
{:db (-> db
|
||||
(update :global-commands merge global-commands)
|
||||
(update :contacts/contacts merge new-contacts'))
|
||||
::save-contacts! (vals new-contacts')})))
|
||||
::save-contacts! (vals new-contacts')}))
|
||||
|
||||
(register-handler-fx
|
||||
:add-contacts
|
||||
[trim-v]
|
||||
(fn [{:keys [db]} [new-contacts]]
|
||||
(add-contacts db new-contacts)))
|
||||
|
||||
(register-handler-db
|
||||
:remove-contacts-click-handler
|
||||
|
@ -1,5 +1,5 @@
|
||||
(ns status-im.ui.screens.events
|
||||
(:require status-im.bots.handlers
|
||||
(:require status-im.bots.events
|
||||
status-im.chat.handlers
|
||||
status-im.commands.handlers.jail
|
||||
status-im.commands.handlers.loading
|
||||
@ -17,7 +17,7 @@
|
||||
status-im.ui.screens.profile.events
|
||||
status-im.ui.screens.qr-scanner.events
|
||||
status-im.ui.screens.wallet.events
|
||||
[re-frame.core :refer [dispatch reg-fx]]
|
||||
[re-frame.core :refer [dispatch reg-fx reg-cofx]]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.components.permissions :as permissions]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
@ -25,6 +25,9 @@
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.js-dependencies :as dependencies]
|
||||
[status-im.ui.screens.db :refer [app-db]]
|
||||
[status-im.utils.sms-listener :as sms-listener-util]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.crypt :as crypt]
|
||||
[status-im.utils.notifications :as notifications]
|
||||
@ -35,10 +38,87 @@
|
||||
[status-im.utils.utils :as utils]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn- call-jail-function
|
||||
[{:keys [chat-id function callback-events-creator] :as opts}]
|
||||
(let [path [:functions function]
|
||||
params (select-keys opts [:parameters :context])]
|
||||
(status/call-jail
|
||||
{:jail-id chat-id
|
||||
:path path
|
||||
:params params
|
||||
:callback (fn [jail-response]
|
||||
(doseq [event (if callback-events-creator
|
||||
(callback-events-creator jail-response)
|
||||
[[:received-bot-response
|
||||
{:chat-id chat-id}
|
||||
jail-response]])
|
||||
:when event]
|
||||
(dispatch event)))})))
|
||||
|
||||
;;;; COFX
|
||||
|
||||
(reg-cofx
|
||||
:now
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :now (time/now-ms))))
|
||||
|
||||
(reg-cofx
|
||||
:random-id
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-id (random/id))))
|
||||
|
||||
(reg-cofx
|
||||
:random-id-seq
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-id-seq
|
||||
((fn rand-id-seq []
|
||||
(cons (random/id) (lazy-seq (rand-id-seq))))))))
|
||||
|
||||
;;;; FX
|
||||
|
||||
(reg-fx
|
||||
:call-jail
|
||||
(fn [{:keys [callback-events-creator] :as opts}]
|
||||
(status/call-jail
|
||||
(-> opts
|
||||
(dissoc :callback-events-creator)
|
||||
(assoc :callback
|
||||
(fn [jail-response]
|
||||
(doseq [event (callback-events-creator jail-response)]
|
||||
(dispatch event))))))))
|
||||
|
||||
(reg-fx
|
||||
:call-jail-function
|
||||
call-jail-function)
|
||||
|
||||
(reg-fx
|
||||
:call-jail-function-n
|
||||
(fn [opts-seq]
|
||||
(doseq [opts opts-seq]
|
||||
(call-jail-function opts))))
|
||||
|
||||
(reg-fx
|
||||
:http-post
|
||||
(fn [{:keys [action data success-event-creator failure-event-creator]}]
|
||||
(utils/http-post action
|
||||
data
|
||||
#(dispatch (success-event-creator %))
|
||||
#(dispatch (failure-event-creator %)))))
|
||||
|
||||
(reg-fx
|
||||
:http-get
|
||||
(fn [{:keys [url success-event-creator failure-event-creator]}]
|
||||
(utils/http-get url
|
||||
#(dispatch (success-event-creator %))
|
||||
#(dispatch (failure-event-creator %)))))
|
||||
|
||||
(reg-fx
|
||||
:remove-sms-listener
|
||||
(fn [subscription]
|
||||
(sms-listener-util/remove-sms-listener subscription)))
|
||||
|
||||
(reg-fx
|
||||
::init-store
|
||||
(fn []
|
||||
|
@ -1,7 +1,7 @@
|
||||
(ns status-im.ui.screens.profile.events
|
||||
(:require [clojure.spec.alpha :as spec]
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame :refer [reg-fx]]
|
||||
[re-frame.core :as re-frame :refer [reg-fx trim-v]]
|
||||
[status-im.components.react :refer [show-image-picker]]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
[status-im.ui.screens.profile.db :as db]
|
||||
@ -28,11 +28,13 @@
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:profile/send-transaction
|
||||
(fn [_ [_ chat-id]]
|
||||
{:dispatch-n [[:clear-seq-arguments]
|
||||
[:navigate-to :chat chat-id]
|
||||
;; TODO https://github.com/status-im/status-react/issues/1621
|
||||
[:select-chat-input-command {:name "send"}]]}))
|
||||
[trim-v]
|
||||
(fn [{:keys [db]} [chat-id contact-id]]
|
||||
{:dispatch-n [[:navigate-to :chat chat-id]
|
||||
[:select-chat-input-command {:name "send"}]
|
||||
[:set-contact-as-command-argument {:arg-index 0
|
||||
:bot-db-key "recipient"
|
||||
:contact (get-in db [:contacts/contacts contact-id])}]]}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:profile/send-message
|
||||
|
@ -75,7 +75,7 @@
|
||||
[action-button {:label (label :t/send-transaction)
|
||||
:icon :icons/arrow-right
|
||||
:icon-opts {:color :blue}
|
||||
:on-press #(dispatch [:profile/send-transaction chat-id])}]])])
|
||||
:on-press #(dispatch [:profile/send-transaction chat-id whisper-identity])}]])])
|
||||
|
||||
(defn profile-info-item [{:keys [label value options text-mode empty-value? accessibility-label]}]
|
||||
[react/view styles/profile-setting-item
|
||||
|
@ -1,16 +1,17 @@
|
||||
(ns status-im.utils.sms-listener
|
||||
(:require [status-im.utils.platform :refer [android?]]
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.platform :refer [android?]]
|
||||
[status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||
|
||||
;; Only android is supported!
|
||||
(defn add-sms-listener
|
||||
"Message format: {:originatingAddress string, :body string}. Returns
|
||||
cancelable subscription."
|
||||
[listen-fn]
|
||||
[listen-event-creator]
|
||||
(when android?
|
||||
(.addListener rn-dependencies/android-sms-listener
|
||||
(fn [message]
|
||||
(listen-fn (js->clj message :keywordize-keys true))))))
|
||||
(re-frame/dispatch (listen-event-creator (js->clj message :keywordize-keys true)))))))
|
||||
|
||||
(defn remove-sms-listener [subscription]
|
||||
(when android?
|
||||
|
48
test/cljs/status_im/test/chat/events.cljs
Normal file
48
test/cljs/status_im/test/chat/events.cljs
Normal file
@ -0,0 +1,48 @@
|
||||
(ns status-im.test.chat.events
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
reagent.core
|
||||
[re-frame.core :as rf]
|
||||
[day8.re-frame.test :refer [run-test-sync]]
|
||||
[status-im.constants :as const]
|
||||
[status-im.chat.sign-up :as sign-up]
|
||||
[status-im.chat.events :as chat-events]))
|
||||
|
||||
(def contact
|
||||
{:address "c296367a939e0957500a25ca89b70bd64b03004e"
|
||||
:whisper-identity "0x04f5722fba79eb36d73263417531007f43d13af76c6233573a8e3e60f667710611feba0785d751b50609bfc0b7cef35448875c5392c0a91948c95798a0ce600847"
|
||||
:name "testuser"
|
||||
:photo-path "contacts://testuser"
|
||||
:dapp? false})
|
||||
|
||||
(deftest init-console-chat
|
||||
(testing "initialising console if console is already added to chats, should not modify anything"
|
||||
(let [db {:chats {const/console-chat-id sign-up/console-chat}}
|
||||
fx (chat-events/init-console-chat db false)]
|
||||
(is (= db (:db fx)))
|
||||
(is (= #{:db} (-> fx keys set)))))
|
||||
|
||||
(testing "initialising console without existing account and console chat not initialisated"
|
||||
(let [fresh-db {:chats {}
|
||||
:accounts/current-account-id nil}
|
||||
{:keys [db dispatch-n]} (chat-events/init-console-chat fresh-db false)]
|
||||
(is (= (:current-chat-id db)
|
||||
(:chat-id sign-up/console-chat)))
|
||||
(is (= (:new-chat db)
|
||||
sign-up/console-chat))
|
||||
(is (= (:current-chat-id db)
|
||||
const/console-chat-id))
|
||||
(is (= dispatch-n
|
||||
(concat [[:add-contacts [sign-up/console-contact]]]
|
||||
sign-up/intro-events)))))
|
||||
|
||||
(testing "initialising console with existing account and console chat not initialisated"
|
||||
(let [fresh-db {:chats {}
|
||||
:accounts/current-account-id (:whisper-identity contact)}
|
||||
{:keys [db dispatch-n]} (chat-events/init-console-chat fresh-db false)]
|
||||
(is (= (:current-chat-id db)
|
||||
(:chat-id sign-up/console-chat)))
|
||||
(is (= (:new-chat db)
|
||||
sign-up/console-chat))
|
||||
(is (= (:current-chat-id db)
|
||||
const/console-chat-id))
|
||||
(is (= dispatch-n [[:add-contacts [sign-up/console-contact]]])))))
|
@ -1,5 +1,6 @@
|
||||
(ns status-im.test.runner
|
||||
(:require [doo.runner :refer-macros [doo-tests]]
|
||||
[status-im.test.chat.events]
|
||||
[status-im.test.contacts.events]
|
||||
[status-im.test.accounts.events]
|
||||
[status-im.test.wallet.events]
|
||||
@ -24,6 +25,7 @@
|
||||
(set! goog.DEBUG false)
|
||||
|
||||
(doo-tests
|
||||
'status-im.test.chat.events
|
||||
'status-im.test.accounts.events
|
||||
'status-im.test.contacts.events
|
||||
'status-im.test.profile.events
|
||||
|
Loading…
x
Reference in New Issue
Block a user