date indicators in chat (fixes #282)
This commit is contained in:
parent
d5de7f4af6
commit
dcd711f5c2
|
@ -4,6 +4,7 @@
|
||||||
[status-im.data-store.messages :as messages]
|
[status-im.data-store.messages :as messages]
|
||||||
[status-im.chat.utils :as cu]
|
[status-im.chat.utils :as cu]
|
||||||
[status-im.commands.utils :refer [generate-hiccup]]
|
[status-im.commands.utils :refer [generate-hiccup]]
|
||||||
|
[status-im.utils.random :as random]
|
||||||
[status-im.constants :refer [content-type-command-request]]
|
[status-im.constants :refer [content-type-command-request]]
|
||||||
[cljs.reader :refer [read-string]]
|
[cljs.reader :refer [read-string]]
|
||||||
[status-im.data-store.chats :as chats]))
|
[status-im.data-store.chats :as chats]))
|
||||||
|
@ -24,7 +25,7 @@
|
||||||
(:public-key (accounts current-account-id)))
|
(:public-key (accounts current-account-id)))
|
||||||
|
|
||||||
(defn receive-message
|
(defn receive-message
|
||||||
[db [_ {:keys [from group-id chat-id message-id] :as message}]]
|
[db [_ {:keys [from group-id chat-id message-id timestamp] :as message}]]
|
||||||
(let [same-message (messages/get-by-id message-id)
|
(let [same-message (messages/get-by-id message-id)
|
||||||
current-identity (get-current-identity db)
|
current-identity (get-current-identity db)
|
||||||
chat-id' (or group-id chat-id from)
|
chat-id' (or group-id chat-id from)
|
||||||
|
@ -39,7 +40,7 @@
|
||||||
(cu/check-author-direction previous-message)
|
(cu/check-author-direction previous-message)
|
||||||
(check-preview))
|
(check-preview))
|
||||||
:chat-id chat-id'
|
:chat-id chat-id'
|
||||||
:timestamp (.getTime (js/Date.)))]
|
:timestamp (or timestamp (random/timestamp)))]
|
||||||
(store-message message')
|
(store-message message')
|
||||||
(when-not exists?
|
(when-not exists?
|
||||||
(dispatch [:add-chat chat-id' (when group-chat? {:group-chat true})]))
|
(dispatch [:add-chat chat-id' (when group-chat? {:group-chat true})]))
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
{:message-id (random/id)
|
{:message-id (random/id)
|
||||||
:from identity
|
:from identity
|
||||||
:to chat-id
|
:to chat-id
|
||||||
|
:timestamp (time/now-ms)
|
||||||
:content (assoc content :preview preview-string)
|
:content (assoc content :preview preview-string)
|
||||||
:content-type content-type-command
|
:content-type content-type-command
|
||||||
:outgoing true
|
:outgoing true
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
[status-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
[status-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
||||||
[status-im.components.toolbar.view :refer [toolbar]]
|
[status-im.components.toolbar.view :refer [toolbar]]
|
||||||
[status-im.chat.views.message :refer [chat-message]]
|
[status-im.chat.views.message :refer [chat-message]]
|
||||||
|
[status-im.chat.views.datemark :refer [chat-datemark]]
|
||||||
[status-im.chat.views.suggestions :refer [suggestion-container]]
|
[status-im.chat.views.suggestions :refer [suggestion-container]]
|
||||||
[status-im.chat.views.response :refer [response-view]]
|
[status-im.chat.views.response :refer [response-view]]
|
||||||
[status-im.chat.views.new-message :refer [chat-message-new]]
|
[status-im.chat.views.new-message :refer [chat-message-new]]
|
||||||
|
@ -26,7 +27,8 @@
|
||||||
[status-im.chat.views.bottom-info :refer [bottom-info-view]]
|
[status-im.chat.views.bottom-info :refer [bottom-info-view]]
|
||||||
[status-im.i18n :refer [label label-pluralize]]
|
[status-im.i18n :refer [label label-pluralize]]
|
||||||
[status-im.components.animation :as anim]
|
[status-im.components.animation :as anim]
|
||||||
[status-im.constants :refer [console-chat-id]]
|
[status-im.constants :refer [console-chat-id
|
||||||
|
content-type-status]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[cljs-time.core :as t]))
|
[cljs-time.core :as t]))
|
||||||
|
@ -66,13 +68,19 @@
|
||||||
(for [member ["Geoff" "Justas"]]
|
(for [member ["Geoff" "Justas"]]
|
||||||
^{:key member} [typing member])])
|
^{:key member} [typing member])])
|
||||||
|
|
||||||
(defn message-row [{:keys [contact-by-identity group-chat messages-count]}]
|
(defmulti message-row (fn [{{:keys [type]} :row}] type))
|
||||||
(fn [row _ idx]
|
|
||||||
|
(defmethod message-row :datemark
|
||||||
|
[{{:keys [value]} :row}]
|
||||||
|
(list-item [chat-datemark value]))
|
||||||
|
|
||||||
|
(defmethod message-row :default
|
||||||
|
[{:keys [contact-by-identity group-chat messages-count row index]}]
|
||||||
(let [message (-> row
|
(let [message (-> row
|
||||||
(add-message-color contact-by-identity)
|
(add-message-color contact-by-identity)
|
||||||
(assoc :group-chat group-chat)
|
(assoc :group-chat group-chat)
|
||||||
(assoc :last-message (= (js/parseInt idx) (dec messages-count))))]
|
(assoc :last-message (= (js/parseInt index) (dec messages-count))))]
|
||||||
(list-item [chat-message message]))))
|
(list-item [chat-message message])))
|
||||||
|
|
||||||
(defn online-text [contact chat-id]
|
(defn online-text [contact chat-id]
|
||||||
(cond
|
(cond
|
||||||
|
@ -134,14 +142,31 @@
|
||||||
:custom-action [toolbar-action]
|
:custom-action [toolbar-action]
|
||||||
:style (get-in platform-specific [:component-styles :toolbar])}]])
|
:style (get-in platform-specific [:component-styles :toolbar])}]])
|
||||||
|
|
||||||
|
(defn messages-with-timemarks [all-messages]
|
||||||
|
(let [messages (->> all-messages
|
||||||
|
(map #(assoc % :datemark (time/day-relative (:timestamp %))))
|
||||||
|
(group-by :datemark)
|
||||||
|
(map (fn [[k v]] [v {:type :datemark :value k}]))
|
||||||
|
(flatten))
|
||||||
|
remove-last? (some (fn [{:keys [content-type]}]
|
||||||
|
(= content-type content-type-status))
|
||||||
|
messages)]
|
||||||
|
(if remove-last?
|
||||||
|
(drop-last messages)
|
||||||
|
messages)))
|
||||||
|
|
||||||
(defview messages-view [group-chat]
|
(defview messages-view [group-chat]
|
||||||
[messages [:chat :messages]
|
[messages [:chat :messages]
|
||||||
contacts [:chat :contacts]
|
contacts [:chat :contacts]
|
||||||
loaded? [:all-messages-loaded?]]
|
loaded? [:all-messages-loaded?]]
|
||||||
(let [contacts' (contacts-by-identity contacts)]
|
(let [contacts' (contacts-by-identity contacts)
|
||||||
[list-view {:renderRow (message-row {:contact-by-identity contacts'
|
messages (messages-with-timemarks messages)]
|
||||||
|
[list-view {:renderRow (fn [row _ index]
|
||||||
|
(message-row {:contact-by-identity contacts'
|
||||||
:group-chat group-chat
|
:group-chat group-chat
|
||||||
:messages-count (count messages)})
|
:messages-count (count messages)
|
||||||
|
:row row
|
||||||
|
:index index}))
|
||||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||||
:onEndReached (when-not loaded? #(dispatch [:load-more-messages]))
|
:onEndReached (when-not loaded? #(dispatch [:load-more-messages]))
|
||||||
:enableEmptySections true
|
:enableEmptySections true
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
(ns status-im.chat.styles.datemark)
|
||||||
|
|
||||||
|
(def datemark-wrapper
|
||||||
|
{:flex 1
|
||||||
|
:flex-direction :column
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center})
|
||||||
|
|
||||||
|
(def datemark
|
||||||
|
{:flex 1
|
||||||
|
:flex-direction :column
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center
|
||||||
|
:background-color "#bbc4cb33"
|
||||||
|
:padding-left 12
|
||||||
|
:padding-right 12
|
||||||
|
:margin-top 8
|
||||||
|
:margin-bottom 8
|
||||||
|
:border-radius 12
|
||||||
|
:height 24})
|
||||||
|
|
||||||
|
(def datemark-text
|
||||||
|
{:color "#838c93"
|
||||||
|
:font-size 12})
|
|
@ -36,9 +36,13 @@
|
||||||
(when (and last-message (not typing))
|
(when (and last-message (not typing))
|
||||||
{:paddingBottom 20}))
|
{:paddingBottom 20}))
|
||||||
|
|
||||||
|
(def message-datemark
|
||||||
|
{:margin-top 10
|
||||||
|
:margin-bottom -4})
|
||||||
|
|
||||||
(def message-body-base
|
(def message-body-base
|
||||||
{:paddingRight 8
|
{:padding-right 8
|
||||||
:paddingLeft 8})
|
:padding-left 8})
|
||||||
|
|
||||||
(defn message-body
|
(defn message-body
|
||||||
[{:keys [outgoing] :as message}]
|
[{:keys [outgoing] :as message}]
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
[status-im.constants :refer [response-suggesstion-resize-duration]]
|
[status-im.constants :refer [response-suggesstion-resize-duration]]
|
||||||
[status-im.chat.constants :as c]
|
[status-im.chat.constants :as c]
|
||||||
[status-im.chat.views.plain-message :as plain-message]
|
[status-im.chat.views.plain-message :as plain-message]
|
||||||
[status-im.chat.views.command :as command]))
|
[status-im.chat.views.command :as command]
|
||||||
|
[status-im.constants :refer [content-type-status]]
|
||||||
|
[status-im.utils.datetime :as time]))
|
||||||
|
|
||||||
(register-sub :chat-properties
|
(register-sub :chat-properties
|
||||||
(fn [db [_ properties]]
|
(fn [db [_ properties]]
|
||||||
|
@ -29,7 +31,6 @@
|
||||||
(get-in [:chats (:current-chat-id @db) k])
|
(get-in [:chats (:current-chat-id @db) k])
|
||||||
(reaction))))
|
(reaction))))
|
||||||
|
|
||||||
|
|
||||||
(register-sub :get-chat-messages
|
(register-sub :get-chat-messages
|
||||||
(fn [db _]
|
(fn [db _]
|
||||||
(let [chat-id (:current-chat-id @db)]
|
(let [chat-id (:current-chat-id @db)]
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
(ns status-im.chat.views.datemark
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||||
|
[status-im.components.react :refer [view
|
||||||
|
text]]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[status-im.i18n :refer [label]]
|
||||||
|
[status-im.chat.styles.datemark :as st]))
|
||||||
|
|
||||||
|
(defn chat-datemark [value]
|
||||||
|
[view st/datemark-wrapper
|
||||||
|
[view st/datemark
|
||||||
|
[text {:style st/datemark-text}
|
||||||
|
(str/capitalize (or value (label :t/datetime-today)))]]])
|
|
@ -13,6 +13,7 @@
|
||||||
[status-im.chat.views.request-message :refer [message-content-command-request]]
|
[status-im.chat.views.request-message :refer [message-content-command-request]]
|
||||||
[status-im.chat.styles.message :as st]
|
[status-im.chat.styles.message :as st]
|
||||||
[status-im.chat.styles.command-pill :as pill-st]
|
[status-im.chat.styles.command-pill :as pill-st]
|
||||||
|
[status-im.chat.views.datemark :refer [chat-datemark]]
|
||||||
[status-im.models.commands :refer [parse-command-message-content
|
[status-im.models.commands :refer [parse-command-message-content
|
||||||
parse-command-request]]
|
parse-command-request]]
|
||||||
[status-im.resources :as res]
|
[status-im.resources :as res]
|
||||||
|
@ -24,13 +25,6 @@
|
||||||
[status-im.utils.identicon :refer [identicon]]
|
[status-im.utils.identicon :refer [identicon]]
|
||||||
[status-im.chat.utils :as cu]))
|
[status-im.chat.utils :as cu]))
|
||||||
|
|
||||||
(defn message-date [timestamp]
|
|
||||||
[view {}
|
|
||||||
[view st/message-date-container
|
|
||||||
[text {:style st/message-date-text
|
|
||||||
:font :default}
|
|
||||||
(time/to-short-str timestamp)]]])
|
|
||||||
|
|
||||||
(defn contact-photo [photo-path]
|
(defn contact-photo [photo-path]
|
||||||
[view st/contact-photo-container
|
[view st/contact-photo-container
|
||||||
[image {:source (if (s/blank? photo-path)
|
[image {:source (if (s/blank? photo-path)
|
||||||
|
@ -45,7 +39,7 @@
|
||||||
[view st/online-dot-right]]))
|
[view st/online-dot-right]]))
|
||||||
|
|
||||||
(defview message-content-status
|
(defview message-content-status
|
||||||
[{:keys [from content]}]
|
[{:keys [from content datemark]}]
|
||||||
[{chat-name :name} [:get-chat-by-id from]
|
[{chat-name :name} [:get-chat-by-id from]
|
||||||
photo-path [:chat-photo from]]
|
photo-path [:chat-photo from]]
|
||||||
[view st/status-container
|
[view st/status-container
|
||||||
|
@ -57,7 +51,9 @@
|
||||||
(or chat-name from)]
|
(or chat-name from)]
|
||||||
[text {:style st/status-text
|
[text {:style st/status-text
|
||||||
:font :default}
|
:font :default}
|
||||||
content]])
|
content]
|
||||||
|
[view st/message-datemark
|
||||||
|
[chat-datemark datemark]]])
|
||||||
|
|
||||||
(defn message-content-audio [_]
|
(defn message-content-audio [_]
|
||||||
[view st/audio-container
|
[view st/audio-container
|
||||||
|
@ -295,11 +291,8 @@
|
||||||
:from from
|
:from from
|
||||||
:message-id message-id}])))
|
:message-id message-id}])))
|
||||||
:reagent-render
|
:reagent-render
|
||||||
(fn [{:keys [outgoing timestamp new-day group-chat] :as message}]
|
(fn [{:keys [outgoing group-chat] :as message}]
|
||||||
[message-container message
|
[message-container message
|
||||||
;; TODO there is no new-day info in message
|
|
||||||
(when new-day
|
|
||||||
[message-date timestamp])
|
|
||||||
[view
|
[view
|
||||||
(let [incoming-group (and group-chat (not outgoing))]
|
(let [incoming-group (and group-chat (not outgoing))]
|
||||||
[message-content
|
[message-content
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
:datetime-multiple "s"
|
:datetime-multiple "s"
|
||||||
:datetime-ago "ago"
|
:datetime-ago "ago"
|
||||||
:datetime-yesterday "yesterday"
|
:datetime-yesterday "yesterday"
|
||||||
|
:datetime-today "today"
|
||||||
|
|
||||||
;profile
|
;profile
|
||||||
:profile "Profile"
|
:profile "Profile"
|
||||||
|
|
|
@ -18,7 +18,10 @@
|
||||||
|
|
||||||
(def time-zone-offset (hours (- (/ (.getTimezoneOffset (js/Date.)) 60))))
|
(def time-zone-offset (hours (- (/ (.getTimezoneOffset (js/Date.)) 60))))
|
||||||
|
|
||||||
(defn to-short-str [ms]
|
(defn to-short-str
|
||||||
|
([ms]
|
||||||
|
(to-short-str ms #(unparse (formatters :hour-minute) %)))
|
||||||
|
([ms today-format-fn]
|
||||||
(let [date (from-long ms)
|
(let [date (from-long ms)
|
||||||
local (plus date time-zone-offset)
|
local (plus date time-zone-offset)
|
||||||
today-date (t/today)
|
today-date (t/today)
|
||||||
|
@ -29,7 +32,11 @@
|
||||||
(cond
|
(cond
|
||||||
(before? local yesterday) (unparse (formatter "dd MMM") local)
|
(before? local yesterday) (unparse (formatter "dd MMM") local)
|
||||||
(before? local today) (label :t/datetime-yesterday)
|
(before? local today) (label :t/datetime-yesterday)
|
||||||
:else (unparse (formatters :hour-minute) local))))
|
:else (today-format-fn local)))))
|
||||||
|
|
||||||
|
(defn day-relative [ms]
|
||||||
|
(when (> ms 0)
|
||||||
|
(to-short-str ms #(label :t/datetime-today))))
|
||||||
|
|
||||||
(defn format-time-ago [diff unit]
|
(defn format-time-ago [diff unit]
|
||||||
(let [name (label-pluralize diff (:name unit))]
|
(let [name (label-pluralize diff (:name unit))]
|
||||||
|
|
Loading…
Reference in New Issue