Show message timestamps on tap, remove from bubbles
Signed-off-by: andrey <motor4ik@gmail.com>
This commit is contained in:
parent
b18d7b6a2a
commit
f3533c5f99
|
@ -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]]))))
|
|
||||||
|
|
|
@ -24,42 +24,64 @@
|
||||||
[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-status [{:keys [outgoing content outgoing-status pinned edited-at in-popover?]}]
|
||||||
|
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
||||||
|
[react/view
|
||||||
|
{:align-self :flex-end
|
||||||
|
:position :absolute
|
||||||
|
:bottom 9 ; 6 Bubble bottom, 3 message baseline
|
||||||
|
(if (:rtl? content) :left :right) 0
|
||||||
|
:flex-direction :row
|
||||||
|
:align-items :flex-end}
|
||||||
|
(when outgoing
|
||||||
|
[icons/icon (case outgoing-status
|
||||||
|
:sending :tiny-icons/tiny-pending
|
||||||
|
:sent :tiny-icons/tiny-sent
|
||||||
|
:not-sent :tiny-icons/tiny-warning
|
||||||
|
:delivered :tiny-icons/tiny-delivered
|
||||||
|
:tiny-icons/tiny-pending)
|
||||||
|
{:width 16
|
||||||
|
:height 12
|
||||||
|
:color (if pinned colors/gray colors/white)
|
||||||
|
:accessibility-label (name outgoing-status)}])
|
||||||
|
(when edited-at [react/text {:style (style/message-status-text (and outgoing (not pinned)))} edited-at-text])]))
|
||||||
|
|
||||||
(defn message-timestamp
|
(defn message-timestamp
|
||||||
([message]
|
[{:keys [timestamp-str in-popover?] :as message} show-timestamp?]
|
||||||
[message-timestamp message false])
|
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
||||||
([{:keys [timestamp-str outgoing content outgoing-status pinned edited-at in-popover?]} justify-timestamp?]
|
(let [anim-opacity (animation/create-value 0)]
|
||||||
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
[react/animated-view {:style (style/message-timestamp-wrapper message) :opacity anim-opacity}
|
||||||
[react/view (when justify-timestamp?
|
(when @show-timestamp? (message-timestamp-anim anim-opacity show-timestamp?))
|
||||||
{:align-self :flex-end
|
[react/text {:style (style/message-timestamp-text)}
|
||||||
:position :absolute
|
timestamp-str]])))
|
||||||
:bottom 9 ; 6 Bubble bottom, 3 message baseline
|
|
||||||
(if (:rtl? content) :left :right) 0
|
|
||||||
:flex-direction :row
|
|
||||||
:align-items :flex-end})
|
|
||||||
(when (and outgoing justify-timestamp?)
|
|
||||||
[icons/icon (case outgoing-status
|
|
||||||
:sending :tiny-icons/tiny-pending
|
|
||||||
:sent :tiny-icons/tiny-sent
|
|
||||||
:not-sent :tiny-icons/tiny-warning
|
|
||||||
:delivered :tiny-icons/tiny-delivered
|
|
||||||
:tiny-icons/tiny-pending)
|
|
||||||
{:width 16
|
|
||||||
:height 12
|
|
||||||
:color (if pinned colors/gray colors/white)
|
|
||||||
:accessibility-label (name outgoing-status)}])
|
|
||||||
[react/text {:style (style/message-timestamp-text (and outgoing (not pinned)))}
|
|
||||||
(str
|
|
||||||
timestamp-str
|
|
||||||
(when edited-at edited-at-text))]])))
|
|
||||||
|
|
||||||
(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,40 +450,41 @@
|
||||||
(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 (style/message-view message)}
|
[react/view (style/message-view-wrapper outgoing)
|
||||||
[react/view {:style (style/message-view-content)
|
[message-timestamp message show-timestamp?]
|
||||||
:max-height max-height}
|
[react/view {:style (style/message-view message)}
|
||||||
(let [response-to (:response-to content)]
|
[react/view {:style (style/message-view-content)
|
||||||
[react/view {:on-layout
|
:max-height max-height}
|
||||||
#(when (and (> (.-nativeEvent.layout.height ^js %) max-message-height-px)
|
(let [response-to (:response-to content)]
|
||||||
(not @collapsible?)
|
[react/view {:on-layout
|
||||||
(not outgoing)
|
#(when (and (> (.-nativeEvent.layout.height ^js %) max-message-height-px)
|
||||||
(not modal))
|
(not @collapsible?)
|
||||||
(reset! collapsed? true)
|
(not outgoing)
|
||||||
(reset! collapsible? true))}
|
(not modal))
|
||||||
(when (and (seq response-to) (:quoted-message message))
|
(reset! collapsed? true)
|
||||||
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
(reset! collapsible? true))}
|
||||||
[render-parsed-text-with-timestamp message (:parsed-text content)]])
|
(when (and (seq response-to) (:quoted-message message))
|
||||||
(when-not @collapsed?
|
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
||||||
[message-timestamp message true])
|
[render-parsed-text-with-message-status message (:parsed-text content)]])
|
||||||
(when (and @collapsible? (not modal))
|
(when-not @collapsible? [message-status message])
|
||||||
(if @collapsed?
|
(when (and @collapsible? (not modal))
|
||||||
(let [color (if pinned colors/pin-background (if mentioned colors/mentioned-background colors/blue-light))]
|
(if @collapsed?
|
||||||
[react/touchable-highlight
|
(let [color (if pinned colors/pin-background (if mentioned colors/mentioned-background colors/blue-light))]
|
||||||
{:on-press #(swap! collapsed? not)
|
[react/touchable-highlight
|
||||||
:style {:position :absolute :bottom 0 :left 0 :right 0 :height 72}}
|
{:on-press #(swap! collapsed? not)
|
||||||
[react/linear-gradient {:colors [(str color "00") color]
|
:style {:position :absolute :bottom 0 :left 0 :right 0 :height 72}}
|
||||||
:start {:x 0 :y 0} :end {:x 0 :y 0.9}}
|
[react/linear-gradient {:colors [(str color "00") color]
|
||||||
[react/view {:height 72 :align-self :center :justify-content :flex-end
|
:start {:x 0 :y 0} :end {:x 0 :y 0.9}}
|
||||||
:padding-bottom 10}
|
[react/view {:height 72 :align-self :center :justify-content :flex-end
|
||||||
[react/view (style/collapse-button)
|
:padding-bottom 10}
|
||||||
[icons/icon :main-icons/dropdown
|
[react/view (style/collapse-button)
|
||||||
{:color colors/white}]]]]])
|
[icons/icon :main-icons/dropdown
|
||||||
[react/touchable-highlight {:on-press #(swap! collapsed? not)
|
{:color colors/white}]]]]])
|
||||||
:style {:align-self :center :margin 5}}
|
[react/touchable-highlight {:on-press #(swap! collapsed? not)
|
||||||
[react/view (style/collapse-button)
|
:style {:align-self :center :margin 5}}
|
||||||
[icons/icon :main-icons/dropdown-up
|
[react/view (style/collapse-button)
|
||||||
{:color colors/white}]]]))]]]))))
|
[icons/icon :main-icons/dropdown-up
|
||||||
|
{: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,33 +509,37 @@
|
||||||
(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)]
|
||||||
[react/touchable-highlight (when-not modal
|
(fn [] [message-content-wrapper message
|
||||||
{:disabled in-popover?
|
[react/touchable-highlight (when-not modal
|
||||||
:on-press (fn []
|
{:disabled in-popover?
|
||||||
(react/dismiss-keyboard!))
|
:on-press (fn []
|
||||||
:delay-long-press 100
|
(react/dismiss-keyboard!)
|
||||||
:on-long-press (fn []
|
(reset! show-timestamp? true))
|
||||||
(on-long-press
|
:delay-long-press 100
|
||||||
(concat
|
:on-long-press (fn []
|
||||||
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
(on-long-press
|
||||||
:id :reply
|
(concat
|
||||||
:label (i18n/label :t/message-reply)}
|
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
||||||
{:on-press #(react/copy-to-clipboard (get content :text))
|
:id :reply
|
||||||
:id :copy
|
:label (i18n/label :t/message-reply)}
|
||||||
:label (i18n/label :t/sharing-copy-to-clipboard)}]
|
{:on-press #(react/copy-to-clipboard (get content :text))
|
||||||
(when message-pin-enabled [{:on-press #(pin-message message)
|
:id :copy
|
||||||
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))})
|
:label (i18n/label :t/sharing-copy-to-clipboard)}]
|
||||||
[react/view (style/message-view message)
|
(when message-pin-enabled [{:on-press #(pin-message message)
|
||||||
[react/view {:style (style/message-view-content)}
|
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))})
|
||||||
[react/view {:style (style/style-message-text outgoing)}
|
[react/view (style/message-view-wrapper outgoing)
|
||||||
(when (and (seq response-to) (:quoted-message message))
|
[message-timestamp message show-timestamp?]
|
||||||
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
[react/view (style/message-view message)
|
||||||
[react/text {:style (style/emoji-message message)}
|
[react/view {:style (style/message-view-content)}
|
||||||
(:text content)]]
|
[react/view {:style (style/style-message-text outgoing)}
|
||||||
[message-timestamp message]]]]
|
(when (and (seq response-to) (:quoted-message message))
|
||||||
reaction-picker]))
|
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
|
||||||
|
[react/text {:style (style/emoji-message message)}
|
||||||
|
(:text content)]]
|
||||||
|
[message-status message]]]]]
|
||||||
|
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)]
|
||||||
[react/touchable-highlight (when-not modal
|
(fn [] [message-content-wrapper message
|
||||||
{:on-long-press
|
[react/touchable-highlight (when-not modal
|
||||||
(fn [] (on-long-press []))})
|
{:on-long-press
|
||||||
[react/view {:style (style/message-view message) :accessibility-label :audio-message}
|
(fn [] (on-long-press []))
|
||||||
[react/view {:style (style/message-view-content)}
|
:on-press (fn []
|
||||||
[message.audio/message-content message [message-timestamp message false]]]]]
|
(reset! show-timestamp? true))})
|
||||||
reaction-picker])
|
[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-content)}
|
||||||
|
[message.audio/message-content message] [message-status message]]]]]
|
||||||
|
reaction-picker])))
|
||||||
|
|
||||||
(defmethod ->message :default [message]
|
(defmethod ->message :default [message]
|
||||||
[message-content-wrapper message
|
[message-content-wrapper message
|
||||||
|
|
|
@ -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}))
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue