From 2438af4e00848df9360a842213746e5c629baf6c Mon Sep 17 00:00:00 2001 From: Andrea Maria Piana Date: Wed, 19 Apr 2023 17:11:43 +0100 Subject: [PATCH] Fix pinned messages & replies https://github.com/status-im/status-go/compare/e8ceed11...213dc463 Both replies and pinned messages relied on subscribing their data from messages. This worked only as long as we loaded the message in the database, so it would break say if another user replied to a message that wasn't in the current user view. It also changes the way pinned messages are handled, before the notification was actually sent over the wire, but that's unnecessary, since it can be generated locally on both parts. This is a bit of a breaking change with the previous version, since if you pin a message with this version, older version will not see a system message. this can be easily fixed by restoring the previous behavior of sending the message, but not sure it's worth it. It also adds the ability to Delete message for everyone that have Deleted for me (discussed with John) and the ability of unpin messages that have been deleted for me. --- src/status_im/chat/models/input.cljs | 5 +- src/status_im/chat/models/message.cljs | 20 ++- src/status_im/data_store/messages.cljs | 5 +- src/status_im/data_store/pin_messages.cljs | 9 +- src/status_im/transport/message/core.cljs | 9 +- .../screens/chat/styles/message/message.cljs | 5 +- .../screens/chat/components/reply/view.cljs | 6 +- .../ui2/screens/chat/messages/message.cljs | 12 +- src/status_im2/constants.cljs | 10 +- .../notification/reply/view.cljs | 12 +- .../chat/menus/pinned_messages/view.cljs | 2 +- .../contexts/chat/messages/avatar/view.cljs | 19 +++ .../chat/messages/content/deleted/view.cljs | 6 +- .../chat/messages/content/pin/style.cljs | 22 ++++ .../chat/messages/content/pin/view.cljs | 69 +++++----- .../contexts/chat/messages/content/view.cljs | 46 +++---- .../contexts/chat/messages/drawers/view.cljs | 23 ++-- .../chat/messages/pin/banner/view.cljs | 10 +- .../contexts/chat/messages/pin/events.cljs | 87 +++++++------ .../chat/messages/pin/events_test.cljs | 36 ++++++ src/status_im2/subs/chat/messages.cljs | 34 ++--- src/status_im2/subs/chat/messages_test.cljs | 120 ++++++------------ status-go-version.json | 6 +- 23 files changed, 311 insertions(+), 262 deletions(-) create mode 100644 src/status_im2/contexts/chat/messages/avatar/view.cljs create mode 100644 src/status_im2/contexts/chat/messages/pin/events_test.cljs diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs index 9484ffbaa4..c16a0eccd0 100644 --- a/src/status_im/chat/models/input.cljs +++ b/src/status_im/chat/models/input.cljs @@ -239,10 +239,7 @@ :on-error #(log/error "failed to edit message " %) :on-success (fn [result] (re-frame/dispatch [:sanitize-messages-and-process-response - result]) - (when pinned-message - (re-frame/dispatch [:pin-message/load-pin-messages - chat-id])))}]} + result]))}]} (cancel-message-edit)))) (rf/defn send-current-message diff --git a/src/status_im/chat/models/message.cljs b/src/status_im/chat/models/message.cljs index d439cb803c..632d4ee2db 100644 --- a/src/status_im/chat/models/message.cljs +++ b/src/status_im/chat/models/message.cljs @@ -32,16 +32,30 @@ ;; TODO this is too expensive, probably we could mark message somehow and just hide it in the UI (message-list/rebuild-message-list {:db (update-in db [:messages chat-id] dissoc message-id)} chat-id)) +(defn add-pinned-message + [acc chat-id message-id message] + (let [{:keys [pinned-by pinned-at] :as pinned-message} + (get-in acc [:db :pin-messages chat-id message-id])] + (if pinned-message + (assoc-in acc + [:db :pin-messages chat-id message-id] + (assoc + message + :pinned-by pinned-by + :pinned-at pinned-at)) + acc))) + (defn add-message [{:keys [db] :as acc} message-js chat-id message-id cursor-clock-value] (let [{:keys [replace from clock-value] :as message} - (data-store.messages/<-rpc (types/js->clj message-js))] + (data-store.messages/<-rpc (types/js->clj message-js)) + acc-with-pinned-message (add-pinned-message acc chat-id message-id message)] (if (message-loaded? db chat-id message-id) ;; If the message is already loaded, it means it's an update, that ;; happens when a message that was missing a reply had the reply ;; coming through, in which case we just insert the new message - (assoc-in acc [:db :messages chat-id message-id] message) - (cond-> acc + (assoc-in acc-with-pinned-message [:db :messages chat-id message-id] message) + (cond-> acc-with-pinned-message ;;add new message to db :always (update-in [:db :messages chat-id] assoc message-id message) diff --git a/src/status_im/data_store/messages.cljs b/src/status_im/data_store/messages.cljs index 175358240f..9660a1d174 100644 --- a/src/status_im/data_store/messages.cljs +++ b/src/status_im/data_store/messages.cljs @@ -46,7 +46,10 @@ (update :quoted-message set/rename-keys - {:parsedText :parsed-text :communityId :community-id}) + {:parsedText :parsed-text + :deleted :deleted? + :deletedForMe :deleted-for-me? + :communityId :community-id}) (update :outgoing-status keyword) (update :command-parameters set/rename-keys diff --git a/src/status_im/data_store/pin_messages.cljs b/src/status_im/data_store/pin_messages.cljs index 70d0c59902..6afadb34aa 100644 --- a/src/status_im/data_store/pin_messages.cljs +++ b/src/status_im/data_store/pin_messages.cljs @@ -29,7 +29,8 @@ (rf/defn send-pin-message [cofx pin-message] - {:json-rpc/call [{:method "wakuext_sendPinMessage" - :params [(messages/->rpc pin-message)] - :on-success #(log/debug "successfully pinned message" pin-message) - :on-error #(log/error "failed to pin message" % pin-message)}]}) + {:json-rpc/call [{:method "wakuext_sendPinMessage" + :params [(messages/->rpc pin-message)] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %]) + :on-error #(log/error "failed to pin message" %)}]}) diff --git a/src/status_im/transport/message/core.cljs b/src/status_im/transport/message/core.cljs index d781417c96..3147da9ce5 100644 --- a/src/status_im/transport/message/core.cljs +++ b/src/status_im/transport/message/core.cljs @@ -11,7 +11,6 @@ [status-im.data-store.activities :as data-store.activities] [status-im.data-store.chats :as data-store.chats] [status-im.data-store.invitations :as data-store.invitations] - [status-im.data-store.messages :as data-store.messages] [status-im.data-store.reactions :as data-store.reactions] [status-im.group-chats.core :as models.group] [status-im.multiaccounts.login.core :as multiaccounts.login] @@ -44,7 +43,7 @@ ^js removed-chats (.-removedChats response-js) ^js activity-notifications (.-activityCenterNotifications response-js) ^js activity-center-state (.-activityCenterState response-js) - ^js pin-messages (.-pinMessages response-js) + ^js pin-messages-js (.-pinMessages response-js) ^js removed-messages (.-removedMessages response-js) ^js visibility-status-updates (.-statusUpdates response-js) ^js current-visibility-status (.-currentStatus response-js) @@ -109,12 +108,12 @@ (process-next response-js sync-handler) (browser/handle-bookmarks bookmarks-clj))) - (seq pin-messages) - (let [pin-messages (types/js->clj pin-messages)] + (seq pin-messages-js) + (do (js-delete response-js "pinMessages") (rf/merge cofx (process-next response-js sync-handler) - (messages.pin/receive-signal (map data-store.messages/<-rpc pin-messages)))) + (messages.pin/receive-signal pin-messages-js))) (seq removed-chats) (let [removed-chats-clj (types/js->clj removed-chats)] diff --git a/src/status_im/ui/screens/chat/styles/message/message.cljs b/src/status_im/ui/screens/chat/styles/message/message.cljs index fea141a1f8..0a72e1951d 100644 --- a/src/status_im/ui/screens/chat/styles/message/message.cljs +++ b/src/status_im/ui/screens/chat/styles/message/message.cljs @@ -258,8 +258,9 @@ (merge (when in-popover? {:number-of-lines 2}) (cond - (= content-type constants/content-type-system-text) (system-text-style) - :else (default-text-style)))) + (= content-type constants/content-type-system-text) (system-text-style) + (= content-type constants/content-type-system-pinned-message) (system-text-style) + :else (default-text-style)))) (defn emph-text-style [] diff --git a/src/status_im/ui2/screens/chat/components/reply/view.cljs b/src/status_im/ui2/screens/chat/components/reply/view.cljs index 93f86d97a3..a5886276ad 100644 --- a/src/status_im/ui2/screens/chat/components/reply/view.cljs +++ b/src/status_im/ui2/screens/chat/components/reply/view.cljs @@ -9,7 +9,7 @@ [status-im2.constants :as constants] [status-im.ethereum.stateofus :as stateofus] [status-im.ui.components.icons.icons :as icons] - [status-im.ui.screens.chat.photos :as photos] + [status-im2.contexts.chat.messages.avatar.view :as avatar] [utils.re-frame :as rf] [status-im.ui2.screens.chat.components.reply.style :as style] [react-native.linear-gradient :as linear-gradient])) @@ -65,9 +65,9 @@ (i18n/label :t/message-deleted)]]) (defn reply-from - [{:keys [from identicon contact-name current-public-key]}] + [{:keys [from contact-name current-public-key]}] [rn/view {:style style/reply-from} - [photos/member-photo from identicon 16] + [avatar/avatar from :xxxs] [quo2.text/text {:weight :semi-bold :size :paragraph-2 diff --git a/src/status_im/ui2/screens/chat/messages/message.cljs b/src/status_im/ui2/screens/chat/messages/message.cljs index abc2a6c675..3fc65ed5d1 100644 --- a/src/status_im/ui2/screens/chat/messages/message.cljs +++ b/src/status_im/ui2/screens/chat/messages/message.cljs @@ -31,7 +31,9 @@ (defn system-text? [content-type] - (= content-type constants/content-type-system-text)) + (or + (= content-type constants/content-type-system-text) + (= content-type constants/content-type-system-pinned-message))) (defn mention-element [from] @@ -142,11 +144,9 @@ (:parsed-text content)))) (defn quoted-message - [{:keys [message-id chat-id]} pin?] - (let [quoted-message (get @(re-frame/subscribe [:chats/chat-messages chat-id]) - message-id)] - [rn/view {:style (when-not pin? (style/quoted-message-container))} - [components.reply/reply-message quoted-message false pin?]])) + [quoted-message pin?] + [rn/view {:style (when-not pin? (style/quoted-message-container))} + [components.reply/reply-message quoted-message false pin?]]) (defn message-not-sent-text [chat-id message-id] diff --git a/src/status_im2/constants.cljs b/src/status_im2/constants.cljs index 074d297c3b..23f07dc890 100644 --- a/src/status_im2/constants.cljs +++ b/src/status_im2/constants.cljs @@ -13,9 +13,13 @@ (def ^:const content-type-community 9) (def ^:const content-type-gap 10) (def ^:const content-type-contact-request 11) ;; TODO: temp, will be removed -(def ^:const content-type-gif 12) -(def ^:const content-type-link 13) -(def ^:const content-type-album 14) +(def ^:const content-type-system-pinned-message 14) + +;; Not implemented in status-go, only used for testing/ui work +(def ^:const content-type-gif 100) +(def ^:const content-type-link 101) +(def ^:const content-type-album 102) + (def ^:const contact-request-state-none 0) (def ^:const contact-request-state-mutual 1) diff --git a/src/status_im2/contexts/activity_center/notification/reply/view.cljs b/src/status_im2/contexts/activity_center/notification/reply/view.cljs index f87f86d59e..a71b878954 100644 --- a/src/status_im2/contexts/activity_center/notification/reply/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/reply/view.cljs @@ -23,11 +23,17 @@ (defn- get-message-content [{:keys [content-type] :as message}] (case content-type - constants/content-type-text (get-in message [:content :text]) + constants/content-type-text [quo/text {:style style/tag-text} + (get-in message [:content :text])] - constants/content-type-image [old-message/message-content-image message] + constants/content-type-image [old-message/message-content-image message] - constants/content-type-sticker [old-message/sticker message] + constants/content-type-sticker [old-message/sticker message] + + constants/content-type-system-pinned-message + [not-implemented/not-implemented + [quo/text {:style style/tag-text} + (get-in message [:content :text])]] ;; NOTE: The following type (system-text) doesn't have a design yet. ;; https://github.com/status-im/status-mobile/issues/14915 diff --git a/src/status_im2/contexts/chat/menus/pinned_messages/view.cljs b/src/status_im2/contexts/chat/menus/pinned_messages/view.cljs index c6fae5613b..1f335bfdab 100644 --- a/src/status_im2/contexts/chat/menus/pinned_messages/view.cljs +++ b/src/status_im2/contexts/chat/menus/pinned_messages/view.cljs @@ -17,7 +17,7 @@ ;; TODO (flexsurfer) probably we don't want reactions here (if (or deleted? deleted-for-me?) [content.deleted/deleted-message message context] - [message/message-with-reactions message context false])) + [message/message-with-reactions message context])) (defn pinned-messages [chat-id] diff --git a/src/status_im2/contexts/chat/messages/avatar/view.cljs b/src/status_im2/contexts/chat/messages/avatar/view.cljs new file mode 100644 index 0000000000..42d9e60644 --- /dev/null +++ b/src/status_im2/contexts/chat/messages/avatar/view.cljs @@ -0,0 +1,19 @@ +(ns status-im2.contexts.chat.messages.avatar.view + (:require [utils.re-frame :as rf] + [react-native.core :as rn] + [quo2.core :as quo])) + +(defn avatar + [public-key size] + (let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key])) + contact (rf/sub [:contacts/contact-by-address public-key]) + photo-path (when (seq (:images contact)) (rf/sub [:chats/photo-path public-key])) + online? (rf/sub [:visibility-status-updates/online? public-key])] + [rn/touchable-without-feedback {:on-press #(rf/dispatch [:chat.ui/show-profile public-key])} + [rn/view {:padding-top 2} + [quo/user-avatar + {:full-name display-name + :profile-picture photo-path + :status-indicator? true + :online? online? + :size size}]]])) diff --git a/src/status_im2/contexts/chat/messages/content/deleted/view.cljs b/src/status_im2/contexts/chat/messages/content/deleted/view.cljs index 66e253076e..b1e61c0fa6 100644 --- a/src/status_im2/contexts/chat/messages/content/deleted/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/deleted/view.cljs @@ -26,10 +26,10 @@ (i18n/label :t/deleted-this-message)]]) (defn- compute-on-long-press-fn - [{:keys [deleted? pinned deleted-for-me?] :as message} - {:keys [message-pin-enabled] :as context}] + [{:keys [deleted?] :as message} + context] ;; only show drawer for user who has the permission to unpin messages - (when (and pinned (or deleted? deleted-for-me?) message-pin-enabled) + (when-not deleted? (fn [] (rf/dispatch [:dismiss-keyboard]) (rf/dispatch [:show-bottom-sheet diff --git a/src/status_im2/contexts/chat/messages/content/pin/style.cljs b/src/status_im2/contexts/chat/messages/content/pin/style.cljs index 130dc373c7..55233ced6b 100644 --- a/src/status_im2/contexts/chat/messages/content/pin/style.cljs +++ b/src/status_im2/contexts/chat/messages/content/pin/style.cljs @@ -1,6 +1,9 @@ (ns status-im2.contexts.chat.messages.content.pin.style (:require [quo2.foundations.colors :as colors])) +(def system-message-default-size 36) +(def system-message-radius (/ system-message-default-size 2)) + (def pin-indicator-container {:margin-top 4 :margin-left 54 @@ -16,3 +19,22 @@ (defn pinned-message-text [] {:color (colors/theme-colors colors/neutral-100 colors/white)}) + +(def system-message-container + {:flex-direction :row :margin-vertical 8}) + +(def system-message-inner-container + {:width system-message-default-size + :height system-message-default-size + :margin-right system-message-radius + :border-radius system-message-default-size + :justify-content :center + :align-items :center + :background-color colors/primary-50-opa-10}) + +(def system-message-author-container + {:flex-direction :row :align-items :center}) + +(def system-message-timestamp-container + {:padding-left 5 + :margin-top 2}) diff --git a/src/status_im2/contexts/chat/messages/content/pin/view.cljs b/src/status_im2/contexts/chat/messages/content/pin/view.cljs index 01b7ba88c2..cfe1460efb 100644 --- a/src/status_im2/contexts/chat/messages/content/pin/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/pin/view.cljs @@ -24,42 +24,33 @@ author-name]])) (defn system-message - [{:keys [from in-popover? timestamp-str chat-id] :as message}] - (let [response-to (:response-to (:content message)) - default-size 36] - [rn/touchable-opacity - {:on-press (fn [] - (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id])) - :active-opacity 1 - :style (merge {:flex-direction :row :margin-vertical 8} - (old-style/message-wrapper message))} - [rn/view - {:style {:width default-size - :height default-size - :margin-right 16 - :border-radius default-size - :justify-content :center - :align-items :center - :background-color colors/primary-50-opa-10} - :accessibility-label :content-type-pin-icon} - [quo/icon :i/pin {:color colors/primary-50 :size 16}]] - [rn/view - [rn/view {:style {:flex-direction :row :align-items :center}} - [rn/touchable-opacity - {:style old-style/message-author-touchable - :disabled in-popover? - :on-press #(rf/dispatch [:chat.ui/show-profile from])} - [old-message/message-author-name from {} 20]] - [quo/text - {:size :label - :style (style/pinned-message-text)} - (str " " (i18n/label :t/pinned-a-message))] - [rn/text - {:style (merge - {:padding-left 5 - :margin-top 2} - (old-style/message-timestamp-text)) - :accessibility-label :message-timestamp} - timestamp-str]] - [old-message/quoted-message {:message-id response-to :chat-id chat-id} true]]])) + [{:keys [from in-popover? quoted-message timestamp-str chat-id] :as message}] + [rn/touchable-opacity + {:on-press (fn [] + (rf/dispatch [:dismiss-keyboard]) + (rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id])) + :active-opacity 1 + :style (merge style/system-message-container + (old-style/message-wrapper message))} + [rn/view + {:style style/system-message-inner-container + :accessibility-label :content-type-pin-icon} + [quo/icon :i/pin {:color colors/primary-50 :size 16}]] + [rn/view + [rn/view {:style style/system-message-author-container} + [rn/touchable-opacity + {:style old-style/message-author-touchable + :disabled in-popover? + :on-press #(rf/dispatch [:chat.ui/show-profile from])} + [old-message/message-author-name from {} 20]] + [quo/text + {:size :label + :style (style/pinned-message-text)} + (str " " (i18n/label :t/pinned-a-message))] + [rn/text + {:style (merge + style/system-message-timestamp-container + (old-style/message-timestamp-text)) + :accessibility-label :message-timestamp} + timestamp-str]] + [old-message/quoted-message quoted-message true]]]) diff --git a/src/status_im2/contexts/chat/messages/content/view.cljs b/src/status_im2/contexts/chat/messages/content/view.cljs index dc6acf8c23..ff1ab9720a 100644 --- a/src/status_im2/contexts/chat/messages/content/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/view.cljs @@ -12,6 +12,7 @@ [status-im2.contexts.chat.messages.content.status.view :as status] [status-im2.contexts.chat.messages.content.system.text.view :as system.text] [status-im2.contexts.chat.messages.content.album.view :as album] + [status-im2.contexts.chat.messages.avatar.view :as avatar] [status-im2.contexts.chat.messages.content.image.view :as image] [quo2.core :as quo] [utils.re-frame :as rf] @@ -23,35 +24,24 @@ (def delivery-state-showing-time-ms 3000) -(defn avatar - [{:keys [content last-in-group? pinned quoted-message from]}] +(defn avatar-container + [{:keys [content last-in-group? pinned-by quoted-message from]}] (if (or (and (seq (:response-to content)) quoted-message) last-in-group? - pinned) - (let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from])) - contact (rf/sub [:contacts/contact-by-address from]) - photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from])) - online? (rf/sub [:visibility-status-updates/online? from])] - [rn/touchable-without-feedback {:on-press #(rf/dispatch [:chat.ui/show-profile from])} - [rn/view {:padding-top 2 :width 32} - [quo/user-avatar - {:full-name display-name - :profile-picture photo-path - :status-indicator? true - :online? online? - :size :small}]]]) + pinned-by) + [avatar/avatar from :small] [rn/view {:padding-top 2 :width 32}])) (defn author [{:keys [response-to compressed-key last-in-group? - pinned + pinned-by quoted-message from timestamp]}] - (when (or (and (seq response-to) quoted-message) last-in-group? pinned) + (when (or (and (seq response-to) quoted-message) last-in-group? pinned-by) (let [[primary-name secondary-name] (rf/sub [:contacts/contact-two-names-by-identity from]) {:keys [ens-verified added?]} (rf/sub [:contacts/contact-by-address from])] [quo/author @@ -65,17 +55,18 @@ (defn system-message-content [{:keys [content-type quoted-message] :as message-data}] (if quoted-message - [not-implemented/not-implemented [pin/system-message message-data]] + [pin/system-message message-data] (case content-type - constants/content-type-system-text [not-implemented/not-implemented - [system.text/text-content message-data]] + constants/content-type-system-text [system.text/text-content message-data] - constants/content-type-community [not-implemented/not-implemented - [old-message/community message-data]] + constants/content-type-system-pinned-message [system.text/text-content message-data] - constants/content-type-contact-request [not-implemented/not-implemented - [old-message/system-contact-request message-data]]))) + constants/content-type-community [not-implemented/not-implemented + [old-message/community message-data]] + + constants/content-type-contact-request [not-implemented/not-implemented + [old-message/system-contact-request message-data]]))) (defn on-long-press [message-data context] @@ -87,7 +78,7 @@ [] (let [show-delivery-state? (reagent/atom false)] (fn [{:keys [content-type quoted-message content outgoing outgoing-status] :as message-data} - {:keys [chat-id] :as context} + context keyboard-shown] (let [first-image (first (:album message-data)) outgoing-status (if (= content-type constants/content-type-album) @@ -117,11 +108,11 @@ :on-long-press #(on-long-press message-data context)} [rn/view {:style {:padding-vertical 8}} (when (and (seq response-to) quoted-message) - [old-message/quoted-message {:message-id response-to :chat-id chat-id}]) + [old-message/quoted-message quoted-message]) [rn/view {:style {:padding-horizontal 12 :flex-direction :row}} - [avatar message-data] + [avatar-container message-data] [rn/view {:style {:margin-left 8 :flex 1}} @@ -159,6 +150,7 @@ (when pinned-by [pin/pinned-by-view pinned-by]) (if (#{constants/content-type-system-text constants/content-type-community + constants/content-type-system-pinned-message constants/content-type-contact-request} content-type) [system-message-content message-data] diff --git a/src/status_im2/contexts/chat/messages/drawers/view.cljs b/src/status_im2/contexts/chat/messages/drawers/view.cljs index 53196416b0..1ba2b077be 100644 --- a/src/status_im2/contexts/chat/messages/drawers/view.cljs +++ b/src/status_im2/contexts/chat/messages/drawers/view.cljs @@ -20,7 +20,7 @@ (assoc message-data :pinned message-not-pinned?)])))) (defn get-actions - [{:keys [outgoing content pinned outgoing-status deleted? deleted-for-me? content-type] + [{:keys [outgoing content pinned-by outgoing-status deleted? deleted-for-me? content-type] :as message-data} {:keys [able-to-send-message? community? can-delete-message-for-everyone? message-pin-enabled group-chat group-admin?]}] @@ -54,15 +54,17 @@ :icon :i/copy :id :copy}]) ;; pinning images are temporarily disabled - (when (and message-pin-enabled (not= content-type constants/content-type-image)) + (when (and message-pin-enabled + (not (or deleted? deleted-for-me?)) + (not= content-type constants/content-type-image)) [{:type :main :on-press #(pin-message message-data) - :label (i18n/label (if pinned + :label (i18n/label (if pinned-by (if community? :t/unpin-from-channel :t/unpin-from-chat) (if community? :t/pin-to-channel :t/pin-to-chat))) :icon :i/pin - :id (if pinned :unpin :pin)}]) - (when-not (or pinned deleted? deleted-for-me?) + :id (if pinned-by :unpin :pin)}]) + (when-not (or deleted? deleted-for-me?) [{:type :danger :on-press (fn [] (rf/dispatch @@ -74,12 +76,11 @@ :icon :i/delete :id :delete-for-me}]) (when (cond - deleted? false - deleted-for-me? false - outgoing true - community? can-delete-message-for-everyone? - group-chat group-admin? - :else false) + deleted? false + outgoing true + community? can-delete-message-for-everyone? + group-chat group-admin? + :else false) [{:type :danger :on-press (fn [] (rf/dispatch [:hide-bottom-sheet]) diff --git a/src/status_im2/contexts/chat/messages/pin/banner/view.cljs b/src/status_im2/contexts/chat/messages/pin/banner/view.cljs index deda5acb56..93c8d4a6de 100644 --- a/src/status_im2/contexts/chat/messages/pin/banner/view.cljs +++ b/src/status_im2/contexts/chat/messages/pin/banner/view.cljs @@ -27,12 +27,10 @@ (defn banner [chat-id] - (let [pinned-messages (rf/sub [:chats/pinned-sorted-list chat-id]) - latest-pinned-message-id (-> pinned-messages last :message-id) - latest-pinned-message (get (rf/sub [:chats/chat-messages chat-id]) latest-pinned-message-id) - latest-pin-text (get-in latest-pinned-message [:content :parsed-text]) - {:keys [deleted? deleted-for-me?]} latest-pinned-message - pins-count (count pinned-messages) + (let [pinned-message (rf/sub [:chats/last-pinned-message chat-id]) + latest-pin-text (get-in pinned-message [:content :parsed-text]) + {:keys [deleted? deleted-for-me?]} pinned-message + pins-count (rf/sub [:chats/pin-messages-count chat-id]) latest-pin-text (cond deleted? (i18n/label :t/message-deleted-for-everyone) diff --git a/src/status_im2/contexts/chat/messages/pin/events.cljs b/src/status_im2/contexts/chat/messages/pin/events.cljs index 12ccd634fe..4fb55cc8a4 100644 --- a/src/status_im2/contexts/chat/messages/pin/events.cljs +++ b/src/status_im2/contexts/chat/messages/pin/events.cljs @@ -2,7 +2,7 @@ (:require [quo2.foundations.colors :as colors] [re-frame.core :as re-frame] [status-im.data-store.pin-messages :as data-store.pin-messages] - [status-im.transport.message.protocol :as protocol] + [status-im.data-store.messages :as data-store.messages] [status-im2.common.toasts.events :as toasts] [status-im2.constants :as constants] [status-im2.contexts.chat.messages.list.events :as message-list] @@ -33,34 +33,48 @@ (assoc-in [:pagination-info chat-id :all-pin-loaded?] (empty? cursor)))})) +(defn remove-pinned-message + [db pinned-message] + (update-in db + [:pin-messages (aget pinned-message "localChatId")] + dissoc + (aget pinned-message "message_id"))) + +(defn add-pinned-message + [db pinned-message] + (let [message (aget pinned-message "pinnedMessage")] + (if (and message + (aget message "message")) + (assoc-in db + [:pin-messages + (aget pinned-message "localChatId") + (aget pinned-message "message_id")] + (-> (aget message "message") + (js->clj :keywordize-keys true) + data-store.messages/<-rpc + (assoc :pinned-by (aget message "pinnedBy") + :pinned-at (aget message "pinnedAt")))) + db))) + (rf/defn receive-signal [{:keys [db]} pin-messages] - (let [{:keys [chat-id]} (first pin-messages)] - (when (= chat-id (db :current-chat-id)) - (let [{:keys [chat-id]} (first pin-messages) - already-loaded-pin-messages (get-in db [:pin-messages chat-id] {}) - already-loaded-messages (get-in db [:messages chat-id] {}) - all-messages (reduce (fn [acc {:keys [message_id pinned from]}] - ;; Add to or remove from pinned message list, and - ;; normalizing pinned-by property - (let [current-message (get already-loaded-messages - message_id) - current-message-pin (merge current-message - {:pinned pinned - :pinned-by from})] - (cond-> acc - (nil? pinned) - (dissoc message_id) - - (and (some? pinned) (some? current-message)) - (assoc message_id current-message-pin)))) - already-loaded-pin-messages - pin-messages)] - {:db (-> db - (assoc-in [:pin-messages chat-id] all-messages) - (assoc-in [:pin-message-lists chat-id] - (message-list/add-many nil (vals all-messages))))})))) - + (let [current-chat-id (db :current-chat-id) + db (reduce (fn [db pin-message] + (let [pinned? (aget pin-message "pinned") + chat-id (aget pin-message "localChatId")] + (cond + (not= chat-id current-chat-id) + db + pinned? + (add-pinned-message db pin-message) + :else + (remove-pinned-message db pin-message)))) + db + pin-messages)] + {:db + (assoc-in db + [:pin-message-lists current-chat-id] + (message-list/add-many nil (vals (get-in db [:pin-messages current-chat-id]))))})) (rf/defn send-pin-message-locally "Pin message, rebuild pinned messages list locally" @@ -84,20 +98,11 @@ "Pin message, rebuild pinned messages list" {:events [:pin-message/send-pin-message]} [{:keys [db] :as cofx} {:keys [chat-id message-id pinned remote-only?] :as pin-message}] - (let [current-public-key (get-in db [:multiaccount :public-key]) - message (merge pin-message {:pinned-by current-public-key}) - preferred-name (get-in db [:multiaccount :preferred-name])] - (rf/merge cofx - (when-not remote-only? (send-pin-message-locally pin-message)) - (data-store.pin-messages/send-pin-message {:chat-id (pin-message :chat-id) - :message_id (pin-message :message-id) - :pinned (pin-message :pinned)}) - (when pinned - (protocol/send-chat-messages [{:chat-id (pin-message :chat-id) - :content-type constants/content-type-system-text - :text "pinned a message" - :response-to (pin-message :message-id) - :ens-name preferred-name}]))))) + (rf/merge cofx + (when-not remote-only? (send-pin-message-locally pin-message)) + (data-store.pin-messages/send-pin-message {:chat-id (pin-message :chat-id) + :message_id (pin-message :message-id) + :pinned (pin-message :pinned)}))) (rf/defn load-pin-messages {:events [:pin-message/load-pin-messages]} diff --git a/src/status_im2/contexts/chat/messages/pin/events_test.cljs b/src/status_im2/contexts/chat/messages/pin/events_test.cljs new file mode 100644 index 0000000000..c9369e8a1b --- /dev/null +++ b/src/status_im2/contexts/chat/messages/pin/events_test.cljs @@ -0,0 +1,36 @@ +(ns status-im2.contexts.chat.messages.pin.events-test + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im2.contexts.chat.messages.pin.events :as events])) + +(deftest receive-signal-test + (let [chat-id "chat-id" + message-id-1 "0x1" + message-id-2 "0x2" + message-id-3 "0x3" + message-1 {:id message-id-1 :whisperTimestamp 1 :timestamp 1 :clock 2} + message-3 {:id message-id-3 :whisperTimestamp 1 :timestamp 1 :clock 2} + db {:current-chat-id chat-id + :pin-messages {chat-id {message-id-1 {} + message-id-2 {}}}}] + (testing "receiving a pinned messages update" + (let [pinned-messages-signal (clj->js [{:pinned true + :localChatId chat-id + :message_id message-id-1 + :pinnedMessage {:pinnedAt 1 + :pinnedBy "0x1" + :message message-1}} + {:pinned false + :localChatId chat-id + :message_id message-id-2} + {:pinned true + :localChatId chat-id + :message_id message-id-3 + :pinnedMessage {:pinnedAt 1 + :pinnedBy "0x1" + :message message-3}}]) + actual (events/receive-signal {:db db} + pinned-messages-signal) + ] + (is (not (get-in actual [:db :pin-messages chat-id message-id-2]))) + (is (get-in actual [:db :pin-messages chat-id message-id-1 :message-id])) + (is (get-in actual [:db :pin-messages chat-id message-id-3 :message-id])))))) diff --git a/src/status_im2/subs/chat/messages.cljs b/src/status_im2/subs/chat/messages.cljs index 4beb3e269a..a15a4aab70 100644 --- a/src/status_im2/subs/chat/messages.cljs +++ b/src/status_im2/subs/chat/messages.cljs @@ -146,22 +146,9 @@ (re-frame/reg-sub :chats/pinned - (fn [[_ chat-id] _] - [(re-frame/subscribe [:messages/pin-messages]) - (re-frame/subscribe [:chats/chat-messages chat-id])]) - (fn [[pin-messages messages] [_ chat-id]] - (let [pinned-messages (get pin-messages chat-id {})] - (reduce-kv - (fn [pinned-messages pinned-message-id pinned-message] - (let [{:keys [deleted? deleted-for-me? deleted-by]} (get messages pinned-message-id) - pinned-message (assoc pinned-message - :deleted? deleted? - :deleted-for-me? deleted-for-me? - :deleted-by deleted-by - :pinned true)] - (assoc pinned-messages pinned-message-id pinned-message))) - pinned-messages - pinned-messages)))) + :<- [:messages/pin-messages] + (fn [pinned-messages [_ chat-id] _] + (get pinned-messages chat-id))) ;; local messages will not have a :pinned-at key until user navigates away and to ;; chat screen. For this reason we want to retain order of local messages with :pinned-at nil @@ -180,9 +167,22 @@ (re-frame/subscribe [:chats/pinned chat-id])) (fn [pin-messages _] (let [pin-messages-vals (vals pin-messages)] - (sort-by :pinned-at sort-pinned pin-messages-vals)))) +(re-frame/reg-sub + :chats/last-pinned-message + (fn [[_ chat-id]] + (re-frame/subscribe [:chats/pinned-sorted-list chat-id])) + (fn [pin-messages _] + (last pin-messages))) + +(re-frame/reg-sub + :chats/pin-messages-count + (fn [[_ chat-id]] + (re-frame/subscribe [:chats/pinned chat-id])) + (fn [pinned-messages _] + (count pinned-messages))) + (re-frame/reg-sub :chats/pin-modal :<- [:messages/pin-modal] diff --git a/src/status_im2/subs/chat/messages_test.cljs b/src/status_im2/subs/chat/messages_test.cljs index dd62378703..8385c3ce0c 100644 --- a/src/status_im2/subs/chat/messages_test.cljs +++ b/src/status_im2/subs/chat/messages_test.cljs @@ -109,92 +109,52 @@ (testing "It sorts three messages with pinned-at property" (swap! rf-db/app-db assoc :pin-messages pinned-messages-state) (is - (= [{:chat-id :0xChat - :message-id :0x1 - :pinned-at 1000 - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil} - {:chat-id :0xChat - :message-id :0x2 - :pinned-at 2000 - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil} - {:chat-id :0xChat - :message-id :0x3 - :pinned-at 3000 - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil}] + (= [{:chat-id :0xChat + :message-id :0x1 + :pinned-at 1000 + :pinned-by :test-user} + {:chat-id :0xChat + :message-id :0x2 + :pinned-at 2000 + :pinned-by :test-user} + {:chat-id :0xChat + :message-id :0x3 + :pinned-at 3000 + :pinned-by :test-user}] (rf/sub [sub-name :0xChat])))) (testing "It sorts messages from backend with pinned-at property and 1 new local pinned message" (swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-1-new-local-message) (is - (= [{:chat-id :0xChat - :message-id :0x1 - :pinned-at 2000 - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil} - {:chat-id :0xChat - :message-id :0x2 - :pinned-at 3000 - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil} - {:chat-id :0xChat - :message-id :0x3 - :pinned-at nil - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil}] + (= [{:chat-id :0xChat + :message-id :0x1 + :pinned-at 2000 + :pinned-by :test-user} + {:chat-id :0xChat + :message-id :0x2 + :pinned-at 3000 + :pinned-by :test-user} + {:chat-id :0xChat + :message-id :0x3 + :pinned-at nil + :pinned-by :test-user}] (rf/sub [sub-name :0xChat])))) (testing "It sorts messages from backend with pinned-at property and 2 new local pinned messages" (swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-2-new-local-messages) (is - (= [{:chat-id :0xChat - :message-id :0x1 - :pinned-at 2000 - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil} - {:chat-id :0xChat - :message-id :0x2 - :pinned-at 3000 - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil} - {:chat-id :0xChat - :message-id :0x3 - :pinned-at nil - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil} - {:chat-id :0xChat - :message-id :0x4 - :pinned-at nil - :pinned-by :test-user - :pinned true - :deleted? nil - :deleted-for-me? nil - :deleted-by nil}] + (= [{:chat-id :0xChat + :message-id :0x1 + :pinned-at 2000 + :pinned-by :test-user} + {:chat-id :0xChat + :message-id :0x2 + :pinned-at 3000 + :pinned-by :test-user} + {:chat-id :0xChat + :message-id :0x3 + :pinned-at nil + :pinned-by :test-user} + {:chat-id :0xChat + :message-id :0x4 + :pinned-at nil + :pinned-by :test-user}] (rf/sub [sub-name :0xChat]))))) diff --git a/status-go-version.json b/status-go-version.json index 543815f69e..6958b0b61e 100644 --- a/status-go-version.json +++ b/status-go-version.json @@ -3,7 +3,7 @@ "_comment": "Instead use: scripts/update-status-go.sh ", "owner": "status-im", "repo": "status-go", - "version": "v0.146.4", - "commit-sha1": "e8ceed11125dfd470c0e0caac0755313fb85cba6", - "src-sha256": "1flwq5sfy1cfdl40fiip0q555rdcq5f5l2lpb4az8j5bwmwmi31x" + "version": "v0.147.1", + "commit-sha1": "213dc463bcc1ae449bc78b6cf7c598c4f68830c5", + "src-sha256": "1q00agdsqc4p16l8d5cv88gwfnpnl7bb61mayc3520c82hw93q3r" }