diff --git a/src/syng_im/chat/screen.cljs b/src/syng_im/chat/screen.cljs index aef8258b45..8b40ce8cfc 100644 --- a/src/syng_im/chat/screen.cljs +++ b/src/syng_im/chat/screen.cljs @@ -64,9 +64,9 @@ (defn on-action-selected [position] (case position - 0 (dispatch [:show-add-participants #_navigator]) - 1 (dispatch [:show-remove-participants #_navigator]) - 2 (dispatch [:leave-group-chat #_navigator]))) + 0 (dispatch [:show-add-participants]) + 1 (dispatch [:show-remove-participants]) + 2 (dispatch [:leave-group-chat]))) (defn overlay [{:keys [on-click-outside]} items] [view st/actions-overlay @@ -97,21 +97,18 @@ :icon :menu_group :icon-style {:width 25 :height 19} - :handler nil #_#(dispatch [:show-add-participants - navigator])} + :handler #(dispatch [:show-add-participants])} {:title "Remove Contact from chat" :subtitle "Alex, John" :icon :search_gray_copy :icon-style {:width 17 :height 17} - :handler nil #_#(dispatch - [:show-remove-participants navigator])} + :handler #(dispatch [:show-remove-participants])} {:title "Leave Chat" :icon :muted :icon-style {:width 18 :height 21} - :handler nil #_#(dispatch [:leave-group-chat - navigator])} + :handler #(dispatch [:leave-group-chat])} {:title "Settings" :subtitle "Not implemented" :icon :settings diff --git a/src/syng_im/components/discovery/discovery.cljs b/src/syng_im/components/discovery/discovery.cljs index 21acf38988..2738781de8 100644 --- a/src/syng_im/components/discovery/discovery.cljs +++ b/src/syng_im/components/discovery/discovery.cljs @@ -31,7 +31,7 @@ :autoFocus true :placeholder "Type your search tags here" :onSubmitEditing (fn [e] - (let [search (aget e "nativeEvent" "text") + (let [search (aget e "nativeEvent" "text") hashtags (get-hashtags search)] (dispatch [:broadcast-status search hashtags])))}] [view @@ -50,25 +50,26 @@ (dispatch [:updated-discoveries])))) (defn discovery [{:keys [navigator]}] + [] (let [showSearch (r/atom false)] (fn [] [view {:style {:flex 1 :backgroundColor "#eef2f5"}} - [toolbar {:style st/discovery-toolbar - :navigator navigator - :nav-action {:image {:source {:uri "icon_hamburger"} - :style {:width 16 - :height 12}} + [toolbar {:style st/discovery-toolbar + :navigator navigator + :nav-action {:image {:source {:uri "icon_hamburger"} + :style {:width 16 + :height 12}} :handler create-fake-discovery} - :title "Add Participants" - :content (title-content @showSearch) - :action {:image {:source {:uri "icon_search"} - :style {:width 17 - :height 17}} - :handler (fn [] - (if @showSearch - (reset! showSearch false) - (reset! showSearch true)))}}] + :title "Add Participants" + :content (title-content @showSearch) + :action {:image {:source {:uri "icon_search"} + :style {:width 17 + :height 17}} + :handler (fn [] + (if @showSearch + (reset! showSearch false) + (reset! showSearch true)))}}] [scroll-view {:style {}} [view {:style st/section-spacing} [text {:style st/discovery-subtitle} "Popular tags"]] @@ -76,7 +77,3 @@ [view {:style st/section-spacing} [text {:style st/discovery-subtitle} "Recent"]] [discovery-recent]]]))) - (comment - (def page-width (aget (natal-shell.dimensions/get "window") "width")) - (def page-height (aget (natal-shell.dimensions/get "window") "height")) - ) diff --git a/src/syng_im/contacts/handlers.cljs b/src/syng_im/contacts/handlers.cljs index 58586cc671..c434a95ea1 100644 --- a/src/syng_im/contacts/handlers.cljs +++ b/src/syng_im/contacts/handlers.cljs @@ -1,6 +1,15 @@ (ns syng-im.contacts.handlers - (:require [re-frame.core :refer [register-handler after]] - [syng-im.models.contacts :as contacts])) + (:require [re-frame.core :refer [register-handler after dispatch]] + [syng-im.models.contacts :as contacts] + [syng-im.utils.crypt :refer [encrypt]] + [clojure.string :as s] + [syng-im.utils.utils :refer [http-post]] + [syng-im.utils.phone-number :refer [format-phone-number]])) + +(defn side-effect! [handler] + (fn [db params] + (handler db params) + db)) (defn save-contact [_ [_ contact]] @@ -11,4 +20,82 @@ (update db :contacts conj contact)) ((after save-contact)))) +(defn load-contacts! [db _] + (let [contacts (contacts/get-contacts)] + (assoc db :contacts contacts))) +(register-handler :load-syng-contacts load-contacts!) + +(def react-native-contacts (js/require "react-native-contacts")) + +(defn contact-name [contact] + (->> contact + ((juxt :givenName :middleName :familyName)) + (remove s/blank?) + (s/join " "))) + +(defn normalize-phone-contacts [contacts] + (let [contacts' (js->clj contacts :keywordize-keys true)] + (map (fn [{:keys [thumbnailPath phoneNumbers] :as contact}] + {:name (contact-name contact) + :photo-path thumbnailPath + :phone-numbers phoneNumbers}) contacts'))) + +(defn fetch-contacts-from-phone! + [_ _] + (.getAll react-native-contacts + (fn [error contacts] + (if error + (dispatch [:error-on-fetching-loading error]) + (let [contacts' (normalize-phone-contacts contacts)] + (dispatch [:get-contacts-identities contacts'])))))) + +(register-handler :sync-contacts + (side-effect! fetch-contacts-from-phone!)) + +(defn get-contacts-by-hash [contacts] + (->> contacts + (mapcat (fn [{:keys [phone-numbers] :as contact}] + (map (fn [{:keys [number]}] + (let [number' (format-phone-number number)] + [(encrypt number') + (-> contact + (assoc :phone-number number') + (dissoc :phone-numbers))])) + phone-numbers))) + (into {}))) + +(defn add-identity [contacts-by-hash contacts] + (map (fn [{:keys [phone-number-hash whisper-identity]}] + (let [contact (contacts-by-hash phone-number-hash)] + (assoc contact :whisper-identity whisper-identity))) + (js->clj contacts))) + +(defn request-stored-contacts [contacts] + (let [contacts-by-hash (get-contacts-by-hash contacts) + data (keys contacts-by-hash)] + (http-post "get-contacts" {:phone-number-hashes data} + (fn [{:keys [contacts]}] + (let [contacts' (add-identity contacts-by-hash contacts)] + (dispatch [:add-contacts contacts'])))))) + +(defn get-identities-by-contacts! [_ [_ contacts]] + (request-stored-contacts contacts)) + +(register-handler :get-contacts-identities + (side-effect! get-identities-by-contacts!)) + +(defn save-contacts! [{:keys [new-contacts]} _] + (contacts/save-syng-contacts new-contacts)) + +(defn add-new-contacts + [{:keys [contacts] :as db} [_ new-contacts]] + (let [identities (set (map :whisper-identity contacts)) + new-contacts' (remove #(identities (:whisper-identity %)) new-contacts)] + (-> db + (update :contacts concat new-contacts') + (assoc :new-contacts new-contacts')))) + +(register-handler :add-contacts + (after save-contacts!) + add-new-contacts) diff --git a/src/syng_im/contacts/screen.cljs b/src/syng_im/contacts/screen.cljs index 5c1f2c0de8..73d3a4d610 100644 --- a/src/syng_im/contacts/screen.cljs +++ b/src/syng_im/contacts/screen.cljs @@ -11,10 +11,11 @@ [syng-im.contacts.views.contact :refer [contact-view]] [syng-im.components.styles :refer [toolbar-background2]] [syng-im.components.toolbar :refer [toolbar]] - [syng-im.contacts.styles :as st])) + [syng-im.contacts.styles :as st] + [syng-im.utils.listview :as lw])) (defn render-row [row _ _] - (list-item [contact-view (js->clj row :keywordize-keys true)])) + (list-item [contact-view row])) (defn get-data-source [contacts] (clone-with-rows (data-source {:rowHasChanged not=}) contacts)) @@ -22,14 +23,14 @@ (defn contact-list-toolbar [] [toolbar {:title "Contacts" :background-color toolbar-background2 - :action {:image {:source {:uri :icon_search} - :style st/search-icon} + :action {:image {:source {:uri :icon_search} + :style st/search-icon} :handler (fn [])}}]) (defn contact-list [] - (let [contacts (subscribe [:get-contacts])] + (let [contacts (subscribe [:get :contacts])] (fn [] - (let [contacts-ds (get-data-source @contacts)] + (let [contacts-ds (lw/to-datasource2 @contacts)] [view st/contacts-list-container [contact-list-toolbar] (when contacts-ds diff --git a/src/syng_im/contacts/subs.cljs b/src/syng_im/contacts/subs.cljs index 8396dac043..81459071c6 100644 --- a/src/syng_im/contacts/subs.cljs +++ b/src/syng_im/contacts/subs.cljs @@ -1,5 +1,3 @@ (ns syng-im.contacts.subs (:require-macros [reagent.ratom :refer [reaction]]) (:require [re-frame.core :refer [register-sub]])) - - diff --git a/src/syng_im/db.cljs b/src/syng_im/db.cljs index d7b452a0f3..f907e5a618 100644 --- a/src/syng_im/db.cljs +++ b/src/syng_im/db.cljs @@ -7,13 +7,12 @@ (def default-view :discovery) ;; initial state of app-db -(def app-db {:greeting "Hello Clojure in iOS and Android!" - :identity-password "replace-me-with-user-entered-password" +(def app-db {:identity-password "replace-me-with-user-entered-password" :identity "me" :contacts [] :current-chat-id "console" - :chat {:command nil - :last-message nil} + :chat {:command nil + :last-message nil} :chats {} :chats-updated-signal 0 :show-actions false diff --git a/src/syng_im/handlers.cljs b/src/syng_im/handlers.cljs index 8b7e1849a7..342ec071df 100644 --- a/src/syng_im/handlers.cljs +++ b/src/syng_im/handlers.cljs @@ -14,7 +14,6 @@ message-by-id]] [syng-im.models.commands :refer [set-commands]] [syng-im.handlers.server :as server] - [syng-im.handlers.contacts :as contacts-service] [syng-im.handlers.suggestions :refer [get-command handle-command get-command-handler @@ -229,19 +228,6 @@ (user-data/load-phone-number) db)) -;; -- Sign up -------------------------------------------------------------- - -(register-handler :sync-contacts - (fn [db [_ handler]] - (contacts-service/sync-contacts handler) - db)) - -;; -- Contacts -------------------------------------------------------------- - -(register-handler :load-syng-contacts - (fn [db [_ value]] - (contacts/load-syng-contacts db))) - ;; -- Chats -------------------------------------------------------------- (defn update-new-participants-selection [db identity add?] (update db :new-participants (fn [new-participants] diff --git a/src/syng_im/handlers/contacts.cljs b/src/syng_im/handlers/contacts.cljs deleted file mode 100644 index 53b0146a49..0000000000 --- a/src/syng_im/handlers/contacts.cljs +++ /dev/null @@ -1,64 +0,0 @@ -(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! 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 (clj raw-contacts :keywordize-keys true)))})))) - ch)) +(defn load-phone-contacts + ([callback] (.getAll react-native-contacts callback)) + ([] + (.getAll react-native-contacts + (fn [error raw-contacts] + (println raw-contacts) + {:error error + :contacts + (when (not error) + (log raw-contacts) + (map (fn [contact] + (merge contact + (generate-contact 1) + {:name (:givenName contact) + :photo-path (:thumbnailPath contact) + :phone-numbers (:phoneNumbers contact)})) + (js->clj raw-contacts :keywordize-keys true)))})))) -(defn- get-contacts [] - (if fake-contacts? - [{:phone-number "123" - :whisper-identity "abc" - :name "fake" - :photo-path ""}] - (realm/get-list :contacts))) - -(defn load-syng-contacts [db] - (let [contacts (map (fn [contact] - (merge contact - {:delivery-status (if (< (rand) 0.5) :delivered :seen) - :datetime "15:30" - :new-messages-count (rand-int 3) - :online (< (rand) 0.5)})) - (get-contacts))] - (assoc db :contacts contacts))) +(defn get-contacts [] + (realm/collection->map (realm/get-all :contacts))) (defn- create-contact [{:keys [phone-number whisper-identity name photo-path]}] (realm/create :contacts diff --git a/src/syng_im/models/messages.cljs b/src/syng_im/models/messages.cljs index b8fc9cff57..bf58efd2cd 100644 --- a/src/syng_im/models/messages.cljs +++ b/src/syng_im/models/messages.cljs @@ -16,10 +16,6 @@ [s] (keywordize-keys (apply hash-map (split s #"[;=]")))) -(defn select-chat-last-message [chat] - (when-let [last-msg-id (:last-msg-id chat)] - (r/single-cljs (r/get-by-field :msgs :msg-id last-msg-id)))) - (defn save-message [chat-id {:keys [from to msg-id content content-type outgoing same-author same-direction] diff --git a/src/syng_im/models/protocol.cljs b/src/syng_im/models/protocol.cljs index 176cab7047..aff7283d97 100644 --- a/src/syng_im/models/protocol.cljs +++ b/src/syng_im/models/protocol.cljs @@ -6,8 +6,7 @@ [syng-im.utils.types :refer [to-edn-string]] [re-frame.db :refer [app-db]] [syng-im.db :as db] - [syng-im.persistence.simple-kv-store :as kv] - [syng-im.utils.logging :as log])) + [syng-im.persistence.simple-kv-store :as kv])) (defn set-initialized [db initialized?] (assoc-in db db/protocol-initialized-path initialized?)) @@ -23,8 +22,3 @@ password (:identity-password db)] (when encrypted (read-string (password-decrypt password encrypted))))) - -(comment - - (stored-identity @re-frame.db/app-db) - ) diff --git a/src/syng_im/utils/phone_number.cljs b/src/syng_im/utils/phone_number.cljs index 6a7481faf4..19ec1ac526 100644 --- a/src/syng_im/utils/phone_number.cljs +++ b/src/syng_im/utils/phone_number.cljs @@ -5,5 +5,6 @@ (def country-code (subs locale 3 5)) (set! js/PhoneNumber (js/require "awesome-phonenumber")) +;; todo check wrong numbers, .getNumber returns empty string (defn format-phone-number [number] (str (.getNumber (js/PhoneNumber. number country-code "international"))))