Merge pull request #202 from status-im/feature/group-chat

Group chat: basic features

Former-commit-id: dc65163da0
This commit is contained in:
Roman Volosovskyi 2016-08-26 16:01:06 +03:00 committed by GitHub
commit a4e928aeb7
17 changed files with 105 additions and 86 deletions

View File

@ -82,10 +82,12 @@
(when needs-update? (when needs-update?
(dispatch [:account-update])))))) (dispatch [:account-update]))))))
(defn initialize-account [db address] (defn initialize-account [{:keys [accounts] :as db} address]
(let [is-login-screen? (= (:view-id db) :login)] (let [is-login-screen? (= (:view-id db) :login)]
(dispatch [:set :login {}]) (dispatch [:set :login {}])
(dispatch [:set :current-account-id address]) (dispatch [:set :current-account-id address])
(let [key (:public-key (accounts address))]
(dispatch [:set :current-public-key key]))
(dispatch [:initialize-account address]) (dispatch [:initialize-account address])
(when is-login-screen? (dispatch [:navigate-to-clean default-view])))) (when is-login-screen? (dispatch [:navigate-to-clean default-view]))))

View File

@ -25,7 +25,7 @@
{:flex 1}))) {:flex 1})))
(def account-list (def account-list
{:margin-top 56 {:margin-top 20
:height 100}) :height 100})
(def row-separator (def row-separator

View File

@ -234,11 +234,6 @@
(after #(dispatch [:load-unviewed-messages!])) (after #(dispatch [:load-unviewed-messages!]))
((enrich initialize-chats) load-chats!)) ((enrich initialize-chats) load-chats!))
(register-handler :group-received-msg
(u/side-effect!
(fn [_ [_ {chat-id :group-id :as msg}]]
(messages/save-message chat-id msg))))
(defmethod nav/preload-data! :chat (defmethod nav/preload-data! :chat
[{:keys [current-chat-id] :as db} [_ _ id]] [{:keys [current-chat-id] :as db} [_ _ id]]
(let [chat-id (or id current-chat-id) (let [chat-id (or id current-chat-id)

View File

@ -16,26 +16,37 @@
:rendered-preview rendered-preview)) :rendered-preview rendered-preview))
message)) message))
(defn store-message [{chat-id :from :as message}] (defn store-message [{chat-id :chat-id :as message}]
(messages/save-message chat-id (dissoc message :rendered-preview :new?))) (messages/save-message chat-id (dissoc message :rendered-preview :new?)))
(register-handler :received-message (defn get-current-identity
(u/side-effect! [{:keys [current-account-id accounts]}]
(fn [{:keys [chats] :as db} [_ {chat-id :from :keys [msg-id] :as message}]] (:public-key (accounts current-account-id)))
(let [same-message (messages/get-message msg-id)]
(when-not same-message (defn receive-message
(let [message' (assoc (->> message [db [_ {:keys [from group-id chat-id msg-id] :as message}]]
(cu/check-author-direction db chat-id) (let [same-message (messages/get-message msg-id)
current-identity (get-current-identity db)]
(when-not (or same-message (= from current-identity))
(let [group-chat? (not (nil? group-id))
chat-id' (or chat-id from)
previous-message (messages/get-last-message chat-id')
message' (assoc (->> message
(cu/check-author-direction previous-message)
(check-previev)) (check-previev))
:delivery-status :pending)] :delivery-status :pending
:chat-id chat-id')]
(store-message message') (store-message message')
(when-not (c/chat-exists? chat-id) (when-not (c/chat-exists? chat-id')
(dispatch [:add-chat chat-id])) (dispatch [:add-chat chat-id' (when group-chat? {:group-chat true})]))
(dispatch [::add-message message']) (dispatch [::add-message message'])
(when (= (:content-type message') content-type-command-request) (when (= (:content-type message') content-type-command-request)
(dispatch [:add-request chat-id message'])) (dispatch [:add-request chat-id' message']))
(dispatch [:add-unviewed-message chat-id msg-id]))))))) (dispatch [:add-unviewed-message chat-id' msg-id])))))
(register-handler :received-message
(u/side-effect! receive-message))
(register-handler ::add-message (register-handler ::add-message
(fn [db [_ {chat-id :from :keys [new?] :as message}]] (fn [db [_ {:keys [chat-id new?] :as message}]]
(cu/add-message-to-db db chat-id message new?))) (cu/add-message-to-db db chat-id message new?)))

View File

@ -20,25 +20,6 @@
:seen :seen
:pending)) :pending))
(defn prepare-message
[{:keys [identity current-chat-id] :as db} _]
(let [text (get-in db [:chats current-chat-id :input-text])
[command] (suggestions/check-suggestion db (str text " "))
message (cu/check-author-direction
db current-chat-id
{:msg-id (random/id)
:chat-id current-chat-id
:content text
:to current-chat-id
:from identity
:content-type text-content-type
:delivery-status (default-delivery-status current-chat-id)
:outgoing true
:timestamp (time/now-ms)})]
(if command
(commands/set-command-input db :commands command)
(assoc db :new-message (when-not (s/blank? text) message)))))
(defn prepare-command (defn prepare-command
[identity chat-id {:keys [preview preview-string content command to-message]}] [identity chat-id {:keys [preview preview-string content command to-message]}]
(let [content {:command (command :name) (let [content {:command (command :name)
@ -166,14 +147,15 @@
:timestamp (time/now-ms)}) :timestamp (time/now-ms)})
params' (assoc params :message message')] params' (assoc params :message message')]
(dispatch [::add-message params']) (dispatch [::add-message params'])
(dispatch [::save-message! params']) (dispatch [::save-message! params'])))))
(dispatch [::send-message! params'])))))
(register-handler ::add-message (register-handler ::add-message
(fn [db [_ {:keys [chat-id message]}]] (fn [db [_ {:keys [chat-id message]}]]
(cu/add-message-to-db db chat-id message))) (cu/add-message-to-db db chat-id message)))
(register-handler ::save-message! (register-handler ::save-message!
(after (fn [_ [_ params]]
(dispatch [::send-message! params])))
(u/side-effect! (u/side-effect!
(fn [_ [_ {:keys [chat-id message]}]] (fn [_ [_ {:keys [chat-id message]}]]
(messages/save-message chat-id message)))) (messages/save-message chat-id message))))

View File

@ -207,7 +207,7 @@
(subscribe [:chat-properties [:group-chat :name :contacts :chat-id]]) (subscribe [:chat-properties [:group-chat :name :contacts :chat-id]])
show-actions (subscribe [:show-actions]) show-actions (subscribe [:show-actions])
contact (subscribe [:get-in [:contacts @chat-id]])] contact (subscribe [:get-in [:contacts @chat-id]])]
(fn [] (fn [platform-specific]
[view (st/chat-name-view @show-actions) [view (st/chat-name-view @show-actions)
[text {:style st/chat-name-text [text {:style st/chat-name-text
:platform-specific platform-specific :platform-specific platform-specific
@ -241,15 +241,14 @@
[view st/action [view st/action
[chat-icon]]])))) [chat-icon]]]))))
(defn chat-toolbar [platform-specific] (defview chat-toolbar [platform-specific]
(let [{:keys [group-chat name contacts]} (subscribe [:chat-properties [:group-chat :name :contacts]]) [show-actions [:show-actions]]
show-actions (subscribe [:show-actions])]
[view [view
[status-bar {:platform-specific platform-specific}] [status-bar {:platform-specific platform-specific}]
[toolbar {:hide-nav? @show-actions [toolbar {:hide-nav? show-actions
:custom-content [toolbar-content platform-specific] :custom-content [toolbar-content platform-specific]
:custom-action [toolbar-action] :custom-action [toolbar-action]
:style (get-in platform-specific [:styles :components :toolbar])}]])) :style (get-in platform-specific [:styles :components :toolbar])}]])
(defview messages-view [platform-specific group-chat] (defview messages-view [platform-specific group-chat]
[messages [:chat :messages] [messages [:chat :messages]
@ -305,7 +304,8 @@
[chat-toolbar platform-specific] [chat-toolbar platform-specific]
[messages-container [messages-container
[messages-view platform-specific @group-chat]] [messages-view platform-specific @group-chat]]
(when @group-chat [typing-all platform-specific]) ;; todo uncomment this
#_(when @group-chat [typing-all platform-specific])
[response-view] [response-view]
(when-not @command? [suggestion-container]) (when-not @command? [suggestion-container])
[chat-message-new platform-specific] [chat-message-new platform-specific]

View File

@ -52,8 +52,9 @@
(dispatch [:sign-up-confirm (second matches)]))) (dispatch [:sign-up-confirm (second matches)])))
(defn start-listening-confirmation-code-sms [db] (defn start-listening-confirmation-code-sms [db]
(when (not (:confirmation-code-sms-listener db)) (if (not (:confirmation-code-sms-listener db))
(assoc db :confirmation-code-sms-listener (add-sms-listener handle-sms)))) (assoc db :confirmation-code-sms-listener (add-sms-listener handle-sms))
db))
(defn stop-listening-confirmation-code-sms [db] (defn stop-listening-confirmation-code-sms [db]
(when-let [listener (:confirmation-code-sms-listener db)] (when-let [listener (:confirmation-code-sms-listener db)]

View File

@ -238,3 +238,8 @@
(fn [db] (fn [db]
(let [chat-id (subscribe [:get-current-chat-id])] (let [chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:chats @chat-id :all-loaded?]))))) (reaction (get-in @db [:chats @chat-id :all-loaded?])))))
(register-sub :photo-path
(fn [_ [_ id]]
(let [contacts (subscribe [:get :contacts])]
(reaction (:photo-path (@contacts id))))))

View File

@ -15,13 +15,18 @@
true true
new?)))))) new?))))))
(defn check-author-direction (defn- check-message [previous-message {:keys [from outgoing] :as message}]
[db chat-id {:keys [from outgoing] :as message}]
(let [previous-message (first (get-in db [:chats chat-id :messages]))]
(merge message (merge message
{:same-author (if previous-message {:same-author (if previous-message
(= (:from previous-message) from) (= (:from previous-message) from)
true) false)
:same-direction (if previous-message :same-direction (if previous-message
(= (:outgoing previous-message) outgoing) (= (:outgoing previous-message) outgoing)
true)}))) true)}))
(defn check-author-direction
([previous-message message]
(check-message previous-message message))
([db chat-id message]
(let [previous-message (first (get-in db [:chats chat-id :messages]))]
(check-message previous-message message))))

View File

@ -159,7 +159,8 @@
:failed "Failed" :failed "Failed"
"Pending")]]) "Pending")]])
(defn member-photo [{:keys [photo-path]}] (defview member-photo [from]
[photo-path [:photo-path from]]
[view st/photo-view [view st/photo-view
[image {:source (if (s/blank? photo-path) [image {:source (if (s/blank? photo-path)
res/user-no-photo res/user-no-photo
@ -167,7 +168,7 @@
:style st/photo}]]) :style st/photo}]])
(defn incoming-group-message-body (defn incoming-group-message-body
[{:keys [selected same-author] :as message} content platform-specific] [{:keys [selected same-author from] :as message} content platform-specific]
(let [delivery-status :seen-by-everyone] (let [delivery-status :seen-by-everyone]
[view st/group-message-wrapper [view st/group-message-wrapper
(when selected (when selected
@ -177,7 +178,7 @@
"Mar 7th, 15:22"]) "Mar 7th, 15:22"])
[view (st/incoming-group-message-body-st message) [view (st/incoming-group-message-body-st message)
[view st/message-author [view st/message-author
(when (not same-author) [member-photo {}])] (when (not same-author) [member-photo from])]
[view st/group-message-view [view st/group-message-view
content content
;; TODO show for last or selected ;; TODO show for last or selected

View File

@ -168,7 +168,7 @@
[view [icon :ok-purple st/add-members-icon]]] [view [icon :ok-purple st/add-members-icon]]]
[touchable-highlight {:style (st/chat-name-btn-edit-container true) [touchable-highlight {:style (st/chat-name-btn-edit-container true)
:on-press focus} :on-press focus}
[text {:style st/chat-name-btn-edit-text} (label :t/edit)]])] [view [text {:style st/chat-name-btn-edit-text} (label :t/edit)]]])]
(when (pos? (count validation-messages)) (when (pos? (count validation-messages))
[text {:style st/chat-name-validation-message} (first validation-messages)])]) [text {:style st/chat-name-validation-message} (first validation-messages)])])

View File

@ -102,8 +102,7 @@
:opacity (if enabled? 1 0.3)}) :opacity (if enabled? 1 0.3)})
(def chat-name-btn-edit-text (def chat-name-btn-edit-text
{:marginTop -1 {:color text2-color
:color text2-color
:fontFamily font :fontFamily font
:fontSize 16 :fontSize 16
:lineHeight 20}) :lineHeight 20})
@ -118,7 +117,7 @@
:lineHeight 20}) :lineHeight 20})
(def add-members-icon (def add-members-icon
{:marginVertical 19 {:marginVertical -1
:marginLeft 19 :marginLeft 19
:marginHorizontal 3 :marginHorizontal 3
:width 17 :width 17

View File

@ -59,7 +59,8 @@
(register-handler :initialize-db (register-handler :initialize-db
(fn [_ _] (fn [_ _]
(realm/reset-account) (realm/reset-account)
(assoc app-db :current-account-id nil))) (assoc app-db :current-account-id nil
:current-public-key nil)))
(register-handler :initialize-account-db (register-handler :initialize-account-db
(fn [db _] (fn [db _]

View File

@ -76,3 +76,8 @@
(defn get-message [id] (defn get-message [id]
(r/get-one-by-field :account :message :msg-id id)) (r/get-one-by-field :account :message :msg-id id))
(defn get-last-message [chat-id]
(-> (r/get-by-field :account :message :chat-id chat-id)
(r/sorted :timestamp :desc)
(r/single)
(js->clj :keywordize-keys true)))

View File

@ -4,7 +4,8 @@
[status-im.utils.handlers :refer [register-handler]] [status-im.utils.handlers :refer [register-handler]]
[status-im.components.styles :refer [default-chat-color]] [status-im.components.styles :refer [default-chat-color]]
[status-im.models.chats :as chats] [status-im.models.chats :as chats]
[clojure.string :as s])) [clojure.string :as s]
[status-im.utils.handlers :as u]))
(defn deselect-contact (defn deselect-contact
[db [_ id]] [db [_ id]]
@ -87,7 +88,14 @@
; todo rewrite ; todo rewrite
(register-handler :group-chat-invite-received (register-handler :group-chat-invite-received
(fn [db [action from group-id identities group-name]] (u/side-effect!
(fn [{:keys [current-public-key] :as db}
[action from group-id identities group-name]]
(if (chats/chat-exists? group-id) (if (chats/chat-exists? group-id)
(chats/re-join-group-chat db group-id identities group-name) (chats/re-join-group-chat db group-id identities group-name)
(chats/create-chat db group-id identities true group-name)))) (let [contacts (keep (fn [ident]
(when (not= ident current-public-key)
{:identity ident})) identities)]
(dispatch [:add-chat group-id {:name group-name
:group-chat true
:contacts contacts}]))))))

View File

@ -74,7 +74,7 @@
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id ack-msg-id]] (fn [_ [action from group-id ack-msg-id]]
(log/debug action from group-id ack-msg-id) (log/debug action from group-id ack-msg-id)
(joined-chat-msg group-id from ack-msg-id)))) #_(joined-chat-msg group-id from ack-msg-id))))
(register-handler :participant-removed-from-group (register-handler :participant-removed-from-group
(u/side-effect! (u/side-effect!

View File

@ -18,7 +18,10 @@
:initialized (let [{:keys [identity]} event] :initialized (let [{:keys [identity]} event]
(dispatch [:protocol-initialized identity])) (dispatch [:protocol-initialized identity]))
:new-msg (let [{:keys [from to payload]} event] :new-msg (let [{:keys [from to payload]} event]
(dispatch [:received-message (assoc payload :from from :to to)])) (dispatch [:received-message (assoc payload
:chat-id from
:from from
:to to)]))
:msg-acked (let [{:keys [msg-id from]} event] :msg-acked (let [{:keys [msg-id from]} event]
(dispatch [:acked-msg from msg-id])) (dispatch [:acked-msg from msg-id]))
:msg-seen (let [{:keys [msg-id from]} event] :msg-seen (let [{:keys [msg-id from]} event]
@ -30,8 +33,9 @@
:new-group-msg (let [{from :from :new-group-msg (let [{from :from
group-id :group-id group-id :group-id
payload :payload} event] payload :payload} event]
(dispatch [:group-received-msg (assoc payload :from from (dispatch [:received-message (assoc payload
:group-id group-id)])) :chat-id group-id
:from from)]))
:group-chat-invite-acked (let [{:keys [from group-id ack-msg-id]} event] :group-chat-invite-acked (let [{:keys [from group-id ack-msg-id]} event]
(dispatch [:group-chat-invite-acked from group-id ack-msg-id])) (dispatch [:group-chat-invite-acked from group-id ack-msg-id]))
:group-new-participant (let [{:keys [group-id identity from msg-id]} event] :group-new-participant (let [{:keys [group-id identity from msg-id]} event]