(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 text image icon touchable-highlight list-view list-item]] [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]] [status-im.components.invertible-scroll-view :refer [invertible-scroll-view]] [status-im.components.toolbar :refer [toolbar]] [status-im.chat.views.message :refer [chat-message]] [status-im.chat.views.new-message :refer [chat-message-new]])) (defn contacts-by-identity [contacts] (->> contacts (map (fn [{:keys [identity] :as contact}] [identity contact])) (into {}))) (defn add-msg-color [{:keys [from] :as msg} contact-by-identity] (if (= "system" from) (assoc msg :text-color :#4A5258 :background-color :#D3EEEF) (let [{:keys [text-color background-color]} (get contact-by-identity from)] (assoc msg :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} (str member " is typing")]]]) (defn typing-all [] [view st/typing-all ;; TODO stub data (for [member ["Geoff" "Justas"]] ^{:key member} [typing member])]) (defn message-row [contact-by-identity group-chat] (fn [row _ idx] (let [msg (-> row (add-msg-color contact-by-identity) (assoc :group-chat group-chat) (assoc :last-msg (zero? (js/parseInt idx))))] (list-item [chat-message msg])))) (defn on-action-selected [position] (case position 0 (dispatch [:show-add-participants]) 1 (dispatch [:show-remove-participants]) 2 (dispatch [:leave-group-chat]))) (defn overlay [{:keys [on-click-outside]} items] [view st/actions-overlay [touchable-highlight {:on-press on-click-outside :style st/overlay-highlight} [view nil]] items]) (defn action-view [{:keys [icon-style custom-icon handler title subtitle] icon-name :icon}] [touchable-highlight {:on-press (fn [] (dispatch [:set-show-actions false]) (when handler (handler)))} [view st/action-icon-row [view st/action-icon-view (or custom-icon [icon icon-name icon-style])] [view st/action-view [text {:style st/action-title} title] (when-let [subtitle subtitle] [text {:style st/action-subtitle} subtitle])]]]) (defview menu-item-icon-profile [] [chat-id [:chat :chat-id] group-chat [:chat :group-chat] name [:chat :name] color [:chat :color]] ;; TODO stub data ('online' property) [chat-icon-view-menu-item chat-id group-chat name color true]) (defn actions-list-view [] (let [{:keys [group-chat chat-id]} (subscribe [:chat-properties [:group-chat :chat-id]])] (when-let [actions (if @group-chat [{:title "Add Contact to chat" :icon :menu_group :icon-style {:width 25 :height 19} :handler #(dispatch [:show-add-participants])} {:title "Remove Contact from chat" :subtitle "Alex, John" :icon :search_gray_copy :icon-style {:width 17 :height 17} :handler #(dispatch [:show-remove-participants])} {:title "Leave Chat" :icon :muted :icon-style {:width 18 :height 21} :handler #(dispatch [:leave-group-chat])} {:title "Settings" :icon :settings :icon-style {:width 20 :height 13} :handler #(dispatch [:show-group-settings])}] [{:title "Profile" :custom-icon [menu-item-icon-profile] :icon :menu_group :icon-style {:width 25 :height 19} :handler #(dispatch [:show-profile @chat-id])} {:title "Search chat" :subtitle "!not implemented" :icon :search_gray_copy :icon-style {:width 17 :height 17} :handler nil} {:title "Notifications and sounds" :subtitle "!not implemented" :icon :muted :icon-style {:width 18 :height 21} :handler nil} {:title "Settings" :subtitle "!not implemented" :icon :settings :icon-style {:width 20 :height 13} :handler (fn [])}])] [view st/actions-wrapper [view st/actions-separator] [view st/actions-view (for [action actions] ^{:key action} [action-view action])]]))) (defn actions-view [] [overlay {:on-click-outside #(dispatch [:set-show-actions false])} [actions-list-view]]) (defn toolbar-content [] (let [{:keys [group-chat name contacts]} (subscribe [:chat-properties [:group-chat :name :contacts]]) show-actions (subscribe [:show-actions])] (fn [] [view (st/chat-name-view @show-actions) [text {:style st/chat-name-text} (or @name "Chat name")] (if @group-chat [view {:flexDirection :row} [icon :group st/group-icon] [text {:style st/members} (let [cnt (inc (count @contacts))] (str cnt (if (< 1 cnt) " members" " member") ", " cnt " active"))]] [text {:style st/last-activity} "Active a minute ago"])]))) (defn toolbar-action [] (let [show-actions (subscribe [:show-actions])] (fn [] (if @show-actions [touchable-highlight {:on-press #(dispatch [:set-show-actions false])} [view st/action [icon :up st/up-icon]]] [touchable-highlight {:on-press #(dispatch [:set-show-actions true])} [view st/action [chat-icon]]])))) (defn chat-toolbar [] (let [{:keys [group-chat name contacts]} (subscribe [:chat-properties [:group-chat :name :contacts]]) show-actions (subscribe [:show-actions])] (fn [] [toolbar {:hide-nav? @show-actions :custom-content [toolbar-content] :custom-action [toolbar-action]}]))) (defview messages-view [group-chat] [messages [:chat :messages] contacts [:chat :contacts]] (let [contacts' (contacts-by-identity contacts)] [list-view {:renderRow (message-row contacts' group-chat) :renderScrollComponent #(invertible-scroll-view (js->clj %)) :onEndReached #(dispatch [:load-more-messages]) :enableEmptySections true :dataSource (to-datasource messages)}])) (defview chat [] [group-chat [:chat :group-chat] show-actions-atom [:show-actions]] [view st/chat-view [chat-toolbar] [messages-view group-chat] (when group-chat [typing-all]) [chat-message-new] (when show-actions-atom [actions-view])])