improved messages delivery (#191)

Former-commit-id: fb06c9161a
This commit is contained in:
alwxndr 2016-08-24 10:29:40 +03:00
parent c6d6cec5d4
commit 91fdff9429
34 changed files with 383 additions and 257 deletions

View File

@ -9,8 +9,8 @@
[re-frame "0.7.0"] [re-frame "0.7.0"]
[prismatic/schema "1.0.4"] [prismatic/schema "1.0.4"]
^{:voom {:repo "git@github.com:status-im/status-lib.git" ^{:voom {:repo "git@github.com:status-im/status-lib.git"
:branch "master"}} :branch "message-delivery"}}
[status-im/protocol "0.1.3-20160818_172519-g2f734a6"] [status-im/protocol "0.2.0-20160829_094621-g83381b2"]
[natal-shell "0.3.0"] [natal-shell "0.3.0"]
[com.andrewmcveigh/cljs-time "0.4.0"] [com.andrewmcveigh/cljs-time "0.4.0"]
[tailrecursion/cljs-priority-map "1.2.0"] [tailrecursion/cljs-priority-map "1.2.0"]

View File

@ -104,9 +104,9 @@
(register-handler :load-accounts load-accounts!) (register-handler :load-accounts load-accounts!)
(defn console-create-account [db _] (defn console-create-account [db _]
(let [msg-id (random/id)] (let [message-id (random/id)]
(dispatch [:received-message (dispatch [:received-message
{:msg-id msg-id {:message-id message-id
:content {:command (name :keypair) :content {:command (name :keypair)
:content (label :t/keypair-generated)} :content (label :t/keypair-generated)}
:content-type content-type-command-request :content-type content-type-command-request

View File

@ -1,20 +1,20 @@
(ns status-im.chat.handlers (ns status-im.chat.handlers
(:require-macros [cljs.core.async.macros :as am]) (:require-macros [cljs.core.async.macros :as am])
(:require [re-frame.core :refer [enrich after debug dispatch]] (:require [re-frame.core :refer [enrich after debug dispatch]]
[status-im.models.commands :as commands] [status-im.models.commands :as commands]
[clojure.string :as str] [clojure.string :as str]
[status-im.components.styles :refer [default-chat-color]] [status-im.components.styles :refer [default-chat-color]]
[status-im.chat.suggestions :as suggestions] [status-im.chat.suggestions :as suggestions]
[status-im.protocol.api :as api] [status-im.protocol.api :as api]
[status-im.models.chats :as chats]
[status-im.models.messages :as messages] [status-im.models.messages :as messages]
[status-im.models.pending-messages :as pending-messages]
[status-im.constants :refer [text-content-type [status-im.constants :refer [text-content-type
content-type-command content-type-command
content-type-command-request content-type-command-request
default-number-of-messages]] default-number-of-messages]]
[status-im.utils.random :as random] [status-im.utils.random :as random]
[status-im.chat.sign-up :as sign-up-service] [status-im.chat.sign-up :as sign-up-service]
[status-im.models.chats :as chats]
[status-im.navigation.handlers :as nav] [status-im.navigation.handlers :as nav]
[status-im.utils.handlers :refer [register-handler] :as u] [status-im.utils.handlers :refer [register-handler] :as u]
[status-im.persistence.realm.core :as r] [status-im.persistence.realm.core :as r]
@ -149,17 +149,17 @@
(register-handler ::set-text update-text) (register-handler ::set-text update-text)
(defn set-message-shown (defn set-message-shown
[db chat-id msg-id] [db chat-id message-id]
(update-in db [:chats chat-id :messages] (fn [messages] (update-in db [:chats chat-id :messages] (fn [messages]
(map (fn [msg] (map (fn [message]
(if (= msg-id (:msg-id msg)) (if (= message-id (:message-id message))
(assoc msg :new? false) (assoc message :new? false)
msg)) message))
messages)))) messages))))
(register-handler :set-message-shown (register-handler :set-message-shown
(fn [db [_ {:keys [chat-id msg-id]}]] (fn [db [_ {:keys [chat-id message-id]}]]
(set-message-shown db chat-id msg-id))) (set-message-shown db chat-id message-id)))
(defn init-console-chat (defn init-console-chat
[{:keys [chats] :as db} existing-account?] [{:keys [chats] :as db} existing-account?]
@ -253,6 +253,11 @@
(after #(dispatch [:load-unviewed-messages!])) (after #(dispatch [:load-unviewed-messages!]))
((enrich initialize-chats) load-chats!)) ((enrich initialize-chats) load-chats!))
(register-handler :initialize-pending-messages
(u/side-effect!
(fn [_ _]
(api/init-pending-messages (pending-messages/get-pending-messages)))))
(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)
@ -332,7 +337,7 @@
(messages/save-message (messages/save-message
current-chat-id current-chat-id
{:from "system" {:from "system"
:msg-id (random/id) :message-id (random/id)
:content "You left this chat" :content "You left this chat"
:content-type text-content-type})) :content-type text-content-type}))
@ -392,7 +397,7 @@
(register-handler :send-seen! (register-handler :send-seen!
(after (fn [_ [_ chat-id message-id]] (after (fn [_ [_ chat-id message-id]]
(when-not (console? chat-id)) (when-not (console? chat-id))
(dispatch [:msg-seen chat-id message-id]))) (dispatch [:message-seen chat-id message-id])))
(u/side-effect! (u/side-effect!
(fn [_ [_ chat-id message-id]] (fn [_ [_ chat-id message-id]]
(when-not (console? chat-id) (when-not (console? chat-id)

View File

@ -128,11 +128,11 @@
(after invoke-command-preview!)] (after invoke-command-preview!)]
(fn [db [_ chat-id]] (fn [db [_ chat-id]]
(let [db (assoc-in db [:chats chat-id :input-text] nil) (let [db (assoc-in db [:chats chat-id :input-text] nil)
{:keys [command content to-msg-id]} (command-input db) {:keys [command content to-message-id]} (command-input db)
content' (content-by-command command content) content' (content-by-command command content)
command-info {:command command command-info {:command command
:content content' :content content'
:to-message to-msg-id :to-message to-message-id
:created-at (time/now-ms) :created-at (time/now-ms)
:id (random/id)}] :id (random/id)}]
(-> db (-> db
@ -157,9 +157,9 @@
(after #(dispatch [:command-edit-mode]))] (after #(dispatch [:command-edit-mode]))]
set-chat-command) set-chat-command)
(defn set-response-command [db [_ to-msg-id command-key]] (defn set-response-command [db [_ to-message-id command-key]]
(-> db (-> db
(commands/set-command-input :responses to-msg-id command-key) (commands/set-command-input :responses to-message-id command-key)
(assoc :canceled-command false))) (assoc :canceled-command false)))
(register-handler :set-response-chat-command (register-handler :set-response-chat-command

View File

@ -8,7 +8,7 @@
[cljs.reader :refer [read-string]] [cljs.reader :refer [read-string]]
[status-im.models.chats :as c])) [status-im.models.chats :as c]))
(defn check-previev [{:keys [content] :as message}] (defn check-preview [{:keys [content] :as message}]
(if-let [preview (:preview content)] (if-let [preview (:preview content)]
(let [rendered-preview (generate-hiccup (read-string preview))] (let [rendered-preview (generate-hiccup (read-string preview))]
(assoc message (assoc message
@ -24,8 +24,8 @@
(:public-key (accounts current-account-id))) (:public-key (accounts current-account-id)))
(defn receive-message (defn receive-message
[db [_ {:keys [from group-id chat-id msg-id] :as message}]] [db [_ {:keys [from group-id chat-id message-id] :as message}]]
(let [same-message (messages/get-message msg-id) (let [same-message (messages/get-message message-id)
current-identity (get-current-identity db)] current-identity (get-current-identity db)]
(when-not (or same-message (= from current-identity)) (when-not (or same-message (= from current-identity))
(let [group-chat? (not (nil? group-id)) (let [group-chat? (not (nil? group-id))
@ -33,8 +33,8 @@
previous-message (messages/get-last-message chat-id') previous-message (messages/get-last-message chat-id')
message' (assoc (->> message message' (assoc (->> message
(cu/check-author-direction previous-message) (cu/check-author-direction previous-message)
(check-previev)) (check-preview))
:delivery-status :pending :delivery-status :sending
:chat-id chat-id')] :chat-id chat-id')]
(store-message message') (store-message message')
(when-not (c/chat-exists? chat-id') (when-not (c/chat-exists? chat-id')
@ -42,7 +42,7 @@
(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' message-id])))))
(register-handler :received-message (register-handler :received-message
(u/side-effect! receive-message)) (u/side-effect! receive-message))

View File

@ -10,9 +10,9 @@
(requests/save-request new-request)) (requests/save-request new-request))
(defn add-request (defn add-request
[db [_ chat-id {:keys [msg-id content]}]] [db [_ chat-id {:keys [message-id content]}]]
(let [request {:chat-id chat-id (let [request {:chat-id chat-id
:message-id msg-id :message-id message-id
:type (:command content) :type (:command content)
:added (js/Date.)} :added (js/Date.)}
request' (update request :type keyword)] request' (update request :type keyword)]
@ -24,9 +24,8 @@
[{:keys [current-chat-id] :as db} [_ chat-id]] [{:keys [current-chat-id] :as db} [_ chat-id]]
(let [chat-id' (or chat-id current-chat-id) (let [chat-id' (or chat-id current-chat-id)
requests (-> ;; todo maybe limit is needed requests (-> ;; todo maybe limit is needed
(realm/get-by-fields :account :request (realm/get-by-fields :account :request :and [[:chat-id chat-id']
{:chat-id chat-id' [:status "open"]])
:status "open"})
(realm/sorted :added :desc) (realm/sorted :added :desc)
(realm/collection->map)) (realm/collection->map))
requests' (map #(update % :type keyword) requests)] requests' (map #(update % :type keyword) requests)]
@ -36,9 +35,8 @@
[_ [_ chat-id message-id]] [_ [_ chat-id message-id]]
(realm/write :account (realm/write :account
(fn [] (fn []
(-> (realm/get-by-fields :account :request (-> (realm/get-by-fields :account :request :and [[:chat-id chat-id]
{:chat-id chat-id [:message-id message-id]])
:message-id message-id})
(realm/single) (realm/single)
(.-status) (.-status)
(set! "answered"))))) (set! "answered")))))

View File

@ -13,18 +13,38 @@
content-type-command content-type-command
content-type-command-request content-type-command-request
default-number-of-messages]] default-number-of-messages]]
[status-im.protocol.api :as api])) [status-im.protocol.api :as api]
[status-im.utils.logging :as log]))
(defn default-delivery-status [chat-id] (defn default-delivery-status [chat-id]
(if (cu/console? chat-id) (if (cu/console? chat-id)
:seen :seen
:pending)) :sending))
(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
{:message-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)
:content content}] :content content}]
{:msg-id (random/id) {:message-id (random/id)
:from identity :from identity
:to chat-id :to chat-id
:content (assoc content :preview preview-string) :content (assoc content :preview preview-string)
@ -37,7 +57,7 @@
:type (:type command) :type (:type command)
:has-handler (:has-handler command)})) :has-handler (:has-handler command)}))
(register-handler :send-chat-msg (register-handler :send-chat-message
(u/side-effect! (u/side-effect!
(fn [{:keys [current-chat-id identity current-account-id] :as db}] (fn [{:keys [current-chat-id identity current-account-id] :as db}]
(let [staged-commands (vals (get-in db [:chats current-chat-id :staged-commands])) (let [staged-commands (vals (get-in db [:chats current-chat-id :staged-commands]))
@ -60,7 +80,7 @@
(fn [_ [_ {:keys [commands message] :as params}]] (fn [_ [_ {:keys [commands message] :as params}]]
(doseq [{:keys [command] :as message} commands] (doseq [{:keys [command] :as message} commands]
(let [params' (assoc params :command message)] (let [params' (assoc params :command message)]
(if (:pending message) (if (:sending message)
(dispatch [:navigate-to :confirm]) (dispatch [:navigate-to :confirm])
(if (:has-handler command) (if (:has-handler command)
(dispatch [::invoke-command-handlers! params']) (dispatch [::invoke-command-handlers! params'])
@ -134,18 +154,21 @@
(register-handler ::prepare-message (register-handler ::prepare-message
(u/side-effect! (u/side-effect!
(fn [db [_ {:keys [chat-id identity message] :as params}]] (fn [db [_ {:keys [chat-id identity message] :as params}]]
(let [message' (cu/check-author-direction (let [{:keys [group-chat]} (get-in db [:chats chat-id])
message' (cu/check-author-direction
db chat-id db chat-id
{:msg-id (random/id) {:message-id (random/id)
:chat-id chat-id :chat-id chat-id
:content message :content message
:to chat-id
:from identity :from identity
:content-type text-content-type :content-type text-content-type
:delivery-status (default-delivery-status chat-id) :delivery-status (default-delivery-status chat-id)
:outgoing true :outgoing true
:timestamp (time/now-ms)}) :timestamp (time/now-ms)})
params' (assoc params :message message')] message'' (if group-chat
(assoc message' :group-id chat-id :message-type :group-user-message)
(assoc message' :to chat-id :message-type :user-message))
params' (assoc params :message message'')]
(dispatch [::add-message params']) (dispatch [::add-message params'])
(dispatch [::save-message! params']))))) (dispatch [::save-message! params'])))))
@ -162,13 +185,13 @@
(register-handler ::send-message! (register-handler ::send-message!
(u/side-effect! (u/side-effect!
(fn [db [_ {:keys [message chat-id]}]] (fn [_ [_ {{:keys [message-type]
:as message} :message
chat-id :chat-id}]]
(when (and message (cu/not-console? chat-id)) (when (and message (cu/not-console? chat-id))
(let [{:keys [group-chat]} (get-in db [:chats chat-id]) (if (= message-type :group-user-message)
message' (select-keys message [:content :msg-id])] (api/send-group-user-message message)
(if group-chat (api/send-user-message message))))))
(api/send-group-user-msg (assoc message' :group-id chat-id))
(api/send-user-msg (assoc message' :to chat-id))))))))
(register-handler ::send-command-protocol! (register-handler ::send-command-protocol!
(u/side-effect! (u/side-effect!
@ -179,5 +202,5 @@
message {:content content message {:content content
:content-type content-type-command}] :content-type content-type-command}]
(if group-chat (if group-chat
(api/send-group-user-msg (assoc message :group-id chat-id)) (api/send-group-user-message (assoc message :group-id chat-id))
(api/send-user-msg (assoc message :to chat-id))))))))) (api/send-user-message (assoc message :to chat-id)))))))))

View File

@ -4,17 +4,15 @@
[status-im.persistence.realm.core :as realm])) [status-im.persistence.realm.core :as realm]))
(defn delivered-messages [] (defn delivered-messages []
(-> (realm/get-by-fields (-> (realm/get-by-fields :account :message :and [[:delivery-status :delivered]
:account :message [:outgoing false]])
{:delivery-status :delivered
:outgoing false})
(realm/collection->map))) (realm/collection->map)))
(defn set-unviewed-messages [db] (defn set-unviewed-messages [db]
(let [messages (->> (::raw-unviewed-messages db) (let [messages (->> (::raw-unviewed-messages db)
(group-by :chat-id) (group-by :chat-id)
(map (fn [[id messages]] (map (fn [[id messages]]
[id {:messages-ids (map :msg-id messages) [id {:messages-ids (map :message-id messages)
:count (count messages)}])) :count (count messages)}]))
(into {}))] (into {}))]
(-> db (-> db

View File

@ -34,13 +34,13 @@
[identity contact])) [identity contact]))
(into {}))) (into {})))
(defn add-msg-color [{:keys [from] :as msg} contact-by-identity] (defn add-message-color [{:keys [from] :as message} contact-by-identity]
(if (= "system" from) (if (= "system" from)
(assoc msg :text-color :#4A5258 (assoc message :text-color :#4A5258
:background-color :#D3EEEF) :background-color :#D3EEEF)
(let [{:keys [text-color background-color]} (get contact-by-identity from)] (let [{:keys [text-color background-color]} (get contact-by-identity from)]
(assoc msg :text-color text-color (assoc message :text-color text-color
:background-color background-color)))) :background-color background-color))))
(defview chat-icon [] (defview chat-icon []
[chat-id [:chat :chat-id] [chat-id [:chat :chat-id]
@ -66,11 +66,11 @@
(defn message-row [{:keys [contact-by-identity platform-specific group-chat messages-count]}] (defn message-row [{:keys [contact-by-identity platform-specific group-chat messages-count]}]
(fn [row _ idx] (fn [row _ idx]
(let [msg (-> row (let [message (-> row
(add-msg-color contact-by-identity) (add-message-color contact-by-identity)
(assoc :group-chat group-chat) (assoc :group-chat group-chat)
(assoc :last-msg (= (js/parseInt idx) (dec messages-count))))] (assoc :last-message (= (js/parseInt idx) (dec messages-count))))]
(list-item [chat-message msg platform-specific])))) (list-item [chat-message message platform-specific]))))
(defn on-action-selected [position] (defn on-action-selected [position]
(case position (case position

View File

@ -16,8 +16,8 @@
content-type-status]] content-type-status]]
[status-im.i18n :refer [label]])) [status-im.i18n :refer [label]]))
(defn send-console-msg [text] (defn send-console-message [text]
{:msg-id (random/id) {:message-id (random/id)
:from "me" :from "me"
:to "console" :to "console"
:content text :content text
@ -36,9 +36,9 @@
;; -- Send phone number ---------------------------------------- ;; -- Send phone number ----------------------------------------
(defn on-sign-up-response [& [message]] (defn on-sign-up-response [& [message]]
(let [msg-id (random/id)] (let [message-id (random/id)]
(dispatch [:received-message (dispatch [:received-message
{:msg-id msg-id {:message-id message-id
:content (command-content :content (command-content
:confirmation-code :confirmation-code
(or message (label :t/confirmation-code))) (or message (label :t/confirmation-code)))
@ -64,7 +64,7 @@
;; -- Send confirmation code and synchronize contacts--------------------------- ;; -- Send confirmation code and synchronize contacts---------------------------
(defn on-sync-contacts [] (defn on-sync-contacts []
(dispatch [:received-message (dispatch [:received-message
{:msg-id (random/id) {:message-id (random/id)
:content (label :t/contacts-syncronized) :content (label :t/contacts-syncronized)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -78,7 +78,7 @@
(defn on-send-code-response [body] (defn on-send-code-response [body]
(dispatch [:received-message (dispatch [:received-message
{:msg-id (random/id) {:message-id (random/id)
:content (:message body) :content (:message body)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -95,9 +95,9 @@
(on-sign-up-response (label :t/incorrect-code))))) (on-sign-up-response (label :t/incorrect-code)))))
(defn start-signup [] (defn start-signup []
(let [msg-id (random/id)] (let [message-id (random/id)]
(dispatch [:received-message (dispatch [:received-message
{:msg-id msg-id {:message-id message-id
:content (command-content :content (command-content
:phone :phone
(label :t/phone-number-required)) (label :t/phone-number-required))
@ -110,7 +110,7 @@
(defn save-password [password mnemonic] (defn save-password [password mnemonic]
;; TODO validate and save password ;; TODO validate and save password
(dispatch [:received-message (dispatch [:received-message
{:msg-id (random/id) {:message-id (random/id)
:content (label :t/password-saved) :content (label :t/password-saved)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -118,7 +118,7 @@
:to "me" :to "me"
:new? false}]) :new? false}])
(dispatch [:received-message (dispatch [:received-message
{:msg-id (random/id) {:message-id (random/id)
:content (label :t/generate-passphrase) :content (label :t/generate-passphrase)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -126,7 +126,7 @@
:to "me" :to "me"
:new? false}]) :new? false}])
(dispatch [:received-message (dispatch [:received-message
{:msg-id (random/id) {:message-id (random/id)
:content (label :t/here-is-your-passphrase) :content (label :t/here-is-your-passphrase)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -134,7 +134,7 @@
:to "me" :to "me"
:new? false}]) :new? false}])
(dispatch [:received-message (dispatch [:received-message
{:msg-id (random/id) {:message-id (random/id)
:content mnemonic :content mnemonic
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -142,7 +142,7 @@
:to "me" :to "me"
:new? false}]) :new? false}])
(dispatch [:received-message (dispatch [:received-message
{:msg-id "8" {:message-id "8"
:content (label :t/written-down) :content (label :t/written-down)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -155,7 +155,7 @@
(def intro-status (def intro-status
{:msg-id "intro-status" {:message-id "intro-status"
:content (label :t/intro-status) :content (label :t/intro-status)
:delivery-status "seen" :delivery-status "seen"
:from "console" :from "console"
@ -167,7 +167,7 @@
(defn intro [logged-in?] (defn intro [logged-in?]
(dispatch [:received-message intro-status]) (dispatch [:received-message intro-status])
(dispatch [:received-message (dispatch [:received-message
{:msg-id "intro-message1" {:message-id "intro-message1"
:content (label :t/intro-message1) :content (label :t/intro-message1)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -175,7 +175,7 @@
:to "me"}]) :to "me"}])
(when-not logged-in? (when-not logged-in?
(dispatch [:received-message (dispatch [:received-message
{:msg-id "intro-message2" {:message-id "intro-message2"
:content (label :t/intro-message2) :content (label :t/intro-message2)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
@ -183,7 +183,7 @@
:to "me"}]) :to "me"}])
(dispatch [:received-message (dispatch [:received-message
{:msg-id "intro-message3" {:message-id "intro-message3"
:content (command-content :content (command-content
:keypair :keypair
(label :t/keypair-generated)) (label :t/keypair-generated))

View File

@ -31,8 +31,8 @@
:else 10)) :else 10))
(defn last-message-padding (defn last-message-padding
[{:keys [last-msg typing]}] [{:keys [last-message typing]}]
(when (and last-msg (not typing)) (when (and last-message (not typing))
{:paddingBottom 20})) {:paddingBottom 20}))
(def message-body-base (def message-body-base

View File

@ -102,9 +102,9 @@
(fn [db _] (fn [db _]
(reaction (commands/get-chat-command-content @db)))) (reaction (commands/get-chat-command-content @db))))
(register-sub :get-chat-command-to-msg-id (register-sub :get-chat-command-to-message-id
(fn [db _] (fn [db _]
(reaction (commands/get-chat-command-to-msg-id @db)))) (reaction (commands/get-chat-command-to-message-id @db))))
(register-sub :chat-command-request (register-sub :chat-command-request
(fn [db _] (fn [db _]

View File

@ -3,7 +3,7 @@
[status-im.db :as db] [status-im.db :as db]
[status-im.models.commands :refer [get-commands [status-im.models.commands :refer [get-commands
get-chat-command-request get-chat-command-request
get-chat-command-to-msg-id]] get-chat-command-to-message-id]]
[status-im.utils.utils :refer [log on-error http-get]] [status-im.utils.utils :refer [log on-error http-get]]
[clojure.string :as s])) [clojure.string :as s]))
@ -28,15 +28,15 @@
(defn handle-command [db command-key content] (defn handle-command [db command-key content]
(when-let [command-handler (get-chat-command-request db)] (when-let [command-handler (get-chat-command-request db)]
(let [to-msg-id (get-chat-command-to-msg-id db)] (let [to-message-id (get-chat-command-to-message-id db)]
(command-handler to-msg-id command-key content))) (command-handler to-message-id command-key content)))
db) db)
(defn get-command-handler [db command-key content] (defn get-command-handler [db command-key content]
(when-let [command-handler (get-chat-command-request db)] (when-let [command-handler (get-chat-command-request db)]
(let [to-msg-id (get-chat-command-to-msg-id db)] (let [to-message-id (get-chat-command-to-message-id db)]
(fn [] (fn []
(command-handler to-msg-id command-key content))))) (command-handler to-message-id command-key content)))))
(defn check-suggestion [db message] (defn check-suggestion [db message]
(when-let [suggestion-text (when (string? message) (when-let [suggestion-text (when (string? message)

View File

@ -3,6 +3,7 @@
(:require [clojure.string :as s] (:require [clojure.string :as s]
[re-frame.core :refer [subscribe dispatch]] [re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r] [reagent.core :as r]
[status-im.i18n :refer [message-status-label]]
[status-im.components.react :refer [view [status-im.components.react :refer [view
text text
image image
@ -11,14 +12,15 @@
[status-im.components.animation :as anim] [status-im.components.animation :as anim]
[status-im.chat.views.request-message :refer [message-content-command-request]] [status-im.chat.views.request-message :refer [message-content-command-request]]
[status-im.chat.styles.message :as st] [status-im.chat.styles.message :as st]
[status-im.models.commands :refer [parse-command-msg-content [status-im.models.commands :refer [parse-command-message-content
parse-command-request]] parse-command-request]]
[status-im.resources :as res] [status-im.resources :as res]
[status-im.utils.datetime :as time] [status-im.utils.datetime :as time]
[status-im.constants :refer [text-content-type [status-im.constants :refer [text-content-type
content-type-status content-type-status
content-type-command content-type-command
content-type-command-request]])) content-type-command-request]]
[status-im.utils.logging :as log]))
(defn message-date [timestamp platform-specific] (defn message-date [timestamp platform-specific]
[view {} [view {}
@ -70,7 +72,7 @@
(defview message-content-command [content preview platform-specific] (defview message-content-command [content preview platform-specific]
[commands [:get-commands-and-responses]] [commands [:get-commands-and-responses]]
(let [{:keys [command content]} (parse-command-msg-content commands content) (let [{:keys [command content]} (parse-command-message-content commands content)
{:keys [name icon type]} command] {:keys [name icon type]} command]
[view st/content-command-view [view st/content-command-view
[view st/command-container [view st/command-container
@ -90,8 +92,8 @@
:font :default} :font :default}
(str content)])])) (str content)])]))
(defn set-chat-command [msg-id command] (defn set-chat-command [message-id command]
(dispatch [:set-response-chat-command msg-id (keyword (:name command))])) (dispatch [:set-response-chat-command message-id (keyword (:name command))]))
(defn message-view (defn message-view
[message content] [message content]
@ -139,9 +141,8 @@
:platform-specific platform-specific}]] :platform-specific platform-specific}]]
platform-specific]) platform-specific])
(defview message-delivery-status (defview message-delivery-status [{:keys [delivery-status chat-id message-id] :as message} platform-specific]
[{:keys [delivery-status msg-id to] :as m} platform-specific] [status [:get-in [:message-status chat-id message-id]]]
[status [:get-in [:message-status to msg-id]]]
[view st/delivery-view [view st/delivery-view
[image {:source (case (or status delivery-status) [image {:source (case (or status delivery-status)
:seen {:uri :icon_ok_small} :seen {:uri :icon_ok_small}
@ -152,12 +153,7 @@
[text {:style st/delivery-text [text {:style st/delivery-text
:platform-specific platform-specific :platform-specific platform-specific
:font :default} :font :default}
(case (or status delivery-status) (message-status-label (or status delivery-status))]])
:delivered "Sent"
:seen "Seen"
:seen-by-everyone "Seen by everyone"
:failed "Failed"
"Pending")]])
(defview member-photo [from] (defview member-photo [from]
[photo-path [:photo-path from]] [photo-path [:photo-path from]]
@ -186,7 +182,7 @@
[message-delivery-status {:delivery-status delivery-status} platform-specific])]]])) [message-delivery-status {:delivery-status delivery-status} platform-specific])]]]))
(defn message-body (defn message-body
[{:keys [outgoing delivery-status] :as message} content platform-specific] [{:keys [outgoing] :as message} content platform-specific]
[view (st/message-body message) [view (st/message-body message)
content content
(when outgoing (when outgoing
@ -226,18 +222,17 @@
children)])})) children)])}))
(into [view] children))) (into [view] children)))
(defn chat-message (defn chat-message [{:keys [outgoing delivery-status timestamp new-day group-chat message-id chat-id]
[{:keys [outgoing delivery-status timestamp new-day group-chat msg-id chat-id] :as message}
:as message} platform-specific]
platform-specific] (let [status (subscribe [:get-in [:message-status chat-id message-id]])]
(let [status (subscribe [:get-in [:message-status chat-id msg-id]])]
(r/create-class (r/create-class
{:component-did-mount {:component-did-mount
(fn [] (fn []
(when (and (not outgoing) (when (and (not outgoing)
(not= :seen delivery-status) (not= :seen delivery-status)
(not= :seen @status)) (not= :seen @status))
(dispatch [:send-seen! chat-id msg-id]))) (dispatch [:send-seen! chat-id message-id])))
:reagent-render :reagent-render
(fn [{:keys [outgoing delivery-status timestamp new-day group-chat] (fn [{:keys [outgoing delivery-status timestamp new-day group-chat]
:as message} :as message}

View File

@ -15,7 +15,7 @@
(dispatch [:set-chat-input-text message])) (dispatch [:set-chat-input-text message]))
(defn send [] (defn send []
(dispatch [:send-chat-msg])) (dispatch [:send-chat-message]))
(defn message-valid? [staged-commands message] (defn message-valid? [staged-commands message]
(or (and (pos? (count message)) (or (and (pos? (count message))

View File

@ -12,8 +12,8 @@
(def request-message-icon-scale-delay 600) (def request-message-icon-scale-delay 600)
(defn set-chat-command [msg-id command] (defn set-chat-command [message-id command]
(dispatch [:set-response-chat-command msg-id (keyword (:name command))])) (dispatch [:set-response-chat-command message-id (keyword (:name command))]))
(defn label [command] (defn label [command]
(when command (when command
@ -42,9 +42,9 @@
(anim/start (anim/start
(button-animation val min-scale loop? answered?))))) (button-animation val min-scale loop? answered?)))))
(defn request-button [msg-id command] (defn request-button [message-id command]
(let [scale-anim-val (anim/create-value min-scale) (let [scale-anim-val (anim/create-value min-scale)
answered? (subscribe [:is-request-answered? msg-id]) answered? (subscribe [:is-request-answered? message-id])
loop? (r/atom true) loop? (r/atom true)
context {:to-value max-scale context {:to-value max-scale
:val scale-anim-val :val scale-anim-val
@ -56,11 +56,11 @@
:component-will-unmount :component-will-unmount
#(reset! loop? false) #(reset! loop? false)
:reagent-render :reagent-render
(fn [msg-id command] (fn [message-id command]
(if command (if command
[touchable-highlight [touchable-highlight
{:on-press (when-not @answered? {:on-press (when-not @answered?
#(set-chat-command msg-id command)) #(set-chat-command message-id command))
:style st/command-request-image-touchable :style st/command-request-image-touchable
:accessibility-label (label command)} :accessibility-label (label command)}
[animated-view {:style (st/command-request-image-view command scale-anim-val)} [animated-view {:style (st/command-request-image-view command scale-anim-val)}
@ -68,9 +68,9 @@
:style st/command-request-image}]]]))}))) :style st/command-request-image}]]]))})))
(defn message-content-command-request (defn message-content-command-request
[{:keys [msg-id content from incoming-group]} platform-specific] [{:keys [message-id content from incoming-group]} platform-specific]
(let [commands-atom (subscribe [:get-responses])] (let [commands-atom (subscribe [:get-responses])]
(fn [{:keys [msg-id content from incoming-group]}] (fn [{:keys [message-id content from incoming-group]}]
(let [commands @commands-atom (let [commands @commands-atom
{:keys [command content]} (parse-command-request commands content)] {:keys [command content]} (parse-command-request commands content)]
[view st/comand-request-view [view st/comand-request-view
@ -84,7 +84,7 @@
:platform-specific platform-specific :platform-specific platform-specific
:font :default} :font :default}
content]] content]]
[request-button msg-id command] [request-button message-id command]
(when (:request-text command) (when (:request-text command)
[view st/command-request-text-view [view st/command-request-text-view
[text {:style st/style-sub-text [text {:style st/style-sub-text

View File

@ -27,12 +27,13 @@
:discovery-search-tags [] :discovery-search-tags []
:tags {} :tags {}
:contacts-ids #{} :chats {}
:selected-contacts #{}
:current-chat-id "console"
:chat {:command nil :chat {:command nil
:last-message nil} :last-message nil}
:chats {} :current-chat-id "console"
:contacts-ids #{}
:selected-contacts #{}
:chats-updated-signal 0 :chats-updated-signal 0
:show-actions false :show-actions false
:selected-participants #{} :selected-participants #{}
@ -52,11 +53,11 @@
[:chats chat-id :staged-commands]) [:chats chat-id :staged-commands])
(defn chat-command-path [chat-id] (defn chat-command-path [chat-id]
[:chats chat-id :command-input :command]) [:chats chat-id :command-input :command])
(defn chat-command-to-msg-id-path [chat-id] (defn chat-command-to-message-id-path [chat-id]
[:chats chat-id :command-input :to-msg-id]) [:chats chat-id :command-input :to-message-id])
(defn chat-command-content-path [chat-id] (defn chat-command-content-path [chat-id]
[:chats chat-id :command-input :content]) [:chats chat-id :command-input :content])
(defn chat-command-requests-path [chat-id] (defn chat-command-requests-path [chat-id]
[:chats chat-id :command-requests]) [:chats chat-id :command-requests])
(defn chat-command-request-path [chat-id msg-id] (defn chat-command-request-path [chat-id message-id]
[:chats chat-id :command-requests msg-id]) [:chats chat-id :command-requests message-id])

View File

@ -36,8 +36,8 @@
(register-handler :discovery-response-received (register-handler :discovery-response-received
(u/side-effect! (u/side-effect!
(fn [db [_ from payload]] (fn [db [_ from payload]]
(let [{:keys [msg-id name photo-path status hashtags]} payload (let [{:keys [message-id name photo-path status hashtags]} payload
discovery {:msg-id msg-id discovery {:message-id message-id
:name name :name name
:photo-path photo-path :photo-path photo-path
:status status :status status
@ -60,8 +60,8 @@
(defn add-discovery (defn add-discovery
[{db-discoveries :discoveries [{db-discoveries :discoveries
:as db} [_ {:keys [msg-id] :as discovery}]] :as db} [_ {:keys [message-id] :as discovery}]]
(let [updated-discoveries (if-let [i (first-index #(= (:msg-id %) msg-id) db-discoveries)] (let [updated-discoveries (if-let [i (first-index #(= (:message-id %) message-id) db-discoveries)]
(assoc db-discoveries i discovery) (assoc db-discoveries i discovery)
(conj db-discoveries discovery))] (conj db-discoveries discovery))]
(-> db (-> db

View File

@ -22,15 +22,15 @@
(doseq [tag (distinct tags)] (doseq [tag (distinct tags)]
(update-tag-counter func tag))) (update-tag-counter func tag)))
(defn get-tags [msg-id] (defn get-tags [message-id]
(-> (r/get-by-field :account :discovery :msg-id msg-id) (-> (r/get-by-field :account :discovery :message-id message-id)
(r/single-cljs) (r/single-cljs)
(:tags) (:tags)
(vals))) (vals)))
(defn- upsert-discovery [{:keys [msg-id tags] :as discovery}] (defn- upsert-discovery [{:keys [message-id tags] :as discovery}]
(log/debug "Creating/updating discovery with tags: " tags) (log/debug "Creating/updating discovery with tags: " tags)
(let [prev-tags (get-tags msg-id)] (let [prev-tags (get-tags message-id)]
(if prev-tags (if prev-tags
(update-tags-counter dec prev-tags)) (update-tags-counter dec prev-tags))
(r/create :account :discovery discovery true) (r/create :account :discovery discovery true)

View File

@ -31,6 +31,6 @@
:platform-specific platform-specific :platform-specific platform-specific
:font :default} :font :default}
count]]] count]]]
(for [{:keys [msg-id] :as discovery} discoveries] (for [{:keys [message-id] :as discovery} discoveries]
^{:key (str "message-" msg-id)} ^{:key (str "message-" message-id)}
[discovery-list-item discovery platform-specific])]) [discovery-list-item discovery platform-specific])])

View File

@ -14,6 +14,6 @@
(defview discovery-recent [{platform-specific :platform-specific}] (defview discovery-recent [{platform-specific :platform-specific}]
[discoveries [:get :discoveries]] [discoveries [:get :discoveries]]
[view st/recent-list [view st/recent-list
(for [{:keys [msg-id] :as discovery} discoveries] (for [{:keys [message-id] :as discovery} discoveries]
^{:key (str "message-" msg-id)} ^{:key (str "message-" message-id)}
[discovery-list-item discovery platform-specific])]) [discovery-list-item discovery platform-specific])])

View File

@ -89,13 +89,13 @@
(doseq [participant selected-participants] (doseq [participant selected-participants]
(api/group-remove-participant current-chat-id participant))) (api/group-remove-participant current-chat-id participant)))
(defn system-message [msg-id content] (defn system-message [message-id content]
{:from "system" {:from "system"
:msg-id msg-id :message-id message-id
:content content :content content
:content-type text-content-type}) :content-type text-content-type})
(defn removed-participant-msg [chat-id identity] (defn removed-participant-message [chat-id identity]
(let [contact-name (:name (contacts/contact-by-identity identity))] (let [contact-name (:name (contacts/contact-by-identity identity))]
(->> (str "You've removed " (or contact-name identity)) (->> (str "You've removed " (or contact-name identity))
(system-message (random/id)) (system-message (random/id))
@ -104,7 +104,7 @@
(defn create-removing-messages! (defn create-removing-messages!
[{:keys [current-chat-id selected-participants]} _] [{:keys [current-chat-id selected-participants]} _]
(doseq [participant selected-participants] (doseq [participant selected-participants]
(removed-participant-msg current-chat-id participant))) (removed-participant-message current-chat-id participant)))
(defn deselect-members [db _] (defn deselect-members [db _]
(assoc db :selected-participants #{})) (assoc db :selected-participants #{}))

View File

@ -74,6 +74,7 @@
(dispatch [:initialize-protocol address]) (dispatch [:initialize-protocol address])
(dispatch [:initialize-account-db]) (dispatch [:initialize-account-db])
(dispatch [:initialize-chats]) (dispatch [:initialize-chats])
(dispatch [:initialize-pending-messages])
(dispatch [:load-contacts]) (dispatch [:load-contacts])
(dispatch [:init-chat]) (dispatch [:init-chat])
(dispatch [:init-discoveries]) (dispatch [:init-discoveries])

View File

@ -16,8 +16,14 @@
(.t i18n (name path) (clj->js options)) (.t i18n (name path) (clj->js options))
(name path)))) (name path))))
(defn label-pluralize [count path & options] (defn label-pluralize [count path & options]
(if (exists? i18n.t) (if (exists? i18n.t)
(.p i18n count (name path) (clj->js options)) (.p i18n count (name path) (clj->js options))
(name path))) (name path)))
(defn message-status-label [status]
(->> status
(name)
(str "t/status-")
(keyword)
(label)))

View File

@ -32,7 +32,7 @@
(save-message chat-id (save-message chat-id
{:from "Status" {:from "Status"
:to nil :to nil
:msg-id (random/id) :message-id (random/id)
:content (str "The brash businessmans braggadocio " :content (str "The brash businessmans braggadocio "
"and public exchange with candidates " "and public exchange with candidates "
"in the US presidential election") "in the US presidential election")
@ -40,8 +40,8 @@
:outgoing false})) :outgoing false}))
(defn create-chat (defn create-chat
([{:keys [last-msg-id] :as chat}] ([{:keys [last-message-id] :as chat}]
(let [chat (assoc chat :last-msg-id (or last-msg-id ""))] (let [chat (assoc chat :last-message-id (or last-message-id ""))]
(r/write :account #(r/create :account :chat chat)))) (r/write :account #(r/create :account :chat chat))))
([db chat-id identities group-chat? chat-name] ([db chat-id identities group-chat? chat-name]
(when-not (chat-exists? chat-id) (when-not (chat-exists? chat-id)
@ -59,7 +59,7 @@
:group-chat group-chat? :group-chat group-chat?
:timestamp (timestamp) :timestamp (timestamp)
:contacts contacts :contacts contacts
:last-msg-id ""})))) :last-message-id ""}))))
(add-status-message chat-id))))) (add-status-message chat-id)))))
(defn chat-contacts [chat-id] (defn chat-contacts [chat-id]

View File

@ -27,16 +27,16 @@
(defn set-command-input (defn set-command-input
([db type command-key] ([db type command-key]
(set-command-input db type nil command-key)) (set-command-input db type nil command-key))
([{:keys [current-chat-id] :as db} type msg-id command-key] ([{:keys [current-chat-id] :as db} type message-id command-key]
(update-in db [:chats current-chat-id :command-input] merge (update-in db [:chats current-chat-id :command-input] merge
{:content nil {:content nil
:command (get-response-or-command type db command-key) :command (get-response-or-command type db command-key)
:parameter-idx 0 :parameter-idx 0
:to-msg-id msg-id}))) :to-message-id message-id})))
(defn get-chat-command-to-msg-id (defn get-chat-command-to-message-id
[{:keys [current-chat-id] :as db}] [{:keys [current-chat-id] :as db}]
(get-in db (db/chat-command-to-msg-id-path current-chat-id))) (get-in db (db/chat-command-to-message-id-path current-chat-id)))
(defn compare-commands (defn compare-commands
[{created-at-1 :created-at} {created-at-2 :created-at}] [{created-at-1 :created-at} {created-at-2 :created-at}]
@ -58,14 +58,14 @@
(defn get-chat-command-request (defn get-chat-command-request
[{:keys [current-chat-id] :as db}] [{:keys [current-chat-id] :as db}]
(get-in db (db/chat-command-request-path current-chat-id (get-in db (db/chat-command-request-path current-chat-id
(get-chat-command-to-msg-id db)))) (get-chat-command-to-message-id db))))
(defn set-chat-command-request (defn set-chat-command-request
[{:keys [current-chat-id] :as db} msg-id handler] [{:keys [current-chat-id] :as db} message-id handler]
(update-in db (db/chat-command-requests-path current-chat-id) (update-in db (db/chat-command-requests-path current-chat-id)
#(assoc % msg-id handler))) #(assoc % message-id handler)))
(defn parse-command-msg-content [commands content] (defn parse-command-message-content [commands content]
(update content :command #((keyword %) commands))) (update content :command #((keyword %) commands)))
(defn parse-command-request [commands content] (defn parse-command-request [commands content]

View File

@ -26,10 +26,10 @@
(defn save-message (defn save-message
;; todo remove chat-id parameter ;; todo remove chat-id parameter
[chat-id {:keys [delivery-status msg-id content] [chat-id {:keys [delivery-status message-id content]
:or {delivery-status :pending} :or {delivery-status :sending}
:as message}] :as message}]
(when-not (r/exists? :account :message :msg-id msg-id) (when-not (r/exists? :account :message :message-id message-id)
(r/write :account (r/write :account
(fn [] (fn []
(let [content' (if (string? content) (let [content' (if (string? content)
@ -66,15 +66,14 @@
(generate-hiccup (read-string preview))))) (generate-hiccup (read-string preview)))))
message)))))) message))))))
(defn update-message! [{:keys [msg-id] :as msg}] (defn update-message! [{:keys [message-id] :as message}]
(log/debug "update-message!" msg)
(r/write :account (r/write :account
(fn [] (fn []
(when (r/exists? :account :message :msg-id msg-id) (when (r/exists? :account :message :message-id message-id)
(r/create :account :message msg true))))) (r/create :account :message message true)))))
(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 :message-id id))
(defn get-last-message [chat-id] (defn get-last-message [chat-id]
(-> (r/get-by-field :account :message :chat-id chat-id) (-> (r/get-by-field :account :message :chat-id chat-id)

View File

@ -0,0 +1,37 @@
(ns status-im.models.pending-messages
(:require [status-im.persistence.realm.core :as r]
[re-frame.core :refer [dispatch]]
[cljs.reader :refer [read-string]]
[status-im.utils.random :refer [timestamp]]
[clojure.string :refer [join split]]
[clojure.walk :refer [stringify-keys keywordize-keys]]
[status-im.constants :as c]
[status-im.utils.types :refer [clj->json json->clj]]
[status-im.commands.utils :refer [generate-hiccup]]))
(defn get-pending-messages []
(let [collection (-> (r/get-by-fields :account :pending-message :or [[:status :sending]
[:status :sent]])
(r/sorted :timestamp :desc)
(r/collection->map))]
(->> collection
(map (fn [{:keys [message-id] :as message}]
(let [message (-> message
(update :message json->clj)
(update :identities json->clj))]
[message-id message])))
(into {}))))
(defn upsert-pending-message!
[message]
(r/write :account
(fn []
(let [message (-> message
(update :message clj->json)
(update :identities clj->json))]
(r/create :account :pending-message message true)))))
(defn remove-pending-message! [message-id]
(r/write :account
(fn []
(r/delete :account (r/get-by-field :account :pending-message :message-id message-id)))))

View File

@ -100,9 +100,12 @@
[schema schema-name obj] [schema schema-name obj]
(write schema (fn [] (create schema schema-name obj true)))) (write schema (fn [] (create schema schema-name obj true))))
(defn and-q [queries] (defn and-query [queries]
(str/join " and " queries)) (str/join " and " queries))
(defn or-query [queries]
(str/join " or " queries))
(defmulti to-query (fn [schema schema-name operator field value] (defmulti to-query (fn [schema schema-name operator field value]
operator)) operator))
@ -122,11 +125,14 @@
(let [q (to-query schema schema-name :eq field value)] (let [q (to-query schema schema-name :eq field value)]
(.filtered (.objects (realm schema) (name schema-name)) q))) (.filtered (.objects (realm schema) (name schema-name)) q)))
(defn get-by-fields [schema schema-name fields] (defn get-by-fields [schema schema-name op fields]
(let [queries (map (fn [[k v]] (let [queries (map (fn [[k v]]
(to-query schema schema-name :eq k v)) (to-query schema schema-name :eq k v))
fields)] fields)]
(.filtered (.objects (realm schema) (name schema-name)) (and-q queries)))) (.filtered (.objects (realm schema) (name schema-name))
(case op
:and (and-query queries)
:or (or-query queries)))))
(defn get-all [schema schema-name] (defn get-all [schema schema-name]
(.objects (realm schema) (to-string schema-name))) (.objects (realm schema) (to-string schema-name)))

View File

@ -37,8 +37,8 @@
:properties {:name "string" :properties {:name "string"
:count {:type "int" :optional true :default 0}}} :count {:type "int" :optional true :default 0}}}
{:name :discovery {:name :discovery
:primaryKey :msg-id :primaryKey :message-id
:properties {:msg-id "string" :properties {:message-id "string"
:name {:type "string" :optional true} :name {:type "string" :optional true}
:status "string" :status "string"
:whisper-id "string" :whisper-id "string"
@ -52,11 +52,13 @@
:properties {:key "string" :properties {:key "string"
:value "string"}} :value "string"}}
{:name :message {:name :message
:primaryKey :msg-id :primaryKey :message-id
:properties {:msg-id "string" :properties {:message-id "string"
:from "string" :from "string"
:to {:type "string" :to {:type "string"
:optional true} :optional true}
:group-id {:type "string"
:optional true}
:content "string" ;; TODO make it ArrayBuffer :content "string" ;; TODO make it ArrayBuffer
:content-type "string" :content-type "string"
:timestamp "int" :timestamp "int"
@ -65,31 +67,49 @@
:outgoing "bool" :outgoing "bool"
:delivery-status {:type "string" :delivery-status {:type "string"
:optional true} :optional true}
:retry-count {:type :int
:default 0}
:same-author "bool" :same-author "bool"
:same-direction "bool" :same-direction "bool"
:preview {:type :string :preview {:type :string
:optional true}
:message-type {:type :string
:optional true}}} :optional true}}}
{:name :pending-message
:primaryKey :message-id
:properties {:message-id "string"
:chat-id {:type "string"
:optional true}
:message "string"
:timestamp "int"
:status "string"
:retry-count "int"
:send-once "bool"
:identities {:type "string"
:optional true}
:internal? {:type "bool"
:optional true}}}
{:name :chat-contact {:name :chat-contact
:properties {:identity "string" :properties {:identity "string"
:is-in-chat {:type "bool" :is-in-chat {:type "bool"
:default true}}} :default true}}}
{:name :chat {:name :chat
:primaryKey :chat-id :primaryKey :chat-id
:properties {:chat-id "string" :properties {:chat-id "string"
:name "string" :name "string"
:color {:type "string" :color {:type "string"
:default default-chat-color} :default default-chat-color}
:group-chat {:type "bool" :group-chat {:type "bool"
:indexed true} :indexed true}
:is-active "bool" :is-active "bool"
:timestamp "int" :timestamp "int"
:contacts {:type "list" :contacts {:type "list"
:objectType "chat-contact"} :objectType "chat-contact"}
:dapp-url {:type :string :dapp-url {:type :string
:optional true} :optional true}
:dapp-hash {:type :int :dapp-hash {:type :int
:optional true} :optional true}
:last-msg-id "string"}} :last-message-id "string"}}
{:name :command {:name :command
:primaryKey :chat-id :primaryKey :chat-id
:properties {:chat-id "string" :properties {:chat-id "string"

View File

@ -7,13 +7,14 @@
[re-frame.core :refer [dispatch after]] [re-frame.core :refer [dispatch after]]
[status-im.utils.handlers :refer [register-handler]] [status-im.utils.handlers :refer [register-handler]]
[status-im.models.contacts :as contacts] [status-im.models.contacts :as contacts]
[status-im.models.messages :as messages]
[status-im.models.pending-messages :as pending-messages]
[status-im.models.chats :as chats]
[status-im.protocol.api :refer [init-protocol]] [status-im.protocol.api :refer [init-protocol]]
[status-im.protocol.protocol-handler :refer [make-handler]] [status-im.protocol.protocol-handler :refer [make-handler]]
[status-im.models.protocol :refer [update-identity [status-im.models.protocol :refer [update-identity
set-initialized]] set-initialized]]
[status-im.constants :refer [text-content-type]] [status-im.constants :refer [text-content-type]]
[status-im.models.messages :as messages]
[status-im.models.chats :as chats]
[status-im.i18n :refer [label]])) [status-im.i18n :refer [label]]))
(register-handler :initialize-protocol (register-handler :initialize-protocol
@ -28,107 +29,130 @@
(update-identity identity) (update-identity identity)
(set-initialized true)))) (set-initialized true))))
(defn system-message [msg-id content] (defn system-message [message-id content]
{:from "system" {:from "system"
:msg-id msg-id :message-id message-id
:content content :content content
:content-type text-content-type}) :content-type text-content-type})
(defn joined-chat-msg [chat-id from msg-id] (defn joined-chat-message [chat-id from message-id]
(let [contact-name (:name (contacts/contact-by-identity from))] (let [contact-name (:name (contacts/contact-by-identity from))]
(messages/save-message chat-id {:from "system" (messages/save-message chat-id {:from "system"
:msg-id (str msg-id "_" from) :message-id (str message-id "_" from)
:content (str (or contact-name from) " " (label :t/received-invitation)) :content (str (or contact-name from) " " (label :t/received-invitation))
:content-type text-content-type}))) :content-type text-content-type})))
(defn participant-invited-to-group-msg [chat-id identity from msg-id] (defn participant-invited-to-group-message [chat-id identity from message-id]
(let [inviter-name (:name (contacts/contact-by-identity from)) (let [inviter-name (:name (contacts/contact-by-identity from))
invitee-name (if (= identity (api/my-identity)) invitee-name (if (= identity (api/my-identity))
(label :t/You) (label :t/You)
(:name (contacts/contact-by-identity identity)))] (:name (contacts/contact-by-identity identity)))]
(messages/save-message chat-id {:from "system" (messages/save-message chat-id {:from "system"
:msg-id msg-id :message-id message-id
:content (str (or inviter-name from) " " (label :t/invited) " " (or invitee-name identity)) :content (str (or inviter-name from) " " (label :t/invited) " " (or invitee-name identity))
:content-type text-content-type}))) :content-type text-content-type})))
(defn participant-removed-from-group-msg [chat-id identity from msg-id] (defn participant-removed-from-group-message [chat-id identity from message-id]
(let [remover-name (:name (contacts/contact-by-identity from)) (let [remover-name (:name (contacts/contact-by-identity from))
removed-name (:name (contacts/contact-by-identity identity))] removed-name (:name (contacts/contact-by-identity identity))]
(->> (str (or remover-name from) " " (label :t/removed) " " (or removed-name identity)) (->> (str (or remover-name from) " " (label :t/removed) " " (or removed-name identity))
(system-message msg-id) (system-message message-id)
(messages/save-message chat-id)))) (messages/save-message chat-id))))
(defn you-removed-from-group-msg [chat-id from msg-id] (defn you-removed-from-group-message [chat-id from message-id]
(let [remover-name (:name (contacts/contact-by-identity from))] (let [remover-name (:name (contacts/contact-by-identity from))]
(->> (str (or remover-name from) " " (label :t/removed-from-chat)) (->> (str (or remover-name from) " " (label :t/removed-from-chat))
(system-message msg-id) (system-message message-id)
(messages/save-message chat-id)))) (messages/save-message chat-id))))
(defn participant-left-group-msg [chat-id from msg-id] (defn participant-left-group-message [chat-id from message-id]
(let [left-name (:name (contacts/contact-by-identity from))] (let [left-name (:name (contacts/contact-by-identity from))]
(->> (str (or left-name from) " " (label :t/left)) (->> (str (or left-name from) " " (label :t/left))
(system-message msg-id) (system-message message-id)
(messages/save-message chat-id)))) (messages/save-message chat-id))))
(register-handler :group-chat-invite-acked (register-handler :group-chat-invite-acked
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id ack-msg-id]] (fn [_ [action from group-id ack-message-id]]
(log/debug action from group-id ack-msg-id) (log/debug action from group-id ack-message-id)
#_(joined-chat-msg group-id from ack-msg-id)))) #_(joined-chat-message group-id from ack-message-id))))
(register-handler :participant-removed-from-group (register-handler :participant-removed-from-group
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id identity msg-id]] (fn [_ [action from group-id identity message-id]]
(log/debug action msg-id from group-id identity) (log/debug action message-id from group-id identity)
(chats/chat-remove-participants group-id [identity]) (chats/chat-remove-participants group-id [identity])
(participant-removed-from-group-msg group-id identity from msg-id)))) (participant-removed-from-group-message group-id identity from message-id))))
(register-handler :you-removed-from-group (register-handler :you-removed-from-group
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id msg-id]] (fn [_ [action from group-id message-id]]
(log/debug action msg-id from group-id) (log/debug action message-id from group-id)
(you-removed-from-group-msg group-id from msg-id) (you-removed-from-group-message group-id from message-id)
(chats/set-chat-active group-id false)))) (chats/set-chat-active group-id false))))
(register-handler :participant-left-group (register-handler :participant-left-group
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id msg-id]] (fn [_ [action from group-id message-id]]
(log/debug action msg-id from group-id) (log/debug action message-id from group-id)
(when-not (= (api/my-identity) from) (when-not (= (api/my-identity) from)
(participant-left-group-msg group-id from msg-id))))) (participant-left-group-message group-id from message-id)))))
(register-handler :participant-invited-to-group (register-handler :participant-invited-to-group
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id identity msg-id]] (fn [_ [action from group-id identity message-id]]
(log/debug action msg-id from group-id identity) (log/debug action message-id from group-id identity)
(participant-invited-to-group-msg group-id identity from msg-id)))) (participant-invited-to-group-message group-id identity from message-id))))
(defn update-message! [status] (defn update-message! [status]
(fn [_ [_ _ msg-id]] (fn [_ [_ _ message-id]]
(messages/update-message! {:msg-id msg-id (messages/update-message! {:message-id message-id
:delivery-status status}))) :delivery-status status})))
(defn update-message-status [status] (defn update-message-status [status]
(fn [db [_ from msg-id]] (fn [db [_ chat-id message-id]]
(let [current-status (get-in db [:message-status from msg-id])] (let [current-status (get-in db [:message-status chat-id message-id])]
(if-not (= :seen current-status) (if-not (= :seen current-status)
(assoc-in db [:message-status from msg-id] status) (assoc-in db [:message-status chat-id message-id] status)
db)))) db))))
(register-handler :acked-msg (register-handler :message-delivered
(after (update-message! :delivered)) (after (update-message! :delivered))
(update-message-status :delivered)) (update-message-status :delivered))
(register-handler :msg-delivery-failed (register-handler :message-failed
(after (update-message! :failed)) (after (update-message! :failed))
(update-message-status :failed)) (update-message-status :failed))
(register-handler :msg-seen (register-handler :message-sent
(after (update-message! :sent))
(update-message-status :sent))
(register-handler :message-seen
[(after (update-message! :seen)) [(after (update-message! :seen))
(after (fn [_ [_ chat-id]] (after (fn [_ [_ chat-id]]
(dispatch [:remove-unviewed-messages chat-id])))] (dispatch [:remove-unviewed-messages chat-id])))]
(update-message-status :seen)) (update-message-status :seen))
(register-handler :pending-message-upsert
(after
(fn [_ [_ {:keys [message-id status] :as pending-message}]]
(pending-messages/upsert-pending-message! pending-message)
(messages/update-message! {:message-id message-id
:delivery-status status})))
(fn [db [_ {:keys [message-id chat-id status] :as pending-message}]]
(if chat-id
(let [current-status (get-in db [:message-status chat-id message-id])]
(if-not (= :seen current-status)
(assoc-in db [:message-status chat-id message-id] status)
db))
db)))
(register-handler :pending-message-remove
(u/side-effect!
(fn [_ [_ message-id]]
(pending-messages/remove-pending-message! message-id))))
(register-handler :send-transaction! (register-handler :send-transaction!
(u/side-effect! (u/side-effect!
(fn [_ [_ amount message]] (fn [_ [_ amount message]]

View File

@ -17,35 +17,40 @@
(case event-type (case event-type
: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] :message-received (let [{:keys [from to payload]} event]
(dispatch [:received-message (assoc payload (dispatch [:received-message (assoc payload :chat-id from
:chat-id from :from from
:from from :to to)]))
:to to)])) :message-delivered (let [{:keys [message-id from]} event]
:msg-acked (let [{:keys [msg-id from]} event] (dispatch [:message-delivered from message-id]))
(dispatch [:acked-msg from msg-id])) :message-seen (let [{:keys [message-id from]} event]
:msg-seen (let [{:keys [msg-id from]} event] (dispatch [:message-seen from message-id]))
(dispatch [:msg-seen from msg-id])) :message-failed (let [{:keys [message-id chat-id] :as event} event]
:delivery-failed (let [{:keys [msg-id from]} event] (dispatch [:message-failed chat-id message-id]))
(dispatch [:msg-delivery-failed from msg-id])) :message-sent (let [{:keys [message-id chat-id]} event]
(dispatch [:message-sent chat-id message-id]))
:pending-message-upsert (let [{message :message} event]
(dispatch [:pending-message-upsert message]))
:pending-message-remove (let [{:keys [message-id]} event]
(dispatch [:pending-message-remove message-id]))
:new-group-chat (let [{:keys [from group-id identities group-name]} event] :new-group-chat (let [{:keys [from group-id identities group-name]} event]
(dispatch [:group-chat-invite-received from group-id identities group-name])) (dispatch [:group-chat-invite-received from group-id identities group-name]))
:new-group-msg (let [{from :from :new-group-message (let [{from :from
group-id :group-id group-id :group-id
payload :payload} event] payload :payload} event]
(dispatch [:received-message (assoc payload (dispatch [:received-message (assoc payload
:chat-id group-id :chat-id group-id
:from from)])) :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-message-id]} event]
(dispatch [:group-chat-invite-acked from group-id ack-msg-id])) (dispatch [:group-chat-invite-acked from group-id ack-message-id]))
:group-new-participant (let [{:keys [group-id identity from msg-id]} event] :group-new-participant (let [{:keys [group-id identity from message-id]} event]
(dispatch [:participant-invited-to-group from group-id identity msg-id])) (dispatch [:participant-invited-to-group from group-id identity message-id]))
:group-removed-participant (let [{:keys [group-id identity from msg-id]} event] :group-removed-participant (let [{:keys [group-id identity from message-id]} event]
(dispatch [:participant-removed-from-group from group-id identity msg-id])) (dispatch [:participant-removed-from-group from group-id identity message-id]))
:removed-from-group (let [{:keys [group-id from msg-id]} event] :removed-from-group (let [{:keys [group-id from message-id]} event]
(dispatch [:you-removed-from-group from group-id msg-id])) (dispatch [:you-removed-from-group from group-id message-id]))
:participant-left-group (let [{:keys [group-id from msg-id]} event] :participant-left-group (let [{:keys [group-id from message-id]} event]
(dispatch [:participant-left-group from group-id msg-id])) (dispatch [:participant-left-group from group-id message-id]))
:discover-response (let [{:keys [from payload]} event] :discover-response (let [{:keys [from payload]} event]
(dispatch [:discovery-response-received from payload])) (dispatch [:discovery-response-received from payload]))
:contact-update (let [{:keys [from payload]} event] :contact-update (let [{:keys [from payload]} event]

View File

@ -23,6 +23,14 @@
:active-online "online" :active-online "online"
:active-unknown "unknown" :active-unknown "unknown"
;messages
:status-sending "Sending"
:status-sent "Sent"
:status-seen-by-everyone "Seen by everyone"
:status-seen "Seen"
:status-delivered "Delivered"
:status-failed "Failed"
;datetime ;datetime
:datetime-second {:one "second" :datetime-second {:one "second"
:other "seconds"} :other "seconds"}

View File

@ -3,7 +3,7 @@
(:require-macros [cljs.core.async.macros :refer [go]])) (:require-macros [cljs.core.async.macros :refer [go]]))
(defn handle-channel-events [chan handler] (defn handle-channel-events [chan handler]
(go (loop [[msg args] (<! chan)] (go (loop [[message args] (<! chan)]
(when msg (when message
(handler msg args) (handler message args)
(recur (<! chan)))))) (recur (<! chan))))))