Refactor command data loading + chat input handling
Also accomplished was removal of redundant preview loading and command markup is now stored as cljs data in app-db, only being translated to RN components in subscriptions
This commit is contained in:
parent
7506689fe5
commit
e3f27ee5ee
|
@ -0,0 +1,122 @@
|
|||
(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]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.data-store.messages :as msg-store]
|
||||
[status-im.utils.handlers :refer [register-handler-fx]]
|
||||
[status-im.components.status :as status]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.commands.utils :as commands-utils]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
(defn generate-context
|
||||
"Generates context for jail call"
|
||||
[{:keys [current-account-id chats]} chat-id to]
|
||||
(merge {:platform platform/platform
|
||||
:from current-account-id
|
||||
:to to
|
||||
:chat {:chat-id chat-id
|
||||
:group-chat (get-in chats [chat-id :group-chat])}}
|
||||
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] :as message}
|
||||
data-type]]
|
||||
(let [{:keys [current-account-id chats]
|
||||
:contacts/keys [contacts]} db
|
||||
jail-id (or jail-id chat-id)
|
||||
jail-id (if (get-in chats [jail-id :group-chat])
|
||||
(get-in chats [jail-id :command-suggestions (keyword command) :owner-id])
|
||||
jail-id)]
|
||||
(if (get-in contacts [jail-id :commands-loaded?])
|
||||
(let [path [(if (= :response (keyword type)) :responses :commands)
|
||||
(or content-command command)
|
||||
data-type]
|
||||
to (get-in contacts [chat-id :address])
|
||||
jail-params {:parameters params
|
||||
:context (generate-context db chat-id to)}]
|
||||
{:chat-fx/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]]}))))
|
||||
|
||||
(register-handler-fx
|
||||
:execute-command-immediately
|
||||
[trim-v]
|
||||
(fn [_ [{command-name :name :as command}]]
|
||||
(case (keyword command-name)
|
||||
:grant-permissions
|
||||
{:dispatch [:request-permissions
|
||||
[:read-external-storage]
|
||||
#(dispatch [:initialize-geth])]}
|
||||
(log/debug "ignoring command: " command))))
|
||||
|
||||
(register-handler-fx
|
||||
:request-command-preview
|
||||
[trim-v (inject-cofx ::get-persisted-message)]
|
||||
(fn [{:keys [db get-persisted-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)]
|
||||
;; 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]}))))))
|
|
@ -0,0 +1,493 @@
|
|||
(ns status-im.chat.events.input
|
||||
(:require [clojure.string :as str]
|
||||
[re-frame.core :refer [reg-fx reg-cofx inject-cofx dispatch trim-v]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.chat.utils :as chat-utils]
|
||||
[status-im.chat.models.input :as input-model]
|
||||
[status-im.chat.models.suggestions :as suggestions]
|
||||
[status-im.components.react :as react-comp]
|
||||
[status-im.components.status :as status]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :refer [register-handler-db register-handler-fx]]
|
||||
[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
|
||||
::focus-rn-component
|
||||
(fn [ref]
|
||||
(try
|
||||
(.focus ref)
|
||||
(catch :default e
|
||||
(log/debug "Cannot focus the reference")))))
|
||||
|
||||
(reg-fx
|
||||
::blur-rn-component
|
||||
(fn [ref]
|
||||
(try
|
||||
(.blur ref)
|
||||
(catch :default e
|
||||
(log/debug "Cannot blur the reference")))))
|
||||
|
||||
(reg-fx
|
||||
::dismiss-keyboard
|
||||
(fn [_]
|
||||
(react-comp/dismiss-keyboard!)))
|
||||
|
||||
(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)))}))))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
(register-handler-db
|
||||
:update-input-data
|
||||
(fn [db]
|
||||
(input-model/modified-db-after-change db)))
|
||||
|
||||
(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]})))
|
||||
|
||||
(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)]})))
|
||||
|
||||
(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
|
||||
:result-box nil
|
||||
:validation-messages nil
|
||||
:prev-command name}]
|
||||
[:load-chat-parameter-box command 0]]}
|
||||
|
||||
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?]]]
|
||||
(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]
|
||||
(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
|
||||
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})))
|
||||
|
||||
(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 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)]
|
||||
(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))
|
||||
path [(if (= :command type) :commands :responses)
|
||||
name
|
||||
:params
|
||||
parameter-index
|
||||
:suggestions]
|
||||
args (-> (get-in db [:chats current-chat-id :input-text])
|
||||
(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
|
||||
:bot-db bot-db
|
||||
:seq-arg seq-arg}
|
||||
:context (merge {:data data
|
||||
: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)
|
||||
:path path
|
||||
:params params
|
||||
:callback-events-creator (fn [jail-response]
|
||||
[[:received-bot-response
|
||||
{:chat-id current-chat-id
|
||||
:command command
|
||||
:parameter-index parameter-index}
|
||||
jail-response]])}})))))
|
||||
|
||||
(register-handler-fx
|
||||
::send-message
|
||||
[trim-v]
|
||||
(fn [{{:keys [current-public-key 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])))})))
|
||||
|
||||
(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]})))
|
||||
|
||||
(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)
|
||||
|
||||
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})))
|
||||
|
||||
(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)})))
|
||||
|
||||
(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])}]})))
|
||||
|
||||
(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
|
||||
metadata
|
||||
args]
|
||||
:as content} :content
|
||||
:keys [chat-id jail-id data-type event-after-creator]}]]
|
||||
(let [{:keys [dapp? dapp-url name]} (get contacts chat-id)
|
||||
metadata (merge metadata
|
||||
(when dapp?
|
||||
{:url (i18n/get-contact-translated chat-id :dapp-url dapp-url)
|
||||
:name (i18n/get-contact-translated chat-id :name name)}))
|
||||
owner-id (:owner-id command)
|
||||
bot-db (get bot-db chat-id)
|
||||
params (merge (input-model/args->params content)
|
||||
{:bot-db bot-db
|
||||
:metadata metadata})
|
||||
|
||||
command-message {:command command
|
||||
:params params
|
||||
:to-message (:to-message-id metadata)
|
||||
:created-at current-time
|
||||
:id message-id
|
||||
:chat-id chat-id
|
||||
:jail-id (or owner-id jail-id)}
|
||||
|
||||
request-data {:message-id message-id
|
||||
:chat-id chat-id
|
||||
:jail-id (or owner-id jail-id)
|
||||
:content {:command (:name command)
|
||||
:params params
|
||||
:type (:type command)}
|
||||
:on-requested (fn [jail-response]
|
||||
(event-after-creator command-message jail-response))}]
|
||||
{:dispatch [:request-command-data 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))})))
|
||||
|
||||
(register-handler-fx
|
||||
::check-dapp-suggestions
|
||||
[trim-v]
|
||||
(fn [{{: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}}})))
|
||||
|
||||
(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)]
|
||||
(-> db
|
||||
(assoc-in [:chats chat-id :seq-arguments] [])
|
||||
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
|
||||
|
||||
(register-handler-db
|
||||
::update-seq-arguments
|
||||
[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])]
|
||||
(-> db
|
||||
(update-in [:chats chat-id :seq-arguments] #(into [] (conj % text)))
|
||||
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
|
||||
|
||||
(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)
|
||||
(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)
|
||||
:data-type :validator
|
||||
:event-after-creator (fn [_ jail-response]
|
||||
[::proceed-validation
|
||||
jail-response
|
||||
[[::update-seq-arguments chat-id]
|
||||
[:send-current-message]]])}]})))
|
||||
|
||||
(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))))
|
||||
|
||||
(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)]]}
|
||||
|
||||
(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
|
||||
: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)]
|
||||
(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)
|
||||
(take (inc arg-pos))
|
||||
(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]})))))))
|
||||
|
||||
(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]}))))
|
|
@ -28,8 +28,8 @@
|
|||
[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.handlers.input
|
||||
status-im.chat.handlers.commands
|
||||
status-im.chat.events.input
|
||||
status-im.chat.events.commands
|
||||
status-im.chat.handlers.animation
|
||||
status-im.chat.handlers.requests
|
||||
status-im.chat.handlers.unviewed-messages
|
||||
|
@ -186,14 +186,7 @@
|
|||
(defn load-messages!
|
||||
([db] (load-messages! db nil))
|
||||
([{:keys [current-chat-id] :as db} _]
|
||||
(let [messages (messages/get-by-chat-id current-chat-id)]
|
||||
(doseq [{:keys [content] :as message} messages]
|
||||
(when (and (:command content)
|
||||
(not (:content content)))
|
||||
;; todo rewrite it so that commands defined outside chat's context
|
||||
;; (bots' commands in group chats and global commands in all chats)
|
||||
;; could be rendered properly
|
||||
(dispatch [:request-command-data (assoc message :chat-id current-chat-id)])))
|
||||
(let [messages (messages/get-by-chat-id current-chat-id)]
|
||||
(assoc db :messages messages))))
|
||||
|
||||
(defn init-chat
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
(ns status-im.chat.handlers.commands
|
||||
(:require [cljs.reader :as reader]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :refer [enrich after dispatch]]
|
||||
[status-im.data-store.messages :as messages]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.components.status :as status]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.commands.utils :as cu]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.platform :as platform]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn generate-context [{:keys [current-account-id chats] :as db} chat-id to]
|
||||
(merge {:platform platform/platform
|
||||
:from current-account-id
|
||||
:to to
|
||||
:chat {:chat-id chat-id
|
||||
:group-chat (get-in chats [chat-id :group-chat])}}
|
||||
i18n/delimeters))
|
||||
|
||||
(handlers/register-handler :request-command-data
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-account-id chats]
|
||||
:contacts/keys [contacts] :as db}
|
||||
[_ {{:keys [command params content-command type]} :content
|
||||
:keys [message-id chat-id jail-id on-requested from] :as message} data-type]]
|
||||
(let [jail-id (or jail-id chat-id)
|
||||
jail-id' (if (get-in chats [jail-id :group-chat])
|
||||
(get-in chats [jail-id :command-suggestions (keyword command) :owner-id])
|
||||
jail-id)]
|
||||
(if-not (get-in contacts [jail-id' :commands-loaded?])
|
||||
(do (dispatch [:add-commands-loading-callback
|
||||
jail-id'
|
||||
#(dispatch [:request-command-data message data-type])])
|
||||
(dispatch [:load-commands! jail-id']))
|
||||
(let [path [(if (= :response (keyword type)) :responses :commands)
|
||||
(if content-command content-command command)
|
||||
data-type]
|
||||
to (get-in contacts [chat-id :address])
|
||||
params {:parameters params
|
||||
:context (generate-context db chat-id to)}
|
||||
callback #(let [result (get-in % [:result :returned])
|
||||
result' (if (:markup result)
|
||||
(update result :markup cu/generate-hiccup)
|
||||
result)]
|
||||
;; don't fill message data with nil results
|
||||
(when result'
|
||||
(dispatch [:set-in [:message-data data-type message-id] result']))
|
||||
(when (and result (= :preview data-type))
|
||||
;; update message in realm with serialized preview
|
||||
(messages/update {:message-id message-id
|
||||
:preview (prn-str result)}))
|
||||
(when on-requested (on-requested result')))]
|
||||
;chat-id path params callback lock? type
|
||||
(status/call-jail {:jail-id jail-id'
|
||||
:path path
|
||||
:params params
|
||||
:callback callback})))))))
|
||||
|
||||
(handlers/register-handler :execute-command-immediately
|
||||
(handlers/side-effect!
|
||||
(fn [_ [_ {command-name :name :as command}]]
|
||||
(case (keyword command-name)
|
||||
:grant-permissions
|
||||
(dispatch [:request-permissions
|
||||
[:read-external-storage]
|
||||
#(dispatch [:initialize-geth])])
|
||||
(log/debug "ignoring command: " command)))))
|
||||
|
||||
(handlers/register-handler :request-command-preview
|
||||
(handlers/side-effect!
|
||||
(fn [db [_ {:keys [message-id] :as message}]]
|
||||
(let [previews (get-in db [:message-data :preview])]
|
||||
(when-not (contains? previews message-id)
|
||||
(let [{serialized-preview :preview} (messages/get-by-id 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
|
||||
(dispatch [:set-in [:message-data :preview message-id]
|
||||
(-> serialized-preview
|
||||
reader/read-string
|
||||
(update :markup cu/generate-hiccup))])
|
||||
(dispatch [:request-command-data message :preview]))))))))
|
|
@ -1,396 +0,0 @@
|
|||
(ns status-im.chat.handlers.input
|
||||
(:require [re-frame.core :refer [enrich after dispatch]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.chat.utils :as chat-utils]
|
||||
[status-im.chat.models.input :as input-model]
|
||||
[status-im.chat.models.suggestions :as suggestions]
|
||||
[status-im.components.react :as react-comp]
|
||||
[status-im.components.status :as status]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.i18n :as i18n]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(handlers/register-handler
|
||||
:update-input-data
|
||||
(fn [db]
|
||||
(input-model/modified-db-after-change db)))
|
||||
|
||||
(handlers/register-handler :set-chat-input-text
|
||||
(fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
ends-with-space? (input-model/text-ends-with-space? text)]
|
||||
(dispatch [:update-suggestions chat-id text])
|
||||
(->> text
|
||||
(input-model/text->emoji)
|
||||
(assoc-in db [:chats chat-id :input-text])))))
|
||||
|
||||
(handlers/register-handler :add-to-chat-input-text
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [chats current-chat-id]} [_ 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)])))))
|
||||
|
||||
(handlers/register-handler :select-chat-input-command
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id chat-ui-props] :as db}
|
||||
[_ {:keys [prefill prefill-bot-db sequential-params name] :as command} metadata prevent-auto-focus?]]
|
||||
(dispatch [:set-chat-input-text (str (chat-utils/command-name command)
|
||||
const/spacing-char
|
||||
(when-not sequential-params
|
||||
(input-model/join-command-args prefill)))])
|
||||
(dispatch [:clear-bot-db])
|
||||
(when prefill-bot-db
|
||||
(dispatch [:update-bot-db {:bot current-chat-id
|
||||
:db prefill-bot-db}]))
|
||||
(dispatch [:set-chat-input-metadata metadata])
|
||||
(dispatch [:set-chat-ui-props {:show-suggestions? false
|
||||
:result-box nil
|
||||
:validation-messages nil
|
||||
:prev-command name}])
|
||||
(dispatch [:load-chat-parameter-box command 0])
|
||||
(if sequential-params
|
||||
(js/setTimeout
|
||||
#(do (when-not prevent-auto-focus?
|
||||
(dispatch [:chat-input-focus :seq-input-ref]))
|
||||
(dispatch [:set-chat-seq-arg-input-text (str/join const/spacing-char prefill)]))
|
||||
100)
|
||||
(when-not prevent-auto-focus?
|
||||
(dispatch [:chat-input-focus :input-ref]))))))
|
||||
|
||||
(handlers/register-handler :set-chat-input-metadata
|
||||
(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))))
|
||||
|
||||
(handlers/register-handler :set-command-argument
|
||||
(handlers/side-effect!
|
||||
(fn [{: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]))]
|
||||
(if seq-params?
|
||||
(dispatch [:set-chat-seq-arg-input-text 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))]
|
||||
(dispatch [:set-chat-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))])))))))
|
||||
|
||||
(handlers/register-handler :chat-input-focus
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id chat-ui-props] :as db} [_ ref]]
|
||||
(try
|
||||
(when-let [ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
(.focus ref))
|
||||
(catch :default e
|
||||
(log/debug "Cannot focus the reference"))))))
|
||||
|
||||
(handlers/register-handler :chat-input-blur
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id chat-ui-props] :as db} [_ ref]]
|
||||
(try
|
||||
(when-let [ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
(.blur ref))
|
||||
(catch :default e
|
||||
(log/debug "Cannot blur the reference"))))))
|
||||
|
||||
(handlers/register-handler :update-suggestions
|
||||
(fn [{:keys [current-chat-id] :as 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])]
|
||||
(when dapp?
|
||||
(if (str/blank? chat-text)
|
||||
(dispatch [:set-in [:chats chat-id :parameter-boxes :message] nil])
|
||||
(when (every? empty? [requests commands])
|
||||
(dispatch [::check-dapp-suggestions chat-id chat-text]))))
|
||||
(-> db
|
||||
(assoc-in [:chats chat-id :request-suggestions] requests)
|
||||
(assoc-in [:chats chat-id :command-suggestions] all-commands)))))
|
||||
|
||||
(handlers/register-handler :load-chat-parameter-box
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id bot-db current-account-id] :as db}
|
||||
[_ {:keys [name type bot owner-id] :as command}]]
|
||||
(let [parameter-index (input-model/argument-position db current-chat-id)]
|
||||
(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))
|
||||
path [(if (= :command type) :commands :responses)
|
||||
name
|
||||
:params
|
||||
parameter-index
|
||||
:suggestions]
|
||||
args (-> (get-in db [:chats current-chat-id :input-text])
|
||||
(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
|
||||
:bot-db bot-db
|
||||
:seq-arg seq-arg}
|
||||
:context (merge {:data data
|
||||
:from current-account-id
|
||||
:to to}
|
||||
(input-model/command-dependent-context-params current-chat-id command))}]
|
||||
(status/call-jail
|
||||
{:jail-id (or bot owner-id current-chat-id)
|
||||
:path path
|
||||
:params params
|
||||
:callback #(dispatch [:received-bot-response
|
||||
{:chat-id current-chat-id
|
||||
:command command
|
||||
:parameter-index parameter-index}
|
||||
%])})))))))
|
||||
|
||||
(handlers/register-handler ::send-message
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-public-key current-account-id] :as 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}]
|
||||
(dispatch [:set-chat-input-text nil chat-id])
|
||||
(dispatch [:set-chat-input-metadata nil chat-id])
|
||||
(dispatch [:set-chat-ui-props {:sending-in-progress? false}])
|
||||
(cond
|
||||
command
|
||||
(dispatch [:check-commands-handlers! data])
|
||||
(not (str/blank? text))
|
||||
(dispatch [:prepare-message data]))))))
|
||||
|
||||
(handlers/register-handler :proceed-command
|
||||
(handlers/side-effect!
|
||||
(fn [db [_ {{: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
|
||||
:after #(dispatch [::send-command %2 content chat-id])})
|
||||
after-validation #(dispatch [::request-command-data on-send-params])
|
||||
validation-params (merge params
|
||||
{:data-type :validator
|
||||
:after #(dispatch [::proceed-validation %2 after-validation])})]
|
||||
|
||||
(dispatch [::request-command-data validation-params])))))
|
||||
|
||||
(handlers/register-handler ::proceed-validation
|
||||
(handlers/side-effect!
|
||||
(fn [db [_ {:keys [markup validationHandler parameters]} proceed-fn]]
|
||||
(let [set-errors #(do (dispatch [:set-chat-ui-props {:validation-messages %
|
||||
:sending-in-progress? false}]))]
|
||||
(cond
|
||||
markup
|
||||
(set-errors markup)
|
||||
|
||||
validationHandler
|
||||
(do (dispatch [::execute-validation-handler validationHandler parameters set-errors proceed-fn])
|
||||
(dispatch [:set-chat-ui-props {:sending-in-progress? false}]))
|
||||
|
||||
:default
|
||||
(proceed-fn))))))
|
||||
|
||||
(handlers/register-handler ::execute-validation-handler
|
||||
(handlers/side-effect!
|
||||
(fn [_ [_ name params set-errors proceed]]
|
||||
(when-let [validator (input-model/validation-handler name)]
|
||||
(validator params set-errors proceed)))))
|
||||
|
||||
(handlers/register-handler ::send-command
|
||||
(handlers/side-effect!
|
||||
(fn [db [_ on-send {{:keys [fullscreen bot]} :command :as content} chat-id]]
|
||||
(if on-send
|
||||
(do
|
||||
(when fullscreen
|
||||
(dispatch [:choose-predefined-expandable-height :result-box :max]))
|
||||
(dispatch [:set-chat-ui-props {:result-box on-send
|
||||
:sending-in-progress? false}])
|
||||
(react-comp/dismiss-keyboard!))
|
||||
(dispatch [::request-command-data
|
||||
{:content content
|
||||
:chat-id chat-id
|
||||
:jail-id (or bot chat-id)
|
||||
:data-type :preview
|
||||
:after #(dispatch [::send-message % chat-id])}])))))
|
||||
|
||||
(handlers/register-handler ::request-command-data
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [bot-db]
|
||||
:contacts/keys [contacts] :as db}
|
||||
[_ {{:keys [command
|
||||
metadata
|
||||
args]
|
||||
:as content} :content
|
||||
:keys [chat-id jail-id data-type after]}]]
|
||||
(let [{:keys [dapp? dapp-url name]} (get contacts chat-id)
|
||||
message-id (random/id)
|
||||
metadata (merge metadata
|
||||
(when dapp?
|
||||
{:url (i18n/get-contact-translated chat-id :dapp-url dapp-url)
|
||||
:name (i18n/get-contact-translated chat-id :name name)}))
|
||||
owner-id (:owner-id command)
|
||||
bot-db (get bot-db chat-id)
|
||||
params (merge (input-model/args->params content)
|
||||
{:bot-db bot-db
|
||||
:metadata metadata})
|
||||
|
||||
command-message {:command command
|
||||
:params params
|
||||
:to-message (:to-message-id metadata)
|
||||
:created-at (time/now-ms)
|
||||
:id message-id
|
||||
:chat-id chat-id
|
||||
:jail-id (or owner-id jail-id)}
|
||||
|
||||
request-data {:message-id message-id
|
||||
:chat-id chat-id
|
||||
:jail-id (or owner-id jail-id)
|
||||
:content {:command (:name command)
|
||||
:params params
|
||||
:type (:type command)}
|
||||
:on-requested #(after command-message %)}]
|
||||
(dispatch [:request-command-data request-data data-type])))))
|
||||
|
||||
(handlers/register-handler :send-current-message
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id] :as db} [_ chat-id]]
|
||||
(dispatch [:set-chat-ui-props {:sending-in-progress? true}])
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
chat-command (input-model/selected-chat-command db chat-id)
|
||||
seq-command? (get-in chat-command [:command :sequential-params])
|
||||
chat-command (if seq-command?
|
||||
(let [args (get-in db [:chats chat-id :seq-arguments])]
|
||||
(assoc chat-command :args args))
|
||||
(update chat-command :args #(remove str/blank? %)))]
|
||||
(if (:command chat-command)
|
||||
(if (= :complete (input-model/command-completion chat-command))
|
||||
(do
|
||||
(dispatch [:proceed-command chat-command chat-id])
|
||||
(dispatch [:clear-seq-arguments chat-id]))
|
||||
(let [text (get-in db [:chats chat-id :input-text])]
|
||||
(dispatch [:set-chat-ui-props {:sending-in-progress? false}])
|
||||
(when-not (input-model/text-ends-with-space? text)
|
||||
(dispatch [:set-chat-input-text (str text const/spacing-char)]))))
|
||||
(dispatch [::send-message nil chat-id]))))))
|
||||
|
||||
(handlers/register-handler ::check-dapp-suggestions
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-account-id] :as db} [_ chat-id text]]
|
||||
(let [data (get-in db [:local-storage chat-id])]
|
||||
(status/call-function!
|
||||
{:chat-id chat-id
|
||||
:function :on-message-input-change
|
||||
:parameters {:message text}
|
||||
:context {:data data
|
||||
:from current-account-id}})))))
|
||||
|
||||
(handlers/register-handler :clear-seq-arguments
|
||||
(fn [{:keys [current-chat-id chats] :as db} [_ chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)]
|
||||
(-> db
|
||||
(assoc-in [:chats chat-id :seq-arguments] [])
|
||||
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
|
||||
|
||||
(handlers/register-handler :update-seq-arguments
|
||||
(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])]
|
||||
(-> db
|
||||
(update-in [:chats chat-id :seq-arguments] #(into [] (conj % text)))
|
||||
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
|
||||
|
||||
(handlers/register-handler :send-seq-argument
|
||||
(handlers/side-effect!
|
||||
(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])
|
||||
seq-arguments (get-in db [:chats chat-id :seq-arguments])
|
||||
command (-> (input-model/selected-chat-command db chat-id)
|
||||
(assoc :args (into [] (conj seq-arguments text))))
|
||||
args (get-in chats [chat-id :seq-arguments])
|
||||
after-validation #(do
|
||||
(dispatch [:update-seq-arguments chat-id])
|
||||
(dispatch [:send-current-message]))]
|
||||
(dispatch [::request-command-data
|
||||
{:content command
|
||||
:chat-id chat-id
|
||||
:jail-id (or (get-in command [:command :bot]) chat-id)
|
||||
:data-type :validator
|
||||
:after #(dispatch [::proceed-validation %2 after-validation])}])))))
|
||||
|
||||
(handlers/register-handler :set-chat-seq-arg-input-text
|
||||
(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))))
|
||||
|
||||
(handlers/register-handler :update-text-selection
|
||||
(handlers/side-effect!
|
||||
(fn [{: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)]
|
||||
(when (and (= selection (+ (count const/command-char)
|
||||
(count (get-in command [:command :name]))
|
||||
(count const/spacing-char)))
|
||||
(get-in command [:command :sequential-params]))
|
||||
(dispatch [:chat-input-focus :seq-input-ref]))
|
||||
(dispatch [:set-chat-ui-props {:selection selection}])
|
||||
(dispatch [:load-chat-parameter-box (:command command)])))))
|
||||
|
||||
(handlers/register-handler :select-prev-argument
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [chat-ui-props current-chat-id] :as 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])
|
||||
(do
|
||||
(dispatch [:set-command-argument [0 "" false]])
|
||||
(dispatch [:set-chat-seq-arg-input-text ""])
|
||||
(dispatch [:load-chat-parameter-box (:command command)]))
|
||||
(let [arg-pos (input-model/argument-position db current-chat-id)]
|
||||
(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)
|
||||
(take (inc arg-pos))
|
||||
(input-model/join-command-args)
|
||||
(count))
|
||||
ref (get-in chat-ui-props [current-chat-id :input-ref])]
|
||||
(.setNativeProps ref (clj->js {:selection {:start new-sel :end new-sel}}))
|
||||
(dispatch [:update-text-selection new-sel])))))))))
|
||||
|
||||
(handlers/register-handler :select-next-argument
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [chat-ui-props current-chat-id] :as 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])]
|
||||
(.setNativeProps ref (clj->js {:selection {:start new-sel :end new-sel}}))
|
||||
(dispatch [:update-text-selection new-sel]))))))
|
|
@ -267,9 +267,8 @@
|
|||
|
||||
(defmethod validation-handler :phone
|
||||
[_]
|
||||
(fn [[number] set-errors proceed]
|
||||
(if (phone-number/valid-mobile-number? number)
|
||||
(proceed)
|
||||
(set-errors [validation-message
|
||||
{:title (i18n/label :t/phone-number)
|
||||
:description (i18n/label :t/invalid-phone)}]))))
|
||||
(fn [[number] error-events-creator]
|
||||
(when-not (phone-number/valid-mobile-number? number)
|
||||
(error-events-creator [validation-message
|
||||
{:title (i18n/label :t/phone-number)
|
||||
:description (i18n/label :t/invalid-phone)}]))))
|
||||
|
|
|
@ -1,23 +1,30 @@
|
|||
(ns status-im.chat.subs
|
||||
(:require [re-frame.core :refer [reg-sub dispatch subscribe path]]
|
||||
(:require [re-frame.core :refer [reg-sub dispatch subscribe path]]
|
||||
[status-im.data-store.chats :as chats]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.chat.models.input :as input-model]
|
||||
[status-im.chat.models.input :as input-model]
|
||||
[status-im.chat.utils :as chat-utils]
|
||||
[status-im.chat.views.input.utils :as input-utils]
|
||||
[status-im.constants :refer [response-suggesstion-resize-duration
|
||||
content-type-status
|
||||
console-chat-id]]
|
||||
[status-im.commands.utils :as commands-utils]
|
||||
[status-im.models.commands :as commands]
|
||||
[status-im.utils.platform :refer [platform-specific ios?]]
|
||||
[taoensso.timbre :as log]
|
||||
[clojure.string :as str]))
|
||||
|
||||
|
||||
(reg-sub
|
||||
:chat-ui-props
|
||||
(fn [db [_ ui-element chat-id]]
|
||||
(let [current-chat-id (subscribe [:get-current-chat-id])]
|
||||
(get-in db [:chat-ui-props (or chat-id @current-chat-id) ui-element]))))
|
||||
(let [current-chat-id (subscribe [:get-current-chat-id])
|
||||
data (get-in db [:chat-ui-props (or chat-id @current-chat-id) ui-element])]
|
||||
(cond-> data
|
||||
(:markup data)
|
||||
(update :markup commands-utils/generate-hiccup)
|
||||
|
||||
(and (= ui-element :validation-messages) data)
|
||||
commands-utils/generate-hiccup))))
|
||||
|
||||
(reg-sub
|
||||
:chat-input-margin
|
||||
|
@ -181,10 +188,16 @@
|
|||
(filter :show?)
|
||||
(first)))))
|
||||
|
||||
(reg-sub :get-last-message-short-preview
|
||||
(reg-sub :get-message-short-preview-markup
|
||||
(fn [db [_ message-id]]
|
||||
(get-in db [:message-data :short-preview message-id :markup])))
|
||||
|
||||
(reg-sub :get-last-message-short-preview
|
||||
(fn [db [_ chat-id]]
|
||||
(let [last-message (subscribe [:get-last-message chat-id])]
|
||||
(get-in db [:message-data :short-preview (:message-id @last-message)]))))
|
||||
(let [last-message (subscribe [:get-last-message chat-id])
|
||||
preview (subscribe [:get-message-short-preview-markup (:message-id @last-message)])]
|
||||
(when-let [markup @preview]
|
||||
(commands-utils/generate-hiccup markup)))))
|
||||
|
||||
(reg-sub :get-default-container-area-height
|
||||
:<- [:chat-ui-props :input-height]
|
||||
|
@ -213,3 +226,13 @@
|
|||
(filter :outgoing)
|
||||
(sort-by :clock-value >)
|
||||
(first))))
|
||||
|
||||
(reg-sub :get-message-preview-markup
|
||||
(fn [db [_ message-id]]
|
||||
(get-in db [:message-data :preview message-id :markup])))
|
||||
|
||||
(reg-sub :get-message-preview
|
||||
(fn [db [_ message-id]]
|
||||
(let [preview (subscribe [:get-message-preview-markup message-id])]
|
||||
(when-let [markup @preview]
|
||||
(commands-utils/generate-hiccup markup)))))
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
global-commands [:get :global-commands]
|
||||
current-chat-id [:get-current-chat-id]
|
||||
contact-chat [:get-in [:chats (if outgoing to from)]]
|
||||
preview [:get-in [:message-data :preview message-id :markup]]]
|
||||
preview [:get-message-preview message-id]]
|
||||
(let [commands (merge commands from-commands)
|
||||
{:keys [command params]} (parse-command-message-content commands global-commands content)
|
||||
{:keys [name type]
|
||||
|
@ -386,7 +386,7 @@
|
|||
(defn chat-message [{:keys [outgoing message-id chat-id user-statuses from] :as message}]
|
||||
(let [my-identity (subscribe [:get :current-public-key])
|
||||
status (subscribe [:get-in [:message-data :user-statuses message-id my-identity]])
|
||||
preview (subscribe [:get-in [:message-data :preview message-id :markup]])]
|
||||
preview (subscribe [:get-message-preview message-id])]
|
||||
(r/create-class
|
||||
{:display-name "chat-message"
|
||||
:component-will-mount
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
(let [commands-atom (subscribe [:get-commands-and-responses chat-id])
|
||||
answered? (subscribe [:is-request-answered? message-id])
|
||||
status-initialized? (subscribe [:get :status-module-initialized?])
|
||||
markup (subscribe [:get-in [:message-data :preview message-id :markup]])]
|
||||
markup (subscribe [:get-message-preview message-id])]
|
||||
(fn [{:keys [message-id content from incoming-group]}]
|
||||
(let [commands @commands-atom
|
||||
{:keys [prefill prefill-bot-db prefillBotDb params]
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
[status-im.models.commands :as cm]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
[status-im.i18n :refer [get-contact-translated]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.commands.utils :as cu]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.data-store.local-storage :as local-storage]))
|
||||
|
||||
(defn command-handler!
|
||||
|
@ -22,7 +21,7 @@
|
|||
(cond
|
||||
handler-error
|
||||
(when-let [markup (:markup handler-error)]
|
||||
(dispatch [:set-chat-ui-props {:validation-messages (cu/generate-hiccup markup)}]))
|
||||
(dispatch [:set-chat-ui-props {:validation-messages markup}]))
|
||||
|
||||
result
|
||||
(let [command' (assoc command :handler-data returned)
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
(:content content)]
|
||||
|
||||
(:command content)
|
||||
(:markup preview)
|
||||
preview
|
||||
|
||||
:else
|
||||
[text {:style st/last-message-text
|
||||
|
|
|
@ -443,4 +443,4 @@
|
|||
[:add-pending-contact id]
|
||||
[:add-new-contact-and-open-chat {:name (generate-gfy)
|
||||
:photo-path (identicon id)
|
||||
:whisper-identity id}])})))
|
||||
:whisper-identity id}])})))
|
||||
|
|
Loading…
Reference in New Issue