fix: image actions (#14996)

* fix: image actions and reactions
This commit is contained in:
Omar Basem 2023-02-09 07:18:49 +04:00 committed by GitHub
parent 574e69acae
commit 95380175a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 139 additions and 102 deletions

View File

@ -82,7 +82,7 @@
:optimizations :simple :optimizations :simple
:target :node-test :target :node-test
;; When running tests without a REPL you can uncomment below line to `make test-watch` a specific file ;; 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 :main
status-im.test-runner/main status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl ;; set :ui-driven to true to let shadow-cljs inject node-repl

View File

@ -214,8 +214,8 @@
{2 {0 image-size {2 {0 image-size
1 image-size} 1 image-size}
3 {0 [(* image-size 2) (* image-size 1.5)] 3 {0 [(* image-size 2) (* image-size 1.5)]
1 [(- image-size 1) (- (* image-size 0.67) 1)] 1 [(- image-size 0.5) (- (* image-size 0.67) 1)]
2 [(- image-size 1) (- (* image-size 0.67) 1)]} 2 [(- image-size 0.5) (- (* image-size 0.67) 1)]}
4 {0 image-size 4 {0 image-size
1 image-size 1 image-size
2 image-size 2 image-size

View File

@ -14,12 +14,12 @@
:overflow :hidden}) :overflow :hidden})
(defn image (defn image
[dimensions index portrait?] [dimensions index portrait? images-count]
{:width (:width dimensions) {:width (:width dimensions)
:height (:height dimensions) :height (:height dimensions)
:margin-left (when (or (and (not= index 0) (not= index 2) (not= count 3)) :margin-left (when (or (and (not= index 0) (not= index 2) (not= images-count 3))
(= count 3) (and (not portrait?) (= images-count 3) (= index 2))
(and portrait? (= index 2))) (and portrait? (= images-count 3) (> index 0)))
1) 1)
:margin-bottom (when (< index 2) 1) :margin-bottom (when (< index 2) 1)
:align-self :flex-start}) :align-self :flex-start})

View File

@ -5,8 +5,7 @@
[react-native.fast-image :as fast-image] [react-native.fast-image :as fast-image]
[status-im2.contexts.chat.messages.content.album.style :as style] [status-im2.contexts.chat.messages.content.album.style :as style]
[status-im2.constants :as constants] [status-im2.constants :as constants]
[utils.re-frame :as rf] [utils.re-frame :as rf]))
[status-im2.contexts.chat.messages.content.image.view :as image]))
(def rectangular-style-count 3) (def rectangular-style-count 3)
@ -17,7 +16,7 @@
{:width (second size-arr) :height (first size-arr) :album-style album-style})) {:width (second size-arr) :height (first size-arr) :album-style album-style}))
(defn album-message (defn album-message
[{:keys [albumize?] :as message}] [message]
(let [shared-element-id (rf/sub [:shared-element-id]) (let [shared-element-id (rf/sub [:shared-element-id])
first-image (first (:album message)) first-image (first (:album message))
album-style (if (> (:image-width first-image) (:image-height first-image)) album-style (if (> (:image-width first-image) (:image-height first-image))
@ -26,8 +25,12 @@
images-count (count (:album message)) images-count (count (:album message))
;; album images are always square, except when we have 3 images, then they must be rectangular ;; album images are always square, except when we have 3 images, then they must be rectangular
;; (portrait or landscape) ;; (portrait or landscape)
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))] portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))
(if (and albumize? (> images-count 1)) 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 [rn/view
{:style (style/album-container portrait?)} {:style (style/album-container portrait?)}
(map-indexed (map-indexed
@ -40,13 +43,15 @@
[rn/touchable-opacity [rn/touchable-opacity
{:key (:message-id item) {:key (:message-id item)
:active-opacity 1 :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 [] :on-press (fn []
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]) (rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)])
(js/setTimeout #(rf/dispatch [:navigate-to :lightbox (js/setTimeout #(rf/dispatch [:navigate-to :lightbox
{:messages (:album message) :index index}]) {:messages (:album message) :index index}])
100))} 100))}
[fast-image/fast-image [fast-image/fast-image
{:style (style/image dimensions index portrait?) {:style (style/image dimensions index portrait? images-count)
:source {:uri (:image (:content item))} :source {:uri (:image (:content item))}
:native-ID (when (and (= shared-element-id (:message-id item)) :native-ID (when (and (= shared-element-id (:message-id item))
(< index constants/max-album-photos)) (< index constants/max-album-photos))
@ -60,9 +65,4 @@
:size :heading-2 :size :heading-2
:style {:color colors/white}} :style {:color colors/white}}
(str "+" (- images-count (dec constants/max-album-photos)))]])])) (str "+" (- images-count (dec constants/max-album-photos)))]])]))
(:album message))] (:album message))]]))
[:<>
(map-indexed
(fn [index item]
[image/image-message index item])
(:album message))])))

View File

@ -1,12 +1,15 @@
(ns status-im2.contexts.chat.messages.content.image.view (ns status-im2.contexts.chat.messages.content.image.view
(:require [react-native.core :as rn] (:require
[quo2.core :as quo]
[react-native.core :as rn]
[react-native.fast-image :as fast-image] [react-native.fast-image :as fast-image]
[status-im2.constants :as constants]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn calculate-dimensions (defn calculate-dimensions
[width height] [width height]
(let [max-width (if (> width height) 320 190) (let [max-width (if (> width height) (* 2 constants/image-size) (* 1.5 constants/image-size))
max-height (if (> width height) 190 320)] max-height (if (> width height) (* 1.5 constants/image-size) (* 2 constants/image-size))]
(if (> height width) (if (> height width)
(let [calculated-height (* (min height max-height) (/ (max width max-width) width)) (let [calculated-height (* (min height max-height) (/ (max width max-width) width))
calculated-width (* (max width max-width) (/ (min height max-height) height))] calculated-width (* (max width max-width) (/ (min height max-height) height))]
@ -16,7 +19,7 @@
{:width calculated-width :height calculated-height})))) {:width calculated-width :height calculated-height}))))
(defn image-message (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)) (let [dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000))
text (:text content)] text (:text content)]
(fn [] (fn []
@ -24,7 +27,7 @@
[rn/touchable-opacity [rn/touchable-opacity
{:active-opacity 1 {:active-opacity 1
:key message-id :key message-id
:style {:margin-top (when (> index 0) 20)} :on-long-press #(on-long-press message context)
:on-press (fn [] :on-press (fn []
(rf/dispatch [:chat.ui/update-shared-element-id message-id]) (rf/dispatch [:chat.ui/update-shared-element-id message-id])
(js/setTimeout #(rf/dispatch [:navigate-to :lightbox (js/setTimeout #(rf/dispatch [:navigate-to :lightbox
@ -32,7 +35,7 @@
100))} 100))}
;; This text comp is temporary. Should later use ;; This text comp is temporary. Should later use
;; `status-im2.contexts.chat.messages.content.text.view` ;; `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 [fast-image/fast-image
{:source {:uri (:image content)} {:source {:uri (:image content)}
:style (merge dimensions {:border-radius 12}) :style (merge dimensions {:border-radius 12})

View File

@ -6,8 +6,10 @@
[status-im2.contexts.chat.messages.drawers.view :as drawers])) [status-im2.contexts.chat.messages.drawers.view :as drawers]))
(defn message-reactions-row (defn message-reactions-row
[chat-id message-id] [chat-id message-id messages-ids]
(let [reactions (rf/sub [:chats/message-reactions message-id chat-id])] (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) (when (seq reactions)
[rn/view {:margin-left 52 :margin-bottom 12 :flex-direction :row} [rn/view {:margin-left 52 :margin-bottom 12 :flex-direction :row}
(for [{:keys [own emoji-id quantity emoji-reaction-id] :as emoji-reaction} reactions] (for [{:keys [own emoji-id quantity emoji-reaction-id] :as emoji-reaction} reactions]
@ -28,8 +30,12 @@
:accessibility-label (str "emoji-reaction-" emoji-id)}]]) :accessibility-label (str "emoji-reaction-" emoji-id)}]])
[quo/add-reaction [quo/add-reaction
{:on-press (fn [] {:on-press (fn []
;; 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 [:dismiss-keyboard])
(rf/dispatch (rf/dispatch
[:bottom-sheet/show-sheet [:bottom-sheet/show-sheet
{:content (fn [] [drawers/reactions {:content (fn [] [drawers/reactions
{:chat-id chat-id :message-id message-id}])}]))}]]))) {:chat-id chat-id :message-id message-id}])}]))))}]])))

View File

@ -83,6 +83,13 @@
(rf/dispatch [:bottom-sheet/show-sheet (rf/dispatch [:bottom-sheet/show-sheet
{:content (drawers/reactions-and-actions message-data context)}])) {: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 (defn user-message-content
[{:keys [content-type quoted-message content outgoing outgoing-status] :as message-data} [{:keys [content-type quoted-message content outgoing outgoing-status] :as message-data}
{:keys [chat-id] :as context}] {:keys [chat-id] :as context}]
@ -112,11 +119,7 @@
(reset! show-delivery-state? true) (reset! show-delivery-state? true)
(js/setTimeout #(reset! show-delivery-state? false) (js/setTimeout #(reset! show-delivery-state? false)
delivery-state-showing-time-ms))) delivery-state-showing-time-ms)))
:on-long-press (fn [] :on-long-press #(on-long-press message-data context)}
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:bottom-sheet/show-sheet
{:content (drawers/reactions-and-actions message-data
context)}]))}
[rn/view {:style {:padding-vertical 8}} [rn/view {:style {:padding-vertical 8}}
(when (and (seq response-to) quoted-message) (when (and (seq response-to) quoted-message)
[old-message/quoted-message {:message-id response-to :chat-id chat-id} quoted-message]) [old-message/quoted-message {:message-id response-to :chat-id chat-id} quoted-message])
@ -130,21 +133,23 @@
[author message-data] [author message-data]
(case content-type (case content-type
constants/content-type-text [not-implemented/not-implemented constants/content-type-text
[content.text/text-content message-data context]] [not-implemented/not-implemented [content.text/text-content message-data context]]
constants/content-type-emoji [not-implemented/not-implemented constants/content-type-emoji
[old-message/emoji message-data]] [not-implemented/not-implemented [old-message/emoji message-data]]
constants/content-type-sticker [not-implemented/not-implemented constants/content-type-sticker
[old-message/sticker message-data]] [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 constants/content-type-image
[old-message/audio message-data]] [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]]) [not-implemented/not-implemented [content.unknown/unknown-content message-data]])
(when @show-delivery-state? (when @show-delivery-state?
@ -152,7 +157,7 @@
(defn message-with-reactions (defn message-with-reactions
[{:keys [pinned pinned-by mentioned in-pinned-view? content-type [{: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} :as message-data}
{:keys [chat-id] :as context}] {:keys [chat-id] :as context}]
[rn/view [rn/view
@ -165,4 +170,4 @@
content-type) content-type)
[system-message-content message-data] [system-message-content message-data]
[user-message-content message-data context]) [user-message-content message-data context])
[reactions/message-reactions-row chat-id message-id]]) [reactions/message-reactions-row chat-id message-id messages-ids]])

View File

@ -29,7 +29,8 @@
:position :absolute :position :absolute
:right 20}) :right 20})
(def camera-button-container (defn close-button-container
[]
{:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80) {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
:width 32 :width 32
:height 32 :height 32

View File

@ -130,7 +130,7 @@
[rn/touchable-opacity [rn/touchable-opacity
{:active-opacity 1 {:active-opacity 1
:on-press #(rf/dispatch [:navigate-back]) :on-press #(rf/dispatch [:navigate-back])
:style style/camera-button-container} :style (style/close-button-container)}
[quo/icon :i/close [quo/icon :i/close
{:size 20 :color (colors/theme-colors colors/black colors/white)}]]) {:size 20 :color (colors/theme-colors colors/black colors/white)}]])
[album-title true selected-album selected temporary-selected] [album-title true selected-album selected temporary-selected]

View File

@ -111,17 +111,34 @@
(defn albumize-messages (defn albumize-messages
[messages] [messages]
(get (get
(reduce (fn [{:keys [messages albums]} message] (reduce
(fn [{:keys [messages albums]} message]
(let [album-id (:album-id 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)) albums (cond-> albums album-id (update album-id conj message))
messages (if album-id ;; 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) (conj (filterv #(not= album-id (:album-id %)) messages)
{:album (get albums album-id) {:album (get albums album-id)
:album-id album-id :album-id album-id
:albumize? (:albumize? message) :albumize? (:albumize? message)
:messages-ids (mapv :message-id (get albums album-id))
:message-id album-id :message-id album-id
:content-type constants/content-type-album}) :content-type constants/content-type-album})
(conj messages message))] ;; 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 {:messages messages
:albums albums})) :albums albums}))
{:messages [] {:messages []

View File

@ -10,7 +10,9 @@
[{:message-id "0x111" :album-id "abc" :albumize? true} [{:message-id "0x111" :album-id "abc" :albumize? true}
{:message-id "0x222" :album-id "abc" :albumize? true} {:message-id "0x222" :album-id "abc" :albumize? true}
{:message-id "0x333" :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 (def messages-albumized-state
[{:album [{:message-id "0x444" :album-id "abc" :albumize? true} [{:album [{:message-id "0x444" :album-id "abc" :albumize? true}
@ -20,7 +22,10 @@
:album-id "abc" :album-id "abc"
:albumize? true :albumize? true
:message-id "abc" :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 (deftest albumize-messages
(testing "Finding albums in the messages list" (testing "Finding albums in the messages list"