Show message timestamps on tap, remove from bubbles

Signed-off-by: andrey <motor4ik@gmail.com>
This commit is contained in:
Ajay Sivan 2021-12-14 12:39:10 +05:30 committed by andrey
parent b18d7b6a2a
commit f3533c5f99
No known key found for this signature in database
GPG Key ID: 89B67245FD2F0272
4 changed files with 172 additions and 113 deletions

View File

@ -181,7 +181,7 @@
:message-id @current-player-message-id})) :message-id @current-player-message-id}))
nil) nil)
(defview message-content [{:keys [audio audio-duration-ms message-id outgoing]} timestamp-view] (defview message-content [{:keys [audio audio-duration-ms message-id outgoing]}]
(letsubs [state (reagent/atom nil) (letsubs [state (reagent/atom nil)
progress (reagent/atom 0) progress (reagent/atom 0)
progress-anim (anim/create-value 0) progress-anim (anim/create-value 0)
@ -223,5 +223,4 @@
(#{:playing :paused :seeking} (:general @state)) @progress (#{:playing :paused :seeking} (:general @state)) @progress
:else (:duration @state)) :else (:duration @state))
s (quot time 1000)] s (quot time 1000)]
(gstring/format "%02d:%02d" (quot s 60) (mod s 60)))] (gstring/format "%02d:%02d" (quot s 60) (mod s 60)))]]]))))
timestamp-view]]))))

View File

@ -24,28 +24,44 @@
[status-im.ui.screens.chat.components.reply :as components.reply] [status-im.ui.screens.chat.components.reply :as components.reply]
[status-im.ui.screens.chat.message.link-preview :as link-preview] [status-im.ui.screens.chat.message.link-preview :as link-preview]
[status-im.ui.screens.communities.icon :as communities.icon] [status-im.ui.screens.communities.icon :as communities.icon]
[status-im.ui.components.animation :as animation]
[status-im.chat.models.pin-message :as models.pin-message]) [status-im.chat.models.pin-message :as models.pin-message])
(:require-macros [status-im.utils.views :refer [defview letsubs]])) (:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn message-timestamp-anim
[anim-opacity show-timestamp?]
(animation/start
(animation/anim-sequence
[(animation/timing
anim-opacity
{:toValue 1
:duration 100
:easing (.-ease ^js animation/easing)
:useNativeDriver true})
(animation/timing
anim-opacity
{:toValue 0
:delay 2000
:duration 100
:easing (.-ease ^js animation/easing)
:useNativeDriver true})]) #(reset! show-timestamp? false)))
(defview mention-element [from] (defview mention-element [from]
(letsubs [contact-name [:contacts/contact-name-by-identity from]] (letsubs [contact-name [:contacts/contact-name-by-identity from]]
contact-name)) contact-name))
(def edited-at-text (str " ⌫ " (i18n/label :t/edited))) (def edited-at-text (str " ⌫ " (i18n/label :t/edited)))
(defn message-timestamp (defn message-status [{:keys [outgoing content outgoing-status pinned edited-at in-popover?]}]
([message]
[message-timestamp message false])
([{:keys [timestamp-str outgoing content outgoing-status pinned edited-at in-popover?]} justify-timestamp?]
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover (when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
[react/view (when justify-timestamp? [react/view
{:align-self :flex-end {:align-self :flex-end
:position :absolute :position :absolute
:bottom 9 ; 6 Bubble bottom, 3 message baseline :bottom 9 ; 6 Bubble bottom, 3 message baseline
(if (:rtl? content) :left :right) 0 (if (:rtl? content) :left :right) 0
:flex-direction :row :flex-direction :row
:align-items :flex-end}) :align-items :flex-end}
(when (and outgoing justify-timestamp?) (when outgoing
[icons/icon (case outgoing-status [icons/icon (case outgoing-status
:sending :tiny-icons/tiny-pending :sending :tiny-icons/tiny-pending
:sent :tiny-icons/tiny-sent :sent :tiny-icons/tiny-sent
@ -56,10 +72,16 @@
:height 12 :height 12
:color (if pinned colors/gray colors/white) :color (if pinned colors/gray colors/white)
:accessibility-label (name outgoing-status)}]) :accessibility-label (name outgoing-status)}])
[react/text {:style (style/message-timestamp-text (and outgoing (not pinned)))} (when edited-at [react/text {:style (style/message-status-text (and outgoing (not pinned)))} edited-at-text])]))
(str
timestamp-str (defn message-timestamp
(when edited-at edited-at-text))]]))) [{:keys [timestamp-str in-popover?] :as message} show-timestamp?]
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
(let [anim-opacity (animation/create-value 0)]
[react/animated-view {:style (style/message-timestamp-wrapper message) :opacity anim-opacity}
(when @show-timestamp? (message-timestamp-anim anim-opacity show-timestamp?))
[react/text {:style (style/message-timestamp-text)}
timestamp-str]])))
(defview quoted-message (defview quoted-message
[_ {:keys [from parsed-text image]} outgoing current-public-key public? pinned] [_ {:keys [from parsed-text image]} outgoing current-public-key public? pinned]
@ -168,19 +190,19 @@
(defn render-parsed-text [message tree] (defn render-parsed-text [message tree]
(reduce (fn [acc e] (render-block message acc e)) [:<>] tree)) (reduce (fn [acc e] (render-block message acc e)) [:<>] tree))
(defn render-parsed-text-with-timestamp [{:keys [timestamp-str outgoing edited-at in-popover?] :as message} tree] (defn render-parsed-text-with-message-status [{:keys [outgoing edited-at in-popover?] :as message} tree]
(let [elements (render-parsed-text message tree) (let [elements (render-parsed-text message tree)
timestamp [react/text {:style (style/message-timestamp-placeholder)} message-status [react/text {:style (style/message-status-placeholder)}
(str (if (and outgoing (not in-popover?)) " " " ") (when-not in-popover? (str timestamp-str (when edited-at edited-at-text))))] (str (if (and outgoing (not in-popover?)) " " " ") (when (and (not in-popover?) edited-at) edited-at-text))]
last-element (peek elements)] last-element (peek elements)]
;; Using `nth` here as slightly faster than `first`, roughly 30% ;; Using `nth` here as slightly faster than `first`, roughly 30%
;; It's worth considering pure js structures for this code path as ;; It's worth considering pure js structures for this code path as
;; it's perfomance critical ;; it's perfomance critical
(if (= react/text-class (nth last-element 0)) (if (= react/text-class (nth last-element 0))
;; Append timestamp to last text ;; Append message status to last text
(conj (pop elements) (conj last-element timestamp)) (conj (pop elements) (conj last-element message-status))
;; Append timestamp to new block ;; Append message status to new block
(conj elements timestamp)))) (conj elements message-status))))
(defn unknown-content-type (defn unknown-content-type
[{:keys [outgoing content-type content] :as message}] [{:keys [outgoing content-type content] :as message}]
@ -409,7 +431,8 @@
(defn collapsible-text-message [{:keys [mentioned]} _] (defn collapsible-text-message [{:keys [mentioned]} _]
(let [collapsed? (reagent/atom false) (let [collapsed? (reagent/atom false)
collapsible? (reagent/atom false)] collapsible? (reagent/atom false)
show-timestamp? (reagent/atom false)]
(fn [{:keys [content outgoing current-public-key public? pinned in-popover?] :as message} on-long-press modal] (fn [{:keys [content outgoing current-public-key public? pinned in-popover?] :as message} on-long-press modal]
(let [max-height (when-not (or outgoing modal) (let [max-height (when-not (or outgoing modal)
(if @collapsible? (if @collapsible?
@ -418,7 +441,8 @@
[react/touchable-highlight [react/touchable-highlight
(when-not modal (when-not modal
{:on-press (fn [_] {:on-press (fn [_]
(react/dismiss-keyboard!)) (react/dismiss-keyboard!)
(reset! show-timestamp? true))
:delay-long-press 100 :delay-long-press 100
:on-long-press (fn [] :on-long-press (fn []
(if @collapsed? (if @collapsed?
@ -426,6 +450,8 @@
(js/setTimeout #(on-long-press-fn on-long-press message content) 200)) (js/setTimeout #(on-long-press-fn on-long-press message content) 200))
(on-long-press-fn on-long-press message content))) (on-long-press-fn on-long-press message content)))
:disabled in-popover?}) :disabled in-popover?})
[react/view (style/message-view-wrapper outgoing)
[message-timestamp message show-timestamp?]
[react/view {:style (style/message-view message)} [react/view {:style (style/message-view message)}
[react/view {:style (style/message-view-content) [react/view {:style (style/message-view-content)
:max-height max-height} :max-height max-height}
@ -439,9 +465,8 @@
(reset! collapsible? true))} (reset! collapsible? true))}
(when (and (seq response-to) (:quoted-message message)) (when (and (seq response-to) (:quoted-message message))
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned]) [quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
[render-parsed-text-with-timestamp message (:parsed-text content)]]) [render-parsed-text-with-message-status message (:parsed-text content)]])
(when-not @collapsed? (when-not @collapsible? [message-status message])
[message-timestamp message true])
(when (and @collapsible? (not modal)) (when (and @collapsible? (not modal))
(if @collapsed? (if @collapsed?
(let [color (if pinned colors/pin-background (if mentioned colors/mentioned-background colors/blue-light))] (let [color (if pinned colors/pin-background (if mentioned colors/mentioned-background colors/blue-light))]
@ -459,7 +484,7 @@
:style {:align-self :center :margin 5}} :style {:align-self :center :margin 5}}
[react/view (style/collapse-button) [react/view (style/collapse-button)
[icons/icon :main-icons/dropdown-up [icons/icon :main-icons/dropdown-up
{:color colors/white}]]]))]]])))) {:color colors/white}]]]))]]]]))))
(defmethod ->message constants/content-type-text (defmethod ->message constants/content-type-text
[message {:keys [on-long-press modal] :as reaction-picker}] [message {:keys [on-long-press modal] :as reaction-picker}]
@ -484,12 +509,14 @@
(defmethod ->message constants/content-type-emoji (defmethod ->message constants/content-type-emoji
[{:keys [content current-public-key outgoing public? pinned in-popover? message-pin-enabled] :as message} {:keys [on-long-press modal] [{:keys [content current-public-key outgoing public? pinned in-popover? message-pin-enabled] :as message} {:keys [on-long-press modal]
:as reaction-picker}] :as reaction-picker}]
(let [response-to (:response-to content)] (let [response-to (:response-to content)
[message-content-wrapper message show-timestamp? (reagent/atom false)]
(fn [] [message-content-wrapper message
[react/touchable-highlight (when-not modal [react/touchable-highlight (when-not modal
{:disabled in-popover? {:disabled in-popover?
:on-press (fn [] :on-press (fn []
(react/dismiss-keyboard!)) (react/dismiss-keyboard!)
(reset! show-timestamp? true))
:delay-long-press 100 :delay-long-press 100
:on-long-press (fn [] :on-long-press (fn []
(on-long-press (on-long-press
@ -502,6 +529,8 @@
:label (i18n/label :t/sharing-copy-to-clipboard)}] :label (i18n/label :t/sharing-copy-to-clipboard)}]
(when message-pin-enabled [{:on-press #(pin-message message) (when message-pin-enabled [{:on-press #(pin-message message)
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))}) :label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))})
[react/view (style/message-view-wrapper outgoing)
[message-timestamp message show-timestamp?]
[react/view (style/message-view message) [react/view (style/message-view message)
[react/view {:style (style/message-view-content)} [react/view {:style (style/message-view-content)}
[react/view {:style (style/style-message-text outgoing)} [react/view {:style (style/style-message-text outgoing)}
@ -509,8 +538,8 @@
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned]) [quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
[react/text {:style (style/emoji-message message)} [react/text {:style (style/emoji-message message)}
(:text content)]] (:text content)]]
[message-timestamp message]]]] [message-status message]]]]]
reaction-picker])) reaction-picker])))
(defmethod ->message constants/content-type-sticker (defmethod ->message constants/content-type-sticker
[{:keys [content from outgoing in-popover?] [{:keys [content from outgoing in-popover?]
@ -556,14 +585,19 @@
(defmethod ->message constants/content-type-audio [message {:keys [on-long-press modal] (defmethod ->message constants/content-type-audio [message {:keys [on-long-press modal]
:as reaction-picker}] :as reaction-picker}]
[message-content-wrapper message (let [show-timestamp? (reagent/atom false)]
(fn [] [message-content-wrapper message
[react/touchable-highlight (when-not modal [react/touchable-highlight (when-not modal
{:on-long-press {:on-long-press
(fn [] (on-long-press []))}) (fn [] (on-long-press []))
:on-press (fn []
(reset! show-timestamp? true))})
[react/view (style/message-view-wrapper (:outgoing message))
[message-timestamp message show-timestamp?]
[react/view {:style (style/message-view message) :accessibility-label :audio-message} [react/view {:style (style/message-view message) :accessibility-label :audio-message}
[react/view {:style (style/message-view-content)} [react/view {:style (style/message-view-content)}
[message.audio/message-content message [message-timestamp message false]]]]] [message.audio/message-content message] [message-status message]]]]]
reaction-picker]) reaction-picker])))
(defmethod ->message :default [message] (defmethod ->message :default [message]
[message-content-wrapper message [message-content-wrapper message

View File

@ -43,5 +43,5 @@
:justify-content :space-between}) :justify-content :space-between})
(defn timestamp [outgoing] (defn timestamp [outgoing]
(merge (message.style/message-timestamp-text outgoing) (merge (message.style/audio-message-timestamp-text outgoing)
{:margin-left 40})) {:margin-left 40}))

View File

@ -29,11 +29,33 @@
(def message-timestamp (def message-timestamp
{:font-size 10}) {:font-size 10})
(defn message-timestamp-placeholder (defn message-status-placeholder
[] []
(merge message-timestamp {:opacity 0 :color "rgba(0,0,0,0)"})) (merge message-timestamp {:opacity 0 :color "rgba(0,0,0,0)"}))
(defn message-timestamp-text (defn message-timestamp-wrapper [{:keys [last-in-group? outgoing group-chat]}]
{:justify-content :center
(if outgoing :margin-right :margin-left) 12 ;; horizontal margin is only required at the adjust side of the message.
:margin-top (if (and last-in-group?
(or outgoing
(not group-chat)))
16
0) ;; Add gap between message groups
:opacity 0})
(defn message-timestamp-text []
(merge message-timestamp
{:color colors/gray
:text-align :center}))
(defn message-status-text [outgoing]
{:font-size 10
:line-height 10
:color (if outgoing
colors/white-transparent-70-persist
colors/gray)})
(defn audio-message-timestamp-text
[outgoing] [outgoing]
(merge message-timestamp (merge message-timestamp
{:line-height 10 {:line-height 10
@ -44,7 +66,7 @@
(defn message-wrapper [{:keys [outgoing in-popover?]}] (defn message-wrapper [{:keys [outgoing in-popover?]}]
(if (and outgoing (not in-popover?)) (if (and outgoing (not in-popover?))
{:margin-left 96} {:margin-left 96}
{:margin-right 52})) {:margin-right 96}))
(defn message-author-wrapper (defn message-author-wrapper
[outgoing display-photo? in-popover?] [outgoing display-photo? in-popover?]
@ -156,10 +178,10 @@
:padding-left 3}) :padding-left 3})
(defn emoji-message (defn emoji-message
[{:keys [incoming-group]}] [{:keys [incoming-group outgoing]}]
{:font-size 28 {:font-size 28
:line-height 34 ;TODO: Smaller crops the icon on the top :line-height 34 ;TODO: Smaller crops the icon on the top
:margin-right 12 :margin-right (if outgoing 18 0) ;; Margin to display outgoing message status
:margin-top (if incoming-group 4 0)}) :margin-top (if incoming-group 4 0)})
(defn collapse-button [] (defn collapse-button []
@ -171,6 +193,10 @@
:shadow-color (:shadow-01 @colors/theme) :shadow-color (:shadow-01 @colors/theme)
:shadow-offset {:width 0 :height 4}}) :shadow-offset {:width 0 :height 4}})
(defn message-view-wrapper [outgoing]
{:align-self :flex-end
:flex-direction (if outgoing :row :row-reverse)})
(defn message-view (defn message-view
[{:keys [content-type outgoing group-chat last-in-group? mentioned pinned]}] [{:keys [content-type outgoing group-chat last-in-group? mentioned pinned]}]
(merge (merge