[Fixes: #10801] Send chat messages in order

Chat messages are now sent in order using a different endpoint
`sendChatMessages`.
Text should always be displayed after images.

This is not implementing a Caption field, that would require either a
protocol change or leverage the `text` in the message.
It applies for both normal chats and timelines.

Move also all inputs under `chat/inputs` so we avoid re-renders as
`chats` has changed.

Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Andrea Maria Piana 2020-12-01 15:11:15 +01:00
parent fd5be21207
commit f04042c643
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
10 changed files with 91 additions and 75 deletions

View File

@ -99,7 +99,7 @@
{:events [:chat.ui/image-captured]} {:events [:chat.ui/image-captured]}
[{:keys [db]} uri] [{:keys [db]} uri]
(let [current-chat-id (:current-chat-id db) (let [current-chat-id (:current-chat-id db)
images (get-in db [:chats current-chat-id :metadata :sending-image])] images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
(when (and (< (count images) config/max-images-batch) (when (and (< (count images) config/max-images-batch)
(not (get images uri))) (not (get images uri)))
{::image-selected uri}))) {::image-selected uri})))
@ -118,7 +118,7 @@
{:events [:chat.ui/clear-sending-images]} {:events [:chat.ui/clear-sending-images]}
[{:keys [db]}] [{:keys [db]}]
(let [current-chat-id (:current-chat-id db)] (let [current-chat-id (:current-chat-id db)]
{:db (update-in db [:chats current-chat-id :metadata] assoc :sending-image {})})) {:db (update-in db [:chat/inputs current-chat-id :metadata] assoc :sending-image {})}))
(fx/defn cancel-sending-image (fx/defn cancel-sending-image
{:events [:chat.ui/cancel-sending-image]} {:events [:chat.ui/cancel-sending-image]}
@ -129,19 +129,19 @@
{:events [:chat.ui/image-selected]} {:events [:chat.ui/image-selected]}
[{:keys [db]} original uri] [{:keys [db]} original uri]
(let [current-chat-id (:current-chat-id db)] (let [current-chat-id (:current-chat-id db)]
{:db (update-in db [:chats current-chat-id :metadata :sending-image original] merge {:uri uri})})) {:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image original] merge {:uri uri})}))
(fx/defn image-unselected (fx/defn image-unselected
{:events [:chat.ui/image-unselected]} {:events [:chat.ui/image-unselected]}
[{:keys [db]} original] [{:keys [db]} original]
(let [current-chat-id (:current-chat-id db)] (let [current-chat-id (:current-chat-id db)]
{:db (update-in db [:chats current-chat-id :metadata :sending-image] dissoc original)})) {:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image] dissoc original)}))
(fx/defn chat-open-image-picker (fx/defn chat-open-image-picker
{:events [:chat.ui/open-image-picker]} {:events [:chat.ui/open-image-picker]}
[{:keys [db]}] [{:keys [db]}]
(let [current-chat-id (:current-chat-id db) (let [current-chat-id (:current-chat-id db)
images (get-in db [:chats current-chat-id :metadata :sending-image])] images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
(when (< (count images) config/max-images-batch) (when (< (count images) config/max-images-batch)
{::chat-open-image-picker nil}))) {::chat-open-image-picker nil})))
@ -149,7 +149,7 @@
{:events [:chat.ui/show-image-picker-camera]} {:events [:chat.ui/show-image-picker-camera]}
[{:keys [db]}] [{:keys [db]}]
(let [current-chat-id (:current-chat-id db) (let [current-chat-id (:current-chat-id db)
images (get-in db [:chats current-chat-id :metadata :sending-image])] images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
(when (< (count images) config/max-images-batch) (when (< (count images) config/max-images-batch)
{::chat-open-image-picker-camera nil}))) {::chat-open-image-picker-camera nil})))
@ -157,9 +157,9 @@
{:events [:chat.ui/camera-roll-pick]} {:events [:chat.ui/camera-roll-pick]}
[{:keys [db]} uri] [{:keys [db]} uri]
(let [current-chat-id (:current-chat-id db) (let [current-chat-id (:current-chat-id db)
images (get-in db [:chats current-chat-id :metadata :sending-image])] images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
(if (get-in db [:chats current-chat-id :timeline?]) (if (get-in db [:chats current-chat-id :timeline?])
{:db (assoc-in db [:chats current-chat-id :metadata :sending-image] {}) {:db (assoc-in db [:chat/inputs current-chat-id :metadata :sending-image] {})
::image-selected uri} ::image-selected uri}
(when (and (< (count images) config/max-images-batch) (when (and (< (count images) config/max-images-batch)
(not (get images uri))) (not (get images uri)))

View File

@ -49,7 +49,7 @@
;; keyboard's cursor position to be changed before the next input. ;; keyboard's cursor position to be changed before the next input.
(mentions/reset-text-input-cursor text-input-ref cursor) (mentions/reset-text-input-cursor text-input-ref cursor)
;; NOTE(roman): on-text-input event is not dispatched when we change input ;; NOTE(roman): on-text-input event is not dispatched when we change input
;; programmatically, so we have to call `on-text-input` manually ;; programmatically, so we have to call `on-text-input` manually
(mentions/on-text-input (mentions/on-text-input
(let [match-len (count match) (let [match-len (count match)
searched-text-len (count searched-text) searched-text-len (count searched-text)
@ -99,51 +99,60 @@
(let [current-chat-id (:current-chat-id db)] (let [current-chat-id (:current-chat-id db)]
(fx/merge cofx (fx/merge cofx
{:db (-> db {:db (-> db
(assoc-in [:chats current-chat-id :metadata :responding-to-message] (assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message]
message) message)
(update-in [:chats current-chat-id :metadata] (update-in [:chat/inputs current-chat-id :metadata]
dissoc :sending-image))}))) dissoc :sending-image))})))
(fx/defn cancel-message-reply (fx/defn cancel-message-reply
"Cancels stage message reply" "Cancels stage message reply"
[{:keys [db]}] [{:keys [db]}]
(let [current-chat-id (:current-chat-id db)] (let [current-chat-id (:current-chat-id db)]
{:db (assoc-in db [:chats current-chat-id :metadata :responding-to-message] nil)})) {:db (assoc-in db [:chat/inputs current-chat-id :metadata :responding-to-message] nil)}))
(fx/defn send-plain-text-message (defn build-text-message
"when not empty, proceed by sending text message" [{:keys [db]} input-text current-chat-id]
[{:keys [db] :as cofx} input-text current-chat-id]
(when-not (string/blank? input-text) (when-not (string/blank? input-text)
(let [{:keys [message-id]} (let [{:keys [message-id]}
(get-in db [:chats current-chat-id :metadata :responding-to-message]) (get-in db [:chat/inputs current-chat-id :metadata :responding-to-message])
preferred-name (get-in db [:multiaccount :preferred-name]) preferred-name (get-in db [:multiaccount :preferred-name])
emoji? (message-content/emoji-only-content? {:text input-text emoji? (message-content/emoji-only-content? {:text input-text
:response-to message-id})] :response-to message-id})]
(fx/merge cofx {:chat-id current-chat-id
{:db (assoc-in db [:chats current-chat-id :metadata :responding-to-message] nil)} :content-type (if emoji?
(chat.message/send-message {:chat-id current-chat-id constants/content-type-emoji
:content-type (if emoji? constants/content-type-text)
constants/content-type-emoji :text input-text
constants/content-type-text) :response-to message-id
:text input-text :ens-name preferred-name})))
:response-to message-id
:ens-name preferred-name})
(set-chat-input-text nil)
(process-cooldown)))))
(fx/defn send-image (defn build-image-messages
[{{:keys [current-chat-id] :as db} :db :as cofx} chat-id] [{{:keys [current-chat-id] :as db} :db} chat-id]
(let [images (get-in db [:chats current-chat-id :metadata :sending-image])] (let [images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
(mapv (fn [[_ {:keys [uri]}]]
{:chat-id chat-id
:content-type constants/content-type-image
:image-path (utils/safe-replace uri #"file://" "")
:text (i18n/label :t/update-to-see-image)})
images)))
(fx/defn clean-input [{:keys [db] :as cofx}]
(let [current-chat-id (:current-chat-id db)]
(fx/merge cofx (fx/merge cofx
;; NOTE(Ferossgp): Ideally here and for all other types of message we should dissoc on success only {:db (-> db
{:db (update-in db [:chats current-chat-id :metadata] dissoc :sending-image)} (assoc-in [:chat/inputs current-chat-id :metadata :sending-image] nil)
(chat.message/send-messages (assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil))}
(map (fn [[_ {:keys [uri]}]] (set-chat-input-text nil))))
{:chat-id chat-id
:content-type constants/content-type-image (fx/defn send-messages [{:keys [db] :as cofx} input-text current-chat-id]
:image-path (utils/safe-replace uri #"file://" "") (let [image-messages (build-image-messages cofx current-chat-id)
:text (i18n/label :t/update-to-see-image)}) text-message (build-text-message cofx input-text current-chat-id)
images))))) messages (keep identity (conj image-messages text-message))]
(when (seq messages)
(fx/merge cofx
(clean-input cofx)
(process-cooldown)
(chat.message/send-messages messages)))))
(fx/defn send-my-status-message (fx/defn send-my-status-message
"when not empty, proceed by sending text message with public key topic" "when not empty, proceed by sending text message with public key topic"
@ -151,9 +160,7 @@
[{{:keys [current-chat-id] :as db} :db :as cofx}] [{{:keys [current-chat-id] :as db} :db :as cofx}]
(let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id]) (let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id])
chat-id (chat/profile-chat-topic (get-in db [:multiaccount :public-key]))] chat-id (chat/profile-chat-topic (get-in db [:multiaccount :public-key]))]
(fx/merge cofx (send-messages cofx input-text chat-id)))
(send-image chat-id)
(send-plain-text-message input-text chat-id))))
(fx/defn send-audio-message (fx/defn send-audio-message
[cofx audio-path duration current-chat-id] [cofx audio-path duration current-chat-id]
@ -179,7 +186,6 @@
(let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id]) (let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id])
input-text-with-mentions (mentions/check-mentions cofx input-text)] input-text-with-mentions (mentions/check-mentions cofx input-text)]
(fx/merge cofx (fx/merge cofx
(send-image current-chat-id) (send-messages input-text-with-mentions current-chat-id)
(send-plain-text-message input-text-with-mentions current-chat-id)
(mentions/clear-mentions) (mentions/clear-mentions)
(mentions/clear-cursor)))) (mentions/clear-cursor))))

View File

@ -43,16 +43,17 @@
(let [last-element-clock-value (:clock-value (.-item last-element)) (let [last-element-clock-value (:clock-value (.-item last-element))
chat-id (:chat-id (.-item last-element))] chat-id (:chat-id (.-item last-element))]
(when (and last-element-clock-value (when (and last-element-clock-value
(get-in db [:chats chat-id :messages-initialized?])) (get-in db [:pagination-info chat-id :messages-initialized?]))
(let [new-messages (reduce-kv (fn [acc message-id {:keys [clock-value] :as v}] (let [new-messages (reduce-kv (fn [acc message-id {:keys [clock-value] :as v}]
(if (<= last-element-clock-value clock-value) (if (<= last-element-clock-value clock-value)
(assoc acc message-id v) (assoc acc message-id v)
acc)) acc))
{} {}
(get-in db [:chats chat-id :messages]))] (get-in db [:messages chat-id]))]
{:db (-> db {:db (-> db
(assoc-in [:messages chat-id] new-messages) (assoc-in [:messages chat-id] new-messages)
(assoc-in [:pagination-info chat-id] {:all-loaded? false (assoc-in [:pagination-info chat-id] {:all-loaded? false
:messages-initialized? true
:cursor (clock-value->cursor last-element-clock-value)}) :cursor (clock-value->cursor last-element-clock-value)})
(assoc-in [:message-lists chat-id] (message-list/add-many nil (vals new-messages))))})))))) (assoc-in [:message-lists chat-id] (message-list/add-many nil (vals new-messages))))}))))))

View File

@ -505,7 +505,7 @@
[:chats chat-id :mentions] [:chats chat-id :mentions]
assoc assoc
:at-idxs new-at-idxs) :at-idxs new-at-idxs)
(assoc-in [:chats/input-with-mentions chat-id] calculated-input))})) (assoc-in [:chat/inputs-with-mentions chat-id] calculated-input))}))
(fx/defn calculate-suggestions (fx/defn calculate-suggestions
{:events [::calculate-suggestions]} {:events [::calculate-suggestions]}
@ -521,7 +521,7 @@
{:db (-> db {:db (-> db
(assoc-in [:chats/mention-suggestions chat-id] nil) (assoc-in [:chats/mention-suggestions chat-id] nil)
(assoc-in [:chats chat-id :mentions :at-idxs] nil) (assoc-in [:chats chat-id :mentions :at-idxs] nil)
(assoc-in [:chats/input-with-mentions chat-id] [[:text text]]))} (assoc-in [:chat/inputs-with-mentions chat-id] [[:text text]]))}
(let [new-at-idxs (check-idx-for-mentions (let [new-at-idxs (check-idx-for-mentions
text text
at-idxs at-idxs
@ -551,7 +551,7 @@
:at-sign-idx at-sign-idx :at-sign-idx at-sign-idx
:at-idxs new-at-idxs :at-idxs new-at-idxs
:mention-end end) :mention-end end)
(assoc-in [:chats/input-with-mentions chat-id] calculated-input) (assoc-in [:chat/inputs-with-mentions chat-id] calculated-input)
(assoc-in [:chats/mention-suggestions chat-id] mentions))})))) (assoc-in [:chats/mention-suggestions chat-id] mentions))}))))
(defn new-input-text-with-mention (defn new-input-text-with-mention
@ -586,7 +586,7 @@
cofx cofx
{:db (-> db {:db (-> db
(update-in [:chats chat-id] dissoc :mentions) (update-in [:chats chat-id] dissoc :mentions)
(update :chats/input-with-mentions dissoc chat-id))} (update :chat/inputs-with-mentions dissoc chat-id))}
(clear-suggestions)))) (clear-suggestions))))
(fx/defn clear-cursor (fx/defn clear-cursor

View File

@ -164,7 +164,7 @@
(fx/merge cofx (fx/merge cofx
;;If its a profile updates we want to add this message to the timeline as well ;;If its a profile updates we want to add this message to the timeline as well
#(when (get-in cofx [:db :chats chat-id :profile-public-key]) #(when (get-in cofx [:db :chats chat-id :profile-public-key])
{:dispatch [::receive-one (assoc message :chat-id chat-model/timeline-chat-id)]}) {:dispatch-n [[::receive-one (assoc message :chat-id chat-model/timeline-chat-id)]]})
#(let [message-with-chat-id (assoc message :chat-id chat-id)] #(let [message-with-chat-id (assoc message :chat-id chat-id)]
(when-not (earlier-than-deleted-at? cofx message-with-chat-id) (when-not (earlier-than-deleted-at? cofx message-with-chat-id)
(if (message-loaded? cofx message-with-chat-id) (if (message-loaded? cofx message-with-chat-id)

View File

@ -45,6 +45,7 @@
"wakuext_enableInstallation" {} "wakuext_enableInstallation" {}
"wakuext_disableInstallation" {} "wakuext_disableInstallation" {}
"wakuext_sendChatMessage" {} "wakuext_sendChatMessage" {}
"wakuext_sendChatMessages" {}
"wakuext_confirmJoiningGroup" {} "wakuext_confirmJoiningGroup" {}
"wakuext_addAdminsToGroupChat" {} "wakuext_addAdminsToGroupChat" {}
"wakuext_addMembersToGroupChat" {} "wakuext_addMembersToGroupChat" {}

View File

@ -124,7 +124,7 @@
(reg-root-key-sub :group-chat/invitations :group-chat/invitations) (reg-root-key-sub :group-chat/invitations :group-chat/invitations)
(reg-root-key-sub :chats/mention-suggestions :chats/mention-suggestions) (reg-root-key-sub :chats/mention-suggestions :chats/mention-suggestions)
(reg-root-key-sub :chats/cursor :chats/cursor) (reg-root-key-sub :chats/cursor :chats/cursor)
(reg-root-key-sub :chats/input-with-mentions :chats/input-with-mentions) (reg-root-key-sub :chat/inputs-with-mentions :chat/inputs-with-mentions)
(reg-root-key-sub :inactive-chat-id :inactive-chat-id) (reg-root-key-sub :inactive-chat-id :inactive-chat-id)
;;browser ;;browser
(reg-root-key-sub :browsers :browser/browsers) (reg-root-key-sub :browsers :browser/browsers)
@ -651,11 +651,17 @@
(get chats current-chat-id))) (get chats current-chat-id)))
(re-frame/reg-sub (re-frame/reg-sub
:chats/current-chat-input-text :chats/current-chat-inputs
:<- [:chats/current-chat-id] :<- [:chats/current-chat-id]
:<- [:chat/inputs] :<- [:chat/inputs]
(fn [[chat-id inputs]] (fn [[chat-id inputs]]
(get-in inputs [chat-id :input-text]))) (get inputs chat-id)))
(re-frame/reg-sub
:chats/current-chat-input-text
:<- [:chats/current-chat-inputs]
(fn [input]
(:input-text input)))
(re-frame/reg-sub (re-frame/reg-sub
:chats/current-chat-membership :chats/current-chat-membership
@ -835,15 +841,15 @@
(re-frame/reg-sub (re-frame/reg-sub
:chats/reply-message :chats/reply-message
:<- [:chats/current-chat] :<- [:chats/current-chat-inputs]
(fn [{:keys [metadata]}] (fn [{:keys [metadata]}]
(:responding-to-message metadata))) (:responding-to-message metadata)))
(re-frame/reg-sub (re-frame/reg-sub
:chats/sending-image :chats/sending-image
:<- [:chats/current-raw-chat] :<- [:chats/current-chat-inputs]
(fn [{:keys [metadata]}] (fn [{:keys [metadata]}]
(get-in metadata [:sending-image]))) (:sending-image metadata)))
(re-frame/reg-sub (re-frame/reg-sub
:public-chat.new/topic-error-message :public-chat.new/topic-error-message
@ -977,7 +983,7 @@
(re-frame/reg-sub (re-frame/reg-sub
:chat/input-with-mentions :chat/input-with-mentions
:<- [:chats/current-chat-id] :<- [:chats/current-chat-id]
:<- [:chats/input-with-mentions] :<- [:chat/inputs-with-mentions]
(fn [[chat-id cursor]] (fn [[chat-id cursor]]
(get cursor chat-id))) (get cursor chat-id)))

View File

@ -14,22 +14,23 @@
audio-duration-ms audio-duration-ms
sticker sticker
content-type]}] content-type]}]
{:method (json-rpc/call-ext-method "sendChatMessage") {:chatId chat-id
:params [{:chatId chat-id :text text
:text text :responseTo response-to
:responseTo response-to :ensName ens-name
:ensName ens-name :imagePath image-path
:imagePath image-path :audioPath audio-path
:audioPath audio-path :audioDurationMs audio-duration-ms
:audioDurationMs audio-duration-ms :sticker sticker
:sticker sticker :contentType content-type})
:contentType content-type}]
:on-success
#(re-frame/dispatch [:transport/message-sent % 1])
:on-failure #(log/error "failed to send a message" %)})
(fx/defn send-chat-messages [cofx messages] (fx/defn send-chat-messages [cofx messages]
{::json-rpc/call (mapv build-message messages)}) {::json-rpc/call
[{:method (json-rpc/call-ext-method "sendChatMessages")
:params [(mapv build-message messages)]
:on-success
#(re-frame/dispatch [:transport/message-sent % 1])
:on-failure #(log/error "failed to send a message" %)}]})
(fx/defn send-reaction [cofx {:keys [message-id chat-id emoji-id]}] (fx/defn send-reaction [cofx {:keys [message-id chat-id emoji-id]}]
{::json-rpc/call [{:method (json-rpc/call-ext-method {::json-rpc/call [{:method (json-rpc/call-ext-method

View File

@ -13,6 +13,7 @@
(def ^:private mergeable-keys (def ^:private mergeable-keys
#{:filters/load-filters #{:filters/load-filters
:pairing/set-installation-metadata :pairing/set-installation-metadata
:dispatch-n
:status-im.ens.core/verify-names :status-im.ens.core/verify-names
:shh/send-direct-message :shh/send-direct-message
:shh/remove-filter :shh/remove-filter

View File

@ -2,7 +2,7 @@
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead", "_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
"owner": "status-im", "owner": "status-im",
"repo": "status-go", "repo": "status-go",
"version": "v0.64.2", "version": "v0.64.3",
"commit-sha1": "0304b3fa46a6a222b0e346d4a2d1472b965eb78c", "commit-sha1": "14f4c40404d4d3b1a4e9f739b156f8c8b2eeded6",
"src-sha256": "0jmwvapv1k3g45gv5xzwshsf2b96b897xs5wyp69sdz9p2nnl18z" "src-sha256": "0h1mbn4xb4r7fwniyjgi3hj5bwj8kyj8jfi47l33rg8i6mnvd3w9"
} }