From f04042c643117ba5977982f20237ccdcc21669fa Mon Sep 17 00:00:00 2001 From: Andrea Maria Piana Date: Tue, 1 Dec 2020 15:11:15 +0100 Subject: [PATCH] [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 --- src/status_im/chat/models/images.cljs | 16 ++-- src/status_im/chat/models/input.cljs | 78 ++++++++++--------- src/status_im/chat/models/loading.cljs | 5 +- src/status_im/chat/models/mentions.cljs | 8 +- src/status_im/chat/models/message.cljs | 2 +- src/status_im/ethereum/json_rpc.cljs | 1 + src/status_im/subs.cljs | 20 +++-- src/status_im/transport/message/protocol.cljs | 29 +++---- src/status_im/utils/fx.cljs | 1 + status-go-version.json | 6 +- 10 files changed, 91 insertions(+), 75 deletions(-) diff --git a/src/status_im/chat/models/images.cljs b/src/status_im/chat/models/images.cljs index 05b39934f7..9a5a14e3bf 100644 --- a/src/status_im/chat/models/images.cljs +++ b/src/status_im/chat/models/images.cljs @@ -99,7 +99,7 @@ {:events [:chat.ui/image-captured]} [{:keys [db]} uri] (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) (not (get images uri))) {::image-selected uri}))) @@ -118,7 +118,7 @@ {:events [:chat.ui/clear-sending-images]} [{:keys [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 {:events [:chat.ui/cancel-sending-image]} @@ -129,19 +129,19 @@ {:events [:chat.ui/image-selected]} [{:keys [db]} original uri] (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 {:events [:chat.ui/image-unselected]} [{:keys [db]} original] (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 {:events [:chat.ui/open-image-picker]} [{:keys [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) {::chat-open-image-picker nil}))) @@ -149,7 +149,7 @@ {:events [:chat.ui/show-image-picker-camera]} [{:keys [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) {::chat-open-image-picker-camera nil}))) @@ -157,9 +157,9 @@ {:events [:chat.ui/camera-roll-pick]} [{:keys [db]} uri] (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?]) - {: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} (when (and (< (count images) config/max-images-batch) (not (get images uri))) diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs index 29e2494c12..89695132f8 100644 --- a/src/status_im/chat/models/input.cljs +++ b/src/status_im/chat/models/input.cljs @@ -49,7 +49,7 @@ ;; keyboard's cursor position to be changed before the next input. (mentions/reset-text-input-cursor text-input-ref cursor) ;; 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 (let [match-len (count match) searched-text-len (count searched-text) @@ -99,51 +99,60 @@ (let [current-chat-id (:current-chat-id db)] (fx/merge cofx {:db (-> db - (assoc-in [:chats current-chat-id :metadata :responding-to-message] + (assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] message) - (update-in [:chats current-chat-id :metadata] + (update-in [:chat/inputs current-chat-id :metadata] dissoc :sending-image))}))) (fx/defn cancel-message-reply "Cancels stage message reply" [{:keys [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 - "when not empty, proceed by sending text message" - [{:keys [db] :as cofx} input-text current-chat-id] +(defn build-text-message + [{:keys [db]} input-text current-chat-id] (when-not (string/blank? input-text) (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]) emoji? (message-content/emoji-only-content? {:text input-text :response-to message-id})] - (fx/merge cofx - {:db (assoc-in db [:chats current-chat-id :metadata :responding-to-message] nil)} - (chat.message/send-message {:chat-id current-chat-id - :content-type (if emoji? - constants/content-type-emoji - constants/content-type-text) - :text input-text - :response-to message-id - :ens-name preferred-name}) - (set-chat-input-text nil) - (process-cooldown))))) + {:chat-id current-chat-id + :content-type (if emoji? + constants/content-type-emoji + constants/content-type-text) + :text input-text + :response-to message-id + :ens-name preferred-name}))) -(fx/defn send-image - [{{:keys [current-chat-id] :as db} :db :as cofx} chat-id] - (let [images (get-in db [:chats current-chat-id :metadata :sending-image])] +(defn build-image-messages + [{{:keys [current-chat-id] :as db} :db} chat-id] + (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 - ;; NOTE(Ferossgp): Ideally here and for all other types of message we should dissoc on success only - {:db (update-in db [:chats current-chat-id :metadata] dissoc :sending-image)} - (chat.message/send-messages - (map (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))))) + {:db (-> db + (assoc-in [:chat/inputs current-chat-id :metadata :sending-image] nil) + (assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil))} + (set-chat-input-text nil)))) + +(fx/defn send-messages [{:keys [db] :as cofx} input-text current-chat-id] + (let [image-messages (build-image-messages cofx current-chat-id) + text-message (build-text-message cofx input-text current-chat-id) + 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 "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}] (let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id]) chat-id (chat/profile-chat-topic (get-in db [:multiaccount :public-key]))] - (fx/merge cofx - (send-image chat-id) - (send-plain-text-message input-text chat-id)))) + (send-messages cofx input-text chat-id))) (fx/defn send-audio-message [cofx audio-path duration current-chat-id] @@ -179,7 +186,6 @@ (let [{:keys [input-text]} (get-in db [:chat/inputs current-chat-id]) input-text-with-mentions (mentions/check-mentions cofx input-text)] (fx/merge cofx - (send-image current-chat-id) - (send-plain-text-message input-text-with-mentions current-chat-id) + (send-messages input-text-with-mentions current-chat-id) (mentions/clear-mentions) (mentions/clear-cursor)))) diff --git a/src/status_im/chat/models/loading.cljs b/src/status_im/chat/models/loading.cljs index f0e9c3d033..d822a81285 100644 --- a/src/status_im/chat/models/loading.cljs +++ b/src/status_im/chat/models/loading.cljs @@ -43,16 +43,17 @@ (let [last-element-clock-value (:clock-value (.-item last-element)) chat-id (:chat-id (.-item last-element))] (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}] (if (<= last-element-clock-value clock-value) (assoc acc message-id v) acc)) {} - (get-in db [:chats chat-id :messages]))] + (get-in db [:messages chat-id]))] {:db (-> db (assoc-in [:messages chat-id] new-messages) (assoc-in [:pagination-info chat-id] {:all-loaded? false + :messages-initialized? true :cursor (clock-value->cursor last-element-clock-value)}) (assoc-in [:message-lists chat-id] (message-list/add-many nil (vals new-messages))))})))))) diff --git a/src/status_im/chat/models/mentions.cljs b/src/status_im/chat/models/mentions.cljs index 704df193df..8603c01120 100644 --- a/src/status_im/chat/models/mentions.cljs +++ b/src/status_im/chat/models/mentions.cljs @@ -505,7 +505,7 @@ [:chats chat-id :mentions] assoc :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 {:events [::calculate-suggestions]} @@ -521,7 +521,7 @@ {:db (-> db (assoc-in [:chats/mention-suggestions chat-id] 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 text at-idxs @@ -551,7 +551,7 @@ :at-sign-idx at-sign-idx :at-idxs new-at-idxs :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))})))) (defn new-input-text-with-mention @@ -586,7 +586,7 @@ cofx {:db (-> db (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)))) (fx/defn clear-cursor diff --git a/src/status_im/chat/models/message.cljs b/src/status_im/chat/models/message.cljs index c96ef4d5dc..10c2cbbb53 100644 --- a/src/status_im/chat/models/message.cljs +++ b/src/status_im/chat/models/message.cljs @@ -164,7 +164,7 @@ (fx/merge cofx ;;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]) - {: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)] (when-not (earlier-than-deleted-at? cofx message-with-chat-id) (if (message-loaded? cofx message-with-chat-id) diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index 29a00205a0..7a0340bfed 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -45,6 +45,7 @@ "wakuext_enableInstallation" {} "wakuext_disableInstallation" {} "wakuext_sendChatMessage" {} + "wakuext_sendChatMessages" {} "wakuext_confirmJoiningGroup" {} "wakuext_addAdminsToGroupChat" {} "wakuext_addMembersToGroupChat" {} diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index abab1442f5..e1aedb8151 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -124,7 +124,7 @@ (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/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) ;;browser (reg-root-key-sub :browsers :browser/browsers) @@ -651,11 +651,17 @@ (get chats current-chat-id))) (re-frame/reg-sub - :chats/current-chat-input-text + :chats/current-chat-inputs :<- [:chats/current-chat-id] :<- [:chat/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 :chats/current-chat-membership @@ -835,15 +841,15 @@ (re-frame/reg-sub :chats/reply-message - :<- [:chats/current-chat] + :<- [:chats/current-chat-inputs] (fn [{:keys [metadata]}] (:responding-to-message metadata))) (re-frame/reg-sub :chats/sending-image - :<- [:chats/current-raw-chat] + :<- [:chats/current-chat-inputs] (fn [{:keys [metadata]}] - (get-in metadata [:sending-image]))) + (:sending-image metadata))) (re-frame/reg-sub :public-chat.new/topic-error-message @@ -977,7 +983,7 @@ (re-frame/reg-sub :chat/input-with-mentions :<- [:chats/current-chat-id] - :<- [:chats/input-with-mentions] + :<- [:chat/inputs-with-mentions] (fn [[chat-id cursor]] (get cursor chat-id))) diff --git a/src/status_im/transport/message/protocol.cljs b/src/status_im/transport/message/protocol.cljs index 6f66a26269..8975667cfe 100644 --- a/src/status_im/transport/message/protocol.cljs +++ b/src/status_im/transport/message/protocol.cljs @@ -14,22 +14,23 @@ audio-duration-ms sticker content-type]}] - {:method (json-rpc/call-ext-method "sendChatMessage") - :params [{:chatId chat-id - :text text - :responseTo response-to - :ensName ens-name - :imagePath image-path - :audioPath audio-path - :audioDurationMs audio-duration-ms - :sticker sticker - :contentType content-type}] - :on-success - #(re-frame/dispatch [:transport/message-sent % 1]) - :on-failure #(log/error "failed to send a message" %)}) + {:chatId chat-id + :text text + :responseTo response-to + :ensName ens-name + :imagePath image-path + :audioPath audio-path + :audioDurationMs audio-duration-ms + :sticker sticker + :contentType content-type}) (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]}] {::json-rpc/call [{:method (json-rpc/call-ext-method diff --git a/src/status_im/utils/fx.cljs b/src/status_im/utils/fx.cljs index 7b029fe162..d6e9b0396b 100644 --- a/src/status_im/utils/fx.cljs +++ b/src/status_im/utils/fx.cljs @@ -13,6 +13,7 @@ (def ^:private mergeable-keys #{:filters/load-filters :pairing/set-installation-metadata + :dispatch-n :status-im.ens.core/verify-names :shh/send-direct-message :shh/remove-filter diff --git a/status-go-version.json b/status-go-version.json index b93d459c78..e54ee5bba7 100644 --- a/status-go-version.json +++ b/status-go-version.json @@ -2,7 +2,7 @@ "_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh ' instead", "owner": "status-im", "repo": "status-go", - "version": "v0.64.2", - "commit-sha1": "0304b3fa46a6a222b0e346d4a2d1472b965eb78c", - "src-sha256": "0jmwvapv1k3g45gv5xzwshsf2b96b897xs5wyp69sdz9p2nnl18z" + "version": "v0.64.3", + "commit-sha1": "14f4c40404d4d3b1a4e9f739b156f8c8b2eeded6", + "src-sha256": "0h1mbn4xb4r7fwniyjgi3hj5bwj8kyj8jfi47l33rg8i6mnvd3w9" }