diff --git a/shadow-cljs.edn b/shadow-cljs.edn index d7b6f1bb39..4b01f08bdc 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -82,7 +82,7 @@ :optimizations :simple :target :node-test ;; When running tests without a REPL you can uncomment below line to `make test-watch` a specific file - ;;:ns-regexp "status-im2.subs.subs-test$" + ;; :ns-regexp "status-im2.subs.chat.messages-test$" :main status-im.test-runner/main ;; set :ui-driven to true to let shadow-cljs inject node-repl diff --git a/src/status_im2/constants.cljs b/src/status_im2/constants.cljs index 2e17340daf..a56861b34d 100644 --- a/src/status_im2/constants.cljs +++ b/src/status_im2/constants.cljs @@ -214,8 +214,8 @@ {2 {0 image-size 1 image-size} 3 {0 [(* image-size 2) (* image-size 1.5)] - 1 [(- image-size 1) (- (* image-size 0.67) 1)] - 2 [(- image-size 1) (- (* image-size 0.67) 1)]} + 1 [(- image-size 0.5) (- (* image-size 0.67) 1)] + 2 [(- image-size 0.5) (- (* image-size 0.67) 1)]} 4 {0 image-size 1 image-size 2 image-size diff --git a/src/status_im2/contexts/chat/messages/content/album/style.cljs b/src/status_im2/contexts/chat/messages/content/album/style.cljs index 1872933a3d..1e70119ce7 100644 --- a/src/status_im2/contexts/chat/messages/content/album/style.cljs +++ b/src/status_im2/contexts/chat/messages/content/album/style.cljs @@ -14,12 +14,12 @@ :overflow :hidden}) (defn image - [dimensions index portrait?] + [dimensions index portrait? images-count] {:width (:width dimensions) :height (:height dimensions) - :margin-left (when (or (and (not= index 0) (not= index 2) (not= count 3)) - (= count 3) - (and portrait? (= index 2))) + :margin-left (when (or (and (not= index 0) (not= index 2) (not= images-count 3)) + (and (not portrait?) (= images-count 3) (= index 2)) + (and portrait? (= images-count 3) (> index 0))) 1) :margin-bottom (when (< index 2) 1) :align-self :flex-start}) diff --git a/src/status_im2/contexts/chat/messages/content/album/view.cljs b/src/status_im2/contexts/chat/messages/content/album/view.cljs index fe79d2aaf5..0704debc95 100644 --- a/src/status_im2/contexts/chat/messages/content/album/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/album/view.cljs @@ -5,8 +5,7 @@ [react-native.fast-image :as fast-image] [status-im2.contexts.chat.messages.content.album.style :as style] [status-im2.constants :as constants] - [utils.re-frame :as rf] - [status-im2.contexts.chat.messages.content.image.view :as image])) + [utils.re-frame :as rf])) (def rectangular-style-count 3) @@ -17,7 +16,7 @@ {:width (second size-arr) :height (first size-arr) :album-style album-style})) (defn album-message - [{:keys [albumize?] :as message}] + [message] (let [shared-element-id (rf/sub [:shared-element-id]) first-image (first (:album message)) album-style (if (> (:image-width first-image) (:image-height first-image)) @@ -26,43 +25,44 @@ images-count (count (:album message)) ;; album images are always square, except when we have 3 images, then they must be rectangular ;; (portrait or landscape) - portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))] - (if (and albumize? (> images-count 1)) - [rn/view - {:style (style/album-container portrait?)} - (map-indexed - (fn [index item] - (let [images-size-key (if (< images-count constants/max-album-photos) images-count :default) - size (get-in constants/album-image-sizes [images-size-key index]) - dimensions (if (not= images-count rectangular-style-count) - {:width size :height size} - (find-size size album-style))] - [rn/touchable-opacity - {:key (:message-id item) - :active-opacity 1 - :on-press (fn [] - (rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]) - (js/setTimeout #(rf/dispatch [:navigate-to :lightbox - {:messages (:album message) :index index}]) - 100))} - [fast-image/fast-image - {:style (style/image dimensions index portrait?) - :source {:uri (:image (:content item))} - :native-ID (when (and (= shared-element-id (:message-id item)) - (< index constants/max-album-photos)) - :shared-element)}] - (when (and (> images-count constants/max-album-photos) - (= index (- constants/max-album-photos 1))) - [rn/view - {:style style/overlay} - [quo/text - {:weight :bold - :size :heading-2 - :style {:color colors/white}} - (str "+" (- images-count (dec constants/max-album-photos)))]])])) - (:album message))] - [:<> - (map-indexed - (fn [index item] - [image/image-message index item]) - (:album message))]))) + portrait? (and (= images-count rectangular-style-count) (= album-style :portrait)) + text (:text (:content first-image))] + [:<> + ;; This text comp is temporary. Should later use + ;; `status-im2.contexts.chat.messages.content.text.view` + (when (not= text "placeholder") [quo/text {:style {:margin-bottom 10}} text]) + [rn/view + {:style (style/album-container portrait?)} + (map-indexed + (fn [index item] + (let [images-size-key (if (< images-count constants/max-album-photos) images-count :default) + size (get-in constants/album-image-sizes [images-size-key index]) + dimensions (if (not= images-count rectangular-style-count) + {:width size :height size} + (find-size size album-style))] + [rn/touchable-opacity + {:key (:message-id item) + :active-opacity 1 + ;; issue: https://github.com/status-im/status-mobile/issues/14995 + :on-long-press #(js/alert "Action drawer for albums is not supported yet") + :on-press (fn [] + (rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]) + (js/setTimeout #(rf/dispatch [:navigate-to :lightbox + {:messages (:album message) :index index}]) + 100))} + [fast-image/fast-image + {:style (style/image dimensions index portrait? images-count) + :source {:uri (:image (:content item))} + :native-ID (when (and (= shared-element-id (:message-id item)) + (< index constants/max-album-photos)) + :shared-element)}] + (when (and (> images-count constants/max-album-photos) + (= index (- constants/max-album-photos 1))) + [rn/view + {:style style/overlay} + [quo/text + {:weight :bold + :size :heading-2 + :style {:color colors/white}} + (str "+" (- images-count (dec constants/max-album-photos)))]])])) + (:album message))]])) diff --git a/src/status_im2/contexts/chat/messages/content/image/view.cljs b/src/status_im2/contexts/chat/messages/content/image/view.cljs index 2c0c7b41ec..e2450bf0d7 100644 --- a/src/status_im2/contexts/chat/messages/content/image/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/image/view.cljs @@ -1,12 +1,15 @@ (ns status-im2.contexts.chat.messages.content.image.view - (:require [react-native.core :as rn] - [react-native.fast-image :as fast-image] - [utils.re-frame :as rf])) + (:require + [quo2.core :as quo] + [react-native.core :as rn] + [react-native.fast-image :as fast-image] + [status-im2.constants :as constants] + [utils.re-frame :as rf])) (defn calculate-dimensions [width height] - (let [max-width (if (> width height) 320 190) - max-height (if (> width height) 190 320)] + (let [max-width (if (> width height) (* 2 constants/image-size) (* 1.5 constants/image-size)) + max-height (if (> width height) (* 1.5 constants/image-size) (* 2 constants/image-size))] (if (> height width) (let [calculated-height (* (min height max-height) (/ (max width max-width) width)) calculated-width (* (max width max-width) (/ (min height max-height) height))] @@ -16,7 +19,7 @@ {:width calculated-width :height calculated-height})))) (defn image-message - [index {:keys [content image-width image-height message-id] :as message}] + [_ {:keys [content image-width image-height message-id] :as message} context on-long-press] (let [dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000)) text (:text content)] (fn [] @@ -24,7 +27,7 @@ [rn/touchable-opacity {:active-opacity 1 :key message-id - :style {:margin-top (when (> index 0) 20)} + :on-long-press #(on-long-press message context) :on-press (fn [] (rf/dispatch [:chat.ui/update-shared-element-id message-id]) (js/setTimeout #(rf/dispatch [:navigate-to :lightbox @@ -32,7 +35,7 @@ 100))} ;; This text comp is temporary. Should later use ;; `status-im2.contexts.chat.messages.content.text.view` - (when (and (not= text "placeholder") (= index 0)) [rn/text text]) + (when (not= text "placeholder") [quo/text {:style {:margin-bottom 10}} text]) [fast-image/fast-image {:source {:uri (:image content)} :style (merge dimensions {:border-radius 12}) diff --git a/src/status_im2/contexts/chat/messages/content/reactions/view.cljs b/src/status_im2/contexts/chat/messages/content/reactions/view.cljs index d5c6193a8e..c008ae55c0 100644 --- a/src/status_im2/contexts/chat/messages/content/reactions/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/reactions/view.cljs @@ -6,8 +6,10 @@ [status-im2.contexts.chat.messages.drawers.view :as drawers])) (defn message-reactions-row - [chat-id message-id] - (let [reactions (rf/sub [:chats/message-reactions message-id chat-id])] + [chat-id message-id messages-ids] + (let [reactions (if messages-ids + (mapcat #(rf/sub [:chats/message-reactions % chat-id]) messages-ids) + (rf/sub [:chats/message-reactions message-id chat-id]))] (when (seq reactions) [rn/view {:margin-left 52 :margin-bottom 12 :flex-direction :row} (for [{:keys [own emoji-id quantity emoji-reaction-id] :as emoji-reaction} reactions] @@ -28,8 +30,12 @@ :accessibility-label (str "emoji-reaction-" emoji-id)}]]) [quo/add-reaction {:on-press (fn [] - (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch - [:bottom-sheet/show-sheet - {:content (fn [] [drawers/reactions - {:chat-id chat-id :message-id message-id}])}]))}]]))) + ;; issue: https://github.com/status-im/status-mobile/issues/14995 + (if messages-ids + (js/alert "Reactions for albums is not yet supported") + (do + (rf/dispatch [:dismiss-keyboard]) + (rf/dispatch + [:bottom-sheet/show-sheet + {:content (fn [] [drawers/reactions + {:chat-id chat-id :message-id message-id}])}]))))}]]))) diff --git a/src/status_im2/contexts/chat/messages/content/view.cljs b/src/status_im2/contexts/chat/messages/content/view.cljs index f5ea43041c..8de12d1b53 100644 --- a/src/status_im2/contexts/chat/messages/content/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/view.cljs @@ -83,6 +83,13 @@ (rf/dispatch [:bottom-sheet/show-sheet {:content (drawers/reactions-and-actions message-data context)}])) +(defn on-long-press + [message-data context] + (rf/dispatch [:dismiss-keyboard]) + (rf/dispatch [:bottom-sheet/show-sheet + {:content (drawers/reactions-and-actions message-data + context)}])) + (defn user-message-content [{:keys [content-type quoted-message content outgoing outgoing-status] :as message-data} {:keys [chat-id] :as context}] @@ -112,11 +119,7 @@ (reset! show-delivery-state? true) (js/setTimeout #(reset! show-delivery-state? false) delivery-state-showing-time-ms))) - :on-long-press (fn [] - (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch [:bottom-sheet/show-sheet - {:content (drawers/reactions-and-actions message-data - context)}]))} + :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} quoted-message]) @@ -130,21 +133,23 @@ [author message-data] (case content-type - constants/content-type-text [not-implemented/not-implemented - [content.text/text-content message-data context]] + constants/content-type-text + [not-implemented/not-implemented [content.text/text-content message-data context]] - constants/content-type-emoji [not-implemented/not-implemented - [old-message/emoji message-data]] + constants/content-type-emoji + [not-implemented/not-implemented [old-message/emoji message-data]] - constants/content-type-sticker [not-implemented/not-implemented - [old-message/sticker message-data]] + constants/content-type-sticker + [not-implemented/not-implemented [old-message/sticker message-data]] - constants/content-type-image [image/image-message 0 message-data context] + constants/content-type-audio + [not-implemented/not-implemented [old-message/audio message-data]] - constants/content-type-audio [not-implemented/not-implemented - [old-message/audio message-data]] + constants/content-type-image + [image/image-message 0 message-data context on-long-press] - constants/content-type-album [album/album-message message-data context] + constants/content-type-album + [album/album-message message-data context on-long-press] [not-implemented/not-implemented [content.unknown/unknown-content message-data]]) (when @show-delivery-state? @@ -152,7 +157,7 @@ (defn message-with-reactions [{:keys [pinned pinned-by mentioned in-pinned-view? content-type - last-in-group? message-id] + last-in-group? message-id messages-ids] :as message-data} {:keys [chat-id] :as context}] [rn/view @@ -165,4 +170,4 @@ content-type) [system-message-content message-data] [user-message-content message-data context]) - [reactions/message-reactions-row chat-id message-id]]) + [reactions/message-reactions-row chat-id message-id messages-ids]]) diff --git a/src/status_im2/contexts/chat/photo_selector/style.cljs b/src/status_im2/contexts/chat/photo_selector/style.cljs index 98bb5f5375..f49934a7ad 100644 --- a/src/status_im2/contexts/chat/photo_selector/style.cljs +++ b/src/status_im2/contexts/chat/photo_selector/style.cljs @@ -29,7 +29,8 @@ :position :absolute :right 20}) -(def camera-button-container +(defn close-button-container + [] {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80) :width 32 :height 32 diff --git a/src/status_im2/contexts/chat/photo_selector/view.cljs b/src/status_im2/contexts/chat/photo_selector/view.cljs index a91eece60c..8b62409184 100644 --- a/src/status_im2/contexts/chat/photo_selector/view.cljs +++ b/src/status_im2/contexts/chat/photo_selector/view.cljs @@ -130,7 +130,7 @@ [rn/touchable-opacity {:active-opacity 1 :on-press #(rf/dispatch [:navigate-back]) - :style style/camera-button-container} + :style (style/close-button-container)} [quo/icon :i/close {:size 20 :color (colors/theme-colors colors/black colors/white)}]]) [album-title true selected-album selected temporary-selected] diff --git a/src/status_im2/subs/chat/messages.cljs b/src/status_im2/subs/chat/messages.cljs index 580cea89d0..5f7641ee75 100644 --- a/src/status_im2/subs/chat/messages.cljs +++ b/src/status_im2/subs/chat/messages.cljs @@ -111,22 +111,39 @@ (defn albumize-messages [messages] (get - (reduce (fn [{:keys [messages albums]} message] - (let [album-id (:album-id message) - albums (cond-> albums album-id (update album-id conj message)) - messages (if album-id - (conj (filterv #(not= album-id (:album-id %)) messages) - {:album (get albums album-id) - :album-id album-id - :albumize? (:albumize? message) - :message-id album-id - :content-type constants/content-type-album}) - (conj messages message))] - {:messages messages - :albums albums})) - {:messages [] - :albums {}} - messages) + (reduce + (fn [{:keys [messages albums]} message] + (let [album-id (:album-id message) + ;; check if this image is the first image in an album (which is not albumized yet) + add-text? (when (and album-id (not (:albumize? message)) (> (count (get albums album-id)) 0)) + (not (some #(= false %) + (mapv #(< (:timestamp message) (:timestamp %)) + (get albums album-id))))) + albums (cond-> albums album-id (update album-id conj message)) + ;; keep text of the first album image only + message (if (or add-text? (<= (count (get albums album-id)) 1)) + message + (assoc-in message [:content :text] nil)) + messages (if (and (> (count (get albums album-id)) 1) (:albumize? message)) + (conj (filterv #(not= album-id (:album-id %)) messages) + {:album (get albums album-id) + :album-id album-id + :albumize? (:albumize? message) + :messages-ids (mapv :message-id (get albums album-id)) + :message-id album-id + :content-type constants/content-type-album}) + ;; remove text of other images in an album + (if add-text? + (conj (mapv #(when (= (:album-id %) album-id) + (assoc-in % [:content :text] nil)) + messages) + message) + (conj messages message)))] + {:messages messages + :albums albums})) + {:messages [] + :albums {}} + messages) :messages)) (re-frame/reg-sub diff --git a/src/status_im2/subs/chat/messages_test.cljs b/src/status_im2/subs/chat/messages_test.cljs index 121f1bd6ed..94b8c8b87b 100644 --- a/src/status_im2/subs/chat/messages_test.cljs +++ b/src/status_im2/subs/chat/messages_test.cljs @@ -10,7 +10,9 @@ [{:message-id "0x111" :album-id "abc" :albumize? true} {:message-id "0x222" :album-id "abc" :albumize? true} {:message-id "0x333" :album-id "abc" :albumize? true} - {:message-id "0x444" :album-id "abc" :albumize? true}]) + {:message-id "0x444" :album-id "abc" :albumize? true} + {:message-id "0x555" :album-id "edf" :timestamp 10 :content {:text "Wassup!"}} + {:message-id "0x666" :album-id "edf" :timestamp 20 :content {:text "Wassup!"}}]) (def messages-albumized-state [{:album [{:message-id "0x444" :album-id "abc" :albumize? true} @@ -20,7 +22,10 @@ :album-id "abc" :albumize? true :message-id "abc" - :content-type constants/content-type-album}]) + :messages-ids ["0x444" "0x333" "0x222" "0x111"] + :content-type constants/content-type-album} + {:message-id "0x555" :album-id "edf" :timestamp 10 :content {:text "Wassup!"}} + {:message-id "0x666" :album-id "edf" :timestamp 20 :content {:text nil}}]) (deftest albumize-messages (testing "Finding albums in the messages list"