From dbfbd18eaf100ad9732799a2b432703953740b8b Mon Sep 17 00:00:00 2001 From: michaelr Date: Wed, 20 Apr 2016 13:12:12 +0300 Subject: [PATCH 1/3] idempotent joined chat msg --- src/syng_im/handlers.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syng_im/handlers.cljs b/src/syng_im/handlers.cljs index 519b62f566..fda44dfc3b 100644 --- a/src/syng_im/handlers.cljs +++ b/src/syng_im/handlers.cljs @@ -148,7 +148,7 @@ (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 msg-id + :msg-id (str msg-id "_" from) :content (str (or contact-name from) " received chat invitation") :content-type text-content-type}))) From 8f04104cc0327c834113b916ae4ebecdafb8a2d2 Mon Sep 17 00:00:00 2001 From: michaelr Date: Fri, 29 Apr 2016 02:06:15 +0300 Subject: [PATCH 2/3] remove participants colors, re-join chat, update contacts instead of remove --- src/syng_im/constants.cljs | 17 +------ src/syng_im/handlers.cljs | 12 +++-- src/syng_im/models/chats.cljs | 76 +++++++++++++++++++----------- src/syng_im/models/contacts.cljs | 8 ++-- src/syng_im/persistence/realm.cljs | 10 ++-- src/syng_im/subs.cljs | 28 +++++------ 6 files changed, 83 insertions(+), 68 deletions(-) diff --git a/src/syng_im/constants.cljs b/src/syng_im/constants.cljs index 4d4c4df55b..84fbff6b8a 100644 --- a/src/syng_im/constants.cljs +++ b/src/syng_im/constants.cljs @@ -9,22 +9,7 @@ (def content-type-command "command") (def content-type-command-request "command-request") (def content-type-status "status") -(def group-chat-colors [{:background "#AB7967", :text "#FFFFFF"} - {:background "#B48EAD", :text "#FFFFFF"} - {:background "#8FA1B3", :text "#FFFFFF"} - {:background "#96B5B4", :text "#FFFFFF"} - {:background "#A3BE8C", :text "#FFFFFF"} - {:background "#EBCB8B", :text "#FFFFFF"} - {:background "#D08770", :text "#FFFFFF"} - {:background "#BF616A", :text "#FFFFFF"} - {:background "#EFF1F5", :text "#000000"} - {:background "#DFE1E8", :text "#000000"} - {:background "#C0C5CE", :text "#000000"} - {:background "#A7ADBA", :text "#000000"} - {:background "#65737E", :text "#FFFFFF"} - {:background "#4F5B66", :text "#FFFFFF"} - {:background "#343D46", :text "#FFFFFF"} - {:background "#2B303B", :text "#FFFFFF"}]) + (comment diff --git a/src/syng_im/handlers.cljs b/src/syng_im/handlers.cljs index fda44dfc3b..3a6d1228c1 100644 --- a/src/syng_im/handlers.cljs +++ b/src/syng_im/handlers.cljs @@ -29,10 +29,12 @@ check-suggestion]] [syng-im.handlers.sign-up :as sign-up-service] - [syng-im.models.chats :refer [create-chat + [syng-im.models.chats :refer [chat-exists? + create-chat chat-add-participants chat-remove-participants - set-chat-active]] + set-chat-active + re-join-group-chat]] [syng-im.models.chat :refer [signal-chat-updated set-current-chat-id current-chat-id @@ -498,8 +500,10 @@ (register-handler :group-chat-invite-received (fn [db [action from group-id identities group-name]] (log/debug action from group-id identities) - (create-chat db group-id identities true group-name))) + (if (chat-exists? group-id) + (re-join-group-chat db group-id identities group-name) + (create-chat db group-id identities true group-name)))) (comment - + (dispatch [:set-signed-up true]) ) diff --git a/src/syng_im/models/chats.cljs b/src/syng_im/models/chats.cljs index d777dc4329..b3e9a768c4 100644 --- a/src/syng_im/models/chats.cljs +++ b/src/syng_im/models/chats.cljs @@ -1,11 +1,12 @@ (ns syng-im.models.chats - (:require [syng-im.persistence.realm :as r] + (:require [clojure.set :refer [difference]] + [syng-im.persistence.realm :as r] [syng-im.utils.random :refer [timestamp]] [clojure.string :refer [join blank?]] [syng-im.db :as db] [syng-im.utils.logging :as log] - [syng-im.constants :refer [group-chat-colors]] - [syng-im.persistence.realm-queries :refer [include-query]])) + [syng-im.persistence.realm-queries :refer [include-query]] + [syng-im.models.chat :refer [signal-chat-updated]])) (defn signal-chats-updated [db] (update-in db db/updated-chats-signal-path (fn [current] @@ -31,21 +32,22 @@ (or (chat-name-from-contacts identities) chat-id)) +(defn chat-exists? [chat-id] + (r/exists? :chats :chat-id chat-id)) + (defn create-chat ([db chat-id identities group-chat?] (create-chat db chat-id identities group-chat? nil)) ([db chat-id identities group-chat? chat-name] - (if (r/exists? :chats :chat-id chat-id) + (if (chat-exists? chat-id) db (let [chat-name (or chat-name (get-chat-name chat-id identities)) _ (log/debug "creating chat" chat-name)] (r/write (fn [] - (let [contacts (mapv (fn [ident {:keys [background text]}] - {:identity ident - :background-color background - :text-color text}) identities group-chat-colors)] + (let [contacts (mapv (fn [ident] + {:identity ident}) identities)] (r/create :chats {:chat-id chat-id :is-active true :name chat-name @@ -54,6 +56,30 @@ :contacts contacts})))) (signal-chats-updated db))))) +(defn chat-contacts [chat-id] + (-> (r/get-by-field :chats :chat-id chat-id) + (r/single) + (aget "contacts"))) + +(defn re-join-group-chat [db group-id identities group-name] + (r/write + (fn [] + (let [new-identities (set identities) + only-old-contacts (->> (chat-contacts group-id) + (r/cljs-list) + (remove (fn [{:keys [identity]}] + (new-identities identity)))) + contacts (->> new-identities + (mapv (fn [ident] + {:identity ident})) + (concat only-old-contacts))] + (r/create :chats {:chat-id group-id + :is-active true + :name group-name + :contacts contacts} true)))) + (-> (signal-chats-updated db) + (signal-chat-updated group-id))) + (defn chats-list [] (r/sorted (r/get-all :chats) :timestamp :desc)) @@ -65,29 +91,22 @@ (defn chat-add-participants [chat-id identities] (r/write (fn [] - (let [contacts (-> (r/get-by-field :chats :chat-id chat-id) - (r/single) - (aget "contacts")) - colors-in-use (set (.map contacts (fn [object index collection] - {:text-color (aget object "text-color") - :background-color (aget object "background-color")}))) - colors (filter (fn [color] - (not (contains? colors-in-use color))) group-chat-colors) - new-contacts (mapv (fn [ident {:keys [background text]}] - {:identity ident - :background-color background - :text-color text}) identities colors)] - (doseq [contact new-contacts] - (.push contacts (clj->js contact))))))) + (let [contacts (chat-contacts chat-id)] + (doseq [contact-identity identities] + (if-let [contact-exists (.find contacts (fn [object index collection] + (= contact-identity (aget object "identity"))))] + (aset contact-exists "is-in-chat" true) + (.push contacts (clj->js {:identity contact-identity})))))))) (defn chat-remove-participants [chat-id identities] (r/write (fn [] (let [query (include-query :identity identities) - chat (r/single (r/get-by-field :chats :chat-id chat-id))] + chat (r/single (r/get-by-field :chats :chat-id chat-id))] (-> (aget chat "contacts") (r/filtered query) - (r/delete)))))) + (.forEach (fn [object index collection] + (aset object "is-in-chat" false)))))))) (defn active-group-chats [] (let [results (r/filtered (r/get-all :chats) @@ -102,7 +121,7 @@ (r/single) (aset "is-active" active?))))) -#_(comment +(comment (active-group-chats) @@ -119,8 +138,7 @@ (-> (aget (aget (chats-list) 0) "contacts") - (js->clj :keywordize-keys true) - ) + (r/cljs-list)) (r/delete (chats-list)) @@ -136,4 +154,8 @@ (swap! re-frame.db/app-db (fn [db] (create-chat db "A group chat"))) + + (-> (chats-list) + (.find (fn [object index collection] + (= "console1" (aget object "chat-id"))))) ) diff --git a/src/syng_im/models/contacts.cljs b/src/syng_im/models/contacts.cljs index fb4fd48f31..53acb69cab 100644 --- a/src/syng_im/models/contacts.cljs +++ b/src/syng_im/models/contacts.cljs @@ -111,13 +111,13 @@ (comment (r/write #(create-contact {:phone-number "0543072333" - :whisper-identity "0x041e1a37a0317a66f8d826e6779d808a9f39b88c2f896c5d3c08c4ded259719be256e4e6d6f49dab2324993ec822b588f2c0591b7a723cb0be659f2eccf48b5fed" - :name "Mr. Bean" + :whisper-identity "0x04e43e861a6dd99ad9eee7bd58af89dcaa430188ebec8698de7b7bad54573324fff4ac5cb9bb277af317efd7abfc917b91bf48cc41e40bf70062fd79400016a1f9" + :name "Splinter" :photo-path ""})) (r/write #(create-contact {:phone-number "0544828649" - :whisper-identity "0x04dcbf434bbf6925f251b7f43337f66a5a3f943e8983284045af703551cab39684d8c838e73f0234169f26fe126d7ef1ea3b8c1013e7dad1d4c5a82c7a651647fd" - :name "Mr. Batman" + :whisper-identity "0x0487954e7fa746d8cf787403c2c491aadad540b9bb1f0f7b8184792e91c33b6a394079295f5777ec6d4af9ad5ba24794b3ff1ec8be9ff6a708c85a163733192665" + :name "Exodius" :photo-path ""})) (r/write #(create-contact {:phone-number "0522222222" diff --git a/src/syng_im/persistence/realm.cljs b/src/syng_im/persistence/realm.cljs index a0ba5dca73..074d70728f 100644 --- a/src/syng_im/persistence/realm.cljs +++ b/src/syng_im/persistence/realm.cljs @@ -34,9 +34,9 @@ :delivery-status {:type "string" :optional true}}} {:name :chat-contact - :properties {:identity "string" - :text-color "string" - :background-color "string"}} + :properties {:identity "string" + :is-in-chat {:type "bool" + :default true}}} {:name :chats :primaryKey :chat-id :properties {:chat-id "string" @@ -106,6 +106,10 @@ (some-> (aget result 0) (js->clj :keywordize-keys true))) +(defn cljs-list [results] + (-> (js->clj results :keywordize-keys true) + (vals))) + (defn list-to-array [record list-field] (update-in record [list-field] (comp vec vals))) diff --git a/src/syng_im/subs.cljs b/src/syng_im/subs.cljs index fd71a3fcfb..2dee0c6335 100644 --- a/src/syng_im/subs.cljs +++ b/src/syng_im/subs.cljs @@ -23,7 +23,7 @@ (register-sub :get-chat-messages (fn [db _] - (let [chat-id (reaction (current-chat-id @db)) + (let [chat-id (reaction (current-chat-id @db)) chat-updated (reaction (chat-updated? @db @chat-id))] (reaction (let [_ @chat-updated] @@ -42,16 +42,16 @@ (reaction (get-suggestions @db @input-text))))) (register-sub :get-commands - (fn [db _] - (reaction (get-commands @db)))) + (fn [db _] + (reaction (get-commands @db)))) (register-sub :get-chat-input-text (fn [db _] (reaction (get-in @db (db/chat-input-text-path (current-chat-id @db)))))) (register-sub :get-chat-staged-commands - (fn [db _] - (reaction (get-in @db (db/chat-staged-commands-path (current-chat-id @db)))))) + (fn [db _] + (reaction (get-in @db (db/chat-staged-commands-path (current-chat-id @db)))))) (register-sub :get-chat-command (fn [db _] @@ -104,16 +104,16 @@ (get @db :loading)))) (register-sub - :signed-up - (fn [db _] - (reaction - (get @db :signed-up)))) + :signed-up + (fn [db _] + (reaction + (get @db :signed-up)))) (register-sub :get-contacts (fn [db _] (reaction - (get @db :contacts)))) + (get @db :contacts)))) (register-sub :all-contacts (fn [db _] @@ -123,8 +123,8 @@ (register-sub :all-new-contacts (fn [db _] (let [current-chat-id (reaction (current-chat-id @db)) - chat (reaction (when-let [chat-id @current-chat-id] - (chat-by-id chat-id)))] + chat (reaction (when-let [chat-id @current-chat-id] + (chat-by-id chat-id)))] (reaction (when @chat (let [current-participants (->> @chat @@ -135,8 +135,8 @@ (register-sub :current-chat-contacts (fn [db _] (let [current-chat-id (reaction (current-chat-id @db)) - chat (reaction (when-let [chat-id @current-chat-id] - (chat-by-id chat-id)))] + chat (reaction (when-let [chat-id @current-chat-id] + (chat-by-id chat-id)))] (reaction (when @chat (let [current-participants (->> @chat From a555c57bcc1fa2e3632e202ef987b83adedd8b0a Mon Sep 17 00:00:00 2001 From: michaelr Date: Fri, 29 Apr 2016 16:24:03 +0300 Subject: [PATCH 3/3] improved system messages for edge cases --- src/syng_im/handlers.cljs | 168 +++++++++++++++++----------------- src/syng_im/models/chats.cljs | 2 +- 2 files changed, 87 insertions(+), 83 deletions(-) diff --git a/src/syng_im/handlers.cljs b/src/syng_im/handlers.cljs index 3a6d1228c1..9febceb3f3 100644 --- a/src/syng_im/handlers.cljs +++ b/src/syng_im/handlers.cljs @@ -1,59 +1,59 @@ (ns syng-im.handlers (:require - [re-frame.core :refer [register-handler after dispatch]] - [schema.core :as s :include-macros true] - [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.user-data :as user-data] - [syng-im.models.contacts :as contacts] - [syng-im.models.messages :refer [save-message - update-message! - message-by-id]] - [syng-im.models.commands :as commands :refer [set-chat-command - set-response-chat-command - set-chat-command-content - set-chat-command-request - stage-command - unstage-command - set-commands]] - [syng-im.handlers.server :as server] - [syng-im.handlers.contacts :as contacts-service] - [syng-im.handlers.suggestions :refer [get-command - handle-command - get-command-handler - load-commands - apply-staged-commands - check-suggestion]] - [syng-im.handlers.sign-up :as sign-up-service] + [re-frame.core :refer [register-handler after dispatch]] + [schema.core :as s :include-macros true] + [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.user-data :as user-data] + [syng-im.models.contacts :as contacts] + [syng-im.models.messages :refer [save-message + update-message! + message-by-id]] + [syng-im.models.commands :as commands :refer [set-chat-command + set-response-chat-command + set-chat-command-content + set-chat-command-request + stage-command + unstage-command + set-commands]] + [syng-im.handlers.server :as server] + [syng-im.handlers.contacts :as contacts-service] + [syng-im.handlers.suggestions :refer [get-command + handle-command + get-command-handler + load-commands + apply-staged-commands + check-suggestion]] + [syng-im.handlers.sign-up :as sign-up-service] - [syng-im.models.chats :refer [chat-exists? - create-chat - chat-add-participants - chat-remove-participants - set-chat-active - re-join-group-chat]] - [syng-im.models.chat :refer [signal-chat-updated - set-current-chat-id - current-chat-id - update-new-group-selection - update-new-participants-selection - clear-new-group - clear-new-participants - new-group-selection - set-chat-input-text - new-participants-selection]] - [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.models.chats :refer [chat-exists? + create-chat + chat-add-participants + chat-remove-participants + set-chat-active + re-join-group-chat]] + [syng-im.models.chat :refer [signal-chat-updated + set-current-chat-id + current-chat-id + update-new-group-selection + update-new-participants-selection + clear-new-group + clear-new-participants + new-group-selection + set-chat-input-text + new-participants-selection]] + [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])) ;; -- Middleware ------------------------------------------------------------ ;; @@ -115,9 +115,9 @@ db)) (register-handler :set-commands - (fn [db [action commands]] - (log/debug action commands) - (set-commands db commands))) + (fn [db [action commands]] + (log/debug action commands) + (set-commands db commands))) ;; -- Protocol -------------------------------------------------------------- @@ -156,7 +156,9 @@ (defn participant-invited-to-group-msg [chat-id identity from msg-id] (let [inviter-name (:name (contacts/contact-by-identity from)) - invitee-name (:name (contacts/contact-by-identity identity))] + 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)) @@ -220,8 +222,10 @@ (register-handler :participant-left-group (fn [db [action from group-id msg-id]] (log/debug action msg-id from group-id) - (participant-left-group-msg group-id from msg-id) - (signal-chat-updated db group-id))) + (if (= (api/my-identity) from) + db + (do (participant-left-group-msg group-id from msg-id) + (signal-chat-updated db group-id))))) (register-handler :participant-invited-to-group (fn [db [action from group-id identity msg-id]] @@ -247,26 +251,26 @@ (defn send-staged-commands [db chat-id] (let [staged-commands (get-in db (db/chat-staged-commands-path chat-id))] (dorun - (map - (fn [staged-command] - (let [command-key (get-in staged-command [:command :command]) - content (commands/format-command-msg-content command-key - (:content staged-command)) - msg (if (= chat-id "console") - (sign-up-service/send-console-command db command-key content) - ;; TODO handle command, now sends as plain message - (let [{msg-id :msg-id - {from :from - to :to} :msg} (api/send-user-msg {:to chat-id - :content content})] - {:msg-id msg-id - :from from - :to to - :content content - :content-type content-type-command - :outgoing true}))] - (save-message chat-id msg))) - staged-commands)) + (map + (fn [staged-command] + (let [command-key (get-in staged-command [:command :command]) + content (commands/format-command-msg-content command-key + (:content staged-command)) + msg (if (= chat-id "console") + (sign-up-service/send-console-command db command-key content) + ;; TODO handle command, now sends as plain message + (let [{msg-id :msg-id + {from :from + to :to} :msg} (api/send-user-msg {:to chat-id + :content content})] + {:msg-id msg-id + :from from + :to to + :content content + :content-type content-type-command + :outgoing true}))] + (save-message chat-id msg))) + staged-commands)) db)) (register-handler :send-chat-msg @@ -278,7 +282,7 @@ (let [msg (when (pos? (count text)) (if (= chat-id "console") (sign-up-service/send-console-msg text) - (let [{msg-id :msg-id + (let [{msg-id :msg-id {from :from to :to} :msg} (api/send-user-msg {:to chat-id :content text})] @@ -307,7 +311,7 @@ (register-handler :send-chat-command (fn [db [action chat-id command content]] (log/debug action "chat-id" chat-id "command" command "content" content) - (let [db (set-chat-input-text db nil) + (let [db (set-chat-input-text db nil) msg (if (= chat-id "console") (sign-up-service/send-console-command db command content) ;; TODO handle command, now sends as plain message @@ -407,7 +411,7 @@ (register-handler :stage-command (fn [db [action chat-id command content]] (log/debug action "chat-id" chat-id "command" command "content" content) - (let [db (set-chat-input-text db nil) + (let [db (set-chat-input-text db nil) command-info {:command command :content content :handler (get-command-handler db (:command command) content)}] diff --git a/src/syng_im/models/chats.cljs b/src/syng_im/models/chats.cljs index b3e9a768c4..a8aab3b576 100644 --- a/src/syng_im/models/chats.cljs +++ b/src/syng_im/models/chats.cljs @@ -140,7 +140,7 @@ (-> (aget (aget (chats-list) 0) "contacts") (r/cljs-list)) - (r/delete (chats-list)) + (r/write (fn [] (r/delete (chats-list)))) (swap! re-frame.db/app-db signal-chats-updated)