Merge pull request #323 from status-im/bug/#282

Date indicators in chat (#282)
This commit is contained in:
Roman Volosovskyi 2016-10-05 17:23:36 +03:00 committed by GitHub
commit 03c4295dd7
10 changed files with 113 additions and 43 deletions

View File

@ -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})]))

View File

@ -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

View File

@ -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]
(let [message (-> row (defmethod message-row :datemark
(add-message-color contact-by-identity) [{{:keys [value]} :row}]
(assoc :group-chat group-chat) (list-item [chat-datemark value]))
(assoc :last-message (= (js/parseInt idx) (dec messages-count))))]
(list-item [chat-message message])))) (defmethod message-row :default
[{:keys [contact-by-identity group-chat messages-count row index]}]
(let [message (-> row
(add-message-color contact-by-identity)
(assoc :group-chat group-chat)
(assoc :last-message (= (js/parseInt index) (dec messages-count))))]
(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)]
:group-chat group-chat [list-view {:renderRow (fn [row _ index]
:messages-count (count messages)}) (message-row {:contact-by-identity contacts'
:group-chat group-chat
: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

View File

@ -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})

View File

@ -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}]

View File

@ -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)]

View File

@ -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)))]]])

View File

@ -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

View File

@ -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"

View File

@ -18,18 +18,25 @@
(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
(let [date (from-long ms) ([ms]
local (plus date time-zone-offset) (to-short-str ms #(unparse (formatters :hour-minute) %)))
today-date (t/today) ([ms today-format-fn]
today (date-time (t/year today-date) (let [date (from-long ms)
(t/month today-date) local (plus date time-zone-offset)
(t/day today-date)) today-date (t/today)
yesterday (plus today (days -1))] today (date-time (t/year today-date)
(cond (t/month today-date)
(before? local yesterday) (unparse (formatter "dd MMM") local) (t/day today-date))
(before? local today) (label :t/datetime-yesterday) yesterday (plus today (days -1))]
:else (unparse (formatters :hour-minute) local)))) (cond
(before? local yesterday) (unparse (formatter "dd MMM") local)
(before? local today) (label :t/datetime-yesterday)
: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))]