From af0ed4c3a92b8eeb1a8955d30effef96e2bf5e85 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Mon, 16 May 2016 10:45:59 +0300 Subject: [PATCH] start chat with contact --- src/syng_im/android/core.cljs | 2 +- src/syng_im/chat/handlers.cljs | 74 ++++++++++++++++--- src/syng_im/chat/screen.cljs | 45 ++++++----- .../chat/styles/{chat.cljs => screen.cljs} | 2 +- src/syng_im/chat/subs.cljs | 4 + src/syng_im/contacts/handlers.cljs | 11 ++- src/syng_im/contacts/screen.cljs | 29 +++----- src/syng_im/contacts/subs.cljs | 5 ++ src/syng_im/contacts/views/contact.cljs | 14 +++- src/syng_im/db.cljs | 2 +- src/syng_im/models/commands.cljs | 62 ++++++++-------- src/syng_im/participants/views/create.cljs | 14 ++-- src/syng_im/subs.cljs | 7 +- 13 files changed, 167 insertions(+), 104 deletions(-) rename src/syng_im/chat/styles/{chat.cljs => screen.cljs} (99%) diff --git a/src/syng_im/android/core.cljs b/src/syng_im/android/core.cljs index 0117816228..dee02d8a98 100644 --- a/src/syng_im/android/core.cljs +++ b/src/syng_im/android/core.cljs @@ -52,7 +52,7 @@ (dispatch [:initialize-chats]) (dispatch [:initialize-protocol]) (dispatch [:load-user-phone-number]) - (dispatch [:load-syng-contacts]) + (dispatch [:load-contacts]) ;; load commands from remote server (todo: uncomment) ;; (dispatch [:load-commands]) (dispatch [:init-console-chat]) diff --git a/src/syng_im/chat/handlers.cljs b/src/syng_im/chat/handlers.cljs index e5fd8213e0..1619f46596 100644 --- a/src/syng_im/chat/handlers.cljs +++ b/src/syng_im/chat/handlers.cljs @@ -1,5 +1,5 @@ (ns syng-im.chat.handlers - (:require [re-frame.core :refer [register-handler enrich after debug]] + (:require [re-frame.core :refer [register-handler enrich after debug dispatch]] [syng-im.models.commands :as commands] [clojure.string :as str] [syng-im.chat.suggestions :as suggestions] @@ -10,7 +10,9 @@ [syng-im.utils.random :as random] [syng-im.components.react :as r] [syng-im.handlers.sign-up :as sign-up-service] - [syng-im.models.chats :as chats])) + [syng-im.models.chats :as chats] + [syng-im.navigation.handlers :as nav] + [syng-im.models.chats :as c])) (register-handler :set-show-actions (fn [db [_ show-actions]] @@ -236,15 +238,16 @@ (defn load-messages! - [db _] - db - (->> (:current-chat-id db) - messages/get-messages - (assoc db :messages))) + ([db] (load-messages! db nil)) + ([db _] + (->> (:current-chat-id db) + messages/get-messages + (assoc db :messages)))) (defn init-chat - [{:keys [messages current-chat-id] :as db} _] - (assoc-in db [:chats current-chat-id :messages] messages)) + ([db] (init-chat db nil)) + ([{:keys [messages current-chat-id] :as db} _] + (assoc-in db [:chats current-chat-id :messages] messages))) (register-handler :init-chat (-> load-messages! @@ -256,9 +259,11 @@ (let [chats (->> loaded-chats (map (fn [{:keys [chat-id] :as chat}] [chat-id chat])) - (into {}))] + (into {})) + ids (set (keys chats))] (-> db (assoc :chats chats) + (assoc :chats-ids ids) (dissoc :loaded-chats)))) (defn load-chats! @@ -268,7 +273,6 @@ (register-handler :initialize-chats ((enrich initialize-chats) load-chats!)) - (defn store-message! [{:keys [new-message]} [_ {chat-id :from}]] (messages/save-message chat-id new-message)) @@ -288,3 +292,51 @@ (fn [db [_ {chat-id :group-id :as msg}]] (messages/save-message chat-id msg) db)) + +(defn load-chat! + [{:keys [chats current-chat-id] :as db}] + (when-not (chats current-chat-id) + (c/create-chat {})) + db) + +(defmethod nav/preload-data! :chat + [{:keys [current-chat-id] :as db} [_ _ id]] + (-> db + (assoc :current-chat-id (or id current-chat-id)) + load-messages! + init-chat)) + +(defn prepare-chat + [{:keys [contacts] :as db} [_ contcat-id]] + (let [name (get-in contacts [contcat-id :name]) + chat {:chat-id contcat-id + :name name + :group-chat false + :is-active true + :timestamp (.getTime (js/Date.)) + ;; todo how to choose color? + ;; todo do we need to have some color for not group chat? + :contacts [{:identity contcat-id + :text-color :#FFFFFF + :background-color :#AB7967}]}] + (assoc db :new-chat chat))) + +(defn add-chat [{:keys [new-chat] :as db} [_ chat-id]] + (-> db + (update :chats assoc chat-id new-chat) + (update :chats-ids conj chat-id))) + +(defn save-chat! + [{:keys [new-chat]} _] + (chats/create-chat new-chat)) + +(defn open-chat! + [_ [_ chat-id]] + (dispatch [:navigate-to :chat chat-id])) + +(register-handler :start-chat + (-> prepare-chat + ((enrich add-chat)) + ((after save-chat!)) + ((after open-chat!)) + debug)) diff --git a/src/syng_im/chat/screen.cljs b/src/syng_im/chat/screen.cljs index 3c7785ab78..e2a18adac0 100644 --- a/src/syng_im/chat/screen.cljs +++ b/src/syng_im/chat/screen.cljs @@ -1,4 +1,5 @@ (ns syng-im.chat.screen + (:require-macros [syng-im.utils.views :refer [defview]]) (:require [clojure.string :as s] [re-frame.core :refer [subscribe dispatch]] [syng-im.components.react :refer [view @@ -8,7 +9,7 @@ touchable-highlight list-view list-item]] - [syng-im.chat.styles.chat :as st] + [syng-im.chat.styles.screen :as st] [syng-im.resources :as res] [syng-im.utils.listview :refer [to-datasource]] [syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]] @@ -91,7 +92,7 @@ (defn actions-list-view [] (let [{:keys [group-chat active]} - (subscribe [:chat-properties [:group-chat :name :contacts :active]])] + (subscribe [:chat-properties [:group-chat :active]])] (when-let [actions (when (and @group-chat @active) [{:title "Add Contact to chat" :icon :menu_group @@ -160,25 +161,23 @@ [chat-photo {}] [contact-online {:online true}]]])]))) -(defn messages-view [group-chat] - (let [messages (subscribe [:chat :messages]) - contacts (subscribe [:chat :contacts])] - (fn [group-chat] - (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 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)}])) -(defn chat [] - (let [is-active (subscribe [:chat :is-active]) - group-chat (subscribe [:chat :group-chat]) - show-actions-atom (subscribe [:show-actions])] - (fn [] - [view st/chat-view - [toolbar] - [messages-view @group-chat] - (when @group-chat [typing-all]) - (when is-active [chat-message-new]) - (when @show-actions-atom [actions-view])]))) +(defview chat [] + [is-active [:chat :is-active] + group-chat [:chat :group-chat] + show-actions-atom [:show-actions]] + [view st/chat-view + [toolbar] + [messages-view group-chat] + (when group-chat [typing-all]) + (when is-active [chat-message-new]) + (when show-actions-atom [actions-view])]) diff --git a/src/syng_im/chat/styles/chat.cljs b/src/syng_im/chat/styles/screen.cljs similarity index 99% rename from src/syng_im/chat/styles/chat.cljs rename to src/syng_im/chat/styles/screen.cljs index 9ebf92eadb..f212f83bcd 100644 --- a/src/syng_im/chat/styles/chat.cljs +++ b/src/syng_im/chat/styles/screen.cljs @@ -1,4 +1,4 @@ -(ns syng-im.chat.styles.chat +(ns syng-im.chat.styles.screen (:require [syng-im.components.styles :refer [font title-font color-white diff --git a/src/syng_im/chat/subs.cljs b/src/syng_im/chat/subs.cljs index 9b5692c094..f2725baeba 100644 --- a/src/syng_im/chat/subs.cljs +++ b/src/syng_im/chat/subs.cljs @@ -76,3 +76,7 @@ (fn [db _] (let [current-chat-id (:current-chat-id @db)] (reaction (get-in @db [:chats current-chat-id]))))) + +(register-sub :get-chat + (fn [db [_ chat-id]] + (reaction (get-in @db [:chats chat-id])))) diff --git a/src/syng_im/contacts/handlers.cljs b/src/syng_im/contacts/handlers.cljs index 9cb4903d9b..ac58a379ba 100644 --- a/src/syng_im/contacts/handlers.cljs +++ b/src/syng_im/contacts/handlers.cljs @@ -12,15 +12,18 @@ (contacts/save-contacts [contact])) (register-handler :add-contact - (-> (fn [db [_ contact]] - (update db :contacts conj contact)) + (-> (fn [db [_ {:keys [whisper-identity] :as contact}]] + (update db :contacts assoc whisper-identity contact)) ((after save-contact)))) (defn load-contacts! [db _] - (let [contacts (contacts/get-contacts)] + (let [contacts (->> (contacts/get-contacts) + (map (fn [{:keys [whisper-identity] :as contact}] + [whisper-identity contact])) + (into {}))] (assoc db :contacts contacts))) -(register-handler :load-syng-contacts load-contacts!) +(register-handler :load-contacts load-contacts!) ;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45 (def react-native-contacts (js/require "react-native-contacts")) diff --git a/src/syng_im/contacts/screen.cljs b/src/syng_im/contacts/screen.cljs index 9170c7b9cb..3e16b78380 100644 --- a/src/syng_im/contacts/screen.cljs +++ b/src/syng_im/contacts/screen.cljs @@ -1,7 +1,5 @@ (ns syng-im.contacts.screen - (:require-macros - [natal-shell.data-source :refer [data-source clone-with-rows]] - [natal-shell.core :refer [with-error-view]]) + (:require-macros [syng-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] [syng-im.components.react :refer [view text image @@ -17,9 +15,6 @@ (defn render-row [row _ _] (list-item [contact-view row])) -(defn get-data-source [contacts] - (clone-with-rows (data-source {:rowHasChanged not=}) contacts)) - (defn contact-list-toolbar [] [toolbar {:title "Contacts" :background-color toolbar-background2 @@ -27,14 +22,14 @@ :style st/search-icon} :handler (fn [])}}]) -(defn contact-list [] - (let [contacts (subscribe [:get :contacts])] - (fn [] - (let [contacts-ds (lw/to-datasource @contacts)] - [view st/contacts-list-container - [contact-list-toolbar] - (when contacts-ds - [list-view {:dataSource contacts-ds - :enableEmptySections true - :renderRow render-row - :style st/contacts-list}])])))) +(defview contact-list [] + [contacts [:get-contacts]] + [view st/contacts-list-container + [contact-list-toolbar] + ;; todo what if there is no contacts, should we show some information + ;; about this? + (when contacts + [list-view {:dataSource (lw/to-datasource contacts) + :enableEmptySections true + :renderRow render-row + :style st/contacts-list}])]) diff --git a/src/syng_im/contacts/subs.cljs b/src/syng_im/contacts/subs.cljs index 81459071c6..5e9616002f 100644 --- a/src/syng_im/contacts/subs.cljs +++ b/src/syng_im/contacts/subs.cljs @@ -1,3 +1,8 @@ (ns syng-im.contacts.subs (:require-macros [reagent.ratom :refer [reaction]]) (:require [re-frame.core :refer [register-sub]])) + +(register-sub :get-contacts + (fn [db _] + (let [contacts (reaction (:contacts @db))] + (reaction (vals @contacts))))) diff --git a/src/syng_im/contacts/views/contact.cljs b/src/syng_im/contacts/views/contact.cljs index d094ae02f0..861a4c3cfa 100644 --- a/src/syng_im/contacts/views/contact.cljs +++ b/src/syng_im/contacts/views/contact.cljs @@ -1,8 +1,16 @@ (ns syng-im.contacts.views.contact + (:require-macros [syng-im.utils.views :refer [defview]]) (:require [syng-im.components.react :refer [view touchable-highlight]] - [re-frame.core :refer [dispatch]] + [re-frame.core :refer [dispatch subscribe]] [syng-im.contacts.views.contact-inner :refer [contact-inner-view]])) -(defn contact-view [contact] - [touchable-highlight {:onPress #(dispatch [:navigate-to :chat])} +(defn on-press [chat whisper-identity] + (if chat + #(dispatch [:navigate-to :chat whisper-identity]) + #(dispatch [:start-chat whisper-identity]))) + +(defview contact-view [{:keys [whisper-identity] :as contact}] + [chat [:get-chat whisper-identity]] + [touchable-highlight + {:onPress (on-press chat whisper-identity)} [view {} [contact-inner-view contact]]]) diff --git a/src/syng_im/db.cljs b/src/syng_im/db.cljs index 6e079af948..19eaa4ced4 100644 --- a/src/syng_im/db.cljs +++ b/src/syng_im/db.cljs @@ -10,6 +10,7 @@ (def app-db {:identity-password "replace-me-with-user-entered-password" :identity "me" :contacts [] + :contacts-ids #{} :current-chat-id "console" :chat {:command nil :last-message nil} @@ -39,4 +40,3 @@ [:chats chat-id :command-requests]) (defn chat-command-request-path [chat-id msg-id] [:chats chat-id :command-requests msg-id]) -(def updated-current-tag-signal-path [:current-tag-updated-signal]) diff --git a/src/syng_im/models/commands.cljs b/src/syng_im/models/commands.cljs index 15d7ffc8fa..c35492bd0a 100644 --- a/src/syng_im/models/commands.cljs +++ b/src/syng_im/models/commands.cljs @@ -75,52 +75,56 @@ (defn find-command [commands command-key] (first (filter #(= command-key (:command %)) commands))) -(defn get-chat-command-content [db] - (get-in db (db/chat-command-content-path (:current-chat-id db)))) +(defn get-chat-command-content + [{:keys [current-chat-id] :as db}] + (get-in db (db/chat-command-content-path current-chat-id))) -(defn set-chat-command-content [db content] - (assoc-in db - [:chats (:current-chat-id db) :command-input :content] - content)) +(defn set-chat-command-content + [{:keys [current-chat-id] :as db} content] + (assoc-in db [:chats current-chat-id :command-input :content] content)) -(defn get-chat-command [db] - (get-in db (db/chat-command-path (:current-chat-id db)))) +(defn get-chat-command + [{:keys [current-chat-id] :as db}] + (get-in db (db/chat-command-path current-chat-id))) -(defn set-response-chat-command [db msg-id command-key] - (let [chat-id (:current-chat-id db)] - (-> db - (assoc-in [:chats chat-id :command-input :content] nil) - (assoc-in [:chats chat-id :command-input :command] - (get-command db command-key)) - (assoc-in [:chats chat-id :command-input :to-msg-id] msg-id)))) +(defn set-response-chat-command + [{:keys [current-chat-id] :as db} msg-id command-key] + (update-in db [:chats current-chat-id :command-input] merge + {:content nil + :command (get-command db command-key) + :to-msg-id msg-id})) (defn set-chat-command [db command-key] (set-response-chat-command db nil command-key)) -(defn get-chat-command-to-msg-id [db] - (get-in db (db/chat-command-to-msg-id-path (:current-chat-id db)))) +(defn get-chat-command-to-msg-id + [{:keys [current-chat-id] :as db}] + (get-in db (db/chat-command-to-msg-id-path current-chat-id))) -(defn stage-command [db command-info] - (update-in db (db/chat-staged-commands-path (:current-chat-id db)) - (fn [staged-commands] - (if staged-commands - (conj staged-commands command-info) - [command-info])))) +(defn stage-command + [{:keys [current-chat-id] :as db} command-info] + (update-in db (db/chat-staged-commands-path current-chat-id) + #(if % + (conj % command-info) + [command-info]))) (defn unstage-command [db staged-command] (update-in db (db/chat-staged-commands-path (:current-chat-id db)) (fn [staged-commands] (filterv #(not= % staged-command) staged-commands)))) -(defn clear-staged-commands [db] - (assoc-in db (db/chat-staged-commands-path (:current-chat-id db)) [])) +(defn clear-staged-commands + [{:keys [current-chat-id] :as db}] + (assoc-in db (db/chat-staged-commands-path current-chat-id) [])) -(defn get-chat-command-request [db] - (get-in db (db/chat-command-request-path (:current-chat-id db) +(defn get-chat-command-request + [{:keys [current-chat-id] :as db}] + (get-in db (db/chat-command-request-path current-chat-id (get-chat-command-to-msg-id db)))) -(defn set-chat-command-request [db msg-id handler] - (update-in db (db/chat-command-requests-path (:current-chat-id db)) +(defn set-chat-command-request + [{:keys [current-chat-id] :as db} msg-id handler] + (update-in db (db/chat-command-requests-path current-chat-id) #(assoc % msg-id handler))) (defn parse-command-msg-content [commands content] diff --git a/src/syng_im/participants/views/create.cljs b/src/syng_im/participants/views/create.cljs index c059bfc785..20a84dfbfa 100644 --- a/src/syng_im/participants/views/create.cljs +++ b/src/syng_im/participants/views/create.cljs @@ -4,29 +4,27 @@ [syng-im.components.react :refer [view list-view list-item]] [syng-im.components.toolbar :refer [toolbar]] [syng-im.utils.listview :refer [to-datasource]] - [syng-im.participants.views.contact - :refer [participant-contact]] + [syng-im.participants.views.contact :refer [participant-contact]] [reagent.core :as r] [syng-im.participants.styles :as st])) -(defn new-participants-toolbar [navigator] +(defn new-participants-toolbar [] [toolbar - {:navigator navigator - :title "Add Participants" + {:title "Add Participants" :action {:image {:source res/v ;; {:uri "icon_search"} :style st/new-participant-image} - :handler #(dispatch [:add-new-participants navigator])}}]) + :handler #(dispatch [:add-new-participants])}}]) (defn new-participants-row [row _ _] (list-item [participant-contact row])) -(defn new-participants [{:keys [navigator]}] +(defn new-participants [] (let [contacts (subscribe [:all-new-contacts])] (fn [] (let [contacts-ds (to-datasource @contacts)] [view st/participants-container - [new-participants-toolbar navigator] + [new-participants-toolbar] [list-view {:dataSource contacts-ds :renderRow new-participants-row :style st/participants-list}]])))) diff --git a/src/syng_im/subs.cljs b/src/syng_im/subs.cljs index e485b39220..a4c96c2ffb 100644 --- a/src/syng_im/subs.cljs +++ b/src/syng_im/subs.cljs @@ -23,11 +23,6 @@ (fn [db _] (reaction (:signed-up @db)))) -(register-sub - :get-contacts - (fn [db _] - (reaction (:contacts @db)))) - (register-sub :all-contacts (fn [db _] (let [contacts (reaction (:contacts @db))] @@ -44,7 +39,7 @@ (map :identity) set)] (fn #(current-participants (:whisper-identity %)) - @contacts)))))) + (vals @contacts))))))) (register-sub :all-new-contacts (fn [db _]