Rewrite sync contacts with server

This commit is contained in:
virvar 2016-03-28 18:27:09 +03:00
parent 7fdb31b73e
commit 2a0d39726a
8 changed files with 193 additions and 22 deletions

View File

@ -10,6 +10,7 @@
[syng-im.components.contact-list.contact-list :refer [contact-list]] [syng-im.components.contact-list.contact-list :refer [contact-list]]
[syng-im.components.chat :refer [chat]] [syng-im.components.chat :refer [chat]]
[syng-im.components.login :refer [login-view]] [syng-im.components.login :refer [login-view]]
[syng-im.components.sign-up-confirm :refer [sign-up-confirm-view]]
;; [syng-im.components.chat.chat :refer [chat]] ;; [syng-im.components.chat.chat :refer [chat]]
[syng-im.components.nav :as nav] [syng-im.components.nav :as nav]
@ -42,7 +43,7 @@
}) })
:render-scene (fn [route nav] :render-scene (fn [route nav]
(log/debug "route" route) (log/debug "route" route)
(when nav/*nav-render* (when true ;; nav/*nav-render*
(let [{:keys [view-id]} (js->clj route :keywordize-keys true) (let [{:keys [view-id]} (js->clj route :keywordize-keys true)
view-id (keyword view-id)] view-id (keyword view-id)]
(init-back-button-handler! nav) (init-back-button-handler! nav)
@ -50,7 +51,9 @@
:contact-list (r/as-element [contact-list :contact-list (r/as-element [contact-list
{:navigator nav}]) {:navigator nav}])
:chat (r/as-element [chat {:navigator nav}]) :chat (r/as-element [chat {:navigator nav}])
:login (r/as-element [login-view {:navigator nav}])))))}]) :login (r/as-element [login-view {:navigator nav}])
:sign-up-confirm (r/as-element [sign-up-confirm-view
{:navigator nav}])))))}])
(defn init [] (defn init []
(dispatch-sync [:initialize-db]) (dispatch-sync [:initialize-db])

View File

@ -6,20 +6,18 @@
[syng-im.components.spinner :refer [spinner]] [syng-im.components.spinner :refer [spinner]]
[syng-im.components.nav :as nav] [syng-im.components.nav :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]]))
;; [messenger.android.sign-up-confirm :refer [sign-up-confirm]]
))
(def nav-atom (atom nil)) ;; (def nav-atom (atom nil))
(defn show-confirm-view [] (defn show-confirm-view [navigator]
(dispatch [:set-loading false]) (dispatch [:set-loading false])
;; TODO 'nav-replace ;; TODO 'nav-replace
(nav/nav-push @nav-atom {:view-id :chat})) (nav/nav-push navigator {:view-id :sign-up-confirm}))
(defn sign-up [user-phone-number user-identity] (defn sign-up [user-phone-number user-identity navigator]
(dispatch [:set-loading true]) (dispatch [:set-loading true])
(dispatch [:sign-up user-phone-number user-identity show-confirm-view])) (dispatch [:sign-up user-phone-number user-identity #(show-confirm-view navigator)]))
(defn update-phone-number [value] (defn update-phone-number [value]
(let [formatted (format-phone-number value)] (let [formatted (format-phone-number value)]
@ -30,7 +28,7 @@
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) ;; (reset! nav-atom navigator)
[view {:style {:flex 1}} [view {:style {:flex 1}}
[view {:style {:flex 1 [view {:style {:flex 1
:backgroundColor "white"}} :backgroundColor "white"}}
@ -53,7 +51,7 @@
:fontFamily "Avenir-Roman" :fontFamily "Avenir-Roman"
:color "#9CBFC0"}} :color "#9CBFC0"}}
@user-phone-number] @user-phone-number]
[touchable-highlight {:onPress #(sign-up @user-phone-number @user-identity) [touchable-highlight {:onPress #(sign-up @user-phone-number @user-identity navigator)
:style {:alignSelf "center" :style {:alignSelf "center"
:borderRadius 7 :borderRadius 7
:backgroundColor "#E5F5F6" :backgroundColor "#E5F5F6"
@ -61,6 +59,5 @@
[text {:style {:marginVertical 10 [text {:style {:marginVertical 10
:textAlign "center"}} :textAlign "center"}}
"Sign up"]]]] "Sign up"]]]]
;; (when (or loading (not user-identity)) (when (or @loading (not @user-identity))
;; [spinner {:visible true}]) [spinner {:visible true}])])))
])))

View File

@ -0,0 +1,86 @@
(ns syng-im.components.sign-up-confirm
(:require-macros
[natal-shell.core :refer [with-error-view]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.components.react :refer [view text image touchable-highlight list-view
toolbar-android text-input]]
[syng-im.components.resources :as res]
[syng-im.components.spinner :refer [spinner]]
[syng-im.components.nav :as nav]
[syng-im.utils.utils :refer [log toast http-post]]))
(defn show-home-view [navigator]
(dispatch [:set-loading false])
(nav/nav-push navigator {:view-id :contact-list}))
(defn sync-contacts [navigator]
(dispatch [:sync-contacts #(show-home-view navigator)]))
(defn on-send-code-response [navigator body]
(log body)
(toast (if (:confirmed body)
"Confirmed"
"Wrong code"))
(if (:confirmed body)
;; TODO user action required
(sync-contacts navigator)
(dispatch [:set-loading false])))
(defn code-valid? [code]
(= 4 (count code)))
(defn send-code [code navigator]
(when (code-valid? code)
(dispatch [:set-loading true])
(dispatch [:sign-up-confirm code (partial on-send-code-response navigator)])))
(defn update-code [value]
(let [formatted value]
(dispatch [:set-confirmation-code formatted])))
(defn sign-up-confirm-view [{:keys [navigator]}]
(let [loading (subscribe [:get-loading])
confirmation-code (subscribe [:get-confirmation-code])]
(fn []
[view {:style {:flex 1}}
[view {:style {:flex 1
:backgroundColor "white"}}
[toolbar-android {:logo res/logo-icon
:title "Confirm"
:titleColor "#4A5258"
:style {:backgroundColor "white"
:height 56
:elevation 2}}]
[view {}
[text-input {:underlineColorAndroid "#9CBFC0"
:placeholder "Enter confirmation code"
:keyboardType "number-pad"
:maxLength 4
:onChangeText (fn [value]
(update-code value))
:style {:flex 1
:marginHorizontal 18
:lineHeight 42
:fontSize 14
:fontFamily "Avenir-Roman"
:color "#9CBFC0"}}
@confirmation-code]
(if (code-valid? @confirmation-code)
[touchable-highlight {:onPress #(send-code @confirmation-code navigator)
:style {:alignSelf "center"
:borderRadius 7
:backgroundColor "#E5F5F6"
:width 100}}
[text {:style {:marginVertical 10
:textAlign "center"}}
"Confirm"]]
[view {:style {:alignSelf "center"
:borderRadius 7
:backgroundColor "#AAB2B2"
:width 100}}
[text {:style {:marginVertical 10
:textAlign "center"}}
"Confirm"]])]]
(when @loading
[spinner {:visible true}])])))

View File

@ -12,6 +12,7 @@
[syng-im.models.messages :refer [save-message [syng-im.models.messages :refer [save-message
new-message-arrived]] new-message-arrived]]
[syng-im.handlers.server :as server] [syng-im.handlers.server :as server]
[syng-im.handlers.contacts :as contacts-service]
[syng-im.utils.logging :as log])) [syng-im.utils.logging :as log]))
;; -- Middleware ------------------------------------------------------------ ;; -- Middleware ------------------------------------------------------------
@ -76,6 +77,20 @@
(server/sign-up phone-number whisper-identity handler) (server/sign-up phone-number whisper-identity handler)
db)) db))
(register-handler :set-confirmation-code
(fn [db [_ value]]
(assoc db :confirmation-code value)))
(register-handler :sign-up-confirm
(fn [db [_ confirmation-code handler]]
(server/sign-up-confirm confirmation-code handler)
db))
(register-handler :sync-contacts
(fn [db [_ handler]]
(contacts-service/sync-contacts handler)
db))
;; -- Contacts -------------------------------------------------------------- ;; -- Contacts --------------------------------------------------------------
(register-handler :load-syng-contacts (register-handler :load-syng-contacts

View File

@ -0,0 +1,64 @@
(ns syng-im.handlers.contacts
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [clojure.string :as cstr]
[cljs.core.async :as async :refer [chan put! <!]]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.utils.utils :refer [log on-error http-post toast]]
[syng-im.utils.crypt :refer [encrypt]]
[syng-im.utils.phone-number :refer [format-phone-number]]
[syng-im.models.contacts :as contacts-model]
[syng-im.utils.logging :as log]))
(defn- get-contact-name [phone-contact]
(cstr/join " "
(filter #(not (cstr/blank? %))
[(:givenName phone-contact)
(:middleName phone-contact)
(:familyName phone-contact)])))
(defn- to-syng-contacts [contacts-by-hash data]
(map (fn [server-contact]
(let [number-info (get contacts-by-hash
(:phone-number-hash server-contact))
phone-contact (:contact number-info)]
{:phone-number (:number number-info)
:whisper-identity (:whisper-identity server-contact)
:name (get-contact-name phone-contact)
:photo-path (:photo-path phone-contact)}))
(js->clj (:contacts data))))
(defn- get-contacts-by-hash [contacts]
(let [numbers-info (reduce (fn [numbers contact]
(into numbers
(map (fn [c]
{:number (format-phone-number (:number c))
:contact contact})
(:phone-numbers contact))))
'()
contacts)]
(reduce (fn [m number-info]
(let [number (:number number-info)
hash (encrypt number)]
(assoc m hash number-info)))
{}
numbers-info)))
(defn- request-syng-contacts [contacts]
(let [contacts-by-hash (get-contacts-by-hash contacts)
data (keys contacts-by-hash)
ch (chan)]
(http-post "get-contacts" {:phone-number-hashes data}
(fn [data]
(put! ch
(to-syng-contacts contacts-by-hash data))))
ch))
(defn sync-contacts [handler]
(go
(let [result (<! (contacts-model/load-phone-contacts))]
(if-let [error (:error result)]
(on-error error)
(let [syng-contacts (<! (request-syng-contacts (:contacts result)))]
(contacts-model/save-syng-contacts syng-contacts)
(dispatch [:load-syng-contacts])
(handler))))))

View File

@ -8,14 +8,13 @@
[phone-number whisper-identity handler] [phone-number whisper-identity handler]
(user-data/save-phone-number phone-number) (user-data/save-phone-number phone-number)
(http-post "sign-up" {:phone-number phone-number (http-post "sign-up" {:phone-number phone-number
:whisper-identity whisper-identity} :whisper-identity (:public whisper-identity)}
(fn [body] (fn [body]
(log body) (log body)
(handler)))) (handler))))
(defn sign-up-confirm (defn sign-up-confirm
[state id {:keys [confirmation-code handler] :as args}] [confirmation-code handler]
(log/info "handling " id " args = " args)
(http-post "sign-up-confirm" (http-post "sign-up-confirm"
{:code confirmation-code} {:code confirmation-code}
handler)) handler))

View File

@ -4,7 +4,9 @@
[syng-im.utils.utils :refer [log toast]] [syng-im.utils.utils :refer [log toast]]
[syng-im.persistence.realm :as realm])) [syng-im.persistence.realm :as realm]))
(def fake-contacts? true) ;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45
(def fake-phone-contacts? true)
(def fake-contacts? false)
(def react-native-contacts (js/require "react-native-contacts")) (def react-native-contacts (js/require "react-native-contacts"))
@ -22,7 +24,7 @@
(defn load-phone-contacts [] (defn load-phone-contacts []
(let [ch (chan)] (let [ch (chan)]
(if fake-contacts? (if fake-phone-contacts?
(put! ch {:error nil, :contacts (generate-contacts 10)}) (put! ch {:error nil, :contacts (generate-contacts 10)})
(.getAll react-native-contacts (.getAll react-native-contacts
(fn [error raw-contacts] (fn [error raw-contacts]
@ -32,7 +34,6 @@
(when (not error) (when (not error)
(log raw-contacts) (log raw-contacts)
(map (fn [contact] (map (fn [contact]
;; (toast (str contact))
(merge contact (merge contact
(generate-contact 1) (generate-contact 1)
{:name (:givenName contact) {:name (:givenName contact)

View File

@ -19,7 +19,7 @@
:get-user-identity :get-user-identity
(fn [db _] (fn [db _]
(reaction (reaction
(get @db :identity)))) (get @db :user-identity))))
(register-sub (register-sub
:get-loading :get-loading
@ -27,6 +27,12 @@
(reaction (reaction
(get @db :loading)))) (get @db :loading))))
(register-sub
:get-confirmation-code
(fn [db _]
(reaction
(get @db :confirmation-code))))
(register-sub (register-sub
:get-contacts :get-contacts
(fn [db _] (fn [db _]