Login form
This commit is contained in:
parent
2d8119be64
commit
7fdb31b73e
|
@ -9,22 +9,25 @@
|
||||||
[syng-im.components.react :refer [navigator app-registry]]
|
[syng-im.components.react :refer [navigator app-registry]]
|
||||||
[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.chat.chat :refer [chat]]
|
||||||
|
[syng-im.components.nav :as nav]
|
||||||
[syng-im.utils.logging :as log]))
|
[syng-im.utils.logging :as log]))
|
||||||
|
|
||||||
(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."
|
||||||
true)
|
;; true)
|
||||||
|
|
||||||
(def back-button-handler (cljs/atom {:nav nil
|
(def back-button-handler (cljs/atom {:nav nil
|
||||||
:handler nil}))
|
:handler nil}))
|
||||||
|
|
||||||
|
|
||||||
(defn init-back-button-handler! [nav]
|
(defn init-back-button-handler! [nav]
|
||||||
(let [handler @back-button-handler]
|
(let [handler @back-button-handler]
|
||||||
(when-not (= nav (:nav handler))
|
(when-not (= nav (:nav handler))
|
||||||
(remove-event-listener "hardwareBackPress" (:handler handler))
|
(remove-event-listener "hardwareBackPress" (:handler handler))
|
||||||
(let [new-listener (fn []
|
(let [new-listener (fn []
|
||||||
(binding [*nav-render* false]
|
(binding [nav/*nav-render* false]
|
||||||
(when (< 1 (.-length (.getCurrentRoutes nav)))
|
(when (< 1 (.-length (.getCurrentRoutes nav)))
|
||||||
(.pop nav)
|
(.pop nav)
|
||||||
true)))]
|
true)))]
|
||||||
|
@ -33,20 +36,25 @@
|
||||||
(add-event-listener "hardwareBackPress" new-listener)))))
|
(add-event-listener "hardwareBackPress" new-listener)))))
|
||||||
|
|
||||||
(defn app-root []
|
(defn app-root []
|
||||||
[navigator {:initial-route (clj->js {:view-id :contact-list})
|
[navigator {:initial-route (clj->js {:view-id ;; :chat
|
||||||
|
;; :contact-list
|
||||||
|
:login
|
||||||
|
})
|
||||||
:render-scene (fn [route nav]
|
:render-scene (fn [route nav]
|
||||||
(log/debug "route" route)
|
(log/debug "route" route)
|
||||||
(when *nav-render*
|
(when 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)
|
||||||
(case view-id
|
(case view-id
|
||||||
: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}])))))}])
|
||||||
|
|
||||||
(defn init []
|
(defn init []
|
||||||
(dispatch-sync [:initialize-db])
|
(dispatch-sync [:initialize-db])
|
||||||
(dispatch [:initialize-protocol])
|
(dispatch [:initialize-protocol])
|
||||||
|
(dispatch [:load-user-phone-number])
|
||||||
(dispatch [:load-syng-contacts])
|
(dispatch [:load-syng-contacts])
|
||||||
(.registerComponent app-registry "SyngIm" #(r/reactify-component app-root)))
|
(.registerComponent app-registry "SyngIm" #(r/reactify-component app-root)))
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
(ns syng-im.components.chat.chat
|
||||||
|
(:require-macros
|
||||||
|
[natal-shell.data-source :refer [data-source clone-with-rows]])
|
||||||
|
(:require [reagent.core :as r]
|
||||||
|
[syng-im.components.nav :as nav]
|
||||||
|
[syng-im.components.react :refer [view list-view toolbar-android list-item]]
|
||||||
|
[syng-im.components.resources :as res]
|
||||||
|
[syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
||||||
|
|
||||||
|
;; [syng-im.components.chat.message :refer [message]]
|
||||||
|
;; [syng-im.components.chat.new-message :refer [new-message NewMessage]]
|
||||||
|
))
|
||||||
|
|
||||||
|
;(defn generate-message [n]
|
||||||
|
; {:id n
|
||||||
|
; :type (if (= (rem n 4) 3)
|
||||||
|
; :audio
|
||||||
|
; :text)
|
||||||
|
; :body (if (= (rem n 3) 0)
|
||||||
|
; (apply str n "." (repeat 5 " This is a text."))
|
||||||
|
; (str n ". This is a text."))
|
||||||
|
; :outgoing (< (rand) 0.5)
|
||||||
|
; :delivery-status (if (< (rand) 0.5) :delivered :seen)
|
||||||
|
; :date "TODAY"
|
||||||
|
; :new-day (= (rem n 3) 0)})
|
||||||
|
;
|
||||||
|
;(defn generate-messages [n]
|
||||||
|
; (map generate-message (range 1 (inc n))))
|
||||||
|
|
||||||
|
;(defn load-messages []
|
||||||
|
; (clone-with-rows (data-source {:rowHasChanged (fn [row1 row2]
|
||||||
|
; (not= row1 row2))})
|
||||||
|
; (vec (generate-messages 100))))
|
||||||
|
;
|
||||||
|
|
||||||
|
;;temp
|
||||||
|
;; (swap! state/app-state assoc :abc "xyz")
|
||||||
|
|
||||||
|
(defn to-datasource [msgs]
|
||||||
|
(-> (data-source {:rowHasChanged (fn [row1 row2]
|
||||||
|
(not= row1 row2))})
|
||||||
|
(clone-with-rows msgs)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn render-row [row section-id row-id]
|
||||||
|
(list-item [message-view {} (js->clj row :keywordize-keys true)]))
|
||||||
|
|
||||||
|
(defn chat [{:keys [navigator]}]
|
||||||
|
(let [greeting (subscribe [:get-greeting])
|
||||||
|
chat-id 1
|
||||||
|
;; messages (subscribe [:get-messages chat-id])
|
||||||
|
]
|
||||||
|
(fn []
|
||||||
|
(let [messages-ds (when messages
|
||||||
|
(to-datasource messages))]
|
||||||
|
[view {:style {:flex 1
|
||||||
|
:backgroundColor "white"}}
|
||||||
|
[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/nav-pop nav))}]
|
||||||
|
;; temp commented
|
||||||
|
;; (when messages-ds
|
||||||
|
;; [list-view {:dataSource messages-ds
|
||||||
|
;; :renderScrollComponent
|
||||||
|
;; (fn [props]
|
||||||
|
;; (r/as-element [invertible-scroll-view {:inverted true}]))
|
||||||
|
;; :renderRow render-row
|
||||||
|
;; :style {:backgroundColor "white"}}])
|
||||||
|
;; (new-message {:chat-id chat-id})
|
||||||
|
]))))
|
|
@ -0,0 +1,99 @@
|
||||||
|
(ns syng-im.components.chat.message
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.components.react :refer [view text image]]
|
||||||
|
[syng-im.components.resources :as res]
|
||||||
|
[syng-im.constants :refer [text-content-type]]))
|
||||||
|
|
||||||
|
(defn message-view []
|
||||||
|
(let [greeting (subscribe [:get-greeting])]
|
||||||
|
(fn []
|
||||||
|
(let [msg-id "1"
|
||||||
|
content "1"
|
||||||
|
content-type "1"
|
||||||
|
outgoing true
|
||||||
|
delivery-status :seen
|
||||||
|
date "1"
|
||||||
|
new-day true]
|
||||||
|
[view {:paddingHorizontal 15}
|
||||||
|
(when new-day
|
||||||
|
[text {:style {:marginVertical 10
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:fontSize 11
|
||||||
|
:color "#AAB2B2"
|
||||||
|
:letterSpacing 1
|
||||||
|
:lineHeight 15
|
||||||
|
:textAlign "center"
|
||||||
|
:opacity 0.8}}
|
||||||
|
date])
|
||||||
|
[view {:style (merge {:flexDirection "column"
|
||||||
|
:width 260
|
||||||
|
:marginVertical 5}
|
||||||
|
(if outgoing
|
||||||
|
{:alignSelf "flex-end"
|
||||||
|
:alignItems "flex-end"}
|
||||||
|
{:alignSelf "flex-start"
|
||||||
|
:alignItems "flex-start"}))}
|
||||||
|
[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]
|
||||||
|
[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"]]])]
|
||||||
|
(when (and outgoing delivery-status)
|
||||||
|
[view {:style {:flexDirection "row"
|
||||||
|
:marginTop 2}}
|
||||||
|
[image {:source (if (= (keyword delivery-status) :seen)
|
||||||
|
res/seen-icon
|
||||||
|
res/delivered-icon)
|
||||||
|
:style {:marginTop 6
|
||||||
|
:opacity 0.6}}]
|
||||||
|
[text {:style {:fontFamily "Avenir-Roman"
|
||||||
|
:fontSize 11
|
||||||
|
:color "#AAB2B2"
|
||||||
|
:opacity 0.8
|
||||||
|
:marginLeft 5}}
|
||||||
|
(if (= (keyword delivery-status) :seen)
|
||||||
|
"Seen"
|
||||||
|
"Delivered")]])]]))))
|
|
@ -0,0 +1,53 @@
|
||||||
|
(ns syng-im.components.chat.new-message
|
||||||
|
;; (:require [syng-im.components.react :refer [view text image text-input]]
|
||||||
|
;; [syng-im.components.resources :as res]
|
||||||
|
;; [syng-im.constants :refer [text-content-type]])
|
||||||
|
)
|
||||||
|
|
||||||
|
;; (defui NewMessage
|
||||||
|
;; static om/IQuery
|
||||||
|
;; (query [this]
|
||||||
|
;; '[:chat/chat-id])
|
||||||
|
;; Object
|
||||||
|
;; (render [this]
|
||||||
|
;; (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 (from-state this :text)
|
||||||
|
;; :onChangeText (fn [text]
|
||||||
|
;; ;(log/debug (with-out-str (pr (js->clj (om/props this)))) (-> (om/props this) :chat-id))
|
||||||
|
;; ;(om/set-state! this (clj->js {:text text}))
|
||||||
|
;; (swap! local-state assoc :text text)
|
||||||
|
;; )
|
||||||
|
;; :onSubmitEditing (fn [e]
|
||||||
|
;; (let [chat-id (-> (om/props this) :chat-id)
|
||||||
|
;; ;text (from-state this :text)
|
||||||
|
;; text (get @local-state :text)]
|
||||||
|
;; ;(om/set-state! this (clj->js {:text nil}))
|
||||||
|
;; (send-msg chat-id text)))})
|
||||||
|
;; (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,17 +1,16 @@
|
||||||
(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]
|
||||||
;; [messenger.comm.intercom :as intercom :refer [show-chat]]
|
[syng-im.components.nav :as nav]))
|
||||||
;; [messenger.components.chat.chat :refer [chat]]
|
|
||||||
))
|
|
||||||
|
|
||||||
(defn contact-view [contact]
|
(defn show-chat [navigator whisper-identity]
|
||||||
|
(nav/nav-push navigator {:view-id :chat}))
|
||||||
|
|
||||||
|
(defn contact-view [{:keys [navigator contact]}]
|
||||||
(let [{:keys [name photo-path delivery-status datetime new-messages-count
|
(let [{:keys [name photo-path delivery-status datetime new-messages-count
|
||||||
online whisper-identity]} contact]
|
online whisper-identity]} contact]
|
||||||
[touchable-highlight {:onPress (fn []
|
[touchable-highlight {:onPress (fn []
|
||||||
;; TODO
|
(show-chat navigator whisper-identity))}
|
||||||
;; (show-chat nav whisper-identity)
|
|
||||||
)}
|
|
||||||
[view {:style {:flexDirection "row"
|
[view {:style {:flexDirection "row"
|
||||||
:marginTop 5
|
:marginTop 5
|
||||||
:marginBottom 5
|
:marginBottom 5
|
||||||
|
|
|
@ -14,83 +14,28 @@
|
||||||
;; [messenger.components.iname :as in]
|
;; [messenger.components.iname :as in]
|
||||||
))
|
))
|
||||||
|
|
||||||
(defn render-row [row section-id row-id]
|
(defn render-row [navigator row section-id row-id]
|
||||||
(list-item (contact-view (js->clj row :keywordize-keys true))))
|
(list-item [contact-view {:navigator navigator
|
||||||
|
:contact (js->clj row :keywordize-keys true)}]))
|
||||||
;; (defn load-contacts []
|
|
||||||
;; (intercom/load-syng-contacts))
|
|
||||||
|
|
||||||
;; (defui ContactList
|
|
||||||
;; static in/IName
|
|
||||||
;; (get-name [this]
|
|
||||||
;; :contacts/contacts)
|
|
||||||
;; static om/IQuery
|
|
||||||
;; (query [this]
|
|
||||||
;; '[:contacts-ds])
|
|
||||||
;; Object
|
|
||||||
;; (componentDidMount [this]
|
|
||||||
;; (load-contacts))
|
|
||||||
;; (render [this]
|
|
||||||
;; (let [{{contacts-ds :contacts-ds} :contacts/contacts} (om/props this)
|
|
||||||
;; {:keys [nav]} (om/get-computed this)]
|
|
||||||
;; (view {:style {:flex 1
|
|
||||||
;; :backgroundColor "white"}}
|
|
||||||
;; (toolbar-android {:logo res/logo-icon
|
|
||||||
;; :title "Chats"
|
|
||||||
;; :titleColor "#4A5258"
|
|
||||||
;; :style {:backgroundColor "white"
|
|
||||||
;; :height 56
|
|
||||||
;; :elevation 2}})
|
|
||||||
;; (when contacts-ds
|
|
||||||
;; (list-view {:dataSource contacts-ds
|
|
||||||
;; :renderRow (partial render-row nav)
|
|
||||||
;; :style {:backgroundColor "white"}}))))))
|
|
||||||
|
|
||||||
;; (def contact-list (om/factory ContactList))
|
|
||||||
|
|
||||||
(defn get-data-source [contacts]
|
(defn get-data-source [contacts]
|
||||||
(clone-with-rows (data-source {:rowHasChanged (fn [row1 row2]
|
(clone-with-rows (data-source {:rowHasChanged (fn [row1 row2]
|
||||||
(not= row1 row2))})
|
(not= row1 row2))})
|
||||||
contacts))
|
contacts))
|
||||||
|
|
||||||
(defn contacts-list-re-frame [contacts]
|
|
||||||
(let [contacts-ds (get-data-source contacts)]
|
|
||||||
[view {:style {:flex 1
|
|
||||||
:backgroundColor "white"}}
|
|
||||||
[toolbar-android {:logo res/logo-icon
|
|
||||||
:title "Chats"
|
|
||||||
:titleColor "#4A5258"
|
|
||||||
:style {:backgroundColor "white"
|
|
||||||
:height 56
|
|
||||||
:elevation 2}}]
|
|
||||||
(when contacts-ds
|
|
||||||
[list-view {:dataSource contacts-ds
|
|
||||||
:renderRow render-row
|
|
||||||
:style {:backgroundColor "white"}}]
|
|
||||||
)
|
|
||||||
]))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(def logo-img (js/require "./images/cljs.png"))
|
|
||||||
|
|
||||||
|
|
||||||
(defn alert [title]
|
|
||||||
(.alert (.-Alert js/React) title))
|
|
||||||
|
|
||||||
(defn contact-list [{:keys [navigator]}]
|
(defn contact-list [{:keys [navigator]}]
|
||||||
(let [greeting (subscribe [:get-greeting])
|
(let [contacts (subscribe [:get-contacts])]
|
||||||
contacts (subscribe [:get-contacts])]
|
|
||||||
(fn []
|
(fn []
|
||||||
(contacts-list-re-frame @contacts)
|
(let [contacts-ds (get-data-source @contacts)]
|
||||||
|
[view {:style {:flex 1
|
||||||
;; [view {:style {:flex-direction "column" :margin 40 :align-items "center"}}
|
:backgroundColor "white"}}
|
||||||
;; [text {:style {:font-size 30 :font-weight "100" :margin-bottom 20 :text-align "center"}} (str @greeting " " (count @contacts))]
|
[toolbar-android {:logo res/logo-icon
|
||||||
;; [image {:source logo-img
|
:title "Chats"
|
||||||
;; :style {:width 80 :height 80 :margin-bottom 30}}]
|
:titleColor "#4A5258"
|
||||||
;; [touchable-highlight {:style {:background-color "#999" :padding 10 :border-radius 5}
|
:style {:backgroundColor "white"
|
||||||
;; :on-press #(alert "HELLO!")}
|
:height 56
|
||||||
;; [text {:style {:color "white" :text-align "center" :font-weight "bold"}} "press me"]]]
|
:elevation 2}}]
|
||||||
)))
|
(when contacts-ds
|
||||||
|
[list-view {:dataSource contacts-ds
|
||||||
|
:renderRow (partial render-row navigator)
|
||||||
|
:style {:backgroundColor "white"}}])]))))
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
(ns syng-im.components.invertible-scroll-view
|
||||||
|
(:require [reagent.core :as r]))
|
||||||
|
|
||||||
|
(set! js/InvertibleScrollView (js/require "react-native-invertible-scroll-view"))
|
||||||
|
|
||||||
|
(def invertible-scroll-view (r/adapt-react-class js/Spinner))
|
||||||
|
;; (defn invertible-scroll-view [props]
|
||||||
|
;; (js/React.createElement js/InvertibleScrollView
|
||||||
|
;; (clj->js (merge {:inverted true} props))))
|
|
@ -0,0 +1,66 @@
|
||||||
|
(ns syng-im.components.login
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.components.react :refer [view text image touchable-highlight
|
||||||
|
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]]
|
||||||
|
[syng-im.utils.phone-number :refer [format-phone-number]]
|
||||||
|
;; [messenger.android.sign-up-confirm :refer [sign-up-confirm]]
|
||||||
|
))
|
||||||
|
|
||||||
|
(def nav-atom (atom nil))
|
||||||
|
|
||||||
|
(defn show-confirm-view []
|
||||||
|
(dispatch [:set-loading false])
|
||||||
|
;; TODO 'nav-replace
|
||||||
|
(nav/nav-push @nav-atom {:view-id :chat}))
|
||||||
|
|
||||||
|
(defn sign-up [user-phone-number user-identity]
|
||||||
|
(dispatch [:set-loading true])
|
||||||
|
(dispatch [:sign-up user-phone-number user-identity show-confirm-view]))
|
||||||
|
|
||||||
|
(defn update-phone-number [value]
|
||||||
|
(let [formatted (format-phone-number value)]
|
||||||
|
(dispatch [:set-user-phone-number formatted])))
|
||||||
|
|
||||||
|
(defn login-view [{:keys [navigator]}]
|
||||||
|
(let [loading (subscribe [:get-loading])
|
||||||
|
user-phone-number (subscribe [:get-user-phone-number])
|
||||||
|
user-identity (subscribe [:get-user-identity])]
|
||||||
|
(fn []
|
||||||
|
(reset! nav-atom navigator)
|
||||||
|
[view {:style {:flex 1}}
|
||||||
|
[view {:style {:flex 1
|
||||||
|
:backgroundColor "white"}}
|
||||||
|
[toolbar-android {:logo res/logo-icon
|
||||||
|
:title "Login"
|
||||||
|
:titleColor "#4A5258"
|
||||||
|
:style {:backgroundColor "white"
|
||||||
|
:height 56
|
||||||
|
:elevation 2}}]
|
||||||
|
[view {}
|
||||||
|
[text-input {:underlineColorAndroid "#9CBFC0"
|
||||||
|
:placeholder "Enter your phone number"
|
||||||
|
:keyboardType "phone-pad"
|
||||||
|
:onChangeText (fn [value]
|
||||||
|
(update-phone-number value))
|
||||||
|
:style {:flex 1
|
||||||
|
:marginHorizontal 18
|
||||||
|
:lineHeight 42
|
||||||
|
:fontSize 14
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:color "#9CBFC0"}}
|
||||||
|
@user-phone-number]
|
||||||
|
[touchable-highlight {:onPress #(sign-up @user-phone-number @user-identity)
|
||||||
|
:style {:alignSelf "center"
|
||||||
|
:borderRadius 7
|
||||||
|
:backgroundColor "#E5F5F6"
|
||||||
|
:width 100}}
|
||||||
|
[text {:style {:marginVertical 10
|
||||||
|
:textAlign "center"}}
|
||||||
|
"Sign up"]]]]
|
||||||
|
;; (when (or loading (not user-identity))
|
||||||
|
;; [spinner {:visible true}])
|
||||||
|
])))
|
|
@ -0,0 +1,17 @@
|
||||||
|
(ns syng-im.components.nav)
|
||||||
|
|
||||||
|
(def ^{:dynamic true :private true} *nav-render*
|
||||||
|
"Flag to suppress navigator re-renders from outside om when pushing/popping."
|
||||||
|
true)
|
||||||
|
|
||||||
|
(defn nav-push [nav route]
|
||||||
|
(binding [*nav-render* false]
|
||||||
|
(.push nav (clj->js route))))
|
||||||
|
|
||||||
|
(defn nav-replace [nav route]
|
||||||
|
(binding [*nav-render* false]
|
||||||
|
(.replace nav (clj->js route))))
|
||||||
|
|
||||||
|
(defn nav-pop [nav]
|
||||||
|
(binding [*nav-render* false]
|
||||||
|
(.pop nav)))
|
|
@ -11,6 +11,7 @@
|
||||||
(def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React)))
|
(def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React)))
|
||||||
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
|
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
|
||||||
(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)))
|
||||||
|
|
||||||
(defn list-item [component]
|
(defn list-item [component]
|
||||||
(r/as-element component))
|
(r/as-element component))
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
(ns syng-im.components.spinner
|
||||||
|
(:require [reagent.core :as r]))
|
||||||
|
|
||||||
|
(set! js/Spinner (.-default (js/require "react-native-loading-spinner-overlay")))
|
||||||
|
|
||||||
|
(def spinner (r/adapt-react-class js/Spinner))
|
||||||
|
;; (defn spinner [props]
|
||||||
|
;; (js/React.createElement js/Spinner
|
||||||
|
;; (clj->js props)))
|
|
@ -2,4 +2,7 @@
|
||||||
|
|
||||||
(def ethereum-rpc-url "http://localhost:8545")
|
(def ethereum-rpc-url "http://localhost:8545")
|
||||||
|
|
||||||
|
;; (def server-address "http://rpc0.syng.im:20000/")
|
||||||
|
(def server-address "http://10.0.3.2:3000/")
|
||||||
|
|
||||||
(def text-content-type "text/plain")
|
(def text-content-type "text/plain")
|
|
@ -7,9 +7,11 @@
|
||||||
[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.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]]
|
new-message-arrived]]
|
||||||
|
[syng-im.handlers.server :as server]
|
||||||
[syng-im.utils.logging :as log]))
|
[syng-im.utils.logging :as log]))
|
||||||
|
|
||||||
;; -- Middleware ------------------------------------------------------------
|
;; -- Middleware ------------------------------------------------------------
|
||||||
|
@ -31,6 +33,12 @@
|
||||||
(fn [_ _]
|
(fn [_ _]
|
||||||
app-db))
|
app-db))
|
||||||
|
|
||||||
|
;; -- Common --------------------------------------------------------------
|
||||||
|
|
||||||
|
(register-handler :set-loading
|
||||||
|
(fn [db [_ value]]
|
||||||
|
(assoc db :loading value)))
|
||||||
|
|
||||||
;; -- Protocol --------------------------------------------------------------
|
;; -- Protocol --------------------------------------------------------------
|
||||||
|
|
||||||
(register-handler :initialize-protocol
|
(register-handler :initialize-protocol
|
||||||
|
@ -50,6 +58,24 @@
|
||||||
(save-message chat-id msg)
|
(save-message chat-id msg)
|
||||||
(new-message-arrived db chat-id msg-id)))
|
(new-message-arrived db chat-id msg-id)))
|
||||||
|
|
||||||
|
;; -- User data --------------------------------------------------------------
|
||||||
|
|
||||||
|
(register-handler :set-user-phone-number
|
||||||
|
(fn [db [_ value]]
|
||||||
|
(assoc db :user-phone-number value)))
|
||||||
|
|
||||||
|
(register-handler :load-user-phone-number
|
||||||
|
(fn [db [_]]
|
||||||
|
(user-data/load-phone-number)
|
||||||
|
db))
|
||||||
|
|
||||||
|
;; -- Sign up --------------------------------------------------------------
|
||||||
|
|
||||||
|
(register-handler :sign-up
|
||||||
|
(fn [db [_ phone-number whisper-identity handler]]
|
||||||
|
(server/sign-up phone-number whisper-identity handler)
|
||||||
|
db))
|
||||||
|
|
||||||
;; -- Contacts --------------------------------------------------------------
|
;; -- Contacts --------------------------------------------------------------
|
||||||
|
|
||||||
(register-handler :load-syng-contacts
|
(register-handler :load-syng-contacts
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
(ns syng-im.handlers.server
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.models.user-data :as user-data]
|
||||||
|
[syng-im.utils.utils :refer [log on-error http-post]]
|
||||||
|
[syng-im.utils.logging :as log]))
|
||||||
|
|
||||||
|
(defn sign-up
|
||||||
|
[phone-number whisper-identity handler]
|
||||||
|
(user-data/save-phone-number phone-number)
|
||||||
|
(http-post "sign-up" {:phone-number phone-number
|
||||||
|
:whisper-identity whisper-identity}
|
||||||
|
(fn [body]
|
||||||
|
(log body)
|
||||||
|
(handler))))
|
||||||
|
|
||||||
|
(defn sign-up-confirm
|
||||||
|
[state id {:keys [confirmation-code handler] :as args}]
|
||||||
|
(log/info "handling " id " args = " args)
|
||||||
|
(http-post "sign-up-confirm"
|
||||||
|
{:code confirmation-code}
|
||||||
|
handler))
|
|
@ -0,0 +1,17 @@
|
||||||
|
(ns syng-im.models.user-data
|
||||||
|
(:require-macros
|
||||||
|
[natal-shell.async-storage :refer [get-item set-item]])
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.utils.utils :refer [log on-error toast]]))
|
||||||
|
|
||||||
|
(defn save-phone-number [phone-number]
|
||||||
|
(set-item "user-phone-number" phone-number)
|
||||||
|
(dispatch [:set-user-phone-number phone-number]))
|
||||||
|
|
||||||
|
(defn load-phone-number []
|
||||||
|
(get-item "user-phone-number"
|
||||||
|
(fn [error value]
|
||||||
|
(if error
|
||||||
|
(on-error error)
|
||||||
|
(dispatch [:set-user-phone-number (when value
|
||||||
|
(str value))])))))
|
|
@ -8,6 +8,25 @@
|
||||||
(reaction
|
(reaction
|
||||||
(get @db :greeting))))
|
(get @db :greeting))))
|
||||||
|
|
||||||
|
;; -- User data --------------------------------------------------------------
|
||||||
|
(register-sub
|
||||||
|
:get-user-phone-number
|
||||||
|
(fn [db _]
|
||||||
|
(reaction
|
||||||
|
(get @db :user-phone-number))))
|
||||||
|
|
||||||
|
(register-sub
|
||||||
|
:get-user-identity
|
||||||
|
(fn [db _]
|
||||||
|
(reaction
|
||||||
|
(get @db :identity))))
|
||||||
|
|
||||||
|
(register-sub
|
||||||
|
:get-loading
|
||||||
|
(fn [db _]
|
||||||
|
(reaction
|
||||||
|
(get @db :loading))))
|
||||||
|
|
||||||
(register-sub
|
(register-sub
|
||||||
:get-contacts
|
:get-contacts
|
||||||
(fn [db _]
|
(fn [db _]
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
(ns syng-im.utils.crypt
|
||||||
|
(:require [goog.crypt :refer [byteArrayToHex]])
|
||||||
|
(:import goog.crypt.Sha256))
|
||||||
|
|
||||||
|
(def sha-256 (Sha256.))
|
||||||
|
|
||||||
|
(defn bytes-to-str [arr]
|
||||||
|
(apply str (map char arr)))
|
||||||
|
|
||||||
|
(defn str-to-bytes [s]
|
||||||
|
(map (comp int) s))
|
||||||
|
|
||||||
|
(defn encrypt [s]
|
||||||
|
(.reset sha-256)
|
||||||
|
(.update sha-256 s)
|
||||||
|
(-> (.digest sha-256)
|
||||||
|
byteArrayToHex))
|
|
@ -0,0 +1,9 @@
|
||||||
|
(ns syng-im.utils.phone-number)
|
||||||
|
|
||||||
|
(def i18n (js/require "react-native-i18n"))
|
||||||
|
(def locale (.-locale i18n))
|
||||||
|
(def country-code (subs locale 3 5))
|
||||||
|
(set! js/PhoneNumber (js/require "awesome-phonenumber"))
|
||||||
|
|
||||||
|
(defn format-phone-number [number]
|
||||||
|
(str (.getNumber (js/PhoneNumber. number country-code "international"))))
|
|
@ -2,10 +2,8 @@
|
||||||
(:require-macros
|
(:require-macros
|
||||||
[natal-shell.async-storage :refer [get-item set-item]]
|
[natal-shell.async-storage :refer [get-item set-item]]
|
||||||
[natal-shell.alert :refer [alert]]
|
[natal-shell.alert :refer [alert]]
|
||||||
[natal-shell.toast-android :as toast]))
|
[natal-shell.toast-android :as toast])
|
||||||
|
(:require [syng-im.constants :as const]))
|
||||||
;; (def server-address "http://rpc0.syng.im:20000/")
|
|
||||||
(def server-address "http://10.0.3.2:3000/")
|
|
||||||
|
|
||||||
(defn log [obj]
|
(defn log [obj]
|
||||||
(.log js/console obj))
|
(.log js/console obj))
|
||||||
|
@ -21,7 +19,7 @@
|
||||||
(http-post action data on-success nil))
|
(http-post action data on-success nil))
|
||||||
([action data on-success on-error]
|
([action data on-success on-error]
|
||||||
(-> (.fetch js/window
|
(-> (.fetch js/window
|
||||||
(str server-address action)
|
(str const/server-address action)
|
||||||
(clj->js {:method "POST"
|
(clj->js {:method "POST"
|
||||||
:headers {:accept "application/json"
|
:headers {:accept "application/json"
|
||||||
:content-type "application/json"}
|
:content-type "application/json"}
|
||||||
|
|
Loading…
Reference in New Issue