mirror of
https://github.com/status-im/status-mobile.git
synced 2025-01-27 08:55:39 +00:00
Show timestamp inside bubble for text messages
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
3b4d7a6a62
commit
4aaecf792b
@ -1,10 +1,10 @@
|
|||||||
(ns status-im.chat.styles.message.message
|
(ns status-im.chat.styles.message.message
|
||||||
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]])
|
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]])
|
||||||
(:require [status-im.ui.components.styles :as styles]
|
(:require [status-im.ui.components.styles :as styles]
|
||||||
|
[status-im.chat.styles.photos :as photos]
|
||||||
[status-im.ui.components.colors :as colors]
|
[status-im.ui.components.colors :as colors]
|
||||||
[status-im.constants :as constants]))
|
[status-im.constants :as constants]))
|
||||||
|
|
||||||
(def photo-size 36)
|
|
||||||
|
|
||||||
(defstyle style-message-text
|
(defstyle style-message-text
|
||||||
{:font-size 15
|
{:font-size 15
|
||||||
@ -48,13 +48,18 @@
|
|||||||
:align-self align
|
:align-self align
|
||||||
:align-items align})))
|
:align-items align})))
|
||||||
|
|
||||||
(def message-timestamp
|
(defn message-timestamp [justify-timestamp?]
|
||||||
{:margin-left 5
|
(merge {:color colors/gray
|
||||||
:margin-right 5
|
:font-size 10
|
||||||
:margin-bottom -2
|
:align-self :flex-end
|
||||||
:color colors/gray
|
:opacity 0.5}
|
||||||
:opacity 0.5
|
(when justify-timestamp? {:position :absolute
|
||||||
:align-self :flex-end})
|
:bottom 10
|
||||||
|
:right 12})))
|
||||||
|
|
||||||
|
(def message-timestamp-placeholder
|
||||||
|
(assoc (message-timestamp false)
|
||||||
|
:color styles/color-white))
|
||||||
|
|
||||||
(def selected-message
|
(def selected-message
|
||||||
{:margin-top 18
|
{:margin-top 18
|
||||||
@ -83,14 +88,9 @@
|
|||||||
:padding-right 22})
|
:padding-right 22})
|
||||||
|
|
||||||
(def message-author
|
(def message-author
|
||||||
{:width photo-size
|
{:width photos/photo-size
|
||||||
:align-self :flex-end})
|
:align-self :flex-end})
|
||||||
|
|
||||||
(def photo
|
|
||||||
{:border-radius (/ photo-size 2)
|
|
||||||
:width photo-size
|
|
||||||
:height photo-size})
|
|
||||||
|
|
||||||
(def delivery-view
|
(def delivery-view
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
:margin-top 2
|
:margin-top 2
|
||||||
@ -136,8 +136,10 @@
|
|||||||
|
|
||||||
(defn message-view
|
(defn message-view
|
||||||
[{:keys [content-type outgoing group-chat selected]}]
|
[{:keys [content-type outgoing group-chat selected]}]
|
||||||
(merge {:padding 12
|
(merge {:padding-top 6
|
||||||
:border-radius 8}
|
:padding-horizontal 12
|
||||||
|
:padding-bottom 8
|
||||||
|
:border-radius 8}
|
||||||
(when-not (= content-type constants/content-type-emoji)
|
(when-not (= content-type constants/content-type-emoji)
|
||||||
{:background-color styles/color-white})
|
{:background-color styles/color-white})
|
||||||
(when (= content-type constants/content-type-command)
|
(when (= content-type constants/content-type-command)
|
||||||
|
8
src/status_im/chat/styles/photos.cljs
Normal file
8
src/status_im/chat/styles/photos.cljs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
(ns status-im.chat.styles.photos)
|
||||||
|
|
||||||
|
(def photo-size 36)
|
||||||
|
|
||||||
|
(def photo
|
||||||
|
{:border-radius (/ photo-size 2)
|
||||||
|
:width photo-size
|
||||||
|
:height photo-size})
|
@ -12,7 +12,8 @@
|
|||||||
:background-color component.styles/chat-background})
|
:background-color component.styles/chat-background})
|
||||||
|
|
||||||
(def toolbar-container
|
(def toolbar-container
|
||||||
{})
|
{:flex 1
|
||||||
|
:flex-direction :row})
|
||||||
|
|
||||||
(def messages-container
|
(def messages-container
|
||||||
{:flex 1
|
{:flex 1
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
[status-im.chat.styles.message.message :as style]
|
[status-im.chat.styles.message.message :as style]
|
||||||
[status-im.chat.styles.message.command-pill :as pill-style]
|
[status-im.chat.styles.message.command-pill :as pill-style]
|
||||||
[status-im.chat.views.message.request-message :as request-message]
|
[status-im.chat.views.message.request-message :as request-message]
|
||||||
|
[status-im.chat.views.photos :as photos]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||||
[status-im.utils.core :as utils]
|
[status-im.utils.core :as utils]
|
||||||
@ -22,8 +23,7 @@
|
|||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.ui.components.colors :as colors]
|
[status-im.ui.components.colors :as colors]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[status-im.chat.events.console :as console]
|
[status-im.chat.events.console :as console]))
|
||||||
[status-im.react-native.resources :as resources]))
|
|
||||||
|
|
||||||
(def window-width (:width (react/get-dimensions "window")))
|
(def window-width (:width (react/get-dimensions "window")))
|
||||||
|
|
||||||
@ -81,10 +81,14 @@
|
|||||||
:font :default}
|
:font :default}
|
||||||
(or preview (str params))])])))
|
(or preview (str params))])])))
|
||||||
|
|
||||||
|
(defview message-timestamp [t justify-timestamp?]
|
||||||
|
[react/text {:style (style/message-timestamp justify-timestamp?)} t])
|
||||||
|
|
||||||
(defn message-view
|
(defn message-view
|
||||||
[{:keys [group-chat] :as message} content]
|
[{:keys [timestamp-str] :as message} content {:keys [justify-timestamp?]}]
|
||||||
[react/view (style/message-view message)
|
[react/view (style/message-view message)
|
||||||
content])
|
content
|
||||||
|
[message-timestamp timestamp-str justify-timestamp?]])
|
||||||
|
|
||||||
(def replacements
|
(def replacements
|
||||||
{"\\*[^*]+\\*" {:font-weight :bold}
|
{"\\*[^*]+\\*" {:font-weight :bold}
|
||||||
@ -162,18 +166,22 @@
|
|||||||
(autolink string event-on-press)))
|
(autolink string event-on-press)))
|
||||||
text-seq))))
|
text-seq))))
|
||||||
|
|
||||||
|
; We can't use CSS as nested Text element don't accept margins nor padding
|
||||||
|
; so we pad the invisible placeholder with some spaces to avoid having too
|
||||||
|
; close to the text.
|
||||||
|
(defn timestamp-with-padding [t]
|
||||||
|
(str " " t))
|
||||||
|
|
||||||
(def cached-parse-text (memoize parse-text))
|
(def cached-parse-text (memoize parse-text))
|
||||||
|
|
||||||
(defn text-message
|
(defn text-message
|
||||||
[{:keys [content] :as message}]
|
[{:keys [content timestamp-str] :as message}]
|
||||||
[message-view message
|
[message-view message
|
||||||
(let [parsed-text (cached-parse-text content :browse-link-from-message)]
|
(let [parsed-text (cached-parse-text content :browse-link-from-message)]
|
||||||
[react/text {:style (style/text-message message)} parsed-text])])
|
[react/text {:style (style/text-message message)}
|
||||||
|
parsed-text
|
||||||
(defn placeholder-message
|
[react/text {:style style/message-timestamp-placeholder} (timestamp-with-padding timestamp-str)]])
|
||||||
[{:keys [content] :as message}]
|
{:justify-timestamp? true}])
|
||||||
[message-view message
|
|
||||||
[react/text {:style (style/text-message message)} content]])
|
|
||||||
|
|
||||||
(defn emoji-message
|
(defn emoji-message
|
||||||
[{:keys [content] :as message}]
|
[{:keys [content] :as message}]
|
||||||
@ -204,10 +212,6 @@
|
|||||||
[wrapper message
|
[wrapper message
|
||||||
[message-view message [message-content-command message]]])
|
[message-view message [message-content-command message]]])
|
||||||
|
|
||||||
(defmethod message-content constants/content-type-placeholder
|
|
||||||
[wrapper message]
|
|
||||||
[wrapper message [placeholder-message message]])
|
|
||||||
|
|
||||||
(defmethod message-content constants/content-type-emoji
|
(defmethod message-content constants/content-type-emoji
|
||||||
[wrapper message]
|
[wrapper message]
|
||||||
[wrapper message [emoji-message message]])
|
[wrapper message [emoji-message message]])
|
||||||
@ -293,29 +297,6 @@
|
|||||||
(when outgoing
|
(when outgoing
|
||||||
[text-status status]))))))
|
[text-status status]))))))
|
||||||
|
|
||||||
(defn- photo [from photo-path]
|
|
||||||
[react/view
|
|
||||||
[react/image {:source (if (and (not (string/blank? photo-path))
|
|
||||||
(string/starts-with? photo-path "contacts://"))
|
|
||||||
(->> (string/replace photo-path #"contacts://" "")
|
|
||||||
(keyword)
|
|
||||||
(get resources/contacts))
|
|
||||||
{:uri photo-path})
|
|
||||||
:style style/photo}]])
|
|
||||||
|
|
||||||
(defview member-photo [from]
|
|
||||||
(letsubs [photo-path [:get-photo-path from]]
|
|
||||||
(photo from (if (string/blank? photo-path)
|
|
||||||
(identicon/identicon from)
|
|
||||||
photo-path))))
|
|
||||||
|
|
||||||
(defview my-photo [from]
|
|
||||||
(letsubs [{:keys [photo-path]} [:get-current-account]]
|
|
||||||
(photo from photo-path)))
|
|
||||||
|
|
||||||
(defview message-timestamp [t]
|
|
||||||
[react/text {:style style/message-timestamp} t])
|
|
||||||
|
|
||||||
(defview message-author-name [from message-username]
|
(defview message-author-name [from message-username]
|
||||||
(letsubs [username [:get-contact-name-by-identity from]]
|
(letsubs [username [:get-contact-name-by-identity from]]
|
||||||
[react/text {:style style/message-author-name} (or username
|
[react/text {:style style/message-author-name} (or username
|
||||||
@ -323,21 +304,21 @@
|
|||||||
(gfycat/generate-gfy from))])) ; TODO: We defensively generate the name for now, to be revisited when new protocol is defined
|
(gfycat/generate-gfy from))])) ; TODO: We defensively generate the name for now, to be revisited when new protocol is defined
|
||||||
|
|
||||||
(defn message-body
|
(defn message-body
|
||||||
[{:keys [timestamp-str last-in-group? first-in-group? from outgoing username] :as message} content]
|
[{:keys [last-in-group? first-in-group? group-chat from outgoing username] :as message} content]
|
||||||
[react/view (style/group-message-wrapper message)
|
[react/view (style/group-message-wrapper message)
|
||||||
[react/view (style/message-body message)
|
[react/view (style/message-body message)
|
||||||
(when (not outgoing)
|
(when (and (not outgoing)
|
||||||
|
group-chat)
|
||||||
[react/view style/message-author
|
[react/view style/message-author
|
||||||
(when last-in-group?
|
(when last-in-group?
|
||||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:show-profile from])}
|
[react/touchable-highlight {:on-press #(re-frame/dispatch [:show-profile from])}
|
||||||
[react/view
|
[react/view
|
||||||
[member-photo from]]])])
|
[photos/member-photo from]]])])
|
||||||
[react/view (style/group-message-view outgoing)
|
[react/view (style/group-message-view outgoing)
|
||||||
(when first-in-group?
|
(when first-in-group?
|
||||||
[message-author-name from username])
|
[message-author-name from username])
|
||||||
[react/view {:style (style/timestamp-content-wrapper message)}
|
[react/view {:style (style/timestamp-content-wrapper message)}
|
||||||
content
|
content]]]
|
||||||
[message-timestamp timestamp-str]]]]
|
|
||||||
[react/view style/delivery-status
|
[react/view style/delivery-status
|
||||||
[message-delivery-status message]]])
|
[message-delivery-status message]]])
|
||||||
|
|
||||||
|
23
src/status_im/chat/views/photos.cljs
Normal file
23
src/status_im/chat/views/photos.cljs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
(ns status-im.chat.views.photos
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
|
(:require [status-im.ui.components.react :as react]
|
||||||
|
[status-im.chat.styles.photos :as style]
|
||||||
|
[status-im.utils.identicon :as identicon]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[status-im.react-native.resources :as resources]))
|
||||||
|
|
||||||
|
(defn- photo [from photo-path]
|
||||||
|
[react/view
|
||||||
|
[react/image {:source (if (and (not (string/blank? photo-path))
|
||||||
|
(string/starts-with? photo-path "contacts://"))
|
||||||
|
(->> (string/replace photo-path #"contacts://" "")
|
||||||
|
(keyword)
|
||||||
|
(get resources/contacts))
|
||||||
|
{:uri photo-path})
|
||||||
|
:style style/photo}]])
|
||||||
|
|
||||||
|
(defview member-photo [from]
|
||||||
|
(letsubs [photo-path [:get-photo-path from]]
|
||||||
|
(photo from (if (string/blank? photo-path)
|
||||||
|
(identicon/identicon from)
|
||||||
|
photo-path))))
|
@ -5,6 +5,7 @@
|
|||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
|
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
|
[status-im.chat.views.photos :as photos]
|
||||||
[status-im.chat.styles.screen :as st]
|
[status-im.chat.styles.screen :as st]
|
||||||
[status-im.utils.datetime :as time]
|
[status-im.utils.datetime :as time]
|
||||||
[status-im.utils.platform :refer [platform-specific]]
|
[status-im.utils.platform :refer [platform-specific]]
|
||||||
@ -60,17 +61,19 @@
|
|||||||
(i18n/label-pluralize cnt :t/members-active)))]])))
|
(i18n/label-pluralize cnt :t/members-active)))]])))
|
||||||
|
|
||||||
(defview toolbar-content-view []
|
(defview toolbar-content-view []
|
||||||
(letsubs [{:keys [group-chat name chat-id
|
(letsubs [{:keys [group-chat name contacts
|
||||||
contacts public? public-key]} [:get-current-chat]
|
public? chat-id]} [:get-current-chat]
|
||||||
show-actions? [:get-current-chat-ui-prop :show-actions?]
|
show-actions? [:get-current-chat-ui-prop :show-actions?]
|
||||||
accounts [:get-accounts]
|
accounts [:get-accounts]
|
||||||
contact [:get-current-chat-contact]
|
contact [:get-current-chat-contact]
|
||||||
sync-state [:sync-state]]
|
sync-state [:sync-state]]
|
||||||
[react/view common.styles/flex
|
[react/view {:style st/toolbar-container}
|
||||||
|
|
||||||
|
[react/view (when-not group-chat [photos/member-photo chat-id])]
|
||||||
[react/view (st/chat-name-view (or (empty? accounts)
|
[react/view (st/chat-name-view (or (empty? accounts)
|
||||||
show-actions?))
|
show-actions?))
|
||||||
(let [chat-name (if (string/blank? name)
|
(let [chat-name (if (string/blank? name)
|
||||||
(generate-gfy public-key)
|
(generate-gfy chat-id)
|
||||||
(or (i18n/get-contact-translated chat-id :name name)
|
(or (i18n/get-contact-translated chat-id :name name)
|
||||||
(i18n/label :t/chat-name)))]
|
(i18n/label :t/chat-name)))]
|
||||||
[react/text {:style st/chat-name-text
|
[react/text {:style st/chat-name-text
|
||||||
|
Loading…
x
Reference in New Issue
Block a user