Merge with re-frame-rewrite
This commit is contained in:
commit
390e454207
|
@ -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 |
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
["do" "clean"
|
["do" "clean"
|
||||||
["with-profile" "prod" "cljsbuild" "once" "ios"]
|
["with-profile" "prod" "cljsbuild" "once" "ios"]
|
||||||
["with-profile" "prod" "cljsbuild" "once" "android"]]}
|
["with-profile" "prod" "cljsbuild" "once" "android"]]}
|
||||||
|
:figwheel {:nrepl-port 7888}
|
||||||
:profiles {:dev {:dependencies [[figwheel-sidecar "0.5.0-2"]
|
:profiles {:dev {:dependencies [[figwheel-sidecar "0.5.0-2"]
|
||||||
[com.cemerick/piggieback "0.2.1"]]
|
[com.cemerick/piggieback "0.2.1"]]
|
||||||
:source-paths ["src" "env/dev"]
|
:source-paths ["src" "env/dev"]
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
[syng-im.components.chat :refer [chat]]
|
[syng-im.components.chat :refer [chat]]
|
||||||
[syng-im.components.sign-up :refer [sign-up-view]]
|
[syng-im.components.sign-up :refer [sign-up-view]]
|
||||||
[syng-im.components.sign-up-confirm :refer [sign-up-confirm-view]]
|
[syng-im.components.sign-up-confirm :refer [sign-up-confirm-view]]
|
||||||
[syng-im.components.nav :as nav]
|
[syng-im.utils.logging :as log]
|
||||||
[syng-im.utils.logging :as log]))
|
[syng-im.navigation :as nav]))
|
||||||
|
|
||||||
(def back-button-handler (cljs/atom {:nav nil
|
(def back-button-handler (cljs/atom {:nav nil
|
||||||
:handler nil}))
|
:handler nil}))
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
(let [new-listener (fn []
|
(let [new-listener (fn []
|
||||||
(binding [nav/*nav-render* false]
|
(binding [nav/*nav-render* false]
|
||||||
(when (< 1 (.-length (.getCurrentRoutes nav)))
|
(when (< 1 (.-length (.getCurrentRoutes nav)))
|
||||||
(.pop nav)
|
(nav/nav-pop nav)
|
||||||
true)))]
|
true)))]
|
||||||
(reset! back-button-handler {:nav nav
|
(reset! back-button-handler {:nav nav
|
||||||
:handler new-listener})
|
:handler new-listener})
|
||||||
|
|
|
@ -1,21 +1,48 @@
|
||||||
(ns syng-im.components.chat
|
(ns syng-im.components.chat
|
||||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.components.react :refer [view text image touchable-highlight navigator]]
|
[syng-im.components.react :refer [android?
|
||||||
[syng-im.utils.logging :as log]))
|
view
|
||||||
|
text
|
||||||
(def logo-img (js/require "./images/cljs.png"))
|
image
|
||||||
|
touchable-highlight
|
||||||
(defn alert [title]
|
navigator
|
||||||
(.alert (.-Alert js/React) title))
|
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-realm-datasource]]
|
||||||
|
[syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
||||||
|
[reagent.core :as r]
|
||||||
|
[syng-im.components.chat-message :refer [chat-message]]
|
||||||
|
[syng-im.components.chat-message-new :refer [chat-message-new]]))
|
||||||
|
|
||||||
|
|
||||||
(defn chat [{:keys [navigator]}]
|
(defn chat [{:keys [navigator]}]
|
||||||
(let [greeting (subscribe [:get-greeting])]
|
(let [messages (subscribe [:get-chat-messages])]
|
||||||
(fn []
|
(fn []
|
||||||
[view {:style {:flex-direction "column" :margin 40 :align-items "center"}}
|
(let [msgs @messages
|
||||||
[text {:style {:font-size 30 :font-weight "100" :margin-bottom 20 :text-align "center"}} @greeting]
|
_ (log/debug "messages=" msgs)
|
||||||
[image {:source logo-img
|
datasource (to-realm-datasource msgs)]
|
||||||
:style {:width 80 :height 80 :margin-bottom 30}}]
|
[view {:style {:flex 1
|
||||||
[touchable-highlight {:style {:background-color "#999" :padding 10 :border-radius 5}
|
:backgroundColor "white"}}
|
||||||
:on-press #(alert "HELLO!")}
|
(when android?
|
||||||
[text {:style {:color "white" :text-align "center" :font-weight "bold"}} "press me"]]])))
|
;; TODO add IOS version
|
||||||
|
[toolbar-android {:logo res/logo-icon
|
||||||
|
:title "Chat name"
|
||||||
|
:titleColor "#4A5258"
|
||||||
|
:subtitle "Last seen just now"
|
||||||
|
:subtitleColor "#AAB2B2"
|
||||||
|
:navIcon res/nav-back-icon
|
||||||
|
:style {:backgroundColor "white"
|
||||||
|
:height 56
|
||||||
|
:elevation 2}
|
||||||
|
:onIconClicked (fn []
|
||||||
|
(nav-pop navigator))}])
|
||||||
|
[list-view {:dataSource datasource
|
||||||
|
:renderScrollComponent (fn [props]
|
||||||
|
(invertible-scroll-view nil))
|
||||||
|
:renderRow (fn [row section-id row-id]
|
||||||
|
(r/as-element [chat-message (js->clj row :keywordize-keys true)]))
|
||||||
|
:style {:backgroundColor "black"}}]
|
||||||
|
[chat-message-new]]))))
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
(ns syng-im.components.chat-message
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.components.react :refer [android?
|
||||||
|
view
|
||||||
|
text
|
||||||
|
image
|
||||||
|
touchable-highlight
|
||||||
|
navigator
|
||||||
|
toolbar-android]]
|
||||||
|
[syng-im.utils.logging :as log]
|
||||||
|
[syng-im.navigation :refer [nav-pop]]
|
||||||
|
[syng-im.resources :as res]
|
||||||
|
[syng-im.constants :refer [text-content-type]]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn message-date [{:keys [date]}]
|
||||||
|
[text {:style {:marginVertical 10
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:fontSize 11
|
||||||
|
:color "#AAB2B2"
|
||||||
|
:letterSpacing 1
|
||||||
|
:lineHeight 15
|
||||||
|
:textAlign "center"
|
||||||
|
:opacity 0.8}}
|
||||||
|
date])
|
||||||
|
|
||||||
|
(defn message-content-audio [{:keys [content-type content-type]}]
|
||||||
|
[view {:style {:flexDirection "row"
|
||||||
|
:alignItems "center"}}
|
||||||
|
[view {:style {:width 33
|
||||||
|
:height 33
|
||||||
|
:borderRadius 50
|
||||||
|
:elevation 1}}
|
||||||
|
[image {:source res/play
|
||||||
|
:style {:width 33
|
||||||
|
:height 33}}]]
|
||||||
|
[view {:style {:marginTop 10
|
||||||
|
:marginLeft 10
|
||||||
|
:width 120
|
||||||
|
:height 26
|
||||||
|
:elevation 1}}
|
||||||
|
[view {:style {:position "absolute"
|
||||||
|
:top 4
|
||||||
|
:width 120
|
||||||
|
:height 2
|
||||||
|
:backgroundColor "#EC7262"}}]
|
||||||
|
[view {:style {:position "absolute"
|
||||||
|
:left 0
|
||||||
|
:top 0
|
||||||
|
:width 2
|
||||||
|
:height 10
|
||||||
|
:backgroundColor "#4A5258"}}]
|
||||||
|
[text {:style {:position "absolute"
|
||||||
|
:left 1
|
||||||
|
:top 11
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:fontSize 11
|
||||||
|
:color "#4A5258"
|
||||||
|
:letterSpacing 1
|
||||||
|
:lineHeight 15}}
|
||||||
|
"03:39"]]])
|
||||||
|
|
||||||
|
(defn message-content [{:keys [content-type content outgoing]}]
|
||||||
|
[view {:style (merge {:borderRadius 6}
|
||||||
|
(if (= content-type text-content-type)
|
||||||
|
{:paddingVertical 12
|
||||||
|
:paddingHorizontal 16}
|
||||||
|
{:paddingVertical 14
|
||||||
|
:paddingHorizontal 10})
|
||||||
|
(if outgoing
|
||||||
|
{:backgroundColor "#D3EEEF"}
|
||||||
|
{:backgroundColor "#FBF6E3"}))}
|
||||||
|
(if (= content-type text-content-type)
|
||||||
|
[text {:style {:fontSize 14
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:color "#4A5258"}}
|
||||||
|
content]
|
||||||
|
[message-content-audio {:content content
|
||||||
|
:content-type content-type}])])
|
||||||
|
|
||||||
|
(defn message-delivery-status [{:keys [delivery-status]}]
|
||||||
|
[view {:style {:flexDirection "row"
|
||||||
|
:marginTop 2}}
|
||||||
|
[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"
|
||||||
|
:fontSize 11
|
||||||
|
:color "#AAB2B2"
|
||||||
|
:opacity 0.8
|
||||||
|
:marginLeft 5}}
|
||||||
|
(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"
|
||||||
|
:width 260
|
||||||
|
:marginVertical 5}
|
||||||
|
(if outgoing
|
||||||
|
{:alignSelf "flex-end"
|
||||||
|
:alignItems "flex-end"}
|
||||||
|
{:alignSelf "flex-start"
|
||||||
|
:alignItems "flex-start"}))}
|
||||||
|
[message-content {:content-type content-type
|
||||||
|
:content content
|
||||||
|
:outgoing outgoing}]
|
||||||
|
(when (and outgoing delivery-status)
|
||||||
|
[message-delivery-status {:delivery-status delivery-status}])])
|
||||||
|
|
||||||
|
(defn chat-message [{:keys [msg-id content content-type outgoing delivery-status date new-day] :as msg}]
|
||||||
|
[view {:paddingHorizontal 15}
|
||||||
|
(when new-day
|
||||||
|
[message-date {:date date}])
|
||||||
|
[message-body {:msg-id msg-id
|
||||||
|
:content content
|
||||||
|
:content-type content-type
|
||||||
|
:outgoing outgoing
|
||||||
|
:delivery-status (keyword delivery-status)}]])
|
|
@ -0,0 +1,51 @@
|
||||||
|
(ns syng-im.components.chat-message-new
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.components.react :refer [android?
|
||||||
|
view
|
||||||
|
image
|
||||||
|
text-input]]
|
||||||
|
[syng-im.utils.logging :as log]
|
||||||
|
[syng-im.resources :as res]
|
||||||
|
[reagent.core :as r]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn chat-message-new []
|
||||||
|
(let [text (r/atom nil)
|
||||||
|
chat-id (subscribe [:get-current-chat-id])]
|
||||||
|
(fn []
|
||||||
|
[view {:style {:flexDirection "row"
|
||||||
|
:margin 10
|
||||||
|
:height 40
|
||||||
|
:backgroundColor "#E5F5F6"
|
||||||
|
:borderRadius 5}}
|
||||||
|
[image {:source res/mic
|
||||||
|
:style {:marginTop 11
|
||||||
|
:marginLeft 14
|
||||||
|
:width 13
|
||||||
|
:height 20}}]
|
||||||
|
[text-input {:underlineColorAndroid "#9CBFC0"
|
||||||
|
:style {:flex 1
|
||||||
|
:marginLeft 18
|
||||||
|
:lineHeight 42
|
||||||
|
:fontSize 14
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:color "#9CBFC0"}
|
||||||
|
:autoFocus true
|
||||||
|
:placeholder "Enter your message here"
|
||||||
|
:value @text
|
||||||
|
:onChangeText (fn [new-text]
|
||||||
|
(reset! text new-text)
|
||||||
|
(r/flush))
|
||||||
|
:onSubmitEditing (fn [e]
|
||||||
|
(dispatch [:send-chat-msg @chat-id @text])
|
||||||
|
(reset! text nil))}]
|
||||||
|
[image {:source res/smile
|
||||||
|
:style {:marginTop 11
|
||||||
|
:marginRight 12
|
||||||
|
:width 18
|
||||||
|
:height 18}}]
|
||||||
|
[image {:source res/att
|
||||||
|
:style {:marginTop 14
|
||||||
|
:marginRight 16
|
||||||
|
:width 17
|
||||||
|
:height 14}}]])))
|
|
@ -1,7 +1,7 @@
|
||||||
(ns syng-im.components.contact-list.contact
|
(ns syng-im.components.contact-list.contact
|
||||||
(:require [syng-im.components.react :refer [view text image touchable-highlight]]
|
(:require [syng-im.components.react :refer [view text image touchable-highlight]]
|
||||||
[syng-im.components.resources :as res]
|
[syng-im.components.resources :as res]
|
||||||
[syng-im.components.nav :as nav]))
|
[syng-im.navigation :as nav]))
|
||||||
|
|
||||||
(defn show-chat [navigator whisper-identity]
|
(defn show-chat [navigator whisper-identity]
|
||||||
(nav/nav-push navigator {:view-id :chat}))
|
(nav/nav-push navigator {:view-id :chat}))
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
(ns syng-im.components.invertible-scroll-view
|
|
||||||
(:require [reagent.core :as r]))
|
|
||||||
|
|
||||||
(def react-invertible-scroll-view (js/require "react-native-invertible-scroll-view"))
|
|
||||||
|
|
||||||
(def invertible-scroll-view (r/adapt-react-class react-invertible-scroll-view))
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
(ns syng-im.components.invertible-scroll-view)
|
||||||
|
|
||||||
|
(set! js/window.InvertibleScrollView (js/require "react-native-invertible-scroll-view"))
|
||||||
|
|
||||||
|
(defn invertible-scroll-view [props]
|
||||||
|
(js/React.createElement js/InvertibleScrollView
|
||||||
|
(clj->js (merge {:inverted true} props))))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(ns syng-im.components.react
|
(ns syng-im.components.react
|
||||||
(:require [reagent.core :as r]))
|
(:require [reagent.core :as r]))
|
||||||
|
|
||||||
(set! js/React (js/require "react-native"))
|
(set! js/window.React (js/require "react-native"))
|
||||||
|
|
||||||
(def app-registry (.-AppRegistry js/React))
|
(def app-registry (.-AppRegistry js/React))
|
||||||
(def navigator (r/adapt-react-class (.-Navigator js/React)))
|
(def navigator (r/adapt-react-class (.-Navigator js/React)))
|
||||||
|
@ -13,6 +13,10 @@
|
||||||
(def list-view (r/adapt-react-class (.-ListView js/React)))
|
(def list-view (r/adapt-react-class (.-ListView js/React)))
|
||||||
(def text-input (r/adapt-react-class (.-TextInput js/React)))
|
(def text-input (r/adapt-react-class (.-TextInput js/React)))
|
||||||
|
|
||||||
|
(def platform (.. js/React -Platform -OS))
|
||||||
|
|
||||||
|
(def android? (= platform "android"))
|
||||||
|
|
||||||
(defn list-item [component]
|
(defn list-item [component]
|
||||||
(r/as-element component))
|
(r/as-element component))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
(ns syng-im.components.realm
|
||||||
|
(:require [reagent.core :as r]))
|
||||||
|
|
||||||
|
(set! js/window.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])
|
||||||
|
|
||||||
|
)
|
|
@ -4,7 +4,7 @@
|
||||||
toolbar-android text-input]]
|
toolbar-android text-input]]
|
||||||
[syng-im.components.resources :as res]
|
[syng-im.components.resources :as res]
|
||||||
[syng-im.components.spinner :refer [spinner]]
|
[syng-im.components.spinner :refer [spinner]]
|
||||||
[syng-im.components.nav :as nav]
|
[syng-im.navigation :as nav]
|
||||||
[syng-im.utils.utils :refer [log toast http-post]]
|
[syng-im.utils.utils :refer [log toast http-post]]
|
||||||
[syng-im.utils.phone-number :refer [format-phone-number]]))
|
[syng-im.utils.phone-number :refer [format-phone-number]]))
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
||||||
user-phone-number (subscribe [:get-user-phone-number])
|
user-phone-number (subscribe [:get-user-phone-number])
|
||||||
user-identity (subscribe [:get-user-identity])]
|
user-identity (subscribe [:get-user-identity])]
|
||||||
(fn []
|
(fn []
|
||||||
;; (reset! nav-atom navigator)
|
|
||||||
[view {:style {:flex 1}}
|
[view {:style {:flex 1}}
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor "white"}}
|
:backgroundColor "white"}}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
toolbar-android text-input]]
|
toolbar-android text-input]]
|
||||||
[syng-im.components.resources :as res]
|
[syng-im.components.resources :as res]
|
||||||
[syng-im.components.spinner :refer [spinner]]
|
[syng-im.components.spinner :refer [spinner]]
|
||||||
[syng-im.components.nav :as nav]
|
[syng-im.navigation :as nav]
|
||||||
[syng-im.utils.utils :refer [log toast http-post]]))
|
[syng-im.utils.utils :refer [log toast http-post]]))
|
||||||
|
|
||||||
(defn show-home-view [navigator]
|
(defn show-home-view [navigator]
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
(def schema {:greeting s/Str})
|
(def schema {:greeting s/Str})
|
||||||
|
|
||||||
;; 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"
|
||||||
:contacts []})
|
:contacts []
|
||||||
|
:chat {:current-chat-id "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd"}
|
||||||
|
:chats {}})
|
||||||
|
|
||||||
|
|
||||||
(def protocol-initialized-path [:protocol-initialized])
|
(def protocol-initialized-path [:protocol-initialized])
|
||||||
(def simple-store-path [:simple-store])
|
|
||||||
(def identity-password-path [:identity-password])
|
(def identity-password-path [:identity-password])
|
||||||
(def current-chat-id-path [:chat :current-chat-id])
|
(def current-chat-id-path [:chat :current-chat-id])
|
||||||
(defn arrived-message-path [chat-id]
|
(defn latest-msg-id-path [chat-id]
|
||||||
[:chat chat-id :arrived-message-id])
|
[:chats chat-id :arrived-message-id])
|
||||||
|
|
|
@ -10,10 +10,14 @@
|
||||||
[syng-im.models.user-data :as user-data]
|
[syng-im.models.user-data :as user-data]
|
||||||
[syng-im.models.contacts :as contacts]
|
[syng-im.models.contacts :as contacts]
|
||||||
[syng-im.models.messages :refer [save-message
|
[syng-im.models.messages :refer [save-message
|
||||||
new-message-arrived]]
|
update-message!
|
||||||
|
message-by-id]]
|
||||||
|
[syng-im.models.chat :refer [signal-chat-updated]]
|
||||||
[syng-im.handlers.server :as server]
|
[syng-im.handlers.server :as server]
|
||||||
[syng-im.handlers.contacts :as contacts-service]
|
[syng-im.handlers.contacts :as contacts-service]
|
||||||
[syng-im.utils.logging :as log]))
|
[syng-im.utils.logging :as log]
|
||||||
|
[syng-im.protocol.api :as api]
|
||||||
|
[syng-im.constants :refer [text-content-type]]))
|
||||||
|
|
||||||
;; -- Middleware ------------------------------------------------------------
|
;; -- Middleware ------------------------------------------------------------
|
||||||
;;
|
;;
|
||||||
|
@ -57,7 +61,36 @@
|
||||||
(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)
|
||||||
(new-message-arrived 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]]
|
||||||
|
(log/debug "chat-id" chat-id "text" text)
|
||||||
|
(let [{msg-id :msg-id
|
||||||
|
{from :from
|
||||||
|
to :to} :msg} (api/send-user-msg {:to chat-id
|
||||||
|
:content text})
|
||||||
|
msg {:msg-id msg-id
|
||||||
|
:from from
|
||||||
|
:to to
|
||||||
|
:content text
|
||||||
|
:content-type text-content-type
|
||||||
|
:outgoing true}]
|
||||||
|
(save-message chat-id msg)
|
||||||
|
(signal-chat-updated db chat-id))))
|
||||||
|
|
||||||
;; -- User data --------------------------------------------------------------
|
;; -- User data --------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
[syng-im.handlers]
|
[syng-im.handlers]
|
||||||
[syng-im.subs]))
|
[syng-im.subs]))
|
||||||
|
|
||||||
(set! js/React (js/require "react-native"))
|
(set! js/window.React (js/require "react-native"))
|
||||||
|
|
||||||
(def app-registry (.-AppRegistry js/React))
|
(def app-registry (.-AppRegistry js/React))
|
||||||
(def text (r/adapt-react-class (.-Text js/React)))
|
(def text (r/adapt-react-class (.-Text js/React)))
|
||||||
|
|
|
@ -6,3 +6,19 @@
|
||||||
|
|
||||||
(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 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)))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
|
||||||
|
(swap! re-frame.db/app-db (fn [db]
|
||||||
|
(signal-chat-updated db "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd")))
|
||||||
|
)
|
|
@ -2,35 +2,44 @@
|
||||||
(: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)
|
||||||
(r/write
|
(r/write
|
||||||
(fn []
|
(fn []
|
||||||
(r/create :msgs {:chat-id chat-id
|
(r/create :msgs {:chat-id chat-id
|
||||||
:msg-id msg-id
|
:msg-id msg-id
|
||||||
:from from
|
:from from
|
||||||
:to to
|
:to to
|
||||||
: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 new-message-arrived [db chat-id msg-id]
|
(defn message-by-id [msg-id]
|
||||||
(assoc-in db (db/arrived-message-path chat-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!"
|
||||||
|
@ -38,9 +47,11 @@
|
||||||
|
|
||||||
(get-messages* "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154")
|
(get-messages* "0x040028c500ff086ecf1cfbb3c1a7240179cde5b86f9802e6799b9bbe9cdd7ad1b05ae8807fa1f9ed19cc8ce930fc2e878738c59f030a6a2f94b3522dc1378ff154")
|
||||||
|
|
||||||
(get-messages "0x043df89d36f6e3d8ade18e55ac3e2e39406ebde152f76f2f82d674681d59319ffd9880eebfb4f5f8d5c222ec485b44d6e30ba3a03c96b1c946144fdeba1caccd43")
|
(get-messages "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd")
|
||||||
|
|
||||||
(doseq [msg (get-messages* "0x043df89d36f6e3d8ade18e55ac3e2e39406ebde152f76f2f82d674681d59319ffd9880eebfb4f5f8d5c222ec485b44d6e30ba3a03c96b1c946144fdeba1caccd43")]
|
(doseq [msg (get-messages* "0x043df89d36f6e3d8ade18e55ac3e2e39406ebde152f76f2f82d674681d59319ffd9880eebfb4f5f8d5c222ec485b44d6e30ba3a03c96b1c946144fdeba1caccd43")]
|
||||||
(r/delete msg))
|
(r/delete msg))
|
||||||
|
|
||||||
|
@re-frame.db/app-db
|
||||||
|
|
||||||
)
|
)
|
|
@ -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)
|
||||||
|
)
|
|
@ -1,4 +1,4 @@
|
||||||
(ns syng-im.components.nav)
|
(ns syng-im.navigation)
|
||||||
|
|
||||||
(def ^{:dynamic true :private true} *nav-render*
|
(def ^{:dynamic true :private true} *nav-render*
|
||||||
"Flag to suppress navigator re-renders from outside om when pushing/popping."
|
"Flag to suppress navigator re-renders from outside om when pushing/popping."
|
|
@ -4,7 +4,7 @@
|
||||||
[syng-im.utils.types :refer [to-string]])
|
[syng-im.utils.types :refer [to-string]])
|
||||||
(:refer-clojure :exclude [exists?]))
|
(:refer-clojure :exclude [exists?]))
|
||||||
|
|
||||||
(set! js/Realm (js/require "realm"))
|
(set! js/window.Realm (js/require "realm"))
|
||||||
|
|
||||||
(def opts {:schema [{:name "Contact"
|
(def opts {:schema [{:name "Contact"
|
||||||
:properties {:phone-number "string"
|
:properties {:phone-number "string"
|
||||||
|
@ -17,14 +17,17 @@
|
||||||
:value "string"}}
|
:value "string"}}
|
||||||
{:name :msgs
|
{:name :msgs
|
||||||
:primaryKey :msg-id
|
:primaryKey :msg-id
|
||||||
:properties {:msg-id "string"
|
:properties {:msg-id "string"
|
||||||
:from "string"
|
:from "string"
|
||||||
:to "string"
|
:to "string"
|
||||||
: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]
|
||||||
(-> (.objects realm (name schema-name))
|
(let [q (to-query schema-name :eq field value)]
|
||||||
(.filtered (to-query schema-name :eq field value))))
|
(-> (.objects realm (name schema-name))
|
||||||
|
(.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))
|
||||||
|
|
||||||
|
|
||||||
|
)
|
|
@ -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)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
(ns syng-im.resources)
|
||||||
|
|
||||||
|
(def logo-icon (js/require "./images/logo.png"))
|
||||||
|
(def nav-back-icon (js/require "./images/nav-back.png"))
|
||||||
|
(def user-no-photo (js/require "./images/no-photo.png"))
|
||||||
|
(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"))
|
||||||
|
(def att (js/require "./images/att.png"))
|
||||||
|
|
|
@ -1,12 +1,28 @@
|
||||||
(ns syng-im.subs
|
(ns syng-im.subs
|
||||||
(:require-macros [reagent.ratom :refer [reaction]])
|
(:require-macros [reagent.ratom :refer [reaction]])
|
||||||
(:require [re-frame.core :refer [register-sub]]))
|
(:require [re-frame.core :refer [register-sub]]
|
||||||
|
[syng-im.models.chat :refer [current-chat-id
|
||||||
|
latest-msg-id]]
|
||||||
|
[syng-im.models.messages :refer [get-messages]]))
|
||||||
|
|
||||||
(register-sub
|
(register-sub :get-greeting (fn [db _]
|
||||||
:get-greeting
|
(reaction
|
||||||
(fn [db _]
|
(get @db :greeting))))
|
||||||
(reaction
|
|
||||||
(get @db :greeting))))
|
(register-sub :get-chat-messages
|
||||||
|
(fn [db _]
|
||||||
|
(let [chat-id (-> (current-chat-id @db)
|
||||||
|
(reaction))
|
||||||
|
latest-msg (-> (latest-msg-id @db @chat-id)
|
||||||
|
(reaction))]
|
||||||
|
;; latest-msg signals us that a new message has been added
|
||||||
|
(reaction
|
||||||
|
(let [_ @latest-msg]
|
||||||
|
(get-messages @chat-id))))))
|
||||||
|
|
||||||
|
(register-sub :get-current-chat-id (fn [db _]
|
||||||
|
(-> (current-chat-id @db)
|
||||||
|
(reaction))))
|
||||||
|
|
||||||
;; -- User data --------------------------------------------------------------
|
;; -- User data --------------------------------------------------------------
|
||||||
(register-sub
|
(register-sub
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
(ns syng-im.utils.listview
|
||||||
|
(: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)))
|
Loading…
Reference in New Issue