From 8f9ee4ba31c1d3aeb03a31d7afd5501203cf10e6 Mon Sep 17 00:00:00 2001 From: michaelr Date: Mon, 28 Mar 2016 19:00:07 +0300 Subject: [PATCH] delivery status, scroll through messages history --- syng-im/.re-natal | 5 +- syng-im/images/deliveryfailed.png | Bin 0 -> 124 bytes syng-im/package.json | 4 +- syng-im/src/syng_im/components/chat.cljs | 8 +-- .../src/syng_im/components/chat_message.cljs | 16 +++--- syng-im/src/syng_im/components/realm.cljs | 18 +++++++ syng-im/src/syng_im/db.cljs | 2 +- syng-im/src/syng_im/handlers.cljs | 23 +++++++-- syng-im/src/syng_im/models/chat.cljs | 15 ++++-- syng-im/src/syng_im/models/messages.cljs | 48 +++++++++++------- syng-im/src/syng_im/models/protocol.cljs | 5 ++ syng-im/src/syng_im/persistence/realm.cljs | 43 +++++++++++----- .../syng_im/protocol/protocol_handler.cljs | 8 +-- syng-im/src/syng_im/resources.cljs | 1 + syng-im/src/syng_im/utils/listview.cljs | 8 ++- 15 files changed, 145 insertions(+), 59 deletions(-) create mode 100644 syng-im/images/deliveryfailed.png create mode 100644 syng-im/src/syng_im/components/realm.cljs diff --git a/syng-im/.re-natal b/syng-im/.re-natal index 7cd8ae4ffa..20f66539ae 100644 --- a/syng-im/.re-natal +++ b/syng-im/.re-natal @@ -1,14 +1,15 @@ { "name": "SyngIm", "interface": "reagent", - "androidHost": "localhost", + "androidHost": "10.0.3.2", "modules": [ "react-native-contacts", "react-native-invertible-scroll-view", "awesome-phonenumber", "realm", "react-native-loading-spinner-overlay", - "react-native-i18n" + "react-native-i18n", + "realm/react-native" ], "imageDirs": [ "images" diff --git a/syng-im/images/deliveryfailed.png b/syng-im/images/deliveryfailed.png new file mode 100644 index 0000000000000000000000000000000000000000..921ee8c62b5fcd5a6aa47f26930c1b973de0b1d2 GIT binary patch literal 124 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRZ!3HF6%}!4MQY^(zo*^7SP{WbZ0puHdx;TbN zOzrJ+FVdQ&MBb@0M)S~%m4rY literal 0 HcmV?d00001 diff --git a/syng-im/package.json b/syng-im/package.json index d344ac3d49..9a81d2f595 100644 --- a/syng-im/package.json +++ b/syng-im/package.json @@ -12,6 +12,6 @@ "react-native-i18n": "0.0.8", "react-native-invertible-scroll-view": "^0.2.0", "react-native-loading-spinner-overlay": "0.0.6", - "realm": "^0.10.0" + "realm": "^0.11.0" } -} \ No newline at end of file +} diff --git a/syng-im/src/syng_im/components/chat.cljs b/syng-im/src/syng_im/components/chat.cljs index dc3e69111b..d0b57cfb8e 100644 --- a/syng-im/src/syng_im/components/chat.cljs +++ b/syng-im/src/syng_im/components/chat.cljs @@ -6,12 +6,12 @@ image touchable-highlight navigator - toolbar-android - list-view]] + toolbar-android]] + [syng-im.components.realm :refer [list-view]] [syng-im.utils.logging :as log] [syng-im.navigation :refer [nav-pop]] [syng-im.resources :as res] - [syng-im.utils.listview :refer [to-datasource]] + [syng-im.utils.listview :refer [to-realm-datasource]] [syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]] [reagent.core :as r] [syng-im.components.chat-message :refer [chat-message]] @@ -23,7 +23,7 @@ (fn [] (let [msgs @messages _ (log/debug "messages=" msgs) - datasource (to-datasource msgs)] + datasource (to-realm-datasource msgs)] [view {:style {:flex 1 :backgroundColor "white"}} (when android? diff --git a/syng-im/src/syng_im/components/chat_message.cljs b/syng-im/src/syng_im/components/chat_message.cljs index 02f449f8bb..e767e96df2 100644 --- a/syng-im/src/syng_im/components/chat_message.cljs +++ b/syng-im/src/syng_im/components/chat_message.cljs @@ -81,9 +81,10 @@ (defn message-delivery-status [{:keys [delivery-status]}] [view {:style {:flexDirection "row" :marginTop 2}} - [image {:source (if (= (keyword delivery-status) :seen) - res/seen-icon - res/delivered-icon) + [image {:source (case delivery-status + :delivered res/delivered-icon + :seen res/seen-icon + :failed res/delivery-failed-icon) :style {:marginTop 6 :opacity 0.6}}] [text {:style {:fontFamily "Avenir-Roman" @@ -91,9 +92,10 @@ :color "#AAB2B2" :opacity 0.8 :marginLeft 5}} - (if (= (keyword delivery-status) :seen) - "Seen" - "Delivered")]]) + (case delivery-status + :delivered "Delivered" + :seen "Seen" + :failed "Failed")]]) (defn message-body [{:keys [msg-id content content-type outgoing delivery-status]}] [view {:style (merge {:flexDirection "column" @@ -118,4 +120,4 @@ :content content :content-type content-type :outgoing outgoing - :delivery-status delivery-status}]]) + :delivery-status (keyword delivery-status)}]]) diff --git a/syng-im/src/syng_im/components/realm.cljs b/syng-im/src/syng_im/components/realm.cljs new file mode 100644 index 0000000000..a3e32f3a71 --- /dev/null +++ b/syng-im/src/syng_im/components/realm.cljs @@ -0,0 +1,18 @@ +(ns syng-im.components.realm + (:require [reagent.core :as r])) + +(set! js/RealmReactNative (js/require "realm/react-native")) + +(def list-view (r/adapt-react-class (.-ListView js/RealmReactNative))) + +(comment + + + ;(set! js/wat (js/require "realm.react-native.ListView")) + ;(.-Results js/Realm) + ; + ;(r/realm) + ; + ;(require '[syng-im.persistence.realm :as r]) + + ) \ No newline at end of file diff --git a/syng-im/src/syng_im/db.cljs b/syng-im/src/syng_im/db.cljs index 8e2ee1a97a..685ac8bb30 100644 --- a/syng-im/src/syng_im/db.cljs +++ b/syng-im/src/syng_im/db.cljs @@ -7,7 +7,7 @@ ;; initial state of app-db (def app-db {:greeting "Hello Clojure in iOS and Android!" :identity-password "replace-me-with-user-entered-password" - :chat {:current-chat-id "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154"} + :chat {:current-chat-id "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd"} :chats {}}) diff --git a/syng-im/src/syng_im/handlers.cljs b/syng-im/src/syng_im/handlers.cljs index fa774b136f..f6234a4295 100644 --- a/syng-im/src/syng_im/handlers.cljs +++ b/syng-im/src/syng_im/handlers.cljs @@ -7,8 +7,10 @@ [syng-im.protocol.protocol-handler :refer [make-handler]] [syng-im.models.protocol :refer [update-identity set-initialized]] - [syng-im.models.messages :refer [save-message]] - [syng-im.models.chat :refer [set-latest-msg-id]] + [syng-im.models.messages :refer [save-message + update-message! + message-by-id]] + [syng-im.models.chat :refer [signal-chat-updated]] [syng-im.utils.logging :as log] [syng-im.protocol.api :as api] [syng-im.constants :refer [text-content-type]])) @@ -49,7 +51,20 @@ (fn [db [_ {chat-id :from msg-id :msg-id :as msg}]] (save-message chat-id msg) - (set-latest-msg-id db chat-id msg-id))) + (signal-chat-updated db chat-id))) + +(register-handler :acked-msg + (fn [db [_ from msg-id]] + (update-message! {:msg-id msg-id + :delivery-status :delivered}) + (signal-chat-updated db from))) + +(register-handler :msg-delivery-failed + (fn [db [_ msg-id]] + (update-message! {:msg-id msg-id + :delivery-status :failed}) + (let [{:keys [chat-id]} (message-by-id msg-id)] + (signal-chat-updated db chat-id)))) (register-handler :send-chat-msg (fn [db [_ chat-id text]] @@ -65,7 +80,7 @@ :content-type text-content-type :outgoing true}] (save-message chat-id msg) - (set-latest-msg-id db chat-id msg-id)))) + (signal-chat-updated db chat-id)))) ;; -- Something -------------------------------------------------------------- diff --git a/syng-im/src/syng_im/models/chat.cljs b/syng-im/src/syng_im/models/chat.cljs index 23a03e79db..28a598714b 100644 --- a/syng-im/src/syng_im/models/chat.cljs +++ b/syng-im/src/syng_im/models/chat.cljs @@ -7,9 +7,18 @@ (defn current-chat-id [db] (get-in db db/current-chat-id-path)) -(defn set-latest-msg-id [db chat-id msg-id] - (assoc-in db (db/latest-msg-id-path chat-id) msg-id)) +(defn signal-chat-updated [db chat-id] + (update-in db (db/latest-msg-id-path chat-id) (fn [current] + (if current + (inc current) + 0)))) (defn latest-msg-id [db chat-id] (->> (db/latest-msg-id-path chat-id) - (get-in db))) \ No newline at end of file + (get-in db))) + +(comment + + (swap! re-frame.db/app-db (fn [db] + (signal-chat-updated db "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd"))) + ) \ No newline at end of file diff --git a/syng-im/src/syng_im/models/messages.cljs b/syng-im/src/syng_im/models/messages.cljs index 93b0bac8bf..36257e47c8 100644 --- a/syng-im/src/syng_im/models/messages.cljs +++ b/syng-im/src/syng_im/models/messages.cljs @@ -2,32 +2,44 @@ (:require [syng-im.persistence.realm :as r] [cljs.reader :refer [read-string]] [syng-im.utils.random :refer [timestamp]] - [syng-im.db :as db])) + [syng-im.db :as db] + [syng-im.utils.logging :as log])) (defn save-message [chat-id {:keys [from to msg-id content content-type outgoing] :or {outgoing false} :as msg}] (when-not (r/exists? :msgs :msg-id msg-id) (r/write (fn [] - (r/create :msgs {:chat-id chat-id - :msg-id msg-id - :from from - :to to - :content content - :content-type content-type - :outgoing outgoing - :timestamp (timestamp)} true))))) - -(defn get-messages* [chat-id] - (-> (r/get-by-field :msgs :chat-id chat-id) - (r/sorted :timestamp :desc) - (r/page 0 10))) + (r/create :msgs {:chat-id chat-id + :msg-id msg-id + :from from + :to to + :content content + :content-type content-type + :outgoing outgoing + :timestamp (timestamp) + :delivery-status nil} true))))) (defn get-messages [chat-id] - (-> (get-messages* chat-id) - (js->clj :keywordize-keys true))) + (-> (r/get-by-field :msgs :chat-id chat-id) + (r/sorted :timestamp :desc))) + +(defn message-by-id [msg-id] + (-> (r/get-by-field :msgs :msg-id msg-id) + (r/single-cljs))) + +(defn update-message! [msg] + (r/write + (fn [] + (r/create :msgs msg true)))) (comment + (update-message! {:msg-id "1459175391577-a2185a35-5c49-5a6b-9c08-6eb5b87ceb7f" + :delivery-status "seen2"}) + + (r/get-by-field :msgs :msg-id "1459175391577-a2185a35-5c49-5a6b-9c08-6eb5b87ceb7f") + + (save-message "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154" {:msg-id "153" :content "hello!" @@ -35,9 +47,11 @@ (get-messages* "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154") - (get-messages nil) + (get-messages "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd") (doseq [msg (get-messages* "0x043df89d36f6e3d8ade18e55ac3e2e39406ebde152f76f2f82d674681d59319ffd9880eebfb4f5f8d5c222ec485b44d6e30ba3a03c96b1c946144fdeba1caccd43")] (r/delete msg)) + @re-frame.db/app-db + ) \ No newline at end of file diff --git a/syng-im/src/syng_im/models/protocol.cljs b/syng-im/src/syng_im/models/protocol.cljs index 47f164e6a2..bb3bb3ca9f 100644 --- a/syng-im/src/syng_im/models/protocol.cljs +++ b/syng-im/src/syng_im/models/protocol.cljs @@ -25,3 +25,8 @@ (when encrypted (-> (password-decrypt password encrypted) (read-string))))) + +(comment + + (stored-identity @re-frame.db/app-db) + ) \ No newline at end of file diff --git a/syng-im/src/syng_im/persistence/realm.cljs b/syng-im/src/syng_im/persistence/realm.cljs index 1c7201f7ec..51330b3bb9 100644 --- a/syng-im/src/syng_im/persistence/realm.cljs +++ b/syng-im/src/syng_im/persistence/realm.cljs @@ -17,14 +17,17 @@ :value "string"}} {:name :msgs :primaryKey :msg-id - :properties {:msg-id "string" - :from "string" - :to "string" - :content "string" ;; TODO make it ArrayBuffer - :content-type "string" - :timestamp "int" - :chat-id "string" - :outgoing "bool"}}]}) + :properties {:msg-id "string" + :from "string" + :to "string" + :content "string" ;; TODO make it ArrayBuffer + :content-type "string" + :timestamp "int" + :chat-id {:type "string" + :indexed true} + :outgoing "bool" + :delivery-status {:type "string" + :optional true}}}]}) (def realm (js/Realm. (clj->js opts))) @@ -34,7 +37,10 @@ (into {}))) (defn field-type [schema-name field] - (get-in schema-by-name [schema-name :properties field])) + (let [field-def (get-in schema-by-name [schema-name :properties field])] + (if (map? field-def) + (:type field-def) + field-def))) (defn write [f] (.write realm f)) @@ -52,14 +58,13 @@ (let [value (to-string value) query (str (name field) "=" (if (= "string" (field-type schema-name field)) (str "\"" value "\"") - value)) - ;_ (log/debug query) - ] + value))] query)) (defn get-by-field [schema-name field value] - (-> (.objects realm (name schema-name)) - (.filtered (to-query schema-name :eq field value)))) + (let [q (to-query schema-name :eq field value)] + (-> (.objects realm (name schema-name)) + (.filtered q)))) (defn sorted [results field-name order] (.sorted results (to-string field-name) (if (= order :asc) @@ -92,3 +97,13 @@ (defn get-list [schema-name] (vals (js->clj (.objects realm schema-name) :keywordize-keys true))) + + +(comment + + (write #(.create realm "msgs" (clj->js {:msg-id "1459175391577-a2185a35-5c49-5a6b-9c08-6eb5b87ceb7f" + :content "sdfd" + :delivery-status "seen"}) true)) + + + ) \ No newline at end of file diff --git a/syng-im/src/syng_im/protocol/protocol_handler.cljs b/syng-im/src/syng_im/protocol/protocol_handler.cljs index 2e240cf910..69e889a717 100644 --- a/syng-im/src/syng_im/protocol/protocol_handler.cljs +++ b/syng-im/src/syng_im/protocol/protocol_handler.cljs @@ -17,10 +17,10 @@ (dispatch [:protocol-initialized identity])) :new-msg (let [{:keys [from to payload]} event] (dispatch [:received-msg (assoc payload :from from :to to)])) - ;:msg-acked (let [{:keys [msg-id]} event] - ; (add-to-chat "chat" ":" (str "Message " msg-id " was acked"))) - ;:delivery-failed (let [{:keys [msg-id]} event] - ; (add-to-chat "chat" ":" (str "Delivery of message " msg-id " failed"))) + :msg-acked (let [{:keys [msg-id from]} event] + (dispatch [:acked-msg from msg-id])) + :delivery-failed (let [{:keys [msg-id]} event] + (dispatch [:msg-delivery-failed msg-id])) ;:new-group-chat (let [{:keys [from group-id identities]} event] ; (set-group-id! group-id) ; (set-group-identities identities) diff --git a/syng-im/src/syng_im/resources.cljs b/syng-im/src/syng_im/resources.cljs index d7e11f0aea..19a0c2ecb7 100644 --- a/syng-im/src/syng_im/resources.cljs +++ b/syng-im/src/syng_im/resources.cljs @@ -6,6 +6,7 @@ (def online-icon (js/require "./images/online.png")) (def seen-icon (js/require "./images/seen.png")) (def delivered-icon (js/require "./images/delivered.png")) +(def delivery-failed-icon (js/require "./images/deliveryfailed.png")) (def play (js/require "./images/play.png")) (def mic (js/require "./images/mic.png")) (def smile (js/require "./images/smile.png")) diff --git a/syng-im/src/syng_im/utils/listview.cljs b/syng-im/src/syng_im/utils/listview.cljs index 4908974276..b6bd9ec080 100644 --- a/syng-im/src/syng_im/utils/listview.cljs +++ b/syng-im/src/syng_im/utils/listview.cljs @@ -1,7 +1,13 @@ (ns syng-im.utils.listview - (:require-macros [natal-shell.data-source :refer [data-source clone-with-rows]])) + (:require-macros [natal-shell.data-source :refer [data-source clone-with-rows]]) + (:require [syng-im.components.realm])) (defn to-datasource [msgs] (-> (data-source {:rowHasChanged (fn [row1 row2] (not= row1 row2))}) + (clone-with-rows msgs))) + +(defn to-realm-datasource [msgs] + (-> (js/RealmReactNative.ListView.DataSource. (cljs.core/clj->js {:rowHasChanged (fn [row1 row2] + (not= row1 row2))})) (clone-with-rows msgs))) \ No newline at end of file