From 7fdb31b73e01a75dfca00fa1b4d7d778e49954ca Mon Sep 17 00:00:00 2001 From: virvar Date: Mon, 28 Mar 2016 15:14:57 +0300 Subject: [PATCH] Login form --- syng-im/src/syng_im/android/core.cljs | 24 +++-- syng-im/src/syng_im/components/chat/chat.cljs | 79 +++++++++++++++ .../src/syng_im/components/chat/message.cljs | 99 +++++++++++++++++++ .../syng_im/components/chat/new_message.cljs | 53 ++++++++++ .../components/contact_list/contact.cljs | 13 ++- .../components/contact_list/contact_list.cljs | 89 ++++------------- .../components/invertible-scroll-view.cljs | 9 ++ syng-im/src/syng_im/components/login.cljs | 66 +++++++++++++ syng-im/src/syng_im/components/nav.cljs | 17 ++++ syng-im/src/syng_im/components/react.cljs | 1 + syng-im/src/syng_im/components/spinner.cljs | 9 ++ syng-im/src/syng_im/constants.cljs | 5 +- syng-im/src/syng_im/handlers.cljs | 26 +++++ syng-im/src/syng_im/handlers/server.cljs | 21 ++++ syng-im/src/syng_im/models/user_data.cljs | 17 ++++ syng-im/src/syng_im/subs.cljs | 19 ++++ syng-im/src/syng_im/utils/crypt.cljs | 17 ++++ syng-im/src/syng_im/utils/phone_number.cljs | 9 ++ syng-im/src/syng_im/utils/utils.cljs | 8 +- 19 files changed, 488 insertions(+), 93 deletions(-) create mode 100644 syng-im/src/syng_im/components/chat/chat.cljs create mode 100644 syng-im/src/syng_im/components/chat/message.cljs create mode 100644 syng-im/src/syng_im/components/chat/new_message.cljs create mode 100644 syng-im/src/syng_im/components/invertible-scroll-view.cljs create mode 100644 syng-im/src/syng_im/components/login.cljs create mode 100644 syng-im/src/syng_im/components/nav.cljs create mode 100644 syng-im/src/syng_im/components/spinner.cljs create mode 100644 syng-im/src/syng_im/handlers/server.cljs create mode 100644 syng-im/src/syng_im/models/user_data.cljs create mode 100644 syng-im/src/syng_im/utils/crypt.cljs create mode 100644 syng-im/src/syng_im/utils/phone_number.cljs diff --git a/syng-im/src/syng_im/android/core.cljs b/syng-im/src/syng_im/android/core.cljs index 3ed4575960..4920ef7775 100644 --- a/syng-im/src/syng_im/android/core.cljs +++ b/syng-im/src/syng_im/android/core.cljs @@ -9,22 +9,25 @@ [syng-im.components.react :refer [navigator app-registry]] [syng-im.components.contact-list.contact-list :refer [contact-list]] [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])) -(def ^{:dynamic true :private true} *nav-render* - "Flag to suppress navigator re-renders from outside om when pushing/popping." - true) +;; (def ^{:dynamic true :private true} *nav-render* +;; "Flag to suppress navigator re-renders from outside om when pushing/popping." +;; true) (def back-button-handler (cljs/atom {:nav nil :handler nil})) - (defn init-back-button-handler! [nav] (let [handler @back-button-handler] (when-not (= nav (:nav handler)) (remove-event-listener "hardwareBackPress" (:handler handler)) (let [new-listener (fn [] - (binding [*nav-render* false] + (binding [nav/*nav-render* false] (when (< 1 (.-length (.getCurrentRoutes nav))) (.pop nav) true)))] @@ -33,20 +36,25 @@ (add-event-listener "hardwareBackPress" new-listener))))) (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] (log/debug "route" route) - (when *nav-render* + (when nav/*nav-render* (let [{:keys [view-id]} (js->clj route :keywordize-keys true) view-id (keyword view-id)] (init-back-button-handler! nav) (case view-id :contact-list (r/as-element [contact-list {: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 [] (dispatch-sync [:initialize-db]) (dispatch [:initialize-protocol]) + (dispatch [:load-user-phone-number]) (dispatch [:load-syng-contacts]) (.registerComponent app-registry "SyngIm" #(r/reactify-component app-root))) diff --git a/syng-im/src/syng_im/components/chat/chat.cljs b/syng-im/src/syng_im/components/chat/chat.cljs new file mode 100644 index 0000000000..d893dd9edb --- /dev/null +++ b/syng-im/src/syng_im/components/chat/chat.cljs @@ -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}) + ])))) diff --git a/syng-im/src/syng_im/components/chat/message.cljs b/syng-im/src/syng_im/components/chat/message.cljs new file mode 100644 index 0000000000..7e1b3fb7dd --- /dev/null +++ b/syng-im/src/syng_im/components/chat/message.cljs @@ -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")]])]])))) diff --git a/syng-im/src/syng_im/components/chat/new_message.cljs b/syng-im/src/syng_im/components/chat/new_message.cljs new file mode 100644 index 0000000000..46c042031f --- /dev/null +++ b/syng-im/src/syng_im/components/chat/new_message.cljs @@ -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}})))) diff --git a/syng-im/src/syng_im/components/contact_list/contact.cljs b/syng-im/src/syng_im/components/contact_list/contact.cljs index 7bd7879948..4fdbc52b87 100644 --- a/syng-im/src/syng_im/components/contact_list/contact.cljs +++ b/syng-im/src/syng_im/components/contact_list/contact.cljs @@ -1,17 +1,16 @@ (ns syng-im.components.contact-list.contact (:require [syng-im.components.react :refer [view text image touchable-highlight]] [syng-im.components.resources :as res] - ;; [messenger.comm.intercom :as intercom :refer [show-chat]] - ;; [messenger.components.chat.chat :refer [chat]] - )) + [syng-im.components.nav :as nav])) -(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 online whisper-identity]} contact] [touchable-highlight {:onPress (fn [] - ;; TODO - ;; (show-chat nav whisper-identity) - )} + (show-chat navigator whisper-identity))} [view {:style {:flexDirection "row" :marginTop 5 :marginBottom 5 diff --git a/syng-im/src/syng_im/components/contact_list/contact_list.cljs b/syng-im/src/syng_im/components/contact_list/contact_list.cljs index 31f4f6ecf3..b355b0f46c 100644 --- a/syng-im/src/syng_im/components/contact_list/contact_list.cljs +++ b/syng-im/src/syng_im/components/contact_list/contact_list.cljs @@ -14,83 +14,28 @@ ;; [messenger.components.iname :as in] )) -(defn render-row [row section-id row-id] - (list-item (contact-view (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 render-row [navigator row section-id row-id] + (list-item [contact-view {:navigator navigator + :contact (js->clj row :keywordize-keys true)}])) (defn get-data-source [contacts] (clone-with-rows (data-source {:rowHasChanged (fn [row1 row2] (not= row1 row2))}) 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]}] - (let [greeting (subscribe [:get-greeting]) - contacts (subscribe [:get-contacts])] + (let [contacts (subscribe [:get-contacts])] (fn [] - (contacts-list-re-frame @contacts) - - ;; [view {:style {:flex-direction "column" :margin 40 :align-items "center"}} - ;; [text {:style {:font-size 30 :font-weight "100" :margin-bottom 20 :text-align "center"}} (str @greeting " " (count @contacts))] - ;; [image {:source logo-img - ;; :style {:width 80 :height 80 :margin-bottom 30}}] - ;; [touchable-highlight {:style {:background-color "#999" :padding 10 :border-radius 5} - ;; :on-press #(alert "HELLO!")} - ;; [text {:style {:color "white" :text-align "center" :font-weight "bold"}} "press me"]]] - ))) + (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 (partial render-row navigator) + :style {:backgroundColor "white"}}])])))) diff --git a/syng-im/src/syng_im/components/invertible-scroll-view.cljs b/syng-im/src/syng_im/components/invertible-scroll-view.cljs new file mode 100644 index 0000000000..89065cd72e --- /dev/null +++ b/syng-im/src/syng_im/components/invertible-scroll-view.cljs @@ -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)))) diff --git a/syng-im/src/syng_im/components/login.cljs b/syng-im/src/syng_im/components/login.cljs new file mode 100644 index 0000000000..69f1d7d42c --- /dev/null +++ b/syng-im/src/syng_im/components/login.cljs @@ -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}]) + ]))) diff --git a/syng-im/src/syng_im/components/nav.cljs b/syng-im/src/syng_im/components/nav.cljs new file mode 100644 index 0000000000..6440e79de5 --- /dev/null +++ b/syng-im/src/syng_im/components/nav.cljs @@ -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))) diff --git a/syng-im/src/syng_im/components/react.cljs b/syng-im/src/syng_im/components/react.cljs index 18ea53dd47..fca29f0d51 100644 --- a/syng-im/src/syng_im/components/react.cljs +++ b/syng-im/src/syng_im/components/react.cljs @@ -11,6 +11,7 @@ (def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React))) (def toolbar-android (r/adapt-react-class (.-ToolbarAndroid 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] (r/as-element component)) diff --git a/syng-im/src/syng_im/components/spinner.cljs b/syng-im/src/syng_im/components/spinner.cljs new file mode 100644 index 0000000000..7202074a81 --- /dev/null +++ b/syng-im/src/syng_im/components/spinner.cljs @@ -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))) diff --git a/syng-im/src/syng_im/constants.cljs b/syng-im/src/syng_im/constants.cljs index d7d0c881cd..c322156e43 100644 --- a/syng-im/src/syng_im/constants.cljs +++ b/syng-im/src/syng_im/constants.cljs @@ -2,4 +2,7 @@ (def ethereum-rpc-url "http://localhost:8545") -(def text-content-type "text/plain") \ No newline at end of file +;; (def server-address "http://rpc0.syng.im:20000/") +(def server-address "http://10.0.3.2:3000/") + +(def text-content-type "text/plain") diff --git a/syng-im/src/syng_im/handlers.cljs b/syng-im/src/syng_im/handlers.cljs index 24c4ff176e..d5f7882f30 100644 --- a/syng-im/src/syng_im/handlers.cljs +++ b/syng-im/src/syng_im/handlers.cljs @@ -7,9 +7,11 @@ [syng-im.protocol.protocol-handler :refer [make-handler]] [syng-im.models.protocol :refer [update-identity set-initialized]] + [syng-im.models.user-data :as user-data] [syng-im.models.contacts :as contacts] [syng-im.models.messages :refer [save-message new-message-arrived]] + [syng-im.handlers.server :as server] [syng-im.utils.logging :as log])) ;; -- Middleware ------------------------------------------------------------ @@ -31,6 +33,12 @@ (fn [_ _] app-db)) +;; -- Common -------------------------------------------------------------- + +(register-handler :set-loading + (fn [db [_ value]] + (assoc db :loading value))) + ;; -- Protocol -------------------------------------------------------------- (register-handler :initialize-protocol @@ -50,6 +58,24 @@ (save-message chat-id msg) (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 -------------------------------------------------------------- (register-handler :load-syng-contacts diff --git a/syng-im/src/syng_im/handlers/server.cljs b/syng-im/src/syng_im/handlers/server.cljs new file mode 100644 index 0000000000..b25fafa16d --- /dev/null +++ b/syng-im/src/syng_im/handlers/server.cljs @@ -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)) diff --git a/syng-im/src/syng_im/models/user_data.cljs b/syng-im/src/syng_im/models/user_data.cljs new file mode 100644 index 0000000000..463a731b5a --- /dev/null +++ b/syng-im/src/syng_im/models/user_data.cljs @@ -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))]))))) diff --git a/syng-im/src/syng_im/subs.cljs b/syng-im/src/syng_im/subs.cljs index 9fcace1759..8899ed7a0b 100644 --- a/syng-im/src/syng_im/subs.cljs +++ b/syng-im/src/syng_im/subs.cljs @@ -8,6 +8,25 @@ (reaction (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 :get-contacts (fn [db _] diff --git a/syng-im/src/syng_im/utils/crypt.cljs b/syng-im/src/syng_im/utils/crypt.cljs new file mode 100644 index 0000000000..cb80de1a8d --- /dev/null +++ b/syng-im/src/syng_im/utils/crypt.cljs @@ -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)) diff --git a/syng-im/src/syng_im/utils/phone_number.cljs b/syng-im/src/syng_im/utils/phone_number.cljs new file mode 100644 index 0000000000..6a7481faf4 --- /dev/null +++ b/syng-im/src/syng_im/utils/phone_number.cljs @@ -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")))) diff --git a/syng-im/src/syng_im/utils/utils.cljs b/syng-im/src/syng_im/utils/utils.cljs index 964878c4cc..03c88afd00 100644 --- a/syng-im/src/syng_im/utils/utils.cljs +++ b/syng-im/src/syng_im/utils/utils.cljs @@ -2,10 +2,8 @@ (:require-macros [natal-shell.async-storage :refer [get-item set-item]] [natal-shell.alert :refer [alert]] - [natal-shell.toast-android :as toast])) - -;; (def server-address "http://rpc0.syng.im:20000/") -(def server-address "http://10.0.3.2:3000/") + [natal-shell.toast-android :as toast]) + (:require [syng-im.constants :as const])) (defn log [obj] (.log js/console obj)) @@ -21,7 +19,7 @@ (http-post action data on-success nil)) ([action data on-success on-error] (-> (.fetch js/window - (str server-address action) + (str const/server-address action) (clj->js {:method "POST" :headers {:accept "application/json" :content-type "application/json"}