leave group/ clear history/ add-remove participants

This commit is contained in:
Roman Volosovskyi 2016-05-21 15:23:24 +03:00
parent cd45d3420e
commit 01d1ccdab8
15 changed files with 302 additions and 291 deletions

View File

@ -11,7 +11,8 @@
[syng-im.chat.sign-up :as sign-up-service]
[syng-im.models.chats :as chats]
[syng-im.navigation.handlers :as nav]
[syng-im.utils.handlers :as u]))
[syng-im.utils.handlers :as u]
[syng-im.persistence.realm :as r]))
(register-handler :set-show-actions
(fn [db [_ show-actions]]
@ -325,3 +326,45 @@
(register-handler :switch-command-suggestions
(fn [db [_]]
(suggestions/switch-command-suggestions db)))
(defn remove-chat
[{:keys [current-chat-id] :as db} _]
(update db :chats dissoc current-chat-id))
(defn notify-about-leaving!
[{:keys [current-chat-id]} _]
(api/leave-group-chat current-chat-id))
; todo do we really need this message?
(defn leaving-message!
[{:keys [current-chat-id]} _]
(messages/save-message
current-chat-id
{:from "system"
:msg-id (random/id)
:content "You left this chat"
:content-type text-content-type}))
(defn delete-messages!
[{:keys [current-chat-id]} _]
(r/write
(fn []
(r/delete (r/get-by-field :msgs :chat-id current-chat-id)))))
(defn delete-chat!
[{:keys [current-chat-id]} _]
(r/write
(fn []
(-> (r/get-by-field :chats :chat-id current-chat-id)
(r/single)
(r/delete)))))
(register-handler :leave-group-chat
;; todo oreder of operations tbd
(after (fn [_ _] (dispatch [:navigation-replace :chat-list])))
(-> remove-chat
;; todo uncomment
;((after notify-about-leaving!))
;((after leaving-message!))
((after delete-messages!))
((after delete-chat!))))

View File

@ -18,7 +18,7 @@
:chats {}
:chats-updated-signal 0
:show-actions false
:new-participants #{}
:selected-participants #{}
:signed-up true
:view-id default-view
:navigation-stack (list default-view)

View File

@ -1,7 +1,20 @@
(ns syng-im.group-settings.handlers
(:require [re-frame.core :refer [register-handler debug dispatch after]]
(:require [re-frame.core :refer [register-handler debug dispatch after
enrich]]
[syng-im.persistence.realm :as r]
[syng-im.models.messages :refer [clear-history]]))
[syng-im.chat.handlers :refer [delete-messages!]]
[syng-im.protocol.api :as api]
[syng-im.utils.random :as random]
[syng-im.models.contacts :as contacts]
[syng-im.models.messages :as messages]
[syng-im.models.chats :as chats]
[syng-im.constants :refer [text-content-type]]
[syng-im.utils.handlers :as u]
[syng-im.navigation.handlers :as nav]))
(defmethod nav/preload-data! :group-settings
[db _]
(assoc db :selected-participants #{}))
(defn save-chat-property!
[db-name property-name]
@ -18,15 +31,6 @@
(let [property (db-name db)]
(assoc-in db [:chats current-chat-id property-name] property))))
(defn delete-chat [chat-id]
(r/write
(fn []
(-> (r/get-by-field :chats :chat-id chat-id)
(r/single)
(r/delete))))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats]))
(defn prepare-chat-settings
[{:keys [current-chat-id] :as db} _]
(let [{:keys [name color]} (-> db
@ -49,10 +53,92 @@
(after (save-chat-property! :new-chat-color :color))
(update-chat-property :new-chat-color :color))
(defn clear-messages
[{:keys [current-chat-id] :as db} _]
(assoc-in db [:chats current-chat-id :messages] '()))
(register-handler :clear-history
(fn [db _]
(clear-history (:current-chat-id db))))
(after delete-messages!)
clear-messages)
(register-handler :group-settings
(fn [db [_ k v]]
(assoc-in db [:group-settings k] v)))
(defn remove-identities [collection identities]
(remove #(identities (:identity %)) collection))
(defn remove-members
[{:keys [current-chat-id selected-participants] :as db} _]
(update-in db [:chats current-chat-id :contacts]
remove-identities selected-participants))
(defn remove-members-from-realm!
[{:keys [current-chat-id selected-participants] :as db} _]
(let [chat (get-in db [:chats current-chat-id])]
(r/write
(fn []
(r/create
:chats
(update chat :contacts remove-identities selected-participants)
true)))))
(defn notify-about-removing!
[{:keys [current-chat-id selected-participants]} _]
(doseq [participant selected-participants]
(api/group-remove-participant current-chat-id participant)))
(defn system-message [msg-id content]
{:from "system"
:msg-id msg-id
:content content
:content-type text-content-type})
(defn removed-participant-msg [chat-id identity]
(let [contact-name (:name (contacts/contact-by-identity identity))]
(->> (str "You've removed " (or contact-name identity))
(system-message (random/id))
(messages/save-message chat-id))))
(defn create-removing-messages!
[{:keys [current-chat-id selected-participants]} _]
(doseq [participant selected-participants]
(removed-participant-msg current-chat-id participant)))
(defn deselect-members [db _]
(assoc db :selected-participants #{}))
(register-handler :remove-participants
;; todo check if user have rights to add/remove participants
;; todo order of operations tbd
(-> remove-members
;; todo shouldn't this be done only after receiving of the "ack message"
;; about the api call that removes participants from the group?
((after remove-members-from-realm!))
;; todo uncomment
;((after notify-about-removing!))
((after create-removing-messages!))
((enrich deselect-members))
debug))
(defn add-memebers
[{:keys [current-chat-id selected-participants] :as db} _]
(let [new-identities (map #(hash-map :identity %) selected-participants)]
(update db [:chats current-chat-id :contacts] concat new-identities)))
(defn add-members-to-realm!
[{:keys [current-chat-id selected-participants]} _]
(chats/chat-add-participants current-chat-id selected-participants))
(defn notify-about-new-members!
[{:keys [current-chat-id selected-participants]} _]
(doseq [identity selected-participants]
(api/group-add-participant current-chat-id identity)))
(register-handler :add-new-participants
;; todo order of operations tbd
(-> add-memebers
((after add-members-to-realm!))
;; todo uncomment
;((after notify-about-new-members!))
((enrich deselect-members))))

View File

@ -16,25 +16,25 @@
[syng-im.group-settings.views.member :refer [member-view]]
[clojure.string :as s]))
(defn remove-member [{:keys [whisper-identity]}]
(dispatch [:chat-remove-member whisper-identity]))
(defn remove-member []
(dispatch [:remove-participants]))
(defn close-member-menu []
(dispatch [:set :group-settings-selected-member nil]))
(dispatch [:set :selected-participants #{}]))
(defview member-menu []
[member [:group-settings-selected-member]]
[{:keys [name] :as participant} [:selected-participant]]
(when participant
[modal {:animated false
:transparent false
:onRequestClose close-member-menu}
[touchable-highlight {:style st/modal-container
:on-press close-member-menu}
[view st/modal-inner-container
[text {:style st/modal-member-name}
(:name member)]
[touchable-highlight {:on-press #(remove-member member)}
[text {:style st/modal-member-name} name]
[touchable-highlight {:on-press remove-member}
[text {:style st/modal-remove-text}
"Remove"]]]]])
"Remove"]]]]]))
(defview chat-members []
[members [:current-chat-contacts]]
@ -42,9 +42,6 @@
(for [member members]
^{:key member} [member-view member])])
(defn show-chat-name-edit []
(dispatch [:navigate-to :chat-name-edit]))
(defn setting-view [{:keys [icon-style custom-icon handler title subtitle]
icon-name :icon}]
[touchable-highlight {:on-press handler}
@ -161,8 +158,7 @@
[text {:style st/chat-name-btn-edit-text} "Edit"]])]])
(defview group-settings []
[selected-member [:group-settings-selected-member]
show-color-picker [:group-settings :show-color-picker]]
[show-color-picker [:group-settings :show-color-picker]]
[view st/group-settings
[new-group-toolbar]
[scroll-view st/body
@ -179,5 +175,4 @@
[settings-view]]
(when show-color-picker
[chat-color-picker])
(when selected-member
[member-menu])])
[member-menu]])

View File

@ -2,10 +2,10 @@
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub]]))
(register-sub :group-settings-selected-member
(register-sub :selected-participant
(fn [db [_]]
(reaction
(let [identity (get @db :group-settings-selected-member)]
(let [identity (first (get @db :selected-participants))]
(get-in @db [:contacts identity])))))
(register-sub :group-settings

View File

@ -38,6 +38,6 @@
[text {:style st/role-text}
role])]
[touchable-highlight
{:on-press #(dispatch [:set :group-settings-selected-member whisper-identity])}
{:on-press #(dispatch [:set :selected-participants #{whisper-identity}])}
[view st/more-btn
[icon :more-vertical st/more-btn-icon]]]])

View File

@ -1,47 +1,23 @@
(ns syng-im.handlers
(:require
[re-frame.core :refer [register-handler after dispatch debug enrich]]
[re-frame.core :refer [register-handler after dispatch debug]]
[schema.core :as s :include-macros true]
[syng-im.persistence.realm :as r]
[syng-im.db :refer [app-db schema]]
[syng-im.persistence.simple-kv-store :as kv]
[syng-im.protocol.state.storage :as storage]
[syng-im.db :as db :refer [app-db schema]]
[syng-im.protocol.api :refer [init-protocol]]
[syng-im.protocol.protocol-handler :refer [make-handler]]
[syng-im.models.protocol :refer [update-identity
set-initialized]]
[syng-im.models.contacts :as contacts]
[syng-im.models.messages :refer [save-message
update-message!
clear-history]]
[syng-im.models.commands :refer [set-commands]]
[syng-im.handlers.server :as server]
[syng-im.chat.suggestions :refer [load-commands]]
[syng-im.models.chats :refer [chat-exists?
create-chat
chat-add-participants
chat-remove-participants
set-chat-active
re-join-group-chat
chat-by-id2]]
[syng-im.utils.logging :as log]
[syng-im.protocol.api :as api]
[syng-im.constants :refer [text-content-type
content-type-command]]
[syng-im.navigation :refer [nav-push
nav-replace
nav-pop]]
[syng-im.utils.crypt :refer [gen-random-bytes]]
[syng-im.utils.random :as random]
[syng-im.utils.handlers :as u]
syng-im.chat.handlers
[syng-im.group-settings.handlers :refer [delete-chat]]
syng-im.group-settings.handlers
syng-im.navigation.handlers
syng-im.contacts.handlers
syng-im.discovery.handlers
syng-im.new-group.handlers
syng-im.participants.handlers))
syng-im.participants.handlers
syng-im.protocol.handlers))
;; -- Middleware ------------------------------------------------------------
;;
@ -106,193 +82,8 @@
(log/debug action commands)
(set-commands db commands)))
;; -- Protocol --------------------------------------------------------------
(register-handler :initialize-protocol
(u/side-effect!
(fn [db [_]]
(init-protocol (make-handler db)))))
(register-handler :protocol-initialized
(fn [db [_ identity]]
(-> db
(update-identity identity)
(set-initialized true))))
(defn system-message [msg-id content]
{:from "system"
:msg-id msg-id
:content content
:content-type text-content-type})
(defn joined-chat-msg [chat-id from msg-id]
(let [contact-name (:name (contacts/contact-by-identity from))]
(save-message chat-id {:from "system"
:msg-id (str msg-id "_" from)
:content (str (or contact-name from) " received chat invitation")
:content-type text-content-type})))
(defn participant-invited-to-group-msg [chat-id identity from msg-id]
(let [inviter-name (:name (contacts/contact-by-identity from))
invitee-name (if (= identity (api/my-identity))
"You"
(:name (contacts/contact-by-identity identity)))]
(save-message chat-id {:from "system"
:msg-id msg-id
:content (str (or inviter-name from) " invited " (or invitee-name identity))
:content-type text-content-type})))
(defn participant-removed-from-group-msg [chat-id identity from msg-id]
(let [remover-name (:name (contacts/contact-by-identity from))
removed-name (:name (contacts/contact-by-identity identity))]
(->> (str (or remover-name from) " removed " (or removed-name identity))
(system-message msg-id)
(save-message chat-id))))
(defn you-removed-from-group-msg [chat-id from msg-id]
(let [remover-name (:name (contacts/contact-by-identity from))]
(->> (str (or remover-name from) " removed you from group chat")
(system-message msg-id)
(save-message chat-id))))
(defn participant-left-group-msg [chat-id from msg-id]
(let [left-name (:name (contacts/contact-by-identity from))]
(->> (str (or left-name from) " left")
(system-message msg-id)
(save-message chat-id))))
(defn removed-participant-msg [chat-id identity]
(let [contact-name (:name (contacts/contact-by-identity identity))]
(->> (str "You've removed " (or contact-name identity))
(system-message (random/id))
(save-message chat-id))))
(defn left-chat-msg [chat-id]
(save-message chat-id {:from "system"
:msg-id (random/id)
:content "You left this chat"
:content-type text-content-type}))
(register-handler :group-chat-invite-acked
(u/side-effect!
(fn [_ [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))))
(register-handler :participant-removed-from-group
(u/side-effect!
(fn [_ [action from group-id identity msg-id]]
(log/debug action msg-id from group-id identity)
(chat-remove-participants group-id [identity])
(participant-removed-from-group-msg group-id identity from msg-id))))
(register-handler :you-removed-from-group
(u/side-effect!
(fn [_ [action from group-id msg-id]]
(log/debug action msg-id from group-id)
(you-removed-from-group-msg group-id from msg-id)
(set-chat-active group-id false))))
(register-handler :participant-left-group
(u/side-effect!
(fn [_ [action from group-id msg-id]]
(log/debug action msg-id from group-id)
(when-not (= (api/my-identity) from)
(participant-left-group-msg group-id from msg-id)))))
(register-handler :participant-invited-to-group
(u/side-effect!
(fn [_ [action from group-id identity msg-id]]
(log/debug action msg-id from group-id identity)
(participant-invited-to-group-msg group-id identity from msg-id))))
(register-handler :acked-msg
(u/side-effect!
(fn [_ [action from msg-id]]
(log/debug action from msg-id)
(update-message! {:msg-id msg-id
:delivery-status :delivered}))))
(register-handler :msg-delivery-failed
(u/side-effect!
(fn [_ [action msg-id]]
(log/debug action msg-id)
(update-message! {:msg-id msg-id
:delivery-status :failed}))))
(register-handler :leave-group-chat
(u/side-effect!
(fn [db [action]]
(log/debug action)
(let [chat-id (:current-chat-id db)]
(api/leave-group-chat chat-id)
(set-chat-active chat-id false)
(left-chat-msg chat-id)
(delete-chat chat-id)
(dispatch [:navigate-back])))))
;; -- User data --------------------------------------------------------------
(register-handler :load-user-phone-number
(fn [db [_]]
;; todo fetch phone number from db
(assoc db :user-phone-number "123")))
;; -- Chats --------------------------------------------------------------
(defn update-new-participants-selection [db identity add?]
(update db :new-participants (fn [new-participants]
(if add?
(conj new-participants identity)
(disj new-participants identity)))))
(register-handler :select-new-participant
(fn [db [action identity add?]]
(log/debug action identity add?)
(update-new-participants-selection db identity add?)))
(register-handler :remove-selected-participants
(fn [db [action]]
(log/debug action)
(let [identities (vec (:new-participants db))
chat-id (:current-chat-id db)]
(chat-remove-participants chat-id identities)
(dispatch [:navigate-back])
(doseq [ident identities]
(api/group-remove-participant chat-id ident)
(removed-participant-msg chat-id ident)))))
(register-handler :add-new-participants
(fn [db [action navigator]]
(log/debug action)
(let [identities (vec (:new-participants db))
chat-id (:current-chat-id db)]
(chat-add-participants chat-id identities)
(dispatch [:navigate-back])
(doseq [ident identities]
(api/group-add-participant chat-id ident))
db)))
(defn chat-remove-member [db]
(let [chat (get-in db [:chats (:current-chat-id db)])
identity (:group-settings-selected-member db)]
(r/write
(fn []
(r/create :chats
(update chat :contacts
(fn [members]
(filter #(not= (:identity %) identity) members)))
true)))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats])
db))
(register-handler :chat-remove-member
(fn [db [action]]
(let [chat-id (:current-chat-id db)
identity (:group-settings-selected-member db)
db (chat-remove-member db)]
(dispatch [:set :group-settings-selected-member nil])
;; TODO fix and uncomment
(api/group-remove-participant chat-id identity)
(removed-participant-msg chat-id identity)
db)))

View File

@ -62,10 +62,3 @@
(fn []
(when (r/exists? :msgs :msg-id msg-id)
(r/create :msgs msg true)))))
(defn clear-history [chat-id]
(r/write
(fn []
(r/delete (r/get-by-field :msgs :chat-id chat-id))))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats]))

View File

@ -1,17 +0,0 @@
(ns syng-im.navigation)
(def ^{:dynamic true :private true} *nav-render*
"Flag to suppress navigator re-renders from outside om when pushing/popping."
true)
(defn nav-pop [nav]
(binding [*nav-render* true]
(.pop nav)))
(defn nav-push [nav route]
(binding [*nav-render* true]
(.push nav (clj->js route))))
(defn nav-replace [nav route]
(binding [*nav-render* true]
(.replace nav (clj->js route))))

View File

@ -18,7 +18,9 @@
(update :navigation-stack replace-top-element view-id)
(assoc :view-id view-id)))
(defmulti preload-data! (fn [_ [_ view-id]] view-id))
(defmulti preload-data!
(fn [db [_ view-id]] (or view-id (:view-id db))))
(defmethod preload-data! :default [db _] db)
(register-handler :navigate-to
@ -32,6 +34,7 @@
(replace-view db view-id)))
(register-handler :navigate-back
(enrich preload-data!)
(fn [{:keys [navigation-stack] :as db} _]
(if (>= 1 (count navigation-stack))
db

View File

@ -4,20 +4,20 @@
(defmethod nav/preload-data! :add-participants
[db _]
(assoc db :new-participants #{}))
(assoc db :selected-participants #{}))
(defmethod nav/preload-data! :remove-participants
[db _]
(assoc db :new-participants #{}))
(assoc db :selected-participants #{}))
(defn deselect-participant
[db [_ id]]
(update db :new-participants disj id))
(update db :selected-participants disj id))
(register-handler :deselect-participant deselect-participant)
(defn select-participant
[db [_ id]]
(update db :new-participants conj id))
(update db :selected-participants conj id))
(register-handler :select-participant (debug select-participant))

View File

@ -4,4 +4,4 @@
[syng-im.utils.subs :as u]))
(register-sub :is-participant-selected?
(u/contains-sub :new-participants))
(u/contains-sub :selected-participants))

View File

@ -14,7 +14,8 @@
{:title "Add Participants"
:action {:image {:source res/v ;; {:uri "icon_search"}
:style st/new-participant-image}
:handler #(dispatch [:add-new-participants])}}])
:handler #(do (dispatch [:add-new-participants])
(dispatch [:navigate-back]))}}])
(defn new-participants-row
[row _ _]

View File

@ -15,7 +15,8 @@
(defn remove-participants-toolbar []
[toolbar
{:title "Remove Participants"
:action {:handler #(dispatch [:remove-selected-participants])
:action {:handler #(do (dispatch [:remove-participants])
(dispatch [:navigate-back]))
:image {:source res/trash-icon ;; {:uri "icon_search"}
:style st/remove-participants-image}}}])

View File

@ -0,0 +1,115 @@
; todo everything inside this namespace must be revievew in common with future
; changes in protocol lib
(ns syng-im.protocol.handlers
(:require [syng-im.utils.handlers :as u]
[syng-im.utils.logging :as log]
[syng-im.protocol.api :as api]
[re-frame.core :refer [register-handler dispatch debug]]
[syng-im.models.contacts :as contacts]
[syng-im.protocol.api :refer [init-protocol]]
[syng-im.protocol.protocol-handler :refer [make-handler]]
[syng-im.models.protocol :refer [update-identity
set-initialized]]
[syng-im.constants :refer [text-content-type]]
[syng-im.models.messages :as messages]
[syng-im.models.chats :as chats]))
(register-handler :initialize-protocol
(u/side-effect!
(fn [db [_]]
(init-protocol (make-handler db)))))
(register-handler :protocol-initialized
(fn [db [_ identity]]
(-> db
(update-identity identity)
(set-initialized true))))
(defn system-message [msg-id content]
{:from "system"
:msg-id msg-id
:content content
:content-type text-content-type})
(defn joined-chat-msg [chat-id from msg-id]
(let [contact-name (:name (contacts/contact-by-identity from))]
(messages/save-message chat-id {:from "system"
:msg-id (str msg-id "_" from)
:content (str (or contact-name from) " received chat invitation")
:content-type text-content-type})))
(defn participant-invited-to-group-msg [chat-id identity from msg-id]
(let [inviter-name (:name (contacts/contact-by-identity from))
invitee-name (if (= identity (api/my-identity))
"You"
(:name (contacts/contact-by-identity identity)))]
(messages/save-message chat-id {:from "system"
:msg-id msg-id
:content (str (or inviter-name from) " invited " (or invitee-name identity))
:content-type text-content-type})))
(defn participant-removed-from-group-msg [chat-id identity from msg-id]
(let [remover-name (:name (contacts/contact-by-identity from))
removed-name (:name (contacts/contact-by-identity identity))]
(->> (str (or remover-name from) " removed " (or removed-name identity))
(system-message msg-id)
(messages/save-message chat-id))))
(defn you-removed-from-group-msg [chat-id from msg-id]
(let [remover-name (:name (contacts/contact-by-identity from))]
(->> (str (or remover-name from) " removed you from group chat")
(system-message msg-id)
(messages/save-message chat-id))))
(defn participant-left-group-msg [chat-id from msg-id]
(let [left-name (:name (contacts/contact-by-identity from))]
(->> (str (or left-name from) " left")
(system-message msg-id)
(messages/save-message chat-id))))
(register-handler :group-chat-invite-acked
(u/side-effect!
(fn [_ [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))))
(register-handler :participant-removed-from-group
(u/side-effect!
(fn [_ [action from group-id identity msg-id]]
(log/debug action msg-id from group-id identity)
(chats/chat-remove-participants group-id [identity])
(participant-removed-from-group-msg group-id identity from msg-id))))
(register-handler :you-removed-from-group
(u/side-effect!
(fn [_ [action from group-id msg-id]]
(log/debug action msg-id from group-id)
(you-removed-from-group-msg group-id from msg-id)
(chats/set-chat-active group-id false))))
(register-handler :participant-left-group
(u/side-effect!
(fn [_ [action from group-id msg-id]]
(log/debug action msg-id from group-id)
(when-not (= (api/my-identity) from)
(participant-left-group-msg group-id from msg-id)))))
(register-handler :participant-invited-to-group
(u/side-effect!
(fn [_ [action from group-id identity msg-id]]
(log/debug action msg-id from group-id identity)
(participant-invited-to-group-msg group-id identity from msg-id))))
(register-handler :acked-msg
(u/side-effect!
(fn [_ [action from msg-id]]
(log/debug action from msg-id)
(messages/update-message! {:msg-id msg-id
:delivery-status :delivered}))))
(register-handler :msg-delivery-failed
(u/side-effect!
(fn [_ [action msg-id]]
(log/debug action msg-id)
(messages/update-message! {:msg-id msg-id
:delivery-status :failed}))))