2016-05-19 18:31:56 +02:00
|
|
|
(ns status-im.chat.screen
|
|
|
|
(:require-macros [status-im.utils.views :refer [defview]])
|
2016-05-19 15:45:16 +03:00
|
|
|
(:require [re-frame.core :refer [subscribe dispatch]]
|
2016-05-19 18:31:56 +02:00
|
|
|
[status-im.components.react :refer [view
|
2016-06-02 16:23:50 +03:00
|
|
|
animated-view
|
|
|
|
text
|
|
|
|
icon
|
|
|
|
touchable-highlight
|
|
|
|
list-view
|
|
|
|
list-item]]
|
2016-07-22 11:53:12 +03:00
|
|
|
[status-im.components.status-bar :refer [status-bar]]
|
2016-05-20 14:20:48 +03:00
|
|
|
[status-im.components.chat-icon.screen :refer [chat-icon-view-action
|
|
|
|
chat-icon-view-menu-item]]
|
2016-05-19 18:31:56 +02:00
|
|
|
[status-im.chat.styles.screen :as st]
|
2016-06-08 14:24:35 +03:00
|
|
|
[status-im.utils.listview :refer [to-datasource-inverted]]
|
2016-05-20 16:36:00 +03:00
|
|
|
[status-im.utils.utils :refer [truncate-str]]
|
2016-08-04 18:36:13 +03:00
|
|
|
[status-im.utils.datetime :as time]
|
2016-09-15 15:33:19 +03:00
|
|
|
[status-im.utils.platform :refer [platform-specific]]
|
2016-05-19 18:31:56 +02:00
|
|
|
[status-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
2016-10-05 11:56:53 +03:00
|
|
|
[status-im.components.toolbar.view :refer [toolbar]]
|
2016-05-19 18:31:56 +02:00
|
|
|
[status-im.chat.views.message :refer [chat-message]]
|
2016-10-04 23:58:33 +03:00
|
|
|
[status-im.chat.views.datemark :refer [chat-datemark]]
|
2016-06-25 18:44:37 +03:00
|
|
|
[status-im.chat.views.suggestions :refer [suggestion-container]]
|
2016-06-03 14:09:34 +03:00
|
|
|
[status-im.chat.views.response :refer [response-view]]
|
2016-05-25 04:27:03 +03:00
|
|
|
[status-im.chat.views.new-message :refer [chat-message-new]]
|
2016-08-24 10:29:40 +03:00
|
|
|
[status-im.chat.views.actions :refer [actions-view]]
|
2016-09-16 14:36:31 +03:00
|
|
|
[status-im.chat.views.bottom-info :refer [bottom-info-view]]
|
2016-10-06 12:52:58 +03:00
|
|
|
[status-im.chat.views.toolbar-content :refer [toolbar-content-view]]
|
2016-06-03 22:34:24 +03:00
|
|
|
[status-im.i18n :refer [label label-pluralize]]
|
|
|
|
[status-im.components.animation :as anim]
|
2016-10-06 12:52:58 +03:00
|
|
|
[status-im.components.sync-state.offline :refer [offline-view]]
|
|
|
|
[status-im.constants :refer [content-type-status]]
|
2016-08-04 18:36:13 +03:00
|
|
|
[reagent.core :as r]
|
2016-09-07 00:37:10 +03:00
|
|
|
[cljs-time.core :as t]))
|
2016-03-25 13:36:16 +03:00
|
|
|
|
2016-04-06 16:13:31 +03:00
|
|
|
(defn contacts-by-identity [contacts]
|
|
|
|
(->> contacts
|
|
|
|
(map (fn [{:keys [identity] :as contact}]
|
|
|
|
[identity contact]))
|
|
|
|
(into {})))
|
|
|
|
|
2016-08-24 10:29:40 +03:00
|
|
|
(defn add-message-color [{:keys [from] :as message} contact-by-identity]
|
2016-04-07 14:01:41 +03:00
|
|
|
(if (= "system" from)
|
2016-08-24 10:29:40 +03:00
|
|
|
(assoc message :text-color :#4A5258
|
|
|
|
:background-color :#D3EEEF)
|
2016-04-07 14:01:41 +03:00
|
|
|
(let [{:keys [text-color background-color]} (get contact-by-identity from)]
|
2016-08-24 10:29:40 +03:00
|
|
|
(assoc message :text-color text-color
|
|
|
|
:background-color background-color))))
|
2016-04-06 16:13:31 +03:00
|
|
|
|
2016-05-19 15:45:16 +03:00
|
|
|
(defview chat-icon []
|
2016-06-27 14:35:33 +03:00
|
|
|
[chat-id [:chat :chat-id]
|
2016-05-19 15:45:16 +03:00
|
|
|
group-chat [:chat :group-chat]
|
2016-06-27 14:35:33 +03:00
|
|
|
name [:chat :name]
|
|
|
|
color [:chat :color]]
|
2016-05-19 15:45:16 +03:00
|
|
|
;; TODO stub data ('online' property)
|
|
|
|
[chat-icon-view-action chat-id group-chat name color true])
|
2016-04-18 13:38:38 +03:00
|
|
|
|
2016-09-15 15:33:19 +03:00
|
|
|
(defn typing [member]
|
2016-05-07 16:39:03 +03:00
|
|
|
[view st/typing-view
|
|
|
|
[view st/typing-background
|
2016-09-15 15:33:19 +03:00
|
|
|
[text {:style st/typing-text
|
|
|
|
:font :default}
|
2016-05-25 18:57:06 +03:00
|
|
|
(str member " " (label :t/is-typing))]]])
|
2016-04-19 15:38:16 +03:00
|
|
|
|
2016-09-15 15:33:19 +03:00
|
|
|
(defn typing-all []
|
2016-05-08 23:13:24 +03:00
|
|
|
[view st/typing-all
|
2016-05-20 14:38:20 +03:00
|
|
|
;; TODO stub data
|
2016-04-19 15:38:16 +03:00
|
|
|
(for [member ["Geoff" "Justas"]]
|
2016-09-15 15:33:19 +03:00
|
|
|
^{:key member} [typing member])])
|
2016-04-19 15:38:16 +03:00
|
|
|
|
2016-10-04 23:58:33 +03:00
|
|
|
(defmulti message-row (fn [{{:keys [type]} :row}] type))
|
|
|
|
|
|
|
|
(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
|
|
|
|
(add-message-color contact-by-identity)
|
|
|
|
(assoc :group-chat group-chat)
|
2016-10-12 13:32:32 +03:00
|
|
|
(assoc :messages-count messages-count)
|
2016-10-04 23:58:33 +03:00
|
|
|
(assoc :last-message (= (js/parseInt index) (dec messages-count))))]
|
|
|
|
(list-item [chat-message message])))
|
2016-05-06 14:06:58 +03:00
|
|
|
|
2016-05-11 13:53:38 +03:00
|
|
|
(defn toolbar-action []
|
2016-09-16 14:36:31 +03:00
|
|
|
(let [show-actions (subscribe [:chat-ui-props :show-actions?])]
|
2016-05-11 13:53:38 +03:00
|
|
|
(fn []
|
|
|
|
(if @show-actions
|
|
|
|
[touchable-highlight
|
2016-09-16 14:36:31 +03:00
|
|
|
{:on-press #(dispatch [:set-chat-ui-props :show-actions? false])}
|
2016-05-19 15:45:16 +03:00
|
|
|
[view st/action
|
2016-05-11 13:53:38 +03:00
|
|
|
[icon :up st/up-icon]]]
|
|
|
|
[touchable-highlight
|
2016-09-16 14:36:31 +03:00
|
|
|
{:on-press #(dispatch [:set-chat-ui-props :show-actions? true])}
|
2016-05-19 15:45:16 +03:00
|
|
|
[view st/action
|
|
|
|
[chat-icon]]]))))
|
2016-05-11 13:53:38 +03:00
|
|
|
|
2016-09-15 15:33:19 +03:00
|
|
|
(defview chat-toolbar []
|
2016-10-17 14:51:33 +03:00
|
|
|
[show-actions? [:chat-ui-props :show-actions?]
|
|
|
|
accounts [:get :accounts]]
|
2016-08-24 16:40:36 +03:00
|
|
|
[view
|
2016-09-15 15:33:19 +03:00
|
|
|
[status-bar]
|
2016-10-17 14:51:33 +03:00
|
|
|
[toolbar {:hide-nav? (or (empty? accounts) show-actions?)
|
2016-10-06 12:52:58 +03:00
|
|
|
:custom-content [toolbar-content-view]
|
2016-08-24 16:40:36 +03:00
|
|
|
:custom-action [toolbar-action]
|
2016-09-15 15:33:19 +03:00
|
|
|
:style (get-in platform-specific [:component-styles :toolbar])}]])
|
2016-05-03 16:39:08 +03:00
|
|
|
|
2016-10-12 13:32:32 +03:00
|
|
|
(defn get-intro-status-message [all-messages]
|
|
|
|
(let [{:keys [timestamp content-type] :as last-message} (last all-messages)]
|
|
|
|
(when (not= content-type content-type-status)
|
|
|
|
{:message-id "intro-status"
|
|
|
|
:content-type content-type-status
|
|
|
|
:timestamp (or timestamp (time/now-ms))})))
|
|
|
|
|
|
|
|
|
2016-10-04 23:58:33 +03:00
|
|
|
(defn messages-with-timemarks [all-messages]
|
2016-10-12 13:32:32 +03:00
|
|
|
(let [status-message (get-intro-status-message all-messages)
|
|
|
|
all-messages (if status-message
|
|
|
|
(concat all-messages [status-message])
|
|
|
|
all-messages)
|
|
|
|
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)]
|
2016-10-04 23:58:33 +03:00
|
|
|
(if remove-last?
|
|
|
|
(drop-last messages)
|
|
|
|
messages)))
|
|
|
|
|
2016-09-15 15:33:19 +03:00
|
|
|
(defview messages-view [group-chat]
|
2016-06-27 14:35:33 +03:00
|
|
|
[messages [:chat :messages]
|
2016-06-30 19:00:44 +03:00
|
|
|
contacts [:chat :contacts]
|
|
|
|
loaded? [:all-messages-loaded?]]
|
2016-10-04 23:58:33 +03:00
|
|
|
(let [contacts' (contacts-by-identity contacts)
|
|
|
|
messages (messages-with-timemarks messages)]
|
|
|
|
[list-view {:renderRow (fn [row _ index]
|
|
|
|
(message-row {:contact-by-identity contacts'
|
|
|
|
:group-chat group-chat
|
|
|
|
:messages-count (count messages)
|
|
|
|
:row row
|
|
|
|
:index index}))
|
2016-06-27 14:35:33 +03:00
|
|
|
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
2016-06-30 19:00:44 +03:00
|
|
|
:onEndReached (when-not loaded? #(dispatch [:load-more-messages]))
|
2016-06-27 14:35:33 +03:00
|
|
|
:enableEmptySections true
|
|
|
|
:keyboardShouldPersistTaps true
|
|
|
|
:dataSource (to-datasource-inverted messages)}]))
|
2016-06-03 22:34:24 +03:00
|
|
|
|
2016-06-25 18:44:37 +03:00
|
|
|
(defn messages-container-animation-logic
|
2016-06-27 14:35:33 +03:00
|
|
|
[{:keys [offset val]}]
|
2016-06-03 22:34:24 +03:00
|
|
|
(fn [_]
|
2016-06-27 14:35:33 +03:00
|
|
|
(anim/start (anim/spring val {:toValue @offset}))))
|
2016-06-03 22:34:24 +03:00
|
|
|
|
|
|
|
(defn messages-container [messages]
|
2016-06-27 14:35:33 +03:00
|
|
|
(let [offset (subscribe [:messages-offset])
|
2016-06-25 18:44:37 +03:00
|
|
|
messages-offset (anim/create-value 0)
|
2016-06-27 14:35:33 +03:00
|
|
|
context {:offset offset
|
|
|
|
:val messages-offset}
|
2016-06-03 22:34:24 +03:00
|
|
|
on-update (messages-container-animation-logic context)]
|
|
|
|
(r/create-class
|
|
|
|
{:component-did-mount
|
|
|
|
on-update
|
|
|
|
:component-did-update
|
|
|
|
on-update
|
|
|
|
:reagent-render
|
|
|
|
(fn [messages]
|
2016-06-27 14:35:33 +03:00
|
|
|
@offset
|
2016-06-03 22:34:24 +03:00
|
|
|
[animated-view {:style (st/messages-container messages-offset)}
|
|
|
|
messages])})))
|
2016-04-19 15:38:16 +03:00
|
|
|
|
2016-09-15 15:33:19 +03:00
|
|
|
(defn chat []
|
2016-08-03 16:15:04 +03:00
|
|
|
(let [group-chat (subscribe [:chat :group-chat])
|
2016-09-16 14:36:31 +03:00
|
|
|
show-actions? (subscribe [:chat-ui-props :show-actions?])
|
|
|
|
show-bottom-info? (subscribe [:chat-ui-props :show-bottom-info?])
|
2016-08-03 16:15:04 +03:00
|
|
|
command? (subscribe [:command?])
|
|
|
|
layout-height (subscribe [:get :layout-height])]
|
|
|
|
(r/create-class
|
|
|
|
{:component-did-mount #(dispatch [:check-autorun])
|
|
|
|
:reagent-render
|
2016-09-15 15:33:19 +03:00
|
|
|
(fn []
|
2016-08-03 16:15:04 +03:00
|
|
|
[view {:style st/chat-view
|
|
|
|
:onLayout (fn [event]
|
|
|
|
(let [height (.. event -nativeEvent -layout -height)]
|
|
|
|
(when (not= height @layout-height)
|
|
|
|
(dispatch [:set-layout-height height]))))}
|
2016-09-15 15:33:19 +03:00
|
|
|
[chat-toolbar]
|
2016-08-03 16:15:04 +03:00
|
|
|
[messages-container
|
2016-09-15 15:33:19 +03:00
|
|
|
[messages-view @group-chat]]
|
2016-08-24 16:40:36 +03:00
|
|
|
;; todo uncomment this
|
2016-09-15 15:33:19 +03:00
|
|
|
#_(when @group-chat [typing-all])
|
2016-08-03 16:15:04 +03:00
|
|
|
[response-view]
|
2016-09-16 14:36:31 +03:00
|
|
|
(when-not @command?
|
|
|
|
[suggestion-container])
|
2016-09-15 15:33:19 +03:00
|
|
|
[chat-message-new]
|
2016-09-16 14:36:31 +03:00
|
|
|
(when @show-actions?
|
|
|
|
[actions-view])
|
|
|
|
(when @show-bottom-info?
|
2016-10-06 12:52:58 +03:00
|
|
|
[bottom-info-view])
|
|
|
|
[offline-view {:top (get-in platform-specific [:component-styles :status-bar :default :height])}]])})))
|