diff --git a/.re-natal b/.re-natal index 526a5b4820..1455b14c43 100644 --- a/.re-natal +++ b/.re-natal @@ -15,7 +15,8 @@ "react-native-circle-checkbox", "react-native-randombytes", "dismissKeyboard", - "react-native-linear-gradient" + "react-native-linear-gradient", + "react-native-android-sms-listener" ], "imageDirs": [ "images" diff --git a/android/app/build.gradle b/android/app/build.gradle index 377ee75866..379551061c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -129,6 +129,7 @@ dependencies { compile project(':react-native-contacts') compile project(':react-native-i18n') compile project(':react-native-linear-gradient') + compile project(':ReactNativeAndroidSmsListener') // compile(name:'geth', ext:'aar') compile(group: 'status-im', name: 'android-geth', version: '1.4.0-201604110816-a97a114', ext: 'aar') diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a7eb44af57..d8e1a14016 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + (fn [db [_ phone-number]] - ;; todo save phone number to db - (assoc db :user-phone-number phone-number)) - ((after (fn [& _] (sign-up-service/on-sign-up-response)))))) + (fn [db [_ phone-number]] + ;; todo save phone number to db + (let [formatted (format-phone-number phone-number)] + (-> db + (assoc :user-phone-number formatted) + sign-up-service/start-listening-confirmation-code-sms + (server/sign-up formatted sign-up-service/on-sign-up-response))))) + +(register-handler :stop-listening-confirmation-code-sms + (fn [db [_]] + (sign-up-service/stop-listening-confirmation-code-sms db))) (register-handler :sign-up-confirm (fn [db [_ confirmation-code]] - (sign-up-service/on-send-code-response confirmation-code) - (sign-up-service/set-signed-up db true))) + (server/sign-up-confirm confirmation-code sign-up-service/on-send-code-response) + db)) (register-handler :set-signed-up (fn [db [_ signed-up]] @@ -299,6 +311,7 @@ (let [name (get-in contacts [contcat-id :name]) chat {:chat-id contcat-id :name name + :color default-chat-color :group-chat false :is-active true :timestamp (.getTime (js/Date.)) diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index f292983cc7..19723aba22 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -1,7 +1,7 @@ (ns status-im.chat.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [clojure.string :as s] - [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [subscribe dispatch]] + [clojure.string :as s] [status-im.components.react :refer [view text image @@ -9,9 +9,11 @@ touchable-highlight list-view list-item]] + [status-im.components.chat-icon.screen :refer [chat-icon-view-action + chat-icon-view-menu-item]] [status-im.chat.styles.screen :as st] - [status-im.resources :as res] [status-im.utils.listview :refer [to-datasource]] + [status-im.utils.utils :refer [truncate-str]] [status-im.components.invertible-scroll-view :refer [invertible-scroll-view]] [status-im.components.toolbar :refer [toolbar]] [status-im.chat.views.message :refer [chat-message]] @@ -32,19 +34,13 @@ (assoc msg :text-color text-color :background-color background-color)))) -(defn chat-photo [{:keys [photo-path]}] - [view {:margin 10 - :borderRadius 50} - [image {:source (if (s/blank? photo-path) - res/user-no-photo - {:uri photo-path}) - :style st/chat-photo}]]) - -(defn contact-online [{:keys [online]}] - (when online - [view st/online-view - [view st/online-dot-left] - [view st/online-dot-right]])) +(defview chat-icon [] + [chat-id [:chat :chat-id] + group-chat [:chat :group-chat] + name [:chat :name] + color [:chat :color]] + ;; TODO stub data ('online' property) + [chat-icon-view-action chat-id group-chat name color true]) (defn typing [member] [view st/typing-view @@ -54,6 +50,7 @@ (defn typing-all [] [view st/typing-all + ;; TODO stub data (for [member ["Geoff" "Justas"]] ^{:key member} [typing member])]) @@ -94,43 +91,44 @@ [text {:style st/action-subtitle} subtitle])]]]) -(defn menu-item-contact-photo [{:keys [photo-path]}] - [image {:source (if (s/blank? photo-path) - res/user-no-photo - {:uri photo-path}) - :style st/menu-item-profile-contact-photo}]) +(defview menu-item-icon-profile [] + [chat-id [:chat :chat-id] + group-chat [:chat :group-chat] + name [:chat :name] + color [:chat :color]] + ;; TODO stub data ('online' property) + [chat-icon-view-menu-item chat-id group-chat name color true]) -(defn menu-item-contact-online [{:keys [online]}] - (when online - [view st/menu-item-profile-online-view - [view st/menu-item-profile-online-dot-left] - [view st/menu-item-profile-online-dot-right]])) - -(defn menu-item-icon-profile [] - [view st/icon-view - [menu-item-contact-photo {}] - [menu-item-contact-online {:online true}]]) +(defn members-text [members] + (truncate-str (str (s/join ", " (map #(:name %) members)) " and you") 35)) (defn actions-list-view [] (let [{:keys [group-chat chat-id]} - (subscribe [:chat-properties [:group-chat :chat-id]])] + (subscribe [:chat-properties [:group-chat :chat-id]]) + members (subscribe [:current-chat-contacts])] (when-let [actions (if @group-chat - [{:title "Add Contact to chat" + [{:title "Members" + :subtitle (members-text @members) :icon :menu_group :icon-style {:width 25 :height 19} - :handler #(dispatch [:navigate-to :add-participants])} - {:title "Remove Contact from chat" - :subtitle "Alex, John" + ;; TODO not implemented: action Members + :handler nil} + {:title "Search chat" + :subtitle "!not implemented" :icon :search_gray_copy :icon-style {:width 17 :height 17} - :handler #(dispatch [:navigate-to :remove-participants])} - {:title "Leave Chat" + ;; TODO not implemented: action Search chat + :handler nil} + {:title "Notifications and sounds" + :subtitle "!not implemented" + ;;:subtitle "Chat muted" :icon :muted :icon-style {:width 18 :height 21} - :handler #(dispatch [:leave-group-chat])} + ;; TODO not implemented: action Notifications + :handler nil} {:title "Settings" :icon :settings :icon-style {:width 20 @@ -147,19 +145,23 @@ :icon :search_gray_copy :icon-style {:width 17 :height 17} + ;; TODO not implemented: action Search chat :handler nil} {:title "Notifications and sounds" :subtitle "!not implemented" + ;;:subtitle "Notifications on" :icon :muted :icon-style {:width 18 :height 21} + ;; TODO not implemented: action Notifications :handler nil} {:title "Settings" :subtitle "!not implemented" :icon :settings :icon-style {:width 20 :height 13} - :handler (fn [])}])] + ;; TODO not implemented: action Settings + :handler nil}])] [view st/actions-wrapper [view st/actions-separator] [view st/actions-view @@ -177,17 +179,19 @@ (fn [] [view (st/chat-name-view @show-actions) [text {:style st/chat-name-text} - (or @name "Chat name")] + (truncate-str (or @name "Chat name") 30)] (if @group-chat [view {:flexDirection :row} [icon :group st/group-icon] [text {:style st/members} - (let [cnt (count @contacts)] + (let [cnt (inc (count @contacts))] (str cnt (if (< 1 cnt) " members" " member") + ;; TODO stub data: active members ", " cnt " active"))]] + ;; TODO stub data: last activity [text {:style st/last-activity} "Active a minute ago"])]))) (defn toolbar-action [] @@ -196,13 +200,12 @@ (if @show-actions [touchable-highlight {:on-press #(dispatch [:set-show-actions false])} - [view st/icon-view + [view st/action [icon :up st/up-icon]]] [touchable-highlight {:on-press #(dispatch [:set-show-actions true])} - [view st/icon-view - [chat-photo {}] - [contact-online {:online true}]]])))) + [view st/action + [chat-icon]]])))) (defn chat-toolbar [] (let [{:keys [group-chat name contacts]} diff --git a/src/status_im/chat/sign_up.cljs b/src/status_im/chat/sign_up.cljs index 3b50530b28..ef855d0021 100644 --- a/src/status_im/chat/sign_up.cljs +++ b/src/status_im/chat/sign_up.cljs @@ -4,13 +4,16 @@ [status-im.persistence.simple-kv-store :as kv] [status-im.protocol.state.storage :as s] [status-im.models.chats :as c] + [status-im.components.styles :refer [default-chat-color]] [status-im.utils.utils :refer [log on-error http-post toast]] [status-im.utils.random :as random] + [status-im.utils.sms-listener :refer [add-sms-listener + remove-sms-listener]] [status-im.utils.phone-number :refer [format-phone-number]] [status-im.constants :refer [text-content-type - content-type-command - content-type-command-request - content-type-status]])) + content-type-command + content-type-command-request + content-type-status]])) (defn send-console-msg [text] {:msg-id (random/id) @@ -37,19 +40,22 @@ (dispatch [:set-signed-up true])) (defn sync-contacts [] + ;; TODO 'on-sync-contacts' is never called (dispatch [:sync-contacts on-sync-contacts])) (defn on-send-code-response [body] (dispatch [:received-msg {:msg-id (random/id) - ;; todo replace by real check - :content (if (= "1111" body) - "Confirmed" - "Wrong code") + :content (:message body) :content-type text-content-type :outgoing false :from "console" - :to "me"}])) + :to "me"}]) + (when (:confirmed body) + (dispatch [:stop-listening-confirmation-code-sms]) + (sync-contacts) + ;; TODO should be called after sync-contacts? + (dispatch [:set-signed-up true]))) ; todo fn name is not too smart, but... (defn command-content @@ -71,9 +77,22 @@ :from "console" :to "me"}]))) +(defn handle-sms [{body :body}] + (when-let [matches (re-matches #"(\d{4})" body)] + (dispatch [:sign-up-confirm (second matches)]))) + +(defn start-listening-confirmation-code-sms [db] + (when (not (:confirmation-code-sms-listener db)) + (assoc db :confirmation-code-sms-listener (add-sms-listener handle-sms)))) + +(defn stop-listening-confirmation-code-sms [db] + (when-let [listener (:confirmation-code-sms-listener db)] + (remove-sms-listener listener) + (dissoc db :confirmation-code-sms-listener))) + ;; -- Saving password ---------------------------------------- (defn save-password [password] - ;; TODO validate and save password + ;; TODO validate and save password (dispatch [:received-msg {:msg-id (random/id) :content (str "OK great! Your password has been saved. Just to let you " @@ -174,6 +193,7 @@ (def console-chat {:chat-id "console" :name "console" + :color default-chat-color :group-chat false :is-active true :timestamp (.getTime (js/Date.)) diff --git a/src/status_im/chat/styles/screen.cljs b/src/status_im/chat/styles/screen.cljs index 5faa905fd6..35e4d0b3d7 100644 --- a/src/status_im/chat/styles/screen.cljs +++ b/src/status_im/chat/styles/screen.cljs @@ -20,6 +20,12 @@ :backgroundColor toolbar-background1 :elevation 2}) +(def action + {:width 56 + :height 56 + :alignItems :center + :justifyContent :center}) + (def icon-view {:width 56 :height 56}) @@ -48,10 +54,8 @@ :height 9}) (def up-icon - {:marginTop 23 - :marginLeft 21 - :width 14 - :height 8}) + {:width 14 + :height 8}) (def members {:marginTop -0.5 @@ -108,28 +112,6 @@ :fontSize 12 :fontFamily font}) -(def online-view - {:position :absolute - :top 30 - :left 30 - :width 20 - :height 20 - :borderRadius 50 - :backgroundColor online-color - :borderWidth 2 - :borderColor color-white}) - -(def online-dot - {:position :absolute - :top 6 - :width 4 - :height 4 - :borderRadius 50 - :backgroundColor color-white}) - -(def online-dot-left (merge online-dot {:left 3})) -(def online-dot-right (merge online-dot {:left 9})) - (def typing-all {:marginBottom 20}) @@ -153,11 +135,6 @@ :fontFamily font :color text2-color}) -(def chat-photo - {:borderRadius 50 - :width 36 - :height 36}) - (def actions-overlay {:position :absolute :top 0 @@ -167,34 +144,3 @@ (def overlay-highlight {:flex 1}) - -;;----- Menu item Profile ---------------- - -(def menu-item-profile-contact-photo - {:marginTop 13 - :marginLeft 16 - :borderRadius 50 - :width 24 - :height 24}) - -(def menu-item-profile-online-view - {:position :absolute - :top 26 - :left 29 - :width 15 - :height 15 - :borderRadius 50 - :backgroundColor online-color - :borderWidth 2 - :borderColor color-white}) - -(def menu-item-profile-online-dot - {:position :absolute - :top 4 - :width 3 - :height 3 - :borderRadius 50 - :backgroundColor color-white}) - -(def menu-item-profile-online-dot-left (merge menu-item-profile-online-dot {:left 1.7})) -(def menu-item-profile-online-dot-right (merge menu-item-profile-online-dot {:left 6.3})) diff --git a/src/status_im/chat/views/plain_input.cljs b/src/status_im/chat/views/plain_input.cljs index 9b6bea54c5..eaece17dfb 100644 --- a/src/status_im/chat/views/plain_input.cljs +++ b/src/status_im/chat/views/plain_input.cljs @@ -45,6 +45,7 @@ :onSubmitEditing #(try-send @chat @staged-commands-atom input-message)} input-message] + ;; TODO emoticons: not implemented [icon :smile st/smile-icon] (when (message-valid? @staged-commands-atom input-message) [touchable-highlight {:on-press #(send @chat input-message)} diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index 32a7ce6ab2..48babbcee1 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -12,7 +12,8 @@ [status-im.components.action-button :refer [action-button action-button-item]] [status-im.components.drawer.view :refer [drawer-view open-drawer]] - [status-im.components.styles :refer [color-blue]] + [status-im.components.styles :refer [color-blue + toolbar-background2]] [status-im.components.toolbar :refer [toolbar]] [status-im.components.main-tabs :refer [main-tabs]] [status-im.components.icons.ionicons :refer [icon]] @@ -23,6 +24,8 @@ :style st/hamburger-icon} :handler open-drawer} :title "Chats" + :background-color toolbar-background2 + ;; TODO implement search :action {:image {:source {:uri :icon_search} :style st/search-icon} :handler (fn [])}}]) diff --git a/src/status_im/chats_list/styles.cljs b/src/status_im/chats_list/styles.cljs index 592a882d3e..0fae1d82fd 100644 --- a/src/status_im/chats_list/styles.cljs +++ b/src/status_im/chats_list/styles.cljs @@ -9,49 +9,17 @@ new-messages-count-color]] [status-im.components.tabs.styles :refer [tab-height]])) -(def contact-photo-container - {:borderRadius 50}) - -(def contact-photo-image - {:borderRadius 50 - :width 40 - :height 40}) - -(def online-container - {:position :absolute - :top 24 - :left 24 - :width 20 - :height 20 - :borderRadius 50 - :backgroundColor online-color - :borderWidth 2 - :borderColor color-white}) - -(def online-dot - {:position :absolute - :top 6 - :width 4 - :height 4 - :borderRadius 50 - :backgroundColor color-white}) - -(def online-dot-left - (assoc online-dot :left 3)) - -(def online-dot-right - (assoc online-dot :left 9)) - (def chat-container {:flexDirection :row :paddingVertical 15 :paddingHorizontal 16 :height 90}) -(def photo-container - {:marginTop 2 - :width 44 - :height 44}) +(def chat-icon-container + {:marginTop -2 + :marginLeft -4 + :width 48 + :height 48}) (def item-container {:flexDirection :column diff --git a/src/status_im/chats_list/views/chat_list_item.cljs b/src/status_im/chats_list/views/chat_list_item.cljs index 412979d42b..0c343f9b59 100644 --- a/src/status_im/chats_list/views/chat_list_item.cljs +++ b/src/status_im/chats_list/views/chat_list_item.cljs @@ -11,10 +11,7 @@ (defn chat-list-item [{:keys [chat-id] :as chat}] [touchable-highlight {:on-press #(dispatch [:navigate-to :chat chat-id])} - ;; TODO add [photo-path delivery-status new-messages-count online] values to chat-obj [view [chat-list-item-inner-view (merge chat - {:photo-path nil - :delivery-status :seen - :new-messages-count 3 - :timestamp "13:54" + ;; TODO stub data + {:new-messages-count 3 :online true})]]]) diff --git a/src/status_im/chats_list/views/inner_item.cljs b/src/status_im/chats_list/views/inner_item.cljs index fc0851183a..e3fc322bb7 100644 --- a/src/status_im/chats_list/views/inner_item.cljs +++ b/src/status_im/chats_list/views/inner_item.cljs @@ -1,52 +1,45 @@ (ns status-im.chats-list.views.inner-item - (:require [clojure.string :as s] - [status-im.components.react :refer [view image icon text]] + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [status-im.components.react :refer [view image icon text]] + [status-im.components.chat-icon.screen :refer [chat-icon-view-chat-list]] [status-im.chats-list.styles :as st] - [status-im.resources :as res])) - - -(defn contact-photo [photo-path] - [view st/contact-photo-container - [image {:source (if (s/blank? photo-path) - res/user-no-photo - {:uri photo-path}) - :style st/contact-photo-image}]]) - -(defn contact-online [online] - (when online - [view st/online-container - [view st/online-dot-left] - [view st/online-dot-right]])) + [status-im.utils.utils :refer [truncate-str]] + [status-im.utils.datetime :as time])) (defn chat-list-item-inner-view - [{:keys [name photo-path delivery-status timestamp new-messages-count online - group-chat contacts]}] - [view st/chat-container - [view st/photo-container - [contact-photo photo-path] - [contact-online online]] - [view st/item-container - [view st/name-view - [text {:style st/name-text} name] - (when group-chat - [icon :group st/group-icon]) - (when group-chat - [text {:style st/memebers-text} - (if (< 1 (count contacts)) - (str (count contacts) " members") - "1 member")])] - [text {:style st/last-message-text - :numberOfLines 2} - (repeatedly 5 #(str "Hi, I'm " name "! "))]] - [view - [view st/status-container - (when delivery-status - [image {:source (if (= (keyword delivery-status) :seen) - {:uri :icon_ok_small} - ;; todo change icon - {:uri :icon_ok_small}) - :style st/status-image}]) - [text {:style st/datetime-text} timestamp]] - (when (pos? new-messages-count) - [view st/new-messages-container - [text {:style st/new-messages-text} new-messages-count]])]]) + [{:keys [chat-id name color photo-path new-messages-count + online group-chat contacts] :as chat}] + (let [last-message (first (:messages chat))] + [view st/chat-container + [view st/chat-icon-container + [chat-icon-view-chat-list chat-id group-chat name color online]] + [view st/item-container + [view st/name-view + [text {:style st/name-text} (truncate-str name 20)] + (when group-chat + [icon :group st/group-icon]) + (when group-chat + [text {:style st/memebers-text} + (if (< 0 (count contacts)) + (str (inc (count contacts)) " members") + "1 member")])] + [text {:style st/last-message-text + :numberOfLines 2} + (when last-message + (:content last-message))]] + [view + (when last-message + [view st/status-container + ;; TODO currently there is not :delivery-status in last-message + (when (:delivery-status last-message) + [image {:source (if (= (keyword (:delivery-status last-message)) :seen) + {:uri :icon_ok_small} + ;; todo change icon + {:uri :icon_ok_small}) + :style st/status-image}]) + (when (:timestamp last-message) + [text {:style st/datetime-text} + (time/to-short-str (:timestamp last-message))])]) + (when (pos? new-messages-count) + [view st/new-messages-container + [text {:style st/new-messages-text} new-messages-count]])]])) diff --git a/src/status_im/components/chat_icon/screen.cljs b/src/status_im/components/chat_icon/screen.cljs new file mode 100644 index 0000000000..e44d334e33 --- /dev/null +++ b/src/status_im/components/chat_icon/screen.cljs @@ -0,0 +1,92 @@ +(ns status-im.components.chat-icon.screen + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch]] + [status-im.components.react :refer [view + text + image + icon]] + [status-im.components.chat-icon.styles :as st] + [status-im.components.styles :refer [color-purple]])) + +(defn default-chat-icon [name styles] + [view (:default-chat-icon styles) + [text {:style (:default-chat-icon-text styles)} + (first name)]]) + +(defn chat-icon [photo-path styles] + [image {:source {:uri photo-path} + :style (:chat-icon styles)}]) + +(defn contact-online [online styles] + (when online + [view (:online-view styles) + [view (:online-dot-left styles)] + [view (:online-dot-right styles)]])) + +(defview chat-icon-view [chat-id group-chat name online styles] + [photo-path [:chat-photo chat-id]] + [view (:container styles) + (if (and photo-path (not (empty? photo-path))) + [chat-icon photo-path styles] + [default-chat-icon name styles]) + (when (not group-chat) + [contact-online online styles])]) + +(defn chat-icon-view-chat-list [chat-id group-chat name color online] + [chat-icon-view chat-id group-chat name online + {:container st/container-chat-list + :online-view st/online-view + :online-dot-left st/online-dot-left + :online-dot-right st/online-dot-right + :chat-icon st/chat-icon-chat-list + :default-chat-icon (st/default-chat-icon-chat-list color) + :default-chat-icon-text st/default-chat-icon-text}]) + +(defn chat-icon-view-action [chat-id group-chat name color online] + [chat-icon-view chat-id group-chat name online + {:container st/container + :online-view st/online-view + :online-dot-left st/online-dot-left + :online-dot-right st/online-dot-right + :chat-icon st/chat-icon + :default-chat-icon (st/default-chat-icon color) + :default-chat-icon-text st/default-chat-icon-text}]) + +(defn chat-icon-view-menu-item [chat-id group-chat name color online] + [chat-icon-view chat-id group-chat name online + {:container st/container-menu-item + :online-view st/online-view-menu-item + :online-dot-left st/online-dot-left-menu-item + :online-dot-right st/online-dot-right-menu-item + :chat-icon st/chat-icon-menu-item + :default-chat-icon (st/default-chat-icon-menu-item color) + :default-chat-icon-text st/default-chat-icon-text}]) + +(defn profile-icon-view [photo-path name color online] + (let [styles {:container st/container-profile + :online-view st/online-view-profile + :online-dot-left st/online-dot-left-profile + :online-dot-right st/online-dot-right-profile + :chat-icon st/chat-icon-profile + :default-chat-icon (st/default-chat-icon-profile color) + :default-chat-icon-text st/default-chat-icon-text}] + [view (:container styles) + (if (and photo-path (not (empty? photo-path))) + [chat-icon photo-path styles] + [default-chat-icon name styles]) + [contact-online online styles]])) + +(defview profile-icon [] + [contact [:contact]] + (let [;; TODO stub data + online true + color color-purple] + [profile-icon-view (:photo-path contact) (:name contact) color online])) + +(defview my-profile-icon [] + [name [:get :username] + photo-path [:get :photo-path]] + (let [;; TODO stub data + online true + color color-purple] + [profile-icon-view photo-path name color online])) diff --git a/src/status_im/components/chat_icon/styles.cljs b/src/status_im/components/chat_icon/styles.cljs new file mode 100644 index 0000000000..41fbcf75ee --- /dev/null +++ b/src/status_im/components/chat_icon/styles.cljs @@ -0,0 +1,130 @@ +(ns status-im.components.chat-icon.styles + (:require [status-im.components.styles :refer [font + title-font + color-white + chat-background + online-color + selected-message-color + separator-color + text1-color + text2-color + toolbar-background1]])) + +(defn default-chat-icon [color] + {:margin 4 + :width 36 + :height 36 + :alignItems :center + :justifyContent :center + :borderRadius 50 + :backgroundColor color}) + +(defn default-chat-icon-chat-list [color] + (merge (default-chat-icon color) + {:width 40 + :height 40})) + +(defn default-chat-icon-menu-item [color] + (merge (default-chat-icon color) + {:width 24 + :height 24})) + +(defn default-chat-icon-profile [color] + (merge (default-chat-icon color) + {:width 64 + :height 64})) + +(def default-chat-icon-text + {:marginTop -2 + :color color-white + :fontFamily font + :fontSize 16 + :lineHeight 20}) + +(def chat-icon + {:margin 4 + :borderRadius 50 + :width 36 + :height 36}) + +(def chat-icon-chat-list + (merge chat-icon + {:width 40 + :height 40})) + +(def chat-icon-menu-item + (merge chat-icon + {:width 24 + :height 24})) + +(def chat-icon-profile + (merge chat-icon + {:width 64 + :height 64})) + +(def online-view + {:position :absolute + :bottom 0 + :right 0 + :width 20 + :height 20 + :borderRadius 50 + :backgroundColor online-color + :borderWidth 2 + :borderColor color-white}) + +(def online-view-menu-item + (merge online-view + {:width 15 + :height 15})) + +(def online-view-profile + (merge online-view + {:width 24 + :height 24})) + +(def online-dot + {:position :absolute + :top 6 + :width 4 + :height 4 + :borderRadius 50 + :backgroundColor color-white}) +(def online-dot-left (merge online-dot {:left 3})) +(def online-dot-right (merge online-dot {:left 9})) + +(def online-dot-menu-item + (merge online-dot + {:top 4 + :width 3 + :height 3})) +(def online-dot-left-menu-item + (merge online-dot-menu-item {:left 1.7})) +(def online-dot-right-menu-item + (merge online-dot-menu-item {:left 6.3})) + +(def online-dot-profile + (merge online-dot + {:top 8 + :width 4 + :height 4})) +(def online-dot-left-profile + (merge online-dot-profile {:left 5})) +(def online-dot-right-profile + (merge online-dot-profile {:left 11})) + +(def container + {:width 44 + :height 44}) + +(def container-chat-list + {:width 48 + :height 48}) + +(def container-menu-item + {:width 32 + :height 32}) + +(def container-profile + {:width 72 + :height 72}) diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index 421224dc92..6ccb836e02 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -26,3 +26,4 @@ (def separator-color "#0000001f") (def toolbar-background1 color-white) (def toolbar-background2 color-light-gray) +(def default-chat-color color-purple) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index abfd54bf77..a684182899 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -4,18 +4,9 @@ (def server-address "http://rpc0.status.im:20000/") ;; (def server-address "http://10.0.3.2:3000/") +;; (def server-address "http://localhost:3000/") (def text-content-type "text/plain") (def content-type-command "command") (def content-type-command-request "command-request") (def content-type-status "status") - - -(comment - - (map (fn [c] - {:background c - :foreground c}) group-chat-colors) - (reverse group-chat-colors) - - ) diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index 7a384d04fd..268b701815 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -73,7 +73,7 @@ (defn request-stored-contacts [contacts] (let [contacts-by-hash (get-contacts-by-hash contacts) - data (keys contacts-by-hash)] + data (or (keys contacts-by-hash) ())] (http-post "get-contacts" {:phone-number-hashes data} (fn [{:keys [contacts]}] (let [contacts' (add-identity contacts-by-hash contacts)] diff --git a/src/status_im/contacts/subs.cljs b/src/status_im/contacts/subs.cljs index a85f20866a..76803f74dd 100644 --- a/src/status_im/contacts/subs.cljs +++ b/src/status_im/contacts/subs.cljs @@ -12,18 +12,21 @@ (let [contacts (reaction (:contacts @db))] (reaction (sort-by :name (vals @contacts)))))) -(defn contacts-by-current-chat [fn db] - (let [current-chat-id (:current-chat-id @db) - chat (reaction (get-in @db [:chats current-chat-id])) - contacts (reaction (:contacts @db))] +(defn contacts-by-chat [fn db chat-id] + (let [chat (reaction (get-in @db [:chats chat-id])) + contacts (reaction (:contacts @db))] (reaction - (when @chat - (let [current-participants (->> @chat - :contacts - (map :identity) - set)] - (fn #(current-participants (:whisper-identity %)) - (vals @contacts))))))) + (when @chat + (let [current-participants (->> @chat + :contacts + (map :identity) + set)] + (fn #(current-participants (:whisper-identity %)) + (vals @contacts))))))) + +(defn contacts-by-current-chat [fn db] + (let [current-chat-id (:current-chat-id @db)] + (contacts-by-chat fn db current-chat-id))) (register-sub :contact (fn [db _] @@ -37,3 +40,15 @@ (register-sub :current-chat-contacts (fn [db _] (contacts-by-current-chat filter db))) + +(register-sub :chat-photo + (fn [db [_ chat-id]] + (let [chat-id (or chat-id (:current-chat-id @db)) + chat (reaction (get-in @db [:chats chat-id])) + contacts (contacts-by-chat filter db chat-id)] + (reaction + (when @chat + (if (:group-chat @chat) + ;; TODO return group chat icon + nil + (:photo-path (first @contacts)))))))) diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index a6b34c65ef..a46c61f087 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -23,6 +23,7 @@ :view-id default-view :navigation-stack (list default-view) ;; TODO fix hardcoded values + :photo-path nil :username "My Name" :phone-number "3147984309" :email "myemail@gmail.com" diff --git a/src/status_im/group_settings/screen.cljs b/src/status_im/group_settings/screen.cljs index 86c38a77de..1c49c4f094 100644 --- a/src/status_im/group_settings/screen.cljs +++ b/src/status_im/group_settings/screen.cljs @@ -2,16 +2,17 @@ (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe dispatch]] [status-im.components.react :refer [view - text-input - text - image - icon - modal - picker - picker-item - scroll-view - touchable-highlight]] + text-input + text + image + icon + modal + picker + picker-item + scroll-view + touchable-highlight]] [status-im.components.toolbar :refer [toolbar]] + [status-im.components.chat-icon.screen :refer [chat-icon-view-action]] [status-im.group-settings.styles.group-settings :as st] [status-im.group-settings.views.member :refer [member-view]])) @@ -21,6 +22,7 @@ (defn close-member-menu [] (dispatch [:set :selected-participants #{}])) +;; TODO not in design (defview member-menu [] [{:keys [name] :as participant} [:selected-participant]] (when participant @@ -61,6 +63,7 @@ (close-chat-color-picker) (dispatch [:set-chat-color])) +;; TODO not in design (defview chat-color-picker [] [show-color-picker [:group-settings :show-color-picker] new-color [:get :new-chat-color]] @@ -88,10 +91,10 @@ (dispatch [:group-settings :show-color-picker true])) (defn settings-view [] - ;; TODO implement settings handlers (let [settings [{:custom-icon [chat-color-icon] :title "Change color" :handler show-chat-color-picker} + ;; TODO not implemented: Notifications (merge {:title "Notifications and sounds" :subtitle "!not implemented" :handler nil} @@ -106,21 +109,25 @@ :icon-style {:width 12 :height 12} :title "Clear history" + ;; TODO show confirmation dialog? :handler #(dispatch [:clear-history])} {:icon :bin :icon-style {:width 12 :height 18} :title "Delete and leave" + ;; TODO show confirmation dialog? :handler #(dispatch [:leave-group-chat])}]] [view st/settings-container (for [setting settings] ^{:key setting} [setting-view setting])])) (defview chat-icon [] - [name [:chat :name] - color [:chat :color]] - [view (st/chat-icon color) - [text {:style st/chat-icon-text} (first name)]]) + [chat-id [:chat :chat-id] + group-chat [:chat :group-chat] + name [:chat :name] + color [:chat :color]] + [view st/action + [chat-icon-view-action chat-id group-chat name color false]]) (defn new-group-toolbar [] [toolbar {:title "Chat settings" @@ -164,6 +171,7 @@ [chat-name] [text {:style st/members-text} "Members"] [touchable-highlight {:on-press #(dispatch [:navigate-to :add-participants])} + ;; TODO add participants view is not in design [view st/add-members-container [icon :add-gray st/add-members-icon] [text {:style st/add-members-text} diff --git a/src/status_im/group_settings/styles/group_settings.cljs b/src/status_im/group_settings/styles/group_settings.cljs index 20b2a42d30..91d407c604 100644 --- a/src/status_im/group_settings/styles/group_settings.cljs +++ b/src/status_im/group_settings/styles/group_settings.cljs @@ -52,20 +52,11 @@ (def chat-members-container {:marginBottom 10}) -(defn chat-icon [color] - {:margin 10 - :width 36 - :height 36 - :borderRadius 50 - :backgroundColor color}) - -(def chat-icon-text - {:marginTop 7 - :marginLeft 13 - :color color-white - :fontFamily font - :fontSize 16 - :lineHeight 20}) +(def action + {:width 56 + :height 56 + :alignItems :center + :justifyContent :center}) (def group-settings {:flex 1 diff --git a/src/status_im/new_group/handlers.cljs b/src/status_im/new_group/handlers.cljs index 4a48a3ebd1..0c34111405 100644 --- a/src/status_im/new_group/handlers.cljs +++ b/src/status_im/new_group/handlers.cljs @@ -1,6 +1,7 @@ (ns status-im.new-group.handlers (:require [status-im.protocol.api :as api] [re-frame.core :refer [register-handler after dispatch debug enrich]] + [status-im.components.styles :refer [default-chat-color]] [status-im.models.chats :as chats] [clojure.string :as s])) @@ -37,6 +38,7 @@ (group-name-from-contacts db))] (assoc db :new-chat {:chat-id new-group-id :name chat-name + :color default-chat-color :group-chat true :is-active true :timestamp (.getTime (js/Date.)) diff --git a/src/status_im/persistence/realm.cljs b/src/status_im/persistence/realm.cljs index 242f98bb9c..a7d564f143 100644 --- a/src/status_im/persistence/realm.cljs +++ b/src/status_im/persistence/realm.cljs @@ -1,5 +1,6 @@ (ns status-im.persistence.realm (:require [cljs.reader :refer [read-string]] + [status-im.components.styles :refer [default-chat-color]] [status-im.utils.logging :as log] [status-im.utils.types :refer [to-string]]) (:refer-clojure :exclude [exists?])) @@ -44,7 +45,7 @@ :properties {:chat-id "string" :name "string" :color {:type "string" - :default "#a187d5"} + :default default-chat-color} :group-chat {:type "bool" :indexed true} :is-active "bool" diff --git a/src/status_im/profile/screen.cljs b/src/status_im/profile/screen.cljs index 40d10c44a1..83470681dc 100644 --- a/src/status_im/profile/screen.cljs +++ b/src/status_im/profile/screen.cljs @@ -1,7 +1,6 @@ (ns status-im.profile.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [clojure.string :as s] - [re-frame.core :refer [subscribe dispatch]] + (:require [re-frame.core :refer [subscribe dispatch]] [status-im.components.react :refer [view text image @@ -9,21 +8,10 @@ scroll-view touchable-highlight touchable-opacity]] - [status-im.resources :as res] + [status-im.components.chat-icon.screen :refer [profile-icon + my-profile-icon]] [status-im.profile.styles :as st])) -(defn user-photo [{:keys [photo-path]}] - [image {:source (if (s/blank? photo-path) - res/user-no-photo - {:uri photo-path}) - :style st/user-photo}]) - -(defn user-online [{:keys [online]}] - (when online - [view st/user-online-container - [view st/user-online-dot-left] - [view st/user-online-dot-right]])) - (defn profile-property-view [{:keys [name value]}] [view st/profile-property-view-container [view st/profile-property-view-sub-container @@ -43,9 +31,9 @@ [icon :back st/back-btn-icon]]] [view st/status-block [view st/user-photo-container - [user-photo {}] - [user-online {:online true}]] + [profile-icon]] [text {:style st/user-name} name] + ;; TODO stub data [text {:style st/status} "!not implemented"] [view st/btns-container [touchable-highlight {:onPress #(message-user whisper-identity)} @@ -61,17 +49,21 @@ :value name}] [profile-property-view {:name "Phone number" :value phone-number}] + ;; TODO stub data [profile-property-view {:name "Email" :value "!not implemented"}] [view st/report-user-container - [touchable-opacity {} + [touchable-highlight {:on-press (fn [] + ;; TODO not implemented + )} [text {:style st/report-user-text} "REPORT USER"]]]]]) (defview my-profile [] - [username [:get :username] + [username [:get :username] + photo-path [:get :photo-path] phone-number [:get :phone-number] - email [:get :email] - status [:get :status]] + email [:get :email] + status [:get :status]] [scroll-view {:style st/profile} [touchable-highlight {:style st/back-btn-touchable :on-press #(dispatch [:navigate-back])} @@ -85,8 +77,7 @@ [icon :dots st/actions-btn-icon]]] [view st/status-block [view st/user-photo-container - [user-photo {}] - [user-online {:online true}]] + [my-profile-icon]] [text {:style st/user-name} username] [text {:style st/status} status]] [view st/profile-properties-container diff --git a/src/status_im/profile/styles.cljs b/src/status_im/profile/styles.cljs index fe2c71a76e..95d230920e 100644 --- a/src/status_im/profile/styles.cljs +++ b/src/status_im/profile/styles.cljs @@ -11,37 +11,6 @@ text1-color text2-color]])) -(def user-photo - {:borderRadius 50 - :width 64 - :height 64}) - -(def user-online-container - {:position :absolute - :top 44 - :left 44 - :width 24 - :height 24 - :borderRadius 50 - :backgroundColor online-color - :borderWidth 2 - :borderColor color-white}) - -(def user-online-dot - {:position :absolute - :top 8 - :left 5 - :width 4 - :height 4 - :borderRadius 50 - :backgroundColor color-white}) - -(def user-online-dot-left - (assoc user-online-dot :left 5)) - -(def user-online-dot-right - (assoc user-online-dot :left 11)) - (def profile-property-view-container {:height 85 :paddingHorizontal 16}) @@ -101,10 +70,10 @@ :width 249}) (def user-photo-container - {:marginTop 26}) + {:marginTop 22}) (def user-name - {:marginTop 20 + {:marginTop 16 :fontSize 18 :fontFamily font :color text1-color}) diff --git a/src/status_im/utils/datetime.cljs b/src/status_im/utils/datetime.cljs new file mode 100644 index 0000000000..03695b427a --- /dev/null +++ b/src/status_im/utils/datetime.cljs @@ -0,0 +1,24 @@ +(ns status-im.utils.datetime + (:require [cljs-time.core :as t :refer [date-time now plus days hours before?]] + [cljs-time.coerce :refer [from-long to-long]] + [cljs-time.format :as format :refer [formatters + formatter + unparse]])) + +(def time-zone-offset (hours (- (/ (.getTimezoneOffset (js/Date.)) 60)))) + +(defn to-short-str [ms] + (let [date (from-long ms) + local (plus date time-zone-offset) + today-date (t/today) + today (date-time (t/year today-date) + (t/month today-date) + (t/day today-date)) + yesterday (plus today (days -1))] + (cond + (before? local yesterday) (unparse (formatter "dd MMM") local) + (before? local today) "Yesterday" + :else (unparse (formatters :hour-minute) local)))) + +(defn now-ms [] + (to-long (now))) diff --git a/src/status_im/utils/sms_listener.cljs b/src/status_im/utils/sms_listener.cljs new file mode 100644 index 0000000000..f00d54b7e9 --- /dev/null +++ b/src/status_im/utils/sms_listener.cljs @@ -0,0 +1,19 @@ +(ns status-im.utils.sms-listener + (:require [status-im.components.react :refer [android?]])) + +(def sms-listener (.-default (js/require "react-native-android-sms-listener"))) + +;; Only android is supported! + +(defn add-sms-listener + "Message format: {:originatingAddress string, :body string}. Returns + cancelable subscription." + [listen-fn] + (when android? + (.addListener sms-listener + (fn [message] + (listen-fn (js->clj message :keywordize-keys true)))))) + +(defn remove-sms-listener [subscription] + (when android? + (.remove subscription))) diff --git a/src/status_im/utils/utils.cljs b/src/status_im/utils/utils.cljs index 8a0be411d7..02d54d3f88 100644 --- a/src/status_im/utils/utils.cljs +++ b/src/status_im/utils/utils.cljs @@ -47,3 +47,8 @@ (.catch (or on-error (fn [error] (toast (str error)))))))) + +(defn truncate-str [s max] + (if (< max (count s)) + (str (subs s 0 (- max 3)) "...") + s))