delivery status, scroll through messages history

Former-commit-id: 8f9ee4ba31
This commit is contained in:
michaelr 2016-03-28 19:00:07 +03:00
parent 8481c751b6
commit c7b3564a29
15 changed files with 145 additions and 59 deletions

View File

@ -1,14 +1,15 @@
{ {
"name": "SyngIm", "name": "SyngIm",
"interface": "reagent", "interface": "reagent",
"androidHost": "localhost", "androidHost": "10.0.3.2",
"modules": [ "modules": [
"react-native-contacts", "react-native-contacts",
"react-native-invertible-scroll-view", "react-native-invertible-scroll-view",
"awesome-phonenumber", "awesome-phonenumber",
"realm", "realm",
"react-native-loading-spinner-overlay", "react-native-loading-spinner-overlay",
"react-native-i18n" "react-native-i18n",
"realm/react-native"
], ],
"imageDirs": [ "imageDirs": [
"images" "images"

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

View File

@ -12,6 +12,6 @@
"react-native-i18n": "0.0.8", "react-native-i18n": "0.0.8",
"react-native-invertible-scroll-view": "^0.2.0", "react-native-invertible-scroll-view": "^0.2.0",
"react-native-loading-spinner-overlay": "0.0.6", "react-native-loading-spinner-overlay": "0.0.6",
"realm": "^0.10.0" "realm": "^0.11.0"
} }
} }

View File

@ -6,12 +6,12 @@
image image
touchable-highlight touchable-highlight
navigator navigator
toolbar-android toolbar-android]]
list-view]] [syng-im.components.realm :refer [list-view]]
[syng-im.utils.logging :as log] [syng-im.utils.logging :as log]
[syng-im.navigation :refer [nav-pop]] [syng-im.navigation :refer [nav-pop]]
[syng-im.resources :as res] [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]] [syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
[reagent.core :as r] [reagent.core :as r]
[syng-im.components.chat-message :refer [chat-message]] [syng-im.components.chat-message :refer [chat-message]]
@ -23,7 +23,7 @@
(fn [] (fn []
(let [msgs @messages (let [msgs @messages
_ (log/debug "messages=" msgs) _ (log/debug "messages=" msgs)
datasource (to-datasource msgs)] datasource (to-realm-datasource msgs)]
[view {:style {:flex 1 [view {:style {:flex 1
:backgroundColor "white"}} :backgroundColor "white"}}
(when android? (when android?

View File

@ -81,9 +81,10 @@
(defn message-delivery-status [{:keys [delivery-status]}] (defn message-delivery-status [{:keys [delivery-status]}]
[view {:style {:flexDirection "row" [view {:style {:flexDirection "row"
:marginTop 2}} :marginTop 2}}
[image {:source (if (= (keyword delivery-status) :seen) [image {:source (case delivery-status
res/seen-icon :delivered res/delivered-icon
res/delivered-icon) :seen res/seen-icon
:failed res/delivery-failed-icon)
:style {:marginTop 6 :style {:marginTop 6
:opacity 0.6}}] :opacity 0.6}}]
[text {:style {:fontFamily "Avenir-Roman" [text {:style {:fontFamily "Avenir-Roman"
@ -91,9 +92,10 @@
:color "#AAB2B2" :color "#AAB2B2"
:opacity 0.8 :opacity 0.8
:marginLeft 5}} :marginLeft 5}}
(if (= (keyword delivery-status) :seen) (case delivery-status
"Seen" :delivered "Delivered"
"Delivered")]]) :seen "Seen"
:failed "Failed")]])
(defn message-body [{:keys [msg-id content content-type outgoing delivery-status]}] (defn message-body [{:keys [msg-id content content-type outgoing delivery-status]}]
[view {:style (merge {:flexDirection "column" [view {:style (merge {:flexDirection "column"
@ -118,4 +120,4 @@
:content content :content content
:content-type content-type :content-type content-type
:outgoing outgoing :outgoing outgoing
:delivery-status delivery-status}]]) :delivery-status (keyword delivery-status)}]])

View File

@ -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])
)

View File

@ -7,7 +7,7 @@
;; initial state of app-db ;; initial state of app-db
(def app-db {:greeting "Hello Clojure in iOS and Android!" (def app-db {:greeting "Hello Clojure in iOS and Android!"
:identity-password "replace-me-with-user-entered-password" :identity-password "replace-me-with-user-entered-password"
:chat {:current-chat-id "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154"} :chat {:current-chat-id "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd"}
:chats {}}) :chats {}})

View File

@ -7,8 +7,10 @@
[syng-im.protocol.protocol-handler :refer [make-handler]] [syng-im.protocol.protocol-handler :refer [make-handler]]
[syng-im.models.protocol :refer [update-identity [syng-im.models.protocol :refer [update-identity
set-initialized]] set-initialized]]
[syng-im.models.messages :refer [save-message]] [syng-im.models.messages :refer [save-message
[syng-im.models.chat :refer [set-latest-msg-id]] update-message!
message-by-id]]
[syng-im.models.chat :refer [signal-chat-updated]]
[syng-im.utils.logging :as log] [syng-im.utils.logging :as log]
[syng-im.protocol.api :as api] [syng-im.protocol.api :as api]
[syng-im.constants :refer [text-content-type]])) [syng-im.constants :refer [text-content-type]]))
@ -49,7 +51,20 @@
(fn [db [_ {chat-id :from (fn [db [_ {chat-id :from
msg-id :msg-id :as msg}]] msg-id :msg-id :as msg}]]
(save-message chat-id 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 (register-handler :send-chat-msg
(fn [db [_ chat-id text]] (fn [db [_ chat-id text]]
@ -65,7 +80,7 @@
:content-type text-content-type :content-type text-content-type
:outgoing true}] :outgoing true}]
(save-message chat-id msg) (save-message chat-id msg)
(set-latest-msg-id db chat-id msg-id)))) (signal-chat-updated db chat-id))))
;; -- Something -------------------------------------------------------------- ;; -- Something --------------------------------------------------------------

View File

@ -7,9 +7,18 @@
(defn current-chat-id [db] (defn current-chat-id [db]
(get-in db db/current-chat-id-path)) (get-in db db/current-chat-id-path))
(defn set-latest-msg-id [db chat-id msg-id] (defn signal-chat-updated [db chat-id]
(assoc-in db (db/latest-msg-id-path chat-id) msg-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] (defn latest-msg-id [db chat-id]
(->> (db/latest-msg-id-path chat-id) (->> (db/latest-msg-id-path chat-id)
(get-in db))) (get-in db)))
(comment
(swap! re-frame.db/app-db (fn [db]
(signal-chat-updated db "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd")))
)

View File

@ -2,7 +2,8 @@
(:require [syng-im.persistence.realm :as r] (:require [syng-im.persistence.realm :as r]
[cljs.reader :refer [read-string]] [cljs.reader :refer [read-string]]
[syng-im.utils.random :refer [timestamp]] [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}] (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) (when-not (r/exists? :msgs :msg-id msg-id)
@ -15,19 +16,30 @@
:content content :content content
:content-type content-type :content-type content-type
:outgoing outgoing :outgoing outgoing
:timestamp (timestamp)} true))))) :timestamp (timestamp)
:delivery-status nil} true)))))
(defn get-messages* [chat-id]
(-> (r/get-by-field :msgs :chat-id chat-id)
(r/sorted :timestamp :desc)
(r/page 0 10)))
(defn get-messages [chat-id] (defn get-messages [chat-id]
(-> (get-messages* chat-id) (-> (r/get-by-field :msgs :chat-id chat-id)
(js->clj :keywordize-keys true))) (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 (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" (save-message "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154"
{:msg-id "153" {:msg-id "153"
:content "hello!" :content "hello!"
@ -35,9 +47,11 @@
(get-messages* "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154") (get-messages* "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154")
(get-messages nil) (get-messages "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd")
(doseq [msg (get-messages* "0x043df89d36f6e3d8ade18e55ac3e2e39406ebde152f76f2f82d674681d59319ffd9880eebfb4f5f8d5c222ec485b44d6e30ba3a03c96b1c946144fdeba1caccd43")] (doseq [msg (get-messages* "0x043df89d36f6e3d8ade18e55ac3e2e39406ebde152f76f2f82d674681d59319ffd9880eebfb4f5f8d5c222ec485b44d6e30ba3a03c96b1c946144fdeba1caccd43")]
(r/delete msg)) (r/delete msg))
@re-frame.db/app-db
) )

View File

@ -25,3 +25,8 @@
(when encrypted (when encrypted
(-> (password-decrypt password encrypted) (-> (password-decrypt password encrypted)
(read-string))))) (read-string)))))
(comment
(stored-identity @re-frame.db/app-db)
)

View File

@ -23,8 +23,11 @@
:content "string" ;; TODO make it ArrayBuffer :content "string" ;; TODO make it ArrayBuffer
:content-type "string" :content-type "string"
:timestamp "int" :timestamp "int"
:chat-id "string" :chat-id {:type "string"
:outgoing "bool"}}]}) :indexed true}
:outgoing "bool"
:delivery-status {:type "string"
:optional true}}}]})
(def realm (js/Realm. (clj->js opts))) (def realm (js/Realm. (clj->js opts)))
@ -34,7 +37,10 @@
(into {}))) (into {})))
(defn field-type [schema-name field] (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] (defn write [f]
(.write realm f)) (.write realm f))
@ -52,14 +58,13 @@
(let [value (to-string value) (let [value (to-string value)
query (str (name field) "=" (if (= "string" (field-type schema-name field)) query (str (name field) "=" (if (= "string" (field-type schema-name field))
(str "\"" value "\"") (str "\"" value "\"")
value)) value))]
;_ (log/debug query)
]
query)) query))
(defn get-by-field [schema-name field value] (defn get-by-field [schema-name field value]
(let [q (to-query schema-name :eq field value)]
(-> (.objects realm (name schema-name)) (-> (.objects realm (name schema-name))
(.filtered (to-query schema-name :eq field value)))) (.filtered q))))
(defn sorted [results field-name order] (defn sorted [results field-name order]
(.sorted results (to-string field-name) (if (= order :asc) (.sorted results (to-string field-name) (if (= order :asc)
@ -92,3 +97,13 @@
(defn get-list [schema-name] (defn get-list [schema-name]
(vals (js->clj (.objects realm schema-name) :keywordize-keys true))) (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))
)

View File

@ -17,10 +17,10 @@
(dispatch [:protocol-initialized identity])) (dispatch [:protocol-initialized identity]))
:new-msg (let [{:keys [from to payload]} event] :new-msg (let [{:keys [from to payload]} event]
(dispatch [:received-msg (assoc payload :from from :to to)])) (dispatch [:received-msg (assoc payload :from from :to to)]))
;:msg-acked (let [{:keys [msg-id]} event] :msg-acked (let [{:keys [msg-id from]} event]
; (add-to-chat "chat" ":" (str "Message " msg-id " was acked"))) (dispatch [:acked-msg from msg-id]))
;:delivery-failed (let [{:keys [msg-id]} event] :delivery-failed (let [{:keys [msg-id]} event]
; (add-to-chat "chat" ":" (str "Delivery of message " msg-id " failed"))) (dispatch [:msg-delivery-failed msg-id]))
;:new-group-chat (let [{:keys [from group-id identities]} event] ;:new-group-chat (let [{:keys [from group-id identities]} event]
; (set-group-id! group-id) ; (set-group-id! group-id)
; (set-group-identities identities) ; (set-group-identities identities)

View File

@ -6,6 +6,7 @@
(def online-icon (js/require "./images/online.png")) (def online-icon (js/require "./images/online.png"))
(def seen-icon (js/require "./images/seen.png")) (def seen-icon (js/require "./images/seen.png"))
(def delivered-icon (js/require "./images/delivered.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 play (js/require "./images/play.png"))
(def mic (js/require "./images/mic.png")) (def mic (js/require "./images/mic.png"))
(def smile (js/require "./images/smile.png")) (def smile (js/require "./images/smile.png"))

View File

@ -1,7 +1,13 @@
(ns syng-im.utils.listview (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] (defn to-datasource [msgs]
(-> (data-source {:rowHasChanged (fn [row1 row2] (-> (data-source {:rowHasChanged (fn [row1 row2]
(not= row1 row2))}) (not= row1 row2))})
(clone-with-rows msgs))) (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)))