214 lines
9.0 KiB
Plaintext
Raw Normal View History

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