More efficient subscriptions

This commit is contained in:
janherich 2017-11-28 13:33:58 +01:00 committed by Jan Herich
parent c38f1ce8a4
commit 25d3940d49
21 changed files with 315 additions and 282 deletions

View File

@ -22,7 +22,7 @@
;; in handlers ;; in handlers
(let [stack (subscribe [:get :navigation-stack]) (let [stack (subscribe [:get :navigation-stack])
creating? (subscribe [:get :accounts/creating-account?]) creating? (subscribe [:get :accounts/creating-account?])
result-box (subscribe [:chat-ui-props :result-box]) result-box (subscribe [:get-current-chat-ui-prop :result-box])
webview (subscribe [:get :webview-bridge])] webview (subscribe [:get :webview-bridge])]
(cond (cond
@creating? true @creating? true

View File

@ -2,14 +2,11 @@
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[status-im.chat.models.input :as input-model])) [status-im.chat.models.input :as input-model]))
(re-frame/reg-sub (re-frame/reg-sub :get-bot-db :bot-db)
:bot-db
(fn [db]
(:bot-db db)))
(re-frame/reg-sub (re-frame/reg-sub
:current-bot-db :current-bot-db
:<- [:bot-db] :<- [:get-bot-db]
:<- [:selected-chat-command] :<- [:selected-chat-command]
(fn [[bot-db command]] (fn [[bot-db command]]
(let [command-owner (get-in command [:command :owner-id])] (let [command-owner (get-in command [:command :owner-id])]

View File

@ -6,7 +6,6 @@
[status-im.chat.utils :as chat-utils] [status-im.chat.utils :as chat-utils]
[status-im.chat.models :as model] [status-im.chat.models :as model]
[status-im.chat.models.input :as input-model] [status-im.chat.models.input :as input-model]
[status-im.chat.models.commands :as commands-model]
[status-im.chat.events.commands :as commands-events] [status-im.chat.events.commands :as commands-events]
[status-im.chat.events.animation :as animation-events] [status-im.chat.events.animation :as animation-events]
[status-im.bots.events :as bots-events] [status-im.bots.events :as bots-events]
@ -64,6 +63,9 @@
(and dapp? (str/blank? chat-text)) (and dapp? (str/blank? chat-text))
(assoc-in [:chats current-chat-id :parameter-boxes :message] nil)))) (assoc-in [:chats current-chat-id :parameter-boxes :message] nil))))
;; TODO janherich: this is super fragile and won't work at all for group chats with bots.
;; The proper way how to do it is to check each chat participant and call `:on-message-input-change`
;; jail function in each participant's jail
(defn call-on-message-input-change (defn call-on-message-input-change
"Calls bot's `on-message-input-change` function" "Calls bot's `on-message-input-change` function"
[{:keys [current-chat-id current-account-id chats local-storage] :as db}] [{:keys [current-chat-id current-account-id chats local-storage] :as db}]
@ -99,7 +101,7 @@
[{:keys [current-chat-id] :as db} index arg move-to-next?] [{:keys [current-chat-id] :as db} index arg move-to-next?]
(let [command (-> (get-in db [:chats current-chat-id :input-text]) (let [command (-> (get-in db [:chats current-chat-id :input-text])
(input-model/split-command-args)) (input-model/split-command-args))
seq-params? (-> (input-model/selected-chat-command db current-chat-id) seq-params? (-> (input-model/selected-chat-command db)
(get-in [:command :sequential-params]))] (get-in [:command :sequential-params]))]
(if seq-params? (if seq-params?
(set-chat-seq-arg-input-text db arg) (set-chat-seq-arg-input-text db arg)
@ -160,9 +162,8 @@
(defn update-text-selection (defn update-text-selection
"Updates text selection in active chat input" "Updates text selection in active chat input"
[{:keys [current-chat-id] :as db} selection] [db selection]
(let [input-text (get-in db [:chats current-chat-id :input-text]) (let [command (input-model/selected-chat-command db)
command (input-model/selected-chat-command db current-chat-id input-text)
new-db (model/set-chat-ui-props db {:selection selection}) new-db (model/set-chat-ui-props db {:selection selection})
chat-parameter-box-fx (when command chat-parameter-box-fx (when command
(load-chat-parameter-box new-db (:command command)))] (load-chat-parameter-box new-db (:command command)))]
@ -213,13 +214,10 @@
(defn set-contact-as-command-argument (defn set-contact-as-command-argument
"Sets contact as command argument for active chat" "Sets contact as command argument for active chat"
[{:keys [current-chat-id] :as db} {:keys [bot-db-key contact arg-index]}] [db {:keys [bot-db-key contact arg-index]}]
(let [name (str/replace (:name contact) (re-pattern const/arg-wrapping-char) "") (let [name (str/replace (:name contact) (re-pattern const/arg-wrapping-char) "")
contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?]) contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?])
command-owner (-> db command-owner (get-in (input-model/selected-chat-command db) [:command :owner-id])]
(input-model/selected-chat-command current-chat-id)
:command
:owner-id)]
(-> db (-> db
(set-command-argument arg-index name true) (set-command-argument arg-index name true)
(bots-events/set-in-bot-db {:bot command-owner (bots-events/set-in-bot-db {:bot command-owner
@ -441,8 +439,7 @@
[(re-frame/inject-cofx :random-id)] [(re-frame/inject-cofx :random-id)]
(fn [{{:keys [current-chat-id current-public-key] :as db} :db message-id :random-id current-time :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]) (let [input-text (get-in db [:chats current-chat-id :input-text])
chat-command (-> db chat-command (-> (input-model/selected-chat-command db)
(input-model/selected-chat-command current-chat-id input-text)
(as-> selected-command (as-> selected-command
(if (get-in selected-command [:command :sequential-params]) (if (get-in selected-command [:command :sequential-params])
(assoc selected-command :args (assoc selected-command :args
@ -493,7 +490,7 @@
(fn [{{:keys [current-chat-id chats] :as db} :db} _] (fn [{{:keys [current-chat-id chats] :as db} :db} _]
(let [text (get-in chats [current-chat-id :seq-argument-input-text]) (let [text (get-in chats [current-chat-id :seq-argument-input-text])
seq-arguments (get-in chats [current-chat-id :seq-arguments]) seq-arguments (get-in chats [current-chat-id :seq-arguments])
command (-> (input-model/selected-chat-command db current-chat-id) command (-> (input-model/selected-chat-command db)
(assoc :args (into [] (conj seq-arguments text))))] (assoc :args (into [] (conj seq-arguments text))))]
(request-command-data db {:content command (request-command-data db {:content command
:chat-id current-chat-id :chat-id current-chat-id
@ -520,8 +517,7 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:select-prev-argument :select-prev-argument
(fn [{{:keys [chat-ui-props current-chat-id] :as db} :db} _] (fn [{{:keys [chat-ui-props current-chat-id] :as db} :db} _]
(let [input-text (get-in db [:chats current-chat-id :input-text]) (let [command (input-model/selected-chat-command db)]
command (input-model/selected-chat-command db current-chat-id input-text)]
(if (get-in command [:command :sequential-params]) (if (get-in command [:command :sequential-params])
(-> db (-> db
(set-command-argument 0 "" false) (set-command-argument 0 "" false)

View File

@ -96,25 +96,35 @@
(str/join const/spacing-char)))) (str/join const/spacing-char))))
(defn selected-chat-command (defn selected-chat-command
"Returns a map containing `:command`, `:metadata` and `:args` keys. "Takes whole db, or current chat and available commands/responses and returns a map
Can also return `nil` if there is no selected command. containing `:command`, `:metadata` and `:args` keys. Can also return `nil` if there is no selected command.
* `:command` key contains a map with all information about command. * `:command` key contains a map with all information about command.
* `:metadata` is also a map which contains some additional information, usually not visible by user. * `:metadata` is also a map which contains some additional information, usually not visible by user.
For instance, we can add a `:to-message-id` key to this map, and this key will allow us to identity For instance, we can add a `:to-message-id` key to this map, and this key will allow us to identity
the request we're responding to. the request we're responding to.
* `:args` contains all arguments provided by user." * `:args` contains all arguments provided by user."
([{:keys [current-chat-id access-scope->commands-responses] ([{:keys [input-text input-metadata seq-arguments] :as current-chat} commands responses]
(let [[command-name :as command-args] (split-command-args input-text)]
(when-let [{{:keys [message-id]} :request :as command} (and command-name
(starts-as-command? command-name)
(get (merge commands
responses)
(subs command-name 1)))]
{:command command
:metadata (if (and message-id (not (:to-message-id input-metadata)))
(assoc input-metadata :to-message-id message-id)
input-metadata)
:args (into [] (if (empty? seq-arguments)
(rest command-args)
seq-arguments))})))
([{:keys [chats current-chat-id access-scope->commands-responses]
:contacts/keys [contacts] :contacts/keys [contacts]
:accounts/keys [accounts current-account-id] :as db} chat-id input-text] :accounts/keys [accounts current-account-id] :as db}]
(let [chat-id (or chat-id current-chat-id) (let [chat (get chats current-chat-id)
chat (get-in db [:chats chat-id]) account (get accounts current-account-id)]
{:keys [input-metadata seq-arguments requests]} chat (selected-chat-command chat
command-args (split-command-args input-text) (commands-model/commands-responses :command
command-name (first command-args)]
(when (starts-as-command? (or command-name ""))
(let [account (get accounts current-account-id)
available-commands-responses (merge (commands-model/commands-responses :command
access-scope->commands-responses access-scope->commands-responses
account account
chat chat
@ -123,18 +133,7 @@
account account
chat chat
contacts contacts
(vals requests)))] (vals (:requests chat)))))))
(when-let [{{:keys [message-id]} :request :as command} (get available-commands-responses (subs command-name 1))]
{:command command
:metadata (if (and (nil? (:to-message-id input-metadata)) message-id)
(assoc input-metadata :to-message-id message-id)
input-metadata)
:args (->> (if (empty? seq-arguments)
(rest command-args)
seq-arguments)
(into []))})))))
([{:keys [current-chat-id] :as db} chat-id]
(selected-chat-command db chat-id (get-in db [:chats chat-id :input-text]))))
(def *no-argument-error* -1) (def *no-argument-error* -1)
@ -169,7 +168,7 @@
(let [input-text (get-in db [:chats current-chat-id :input-text]) (let [input-text (get-in db [:chats current-chat-id :input-text])
seq-arguments (get-in db [:chats current-chat-id :seq-arguments]) seq-arguments (get-in db [:chats current-chat-id :seq-arguments])
selection (get-in db [:chat-ui-props current-chat-id :selection]) selection (get-in db [:chat-ui-props current-chat-id :selection])
chat-command (selected-chat-command db current-chat-id)] chat-command (selected-chat-command db)]
(current-chat-argument-position chat-command input-text selection seq-arguments))) (current-chat-argument-position chat-command input-text selection seq-arguments)))
(defn command-completion (defn command-completion
@ -178,12 +177,7 @@
* `:less-than-needed` means that the command is not complete and additional arguments should be provided; * `:less-than-needed` means that the command is not complete and additional arguments should be provided;
* `:more-than-needed` means that the command is more than complete and contains redundant arguments; * `:more-than-needed` means that the command is more than complete and contains redundant arguments;
* `:no-command` means that there is no selected command." * `:no-command` means that there is no selected command."
([{:keys [current-chat-id] :as db} chat-id] [{:keys [args] :as chat-command}]
(let [chat-id (or chat-id current-chat-id)
input-text (get-in db [:chats chat-id :input-text])
chat-command (selected-chat-command db chat-id)]
(command-completion chat-command)))
([{:keys [args] :as chat-command}]
(let [args (remove str/blank? args) (let [args (remove str/blank? args)
params (get-in chat-command [:command :params]) params (get-in chat-command [:command :params])
required-params (remove :optional params)] required-params (remove :optional params)]
@ -201,7 +195,7 @@
:default :default
:no-command) :no-command)
:no-command)))) :no-command)))
(defn args->params (defn args->params
"Uses `args` (which is a list or vector like ['Jarrad' '1.0']) and command's `params` "Uses `args` (which is a list or vector like ['Jarrad' '1.0']) and command's `params`
@ -228,8 +222,7 @@
(defn modified-db-after-change (defn modified-db-after-change
"Returns the new db object that should be used after any input change." "Returns the new db object that should be used after any input change."
[{:keys [current-chat-id] :as db}] [{:keys [current-chat-id] :as db}]
(let [input-text (get-in db [:chats current-chat-id :input-text]) (let [command (selected-chat-command db)
command (selected-chat-command db current-chat-id input-text)
prev-command (get-in db [:chat-ui-props current-chat-id :prev-command])] prev-command (get-in db [:chat-ui-props current-chat-id :prev-command])]
(if command (if command
(cond-> db (cond-> db

View File

@ -86,7 +86,7 @@
(list-item [chat-message message]))) (list-item [chat-message message])))
(defn toolbar-action [] (defn toolbar-action []
(let [show-actions (subscribe [:chat-ui-props :show-actions?])] (let [show-actions (subscribe [:get-current-chat-ui-prop :show-actions?])]
(fn [] (fn []
(let [show-actions @show-actions] (let [show-actions @show-actions]
[touchable-highlight [touchable-highlight
@ -108,7 +108,7 @@
(label :t/add-to-contacts)]]])) (label :t/add-to-contacts)]]]))
(defview chat-toolbar [] (defview chat-toolbar []
[show-actions? [:chat-ui-props :show-actions?] [show-actions? [:get-current-chat-ui-prop :show-actions?]
accounts [:get-accounts] accounts [:get-accounts]
creating? [:get :accounts/creating-account?]] creating? [:get :accounts/creating-account?]]
[view [view
@ -175,9 +175,9 @@
(defview chat [] (defview chat []
[group-chat [:chat :group-chat] [group-chat [:chat :group-chat]
show-actions? [:chat-ui-props :show-actions?] show-actions? [:get-current-chat-ui-prop :show-actions?]
show-bottom-info? [:chat-ui-props :show-bottom-info?] show-bottom-info? [:get-current-chat-ui-prop :show-bottom-info?]
show-emoji? [:chat-ui-props :show-emoji?] show-emoji? [:get-current-chat-ui-prop :show-emoji?]
layout-height [:get :layout-height] layout-height [:get :layout-height]
input-text [:chat :input-text]] input-text [:chat :input-text]]
{:component-did-mount #(dispatch [:check-and-open-dapp!]) {:component-did-mount #(dispatch [:check-and-open-dapp!])

View File

@ -14,17 +14,36 @@
[taoensso.timbre :as log] [taoensso.timbre :as log]
[clojure.string :as str])) [clojure.string :as str]))
(reg-sub (reg-sub :chats :chats)
:chat-ui-props
(fn [db [_ ui-element chat-id]]
(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) (reg-sub :get-current-chat-id :current-chat-id)
commands-utils/generate-hiccup))))
(reg-sub :chat-ui-props :chat-ui-props)
(reg-sub
:get-current-chat-ui-props
:<- [:chat-ui-props]
:<- [:get-current-chat-id]
(fn [[chat-ui-props id]]
(get chat-ui-props id)))
(reg-sub
:get-current-chat-ui-prop
:<- [:get-current-chat-ui-props]
(fn [ui-props [_ prop]]
(get ui-props prop)))
(reg-sub
:validation-messages
:<- [:get-current-chat-ui-props]
(fn [ui-props]
(some-> ui-props :validation-messages commands-utils/generate-hiccup)))
(reg-sub
:result-box-markup
:<- [:get-current-chat-ui-props]
(fn [ui-props]
(some-> ui-props :result-box :markup commands-utils/generate-hiccup)))
(reg-sub (reg-sub
:chat-input-margin :chat-input-margin
@ -32,11 +51,6 @@
(fn [kb-height] (fn [kb-height]
(if ios? kb-height 0))) (if ios? kb-height 0)))
(reg-sub
:chats
(fn [db]
(:chats db)))
(reg-sub (reg-sub
:get-current-chat :get-current-chat
:<- [:chats] :<- [:chats]
@ -96,55 +110,48 @@
(fn [[commands responses]] (fn [[commands responses]]
(map->sorted-seq (merge commands responses)))) (map->sorted-seq (merge commands responses))))
(reg-sub
:get-current-chat-id
(fn [db]
(:current-chat-id db)))
(reg-sub
:get-chat-by-id
(fn [_ [_ chat-id]]
(chats/get-by-id chat-id)))
(reg-sub (reg-sub
:selected-chat-command :selected-chat-command
(fn [db [_ chat-id]] :<- [:get-current-chat]
(let [current-chat-id (subscribe [:get :current-chat-id]) :<- [:get-commands-for-chat]
input-text (subscribe [:chat :input-text])] :<- [:get-responses-for-chat]
(input-model/selected-chat-command db (or chat-id @current-chat-id) @input-text)))) (fn [[chat commands responses]]
(input-model/selected-chat-command chat commands responses)))
(reg-sub (reg-sub
:current-chat-argument-position :current-chat-argument-position
:<- [:selected-chat-command] :<- [:selected-chat-command]
:<- [:chat :input-text] :<- [:chat :input-text]
:<- [:chat :seq-arguments] :<- [:chat :seq-arguments]
:<- [:chat-ui-props :selection] :<- [:get-current-chat-ui-prop :selection]
(fn [[command input-text seq-arguments selection]] (fn [[command input-text seq-arguments selection]]
(input-model/current-chat-argument-position command input-text selection seq-arguments))) (input-model/current-chat-argument-position command input-text selection seq-arguments)))
(reg-sub (reg-sub
:chat-parameter-box :chat-parameter-box
(fn [db] :<- [:get-current-chat]
(let [chat-id (subscribe [:get-current-chat-id]) :<- [:selected-chat-command]
command (subscribe [:selected-chat-command]) :<- [:current-chat-argument-position]
index (subscribe [:current-chat-argument-position])] (fn [[current-chat selected-chat-command argument-position]]
(cond (cond
(and @command (not= @index input-model/*no-argument-error*)) (and selected-chat-command
(let [command-name (get-in @command [:command :name])] (not= argument-position input-model/*no-argument-error*))
(get-in db [:chats @chat-id :parameter-boxes command-name @index])) (get-in current-chat [:parameter-boxes
(get-in selected-chat-command [:command :name])
argument-position])
(not @command) (not selected-chat-command)
(get-in db [:chats @chat-id :parameter-boxes :message]) (get-in current-chat [:parameter-boxes :message])
:default :default
nil)))) nil)))
(reg-sub (reg-sub
:show-parameter-box? :show-parameter-box?
:<- [:chat-parameter-box] :<- [:chat-parameter-box]
:<- [:show-suggestions?] :<- [:show-suggestions?]
:<- [:chat :input-text] :<- [:chat :input-text]
:<- [:chat-ui-props :validation-messages] :<- [:validation-messages]
(fn [[chat-parameter-box show-suggestions? input-text validation-messages]] (fn [[chat-parameter-box show-suggestions? input-text validation-messages]]
(and (get chat-parameter-box :markup) (and (get chat-parameter-box :markup)
(not validation-messages) (not validation-messages)
@ -152,102 +159,109 @@
(reg-sub (reg-sub
:command-completion :command-completion
(fn [db [_ chat-id]] :<- [:selected-chat-command]
(input-model/command-completion db chat-id))) input-model/command-completion)
(reg-sub (reg-sub
:show-suggestions? :show-suggestions?
(fn [db [_ chat-id]] :<- [:get-current-chat-ui-prop :show-suggestions?]
(let [chat-id (or chat-id (db :current-chat-id)) :<- [:chat :input-text]
show-suggestions? (subscribe [:chat-ui-props :show-suggestions? chat-id]) :<- [:selected-chat-command]
input-text (subscribe [:chat :input-text chat-id]) :<- [:get-available-commands-responses]
selected-command (subscribe [:selected-chat-command chat-id]) (fn [[show-suggestions? input-text selected-command commands-responses]]
commands-responses (subscribe [:get-available-commands-responses])] (and (or show-suggestions? (input-model/starts-as-command? (str/trim (or input-text ""))))
(and (or @show-suggestions? (input-model/starts-as-command? (str/trim (or @input-text "")))) (not (:command selected-command))
(not (:command @selected-command)) (seq commands-responses))))
(seq @commands-responses)))))
(reg-sub :get-chat (reg-sub
(fn [db [_ chat-id]] :is-request-answered?
(get-in db [:chats chat-id])))
(reg-sub :get-response
(fn [db [_ n]]
(let [chat-id (subscribe [:get-current-chat-id])]
(get-in db [:contacts/contacts @chat-id :responses n]))))
(reg-sub :is-request-answered?
:<- [:chat :requests] :<- [:chat :requests]
(fn [requests [_ message-id]] (fn [requests [_ message-id]]
(not= "open" (get-in requests [message-id :status])))) (not= "open" (get-in requests [message-id :status]))))
(reg-sub :unviewed-messages-count (reg-sub
:unviewed-messages-count
(fn [db [_ chat-id]] (fn [db [_ chat-id]]
(get-in db [:unviewed-messages chat-id :count]))) (get-in db [:unviewed-messages chat-id :count])))
(reg-sub :web-view-extra-js (reg-sub
(fn [db] :web-view-extra-js
(let [chat-id (subscribe [:get-current-chat-id])] :<- [:get-current-chat]
(get-in db [:web-view-extra-js @chat-id])))) (fn [current-chat]
(:web-view-extra-js current-chat)))
(reg-sub :all-messages-loaded? (reg-sub
(fn [db] :all-messages-loaded?
(let [chat-id (subscribe [:get-current-chat-id])] :<- [:get-current-chat]
(get-in db [:chats @chat-id :all-loaded?])))) (fn [current-chat]
(:all-loaded? current-chat)))
(reg-sub :photo-path (reg-sub
:photo-path
:<- [:get-contacts] :<- [:get-contacts]
(fn [contacts [_ id]] (fn [contacts [_ id]]
(:photo-path (contacts id)))) (:photo-path (contacts id))))
(reg-sub :get-last-message ;; TODO janherich: this is just bad and horribly ineffecient (always sorting to get last msg +
(fn [db [_ chat-id]] ;; stale `:last-message` in app-db) refactor messages data-model to properly index them ASAP
(let [{:keys [last-message messages]} (get-in db [:chats chat-id])] (reg-sub
:get-last-message
:<- [:chats]
(fn [chats [_ chat-id]]
(let [{:keys [last-message messages]} (get chats chat-id)]
(->> (conj messages last-message) (->> (conj messages last-message)
(sort-by :clock-value >) (sort-by :clock-value >)
(filter :show?) (filter :show?)
(first))))) first))))
(reg-sub :get-message-short-preview-markup (reg-sub
:get-message-short-preview-markup
(fn [db [_ message-id]] (fn [db [_ message-id]]
(get-in db [:message-data :short-preview message-id :markup]))) (get-in db [:message-data :short-preview message-id :markup])))
(reg-sub :get-last-message-short-preview (reg-sub
:get-last-message-short-preview
(fn [db [_ chat-id]] (fn [db [_ chat-id]]
(let [last-message (subscribe [:get-last-message chat-id]) (let [last-message (subscribe [:get-last-message chat-id])
preview (subscribe [:get-message-short-preview-markup (:message-id @last-message)])] preview (subscribe [:get-message-short-preview-markup (:message-id @last-message)])]
(when-let [markup @preview] (when-let [markup @preview]
(commands-utils/generate-hiccup markup))))) (commands-utils/generate-hiccup markup)))))
(reg-sub :get-default-container-area-height (reg-sub
:<- [:chat-ui-props :input-height] :get-default-container-area-height
:<- [:get-current-chat-ui-prop :input-height]
:<- [:get :layout-height] :<- [:get :layout-height]
:<- [:chat-input-margin] :<- [:chat-input-margin]
(fn [[input-height layout-height chat-input-margin]] (fn [[input-height layout-height chat-input-margin]]
(let [bottom (+ input-height chat-input-margin)] (let [bottom (+ input-height chat-input-margin)]
(input-utils/default-container-area-height bottom layout-height)))) (input-utils/default-container-area-height bottom layout-height))))
(reg-sub :get-max-container-area-height (reg-sub
:<- [:chat-ui-props :input-height] :get-max-container-area-height
:<- [:get-current-chat-ui-prop :input-height]
:<- [:get :layout-height] :<- [:get :layout-height]
:<- [:chat-input-margin] :<- [:chat-input-margin]
(fn [[input-height layout-height chat-input-margin]] (fn [[input-height layout-height chat-input-margin]]
(let [bottom (+ input-height chat-input-margin)] (let [bottom (+ input-height chat-input-margin)]
(input-utils/max-container-area-height bottom layout-height)))) (input-utils/max-container-area-height bottom layout-height))))
(reg-sub :chat-animations (reg-sub
:chat-animations
(fn [db [_ key type]] (fn [db [_ key type]]
(let [chat-id (subscribe [:get-current-chat-id])] (let [chat-id (subscribe [:get-current-chat-id])]
(get-in db [:chat-animations @chat-id key type])))) (get-in db [:chat-animations @chat-id key type]))))
(reg-sub :get-chat-last-outgoing-message (reg-sub
(fn [db [_ chat-id]] :get-chat-last-outgoing-message
(->> (:messages (get-in db [:chats chat-id])) :<- [:chats]
(fn [chats [_ chat-id]]
(->> (:messages (get chats chat-id))
(filter :outgoing) (filter :outgoing)
(sort-by :clock-value >) (sort-by :clock-value >)
(first)))) first)))
(reg-sub :get-message-preview-markup (reg-sub
:get-message-preview-markup
(fn [db [_ message-id]] (fn [db [_ message-id]]
(get-in db [:message-data :preview message-id :markup]))) (get-in db [:message-data :preview message-id :markup])))

View File

@ -67,7 +67,7 @@
(list-item [message-status-row contact row])))) (list-item [message-status-row contact row]))))
(defn bottom-info-view [] (defn bottom-info-view []
(let [bottom-info (subscribe [:chat-ui-props :bottom-info]) (let [bottom-info (subscribe [:get-current-chat-ui-prop :bottom-info])
contacts (subscribe [:get-contacts])] contacts (subscribe [:get-contacts])]
(r/create-class (r/create-class
{:display-name "bottom-info-view" {:display-name "bottom-info-view"

View File

@ -54,9 +54,9 @@
(defn expandable-view [{:keys [key height hide-overlay?]} & _] (defn expandable-view [{:keys [key height hide-overlay?]} & _]
(let [anim-value (anim/create-value 0) (let [anim-value (anim/create-value 0)
input-height (subscribe [:chat-ui-props :input-height]) input-height (subscribe [:get-current-chat-ui-prop :input-height])
max-height (subscribe [:get-max-container-area-height]) max-height (subscribe [:get-max-container-area-height])
fullscreen? (subscribe [:chat-ui-props :fullscreen?]) fullscreen? (subscribe [:get-current-chat-ui-prop :fullscreen?])
chat-input-margin (subscribe [:chat-input-margin]) chat-input-margin (subscribe [:chat-input-margin])
to-changed-height (subscribe [:chat-animations key :height]) to-changed-height (subscribe [:chat-animations key :height])
changes-counter (subscribe [:chat-animations key :changes-counter]) changes-counter (subscribe [:chat-animations key :changes-counter])

View File

@ -11,7 +11,7 @@
(defn get-header [type] (defn get-header [type]
(fn [] (fn []
(let [parameter-box (subscribe [:chat-parameter-box]) (let [parameter-box (subscribe [:chat-parameter-box])
result-box (subscribe [:chat-ui-props :result-box]) result-box (subscribe [:get-current-chat-ui-prop :result-box])
chat-id (subscribe [:get-current-chat-id]) chat-id (subscribe [:get-current-chat-id])
command (subscribe [:selected-chat-command]) command (subscribe [:selected-chat-command])
index (subscribe [:current-chat-argument-position])] index (subscribe [:current-chat-argument-position])]

View File

@ -55,8 +55,8 @@
(defn- basic-text-input [_] (defn- basic-text-input [_]
(let [input-text (subscribe [:chat :input-text]) (let [input-text (subscribe [:chat :input-text])
command (subscribe [:selected-chat-command]) command (subscribe [:selected-chat-command])
sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?]) sending-in-progress? (subscribe [:get-current-chat-ui-prop :sending-in-progress?])
input-focused? (subscribe [:chat-ui-props :input-focused?]) input-focused? (subscribe [:get-current-chat-ui-prop :input-focused?])
input-ref (atom nil)] input-ref (atom nil)]
(fn [{:keys [set-layout-height-fn set-container-width-fn height single-line-input?]}] (fn [{:keys [set-layout-height-fn set-container-width-fn height single-line-input?]}]
[text-input [text-input
@ -143,7 +143,7 @@
(let [command (subscribe [:selected-chat-command]) (let [command (subscribe [:selected-chat-command])
arg-pos (subscribe [:current-chat-argument-position]) arg-pos (subscribe [:current-chat-argument-position])
seq-arg-input-text (subscribe [:chat :seq-argument-input-text]) seq-arg-input-text (subscribe [:chat :seq-argument-input-text])
sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])] sending-in-progress? (subscribe [:get-current-chat-ui-prop :sending-in-progress?])]
(fn [{:keys [command-width container-width]}] (fn [{:keys [command-width container-width]}]
(when (get-in @command [:command :sequential-params]) (when (get-in @command [:command :sequential-params])
(let [{:keys [placeholder hidden type]} (get-in @command [:command :params @arg-pos])] (let [{:keys [placeholder hidden type]} (get-in @command [:command :params @arg-pos])]
@ -210,7 +210,7 @@
selected-command [:selected-chat-command] selected-command [:selected-chat-command]
input-text [:chat :input-text] input-text [:chat :input-text]
seq-arg-input-text [:chat :seq-argument-input-text] seq-arg-input-text [:chat :seq-argument-input-text]
result-box [:chat-ui-props :result-box]] result-box [:get-current-chat-ui-prop :result-box]]
(let [single-line-input? (:singleLineInput result-box) (let [single-line-input? (:singleLineInput result-box)
{:keys [hide-send-button sequential-params]} (:command selected-command)] {:keys [hide-send-button sequential-params]} (:command selected-command)]
[view style/input-container [view style/input-container
@ -236,7 +236,7 @@
(defn container [] (defn container []
(let [margin (subscribe [:chat-input-margin]) (let [margin (subscribe [:chat-input-margin])
show-emoji? (subscribe [:chat-ui-props :show-emoji?]) show-emoji? (subscribe [:get-current-chat-ui-prop :show-emoji?])
input-text (subscribe [:chat :input-text]) input-text (subscribe [:chat :input-text])
anim-margin (anim/create-value 10) anim-margin (anim/create-value 10)
container-anim-margin (anim/create-value 16) container-anim-margin (anim/create-value 16)

View File

@ -8,7 +8,7 @@
(defmethod action-view :fullscreen (defmethod action-view :fullscreen
[_] [_]
(let [fullscreen? (re-frame/subscribe [:chat-ui-props :fullscreen?])] (let [fullscreen? (re-frame/subscribe [:get-current-chat-ui-prop :fullscreen?])]
(fn [] (fn []
[react/touchable-highlight [react/touchable-highlight
{:on-press #(re-frame/dispatch [:set-chat-ui-props {:fullscreen? (not @fullscreen?)}])} {:on-press #(re-frame/dispatch [:set-chat-ui-props {:fullscreen? (not @fullscreen?)}])}
@ -20,7 +20,7 @@
(defmethod action-view :web-view-back (defmethod action-view :web-view-back
[_] [_]
(let [result-box (re-frame/subscribe [:chat-ui-props :result-box]) (let [result-box (re-frame/subscribe [:get-current-chat-ui-prop :result-box])
webview (re-frame/subscribe [:get :webview-bridge])] webview (re-frame/subscribe [:get :webview-bridge])]
(fn [] (fn []
[react/touchable-highlight [react/touchable-highlight
@ -33,7 +33,7 @@
(defmethod action-view :web-view-forward (defmethod action-view :web-view-forward
[_] [_]
(let [result-box (re-frame/subscribe [:chat-ui-props :result-box]) (let [result-box (re-frame/subscribe [:get-current-chat-ui-prop :result-box])
webview (re-frame/subscribe [:get :webview-bridge])] webview (re-frame/subscribe [:get :webview-bridge])]
(fn [] (fn []
[react/touchable-highlight [react/touchable-highlight
@ -54,7 +54,7 @@
[react/icon (str "action_" image) style/action-view-icon]]]) [react/icon (str "action_" image) style/action-view-icon]]])
(defn input-actions-view [] (defn input-actions-view []
(let [result-box (re-frame/subscribe [:chat-ui-props :result-box])] (let [result-box (re-frame/subscribe [:get-current-chat-ui-prop :result-box])]
(fn [] (fn []
(let [{:keys [actions]} @result-box] (let [{:keys [actions]} @result-box]
[react/view style/actions-container [react/view style/actions-container

View File

@ -15,8 +15,8 @@
markup]) markup])
(defview result-box-view [] (defview result-box-view []
[{:keys [markup] :as result-box} [:chat-ui-props :result-box]] [markup [:result-box-markup]]
(when result-box (when markup
[expandable-view {:key :result-box [expandable-view {:key :result-box
:draggable? true :draggable? true
:custom-header (box-header/get-header :result-box)} :custom-header (box-header/get-header :result-box)}

View File

@ -19,8 +19,8 @@
(defview validation-messages-view [] (defview validation-messages-view []
(letsubs [chat-input-margin [:chat-input-margin] (letsubs [chat-input-margin [:chat-input-margin]
input-height [:chat-ui-props :input-height] input-height [:get-current-chat-ui-prop :input-height]
messages [:chat-ui-props :validation-messages]] messages [:validation-messages]]
(when messages (when messages
[c/view (style/root (+ input-height chat-input-margin)) [c/view (style/root (+ input-height chat-input-margin))
(if (string? messages) (if (string? messages)

View File

@ -32,7 +32,7 @@
(defview bridged-web-view [{:keys [url]}] (defview bridged-web-view [{:keys [url]}]
[extra-js [:web-view-extra-js] [extra-js [:web-view-extra-js]
rpc-url [:get :rpc-url] rpc-url [:get :rpc-url]
result-box [:chat-ui-props :result-box]] result-box [:get-current-chat-ui-prop :result-box]]
(when url (when url
[webview-bridge [webview-bridge
{:ref #(dispatch [:chat-webview-bridge/set-ref %]) {:ref #(dispatch [:chat-webview-bridge/set-ref %])

View File

@ -246,7 +246,7 @@
(defview group-message-delivery-status [{:keys [message-id group-id message-status user-statuses] :as msg}] (defview group-message-delivery-status [{:keys [message-id group-id message-status user-statuses] :as msg}]
[app-db-message-user-statuses [:get-in [:message-data :user-statuses message-id]] [app-db-message-user-statuses [:get-in [:message-data :user-statuses message-id]]
app-db-message-status-value [:get-in [:message-data :statuses message-id :status]] app-db-message-status-value [:get-in [:message-data :statuses message-id :status]]
chat [:get-chat-by-id group-id] chat [:get-current-chat]
contacts [:get-contacts]] contacts [:get-contacts]]
(let [status (or message-status app-db-message-status-value :sending) (let [status (or message-status app-db-message-status-value :sending)
user-statuses (merge user-statuses app-db-message-user-statuses) user-statuses (merge user-statuses app-db-message-user-statuses)

View File

@ -68,7 +68,7 @@
contacts [:chat :contacts] contacts [:chat :contacts]
public? [:chat :public?] public? [:chat :public?]
public-key [:chat :public-key] public-key [:chat :public-key]
show-actions? [:chat-ui-props :show-actions?] show-actions? [:get-current-chat-ui-prop :show-actions?]
accounts [:get-accounts] accounts [:get-accounts]
contact [:get-in [:contacts/contacts @chat-id]] contact [:get-in [:contacts/contacts @chat-id]]
sync-state [:sync-state] sync-state [:sync-state]

View File

@ -1,10 +1,7 @@
(ns status-im.commands.subs (ns status-im.commands.subs
(:require [re-frame.core :refer [reg-sub]])) (:require [re-frame.core :refer [reg-sub]]))
(reg-sub (reg-sub :get-commands-responses-by-access-scope :access-scope->commands-responses)
:get-commands-responses-by-access-scope
(fn [db _]
(:access-scope->commands-responses db)))
(reg-sub (reg-sub
:get-command :get-command

View File

@ -1,14 +1,20 @@
(ns status-im.ui.screens.accounts.subs (ns status-im.ui.screens.accounts.subs
(:require [re-frame.core :refer [reg-sub subscribe]])) (:require [re-frame.core :refer [reg-sub subscribe]]))
(reg-sub (reg-sub :get-current-public-key
:get-accounts (fn [db]
(fn [db _] (:current-public-key db)))
(get db :accounts/accounts)))
(reg-sub (reg-sub :get-accounts
:get-current-account (fn [db]
:<- [:get :accounts/current-account-id] (:accounts/accounts db)))
(reg-sub :get-current-account-id
(fn [db]
(:accounts/current-account-id db)))
(reg-sub :get-current-account
:<- [:get-current-account-id]
:<- [:get-accounts] :<- [:get-accounts]
(fn [[account-id accounts]] (fn [[account-id accounts]]
(some-> accounts (get account-id)))) (some-> accounts (get account-id))))

View File

@ -154,12 +154,9 @@
(:name (contacts identity)))) (:name (contacts identity))))
(reg-sub :chat-by-id (reg-sub :chat-by-id
(fn [db [_ chat-id]] :<- [:chats]
(get-in db [:chats chat-id]))) (fn [chats [_ chat-id]]
(get chats chat-id)))
(reg-sub :current-chat
(fn [db _]
(get-in db [:chats (:current-chat-id db)])))
(defn chat-contacts [[chat contacts] [_ fn]] (defn chat-contacts [[chat contacts] [_ fn]]
(when chat (when chat
@ -171,7 +168,7 @@
(vals contacts))))) (vals contacts)))))
(reg-sub :contacts-current-chat (reg-sub :contacts-current-chat
:<- [:current-chat] :<- [:get-current-chat]
:<- [:get-contacts] :<- [:get-contacts]
chat-contacts) chat-contacts)
@ -195,7 +192,7 @@
(fn [[_ chat-id] _] (fn [[_ chat-id] _]
[(if chat-id [(if chat-id
(subscribe [:chat-by-id chat-id]) (subscribe [:chat-by-id chat-id])
(subscribe [:current-chat])) (subscribe [:get-current-chat]))
(subscribe [:contacts-by-chat filter chat-id])]) (subscribe [:contacts-by-chat filter chat-id])])
(fn [[chat contacts] [_ chat-id]] (fn [[chat contacts] [_ chat-id]]
(when (and chat (not (:group-chat chat))) (when (and chat (not (:group-chat chat)))

View File

@ -2,18 +2,25 @@
(:require [re-frame.core :refer [reg-sub]] (:require [re-frame.core :refer [reg-sub]]
[status-im.utils.datetime :as time])) [status-im.utils.datetime :as time]))
(defn- calculate-priority [{:keys [chats current-public-key] (reg-sub :get-discoveries :discoveries)
:contacts/keys [contacts]}
(reg-sub :get-current-tag :current-tag)
(reg-sub :get-discover-search-tags :discover-search-tags)
(reg-sub :get-tags :tags)
(defn- calculate-priority [chats current-public-key contacts
{:keys [whisper-id created-at]}] {:keys [whisper-id created-at]}]
(let [contact (get contacts whisper-id) (let [contact (get contacts whisper-id)
chat (get chats whisper-id) chat (get chats whisper-id)
seen-online-recently? (< (- (time/now-ms) (get contact :last-online)) seen-online-recently? (< (- (time/now-ms) (get contact :last-online))
time/hour) time/hour)
me? (= current-public-key whisper-id)] me? (= current-public-key whisper-id)]
(+ created-at ;; message is newer => priority is higher (+ created-at ; message is newer => priority is higher
(if (or me? contact) time/day 0) ;; user exists in contact list => increase priority (if (or me? contact) time/day 0) ; user exists in contact list => increase priority
(if (or me? chat) time/day 0) ;; chat with this user exists => increase priority (if (or me? chat) time/day 0) ; chat with this user exists => increase priority
(if (or me? seen-online-recently?) time/hour 0)))) ;; the user was online recently => increase priority (if (or me? seen-online-recently?) time/hour 0)))) ; the user was online recently => increase priority
(defn- get-discoveries-by-tags [discoveries current-tag tags] (defn- get-discoveries-by-tags [discoveries current-tag tags]
@ -24,45 +31,59 @@
tags') tags')
(vals discoveries)))) (vals discoveries))))
(reg-sub :get-popular-discoveries (reg-sub
(fn [db [_ limit tags]] :get-popular-discoveries
(let [discoveries (:discoveries db) :<- [:get-discoveries]
current-tag (:current-tag db) :<- [:get-current-tag]
search-tags (:discover-search-tags db)] :<- [:get-discover-search-tags]
(let [discoveries (->> (get-discoveries-by-tags discoveries current-tag (or tags search-tags)) :<- [:chats]
(map #(assoc % :priority (calculate-priority db %))) :<- [:get-contacts]
:<- [:get-current-public-key]
(fn [[discoveries current-tag discover-search-tags chats contacts public-key]
[_ limit tags]]
(let [discoveries (->> (get-discoveries-by-tags discoveries
current-tag
(or tags discover-search-tags))
(map #(assoc % :priority (calculate-priority chats public-key contacts %)))
(sort-by :priority >))] (sort-by :priority >))]
{:discoveries (take limit discoveries) {:discoveries (take limit discoveries)
:total (count discoveries)})))) :total (count discoveries)})))
(reg-sub :get-top-discovery-per-tag (reg-sub
(fn [{:keys [discoveries tags]} [_ limit]] :get-top-discovery-per-tag
:<- [:get-discoveries]
:<- [:get-tags]
(fn [[discoveries tags] [_ limit]]
(let [tag-names (map :name (take limit tags))] (let [tag-names (map :name (take limit tags))]
(for [tag tag-names] (for [tag tag-names]
(let [results (get-discoveries-by-tags discoveries tag nil)] (let [results (get-discoveries-by-tags discoveries tag nil)]
[tag {:discovery (first results) [tag {:discovery (first results)
:total (count results)}]))))) :total (count results)}])))))
(reg-sub :get-recent-discoveries (reg-sub
(fn [db] :get-recent-discoveries
(sort-by :created-at > (vals (:discoveries db))))) :<- [:get-discoveries]
(fn [discoveries]
(sort-by :created-at > (vals discoveries))))
(reg-sub :get-popular-tags (reg-sub
(fn [db [_ limit]] :get-popular-tags
(take limit (:tags db)))) :<- [:get-tags]
(fn [tags [_ limit]]
(take limit tags)))
(reg-sub :get-discover-search-results (reg-sub
(fn [db] :get-discover-search-results
(let [discoveries (:discoveries db) :<- [:get-discoveries]
current-tag (:current-tag db) :<- [:get-current-tag]
tags (:discover-search-tags db)] :<- [:get-discover-search-tags]
(get-discoveries-by-tags discoveries current-tag tags)))) (fn [[discoveries current-tag discover-search-tags]]
(get-discoveries-by-tags discoveries current-tag discover-search-tags)))
(reg-sub :get-all-dapps (reg-sub
(fn [db] :get-all-dapps
(let [dapp? (->> (get-in db [:group/contact-groups "dapps" :contacts]) :<- [:get-contact-groups]
(map :identity) :<- [:get-contacts]
set)] (fn [[groups contacts]]
(->> (:contacts/contacts db) (let [dapp-ids (into #{} (map :identity) (get-in groups ["dapps" :contacts]))]
(filter #(-> % key dapp?)) (select-keys contacts dapp-ids))))
(into {})))))

View File

@ -65,28 +65,40 @@
(is (= "/send 1.0 \"John Doe\"" (input/join-command-args ["/send" "1.0" "John Doe"])))) (is (= "/send 1.0 \"John Doe\"" (input/join-command-args ["/send" "1.0" "John Doe"]))))
(deftest selected-chat-command (deftest selected-chat-command
(is (= (input/selected-chat-command fake-db "test1" "/global-command1") (is (= (input/selected-chat-command (-> fake-db
(assoc :current-chat-id "test1")
(assoc-in [:chats "test1" :input-text] "/global-command1")))
{:command {:name "global-command1" {:command {:name "global-command1"
:ref ["0x1" :command 0 "global-command1"]} :ref ["0x1" :command 0 "global-command1"]}
:metadata nil :metadata nil
:args ["arg1" "arg2"]})) :args ["arg1" "arg2"]}))
(is (= (input/selected-chat-command fake-db "test2" "/command2") (is (= (input/selected-chat-command (-> fake-db
(assoc :current-chat-id "test2")
(assoc-in [:chats "test2" :input-text] "/command2")))
{:command {:name "command2" {:command {:name "command2"
:ref ["0x1" :command 4 "command2"]} :ref ["0x1" :command 4 "command2"]}
:metadata nil :metadata nil
:args []})) :args []}))
(is (nil? (input/selected-chat-command fake-db "test1" "/command3"))) (is (nil? (input/selected-chat-command (-> fake-db
(is (= (input/selected-chat-command fake-db "test1" "/command2") (assoc :current-chat-id "test1")
(assoc-in [:chats "test1" :input-text] "/command3")))))
(is (= (input/selected-chat-command (-> fake-db
(assoc :current-chat-id "test1")
(assoc-in [:chats "test1" :input-text] "/command2")))
{:command {:name "command2" {:command {:name "command2"
:ref ["0x1" :command 2 "command2"]} :ref ["0x1" :command 2 "command2"]}
:metadata nil :metadata nil
:args ["arg1" "arg2"]})) :args ["arg1" "arg2"]}))
(is (= (input/selected-chat-command fake-db "test2" "/response1 arg1") (is (= (input/selected-chat-command (-> fake-db
(assoc :current-chat-id "test2")
(assoc-in [:chats "test2" :input-text] "/response1 arg1")))
{:command {:name "response1" {:command {:name "response1"
:ref ["0x2" :response 4 "response1"]} :ref ["0x2" :response 4 "response1"]}
:metadata nil :metadata nil
:args ["arg1"]})) :args ["arg1"]}))
(is (= (input/selected-chat-command fake-db "test4" "/command2 arg1") (is (= (input/selected-chat-command (-> fake-db
(assoc :current-chat-id "test4")
(assoc-in [:chats "test4" :input-text] "/command2 arg1")))
{:command {:name "command2" {:command {:name "command2"
:ref ["0x1" :command 4 "command2"]} :ref ["0x1" :command 4 "command2"]}
:metadata {:meta-k "meta-v"} :metadata {:meta-k "meta-v"}