diff --git a/src/status_im/components/drawer/styles.cljs b/src/status_im/components/drawer/styles.cljs index 0cb6ff24d0..6478a9c023 100644 --- a/src/status_im/components/drawer/styles.cljs +++ b/src/status_im/components/drawer/styles.cljs @@ -9,7 +9,8 @@ separator-color text1-color text2-color - text3-color]])) + text3-color + color-red]])) (def drawer-menu {:flex 1 @@ -27,14 +28,38 @@ :height 64}) (def name-container - {:margin-top 20 + {:margin-top -16 + :margin-bottom -16 :margin-left 16 + :margin-right 16}) + +(def name-input-wrapper + {}) + +(defn name-input-text [valid?] + {:color (if valid? text1-color + color-red) + :text-align :center}) + +(def status-container + {:margin-left 16 :margin-right 16 + :margin-top 4 :align-items :center}) +(def status-input + {:align-self "stretch" + :height 56 + :font-size 14 + :padding-left 4 + :line-height 20 + :text-align :center + :text-align-vertical :top + :color text2-color}) + (def menu-items-container {:flex 1 - :margin-top 50 + :margin-top 20 :align-items :stretch :flex-direction :column}) diff --git a/src/status_im/components/drawer/view.cljs b/src/status_im/components/drawer/view.cljs index e4fba90368..96730cfde0 100644 --- a/src/status_im/components/drawer/view.cljs +++ b/src/status_im/components/drawer/view.cljs @@ -1,17 +1,23 @@ (ns status-im.components.drawer.view (:require-macros [status-im.utils.views :refer [defview]]) - (:require [clojure.string :as s] + (:require [reagent.core :as r] [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [reagent.core :as r] - [status-im.components.react :refer [react-native - view + [clojure.string :as str] + [cljs.spec :as s] + [status-im.components.react :refer [view text + text-input image drawer-layout + touchable-without-feedback touchable-opacity]] - [status-im.resources :as res] + [status-im.components.text-field.view :refer [text-field]] [status-im.components.drawer.styles :as st] - [status-im.i18n :refer [label]])) + [status-im.profile.validations :as v] + [status-im.profile.handlers :refer [update-profile]] + [status-im.resources :as res] + [status-im.i18n :refer [label]] + [status-im.components.react :refer [dismiss-keyboard!]])) (defonce drawer-atom (atom)) @@ -22,7 +28,7 @@ (.closeDrawer @drawer-atom)) (defn user-photo [{:keys [photo-path]}] - [image {:source (if (s/blank? photo-path) + [image {:source (if (str/blank? photo-path) res/user-no-photo {:uri photo-path}) :style st/user-photo}]) @@ -37,47 +43,70 @@ name]]) (defview drawer-menu [] - [{:keys [name address photo-path]} [:get-current-account]] + [{:keys [name address photo-path status] :as account} [:get-current-account] + {new-name :name :as profile-edit-data} [:get :profile-edit] + keyboard-height [:get :keyboard-height]] [view st/drawer-menu - [view st/user-photo-container - [user-photo {:photo-path photo-path}]] - [view st/name-container - [text {:style st/name-text - :number-of-lines 1 - :font :default} - (if (= name address) - (label :t/user-anonymous) - name)]] - [view st/menu-items-container - [menu-item {:name (label :t/profile) - :handler #(dispatch [:navigate-to :my-profile])}] - [menu-item {:name (label :t/settings) - :handler (fn [] - ;; TODO not implemented - )}] - [menu-item {:name (label :t/discovery) - :handler #(dispatch [:navigate-to :discovery])}] - [menu-item {:name (label :t/contacts) - :handler #(dispatch [:navigate-to :contact-list])}] - [menu-item {:name (label :t/invite-friends) - :handler (fn [] - ;; TODO not implemented - )}] - [menu-item {:name (label :t/faq) - :handler (fn [])}]] - [view st/switch-users-container - [touchable-opacity {:onPress (fn [] - (close-drawer) - (dispatch [:navigate-to :accounts]) - ;; TODO not implemented - )} - [text {:style st/switch-users-text - :font :default} - (label :t/switch-users)]]]]) + [touchable-without-feedback {:on-press #(dismiss-keyboard!)} + [view st/drawer-menu + [touchable-opacity {:on-press #(dispatch [:navigate-to :my-profile])} + [view st/user-photo-container + [user-photo {:photo-path photo-path}]]] + [view st/name-container + [text-field + {:line-color :white + :focus-line-color :white + :placeholder (label :t/user-anonymous) + :editable true + :input-style (st/name-input-text (s/valid? ::v/name (or new-name name))) + :wrapper-style st/name-input-wrapper + :value (if (not= name address) + name) + :on-change-text #(dispatch [:set-in [:profile-edit :name] %]) + :on-end-editing #(update-profile account profile-edit-data)}]] + [view st/status-container + [text-input {:style st/status-input + :editable true + :multiline true + :blur-on-submit true + :maxLength 140 + :accessibility-label :input + :placeholder (label :t/profile-no-status) + :on-change-text #(dispatch [:set-in [:profile-edit :status] %]) + :on-blur #(update-profile account profile-edit-data) + :default-value status}]] + [view st/menu-items-container + [menu-item {:name (label :t/profile) + :handler #(dispatch [:navigate-to :my-profile])}] + [menu-item {:name (label :t/settings) + :handler (fn [] + ;; TODO not implemented + )}] + [menu-item {:name (label :t/discovery) + :handler #(dispatch [:navigate-to :discovery])}] + [menu-item {:name (label :t/contacts) + :handler #(dispatch [:navigate-to :contact-list])}] + [menu-item {:name (label :t/invite-friends) + :handler (fn [] + ;; TODO not implemented + )}] + [menu-item {:name (label :t/faq) + :handler (fn [])}]] + (when (= keyboard-height 0) + [view st/switch-users-container + [touchable-opacity {:onPress (fn [] + (close-drawer) + (dispatch [:navigate-to :accounts]) + ;; TODO not implemented + )} + [text {:style st/switch-users-text + :font :default} + (label :t/switch-users)]]])]]]) (defn drawer-view [items] - [drawer-layout {:drawerWidth 260 - :render-navigation-view #(r/as-element [drawer-menu]) - :ref (fn [drawer] - (reset! drawer-atom drawer))} + [drawer-layout {:drawerWidth 260 + :renderNavigationView #(r/as-element [drawer-menu]) + :onDrawerSlide dismiss-keyboard! + :ref (fn [drawer] + (reset! drawer-atom drawer))} items]) diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index c2cfbad64b..4cbdbcb3f4 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -8,11 +8,10 @@ (def color-gray "#838c93de") (def color-gray2 "#8f838c93") (def color-gray3 "#00000040") -(def color-white :white) -(def color-light-blue "#bbc4cb") +(def color-white "white") (def color-light-blue-transparent "#bbc4cb32") -(def color-dark-mint "#5fc48d") (def color-light-gray "#EEF2F5") +(def color-red "red") (def text1-color color-black) (def text1-disabled-color "#555555") diff --git a/src/status_im/components/text_field/view.cljs b/src/status_im/components/text_field/view.cljs index 988226722f..3a9c6402f6 100644 --- a/src/status_im/components/text_field/view.cljs +++ b/src/status_im/components/text_field/view.cljs @@ -144,10 +144,10 @@ label-font-size line-width current-value - max-line-width] :as state} (r/state component) + max-line-width]} (r/state component) {:keys [wrapper-style input-style label-hidden? line-color focus-line-color secure-text-entry label-color error-color error label value on-focus on-blur - on-change-text on-change editable] :as props} (merge default-props (r/props component)) + on-change-text on-change on-end-editing editable placeholder]} (merge default-props (r/props component)) line-color (if error error-color line-color) focus-line-color (if error error-color focus-line-color) label-color (if (and error (not float-label?)) error-color label-color) @@ -157,7 +157,7 @@ (when-not label-hidden? [animated-text {:style (st/label label-top label-font-size label-color)} label]) [text-input {:style (merge st/text-input input-style) - :placeholder "" + :placeholder (or placeholder "") :editable editable :secure-text-entry secure-text-entry :on-focus #(on-input-focus {:component component @@ -181,7 +181,9 @@ (r/set-state component {:current-value text}) (on-change-text text)) :on-change #(on-change %) - :default-value value}] + :default-value value + :on-end-editing (when on-end-editing + on-end-editing)}] [view {:style (st/underline-container line-color) :onLayout #(r/set-state component {:max-line-width (get-width %)})} [animated-view {:style (st/underline focus-line-color line-width)}]] diff --git a/src/status_im/profile/handlers.cljs b/src/status_im/profile/handlers.cljs index 9e7ee756a4..bade371834 100644 --- a/src/status_im/profile/handlers.cljs +++ b/src/status_im/profile/handlers.cljs @@ -6,7 +6,9 @@ [status-im.i18n :refer [label]] [status-im.utils.handlers :as u :refer [get-hashtags]] [status-im.utils.platform :refer [ios?]] - [clojure.string :as str])) + [clojure.string :as str] + [status-im.profile.validations :as v] + [cljs.spec :as s])) (defn message-user [identity] (when identity @@ -20,7 +22,11 @@ new-email :email new-status :status new-photo-path :photo-path}] - (let [new-name (if (or (not new-name) (str/blank? new-name)) name new-name) + (let [new-name (if (or (not new-name) + (str/blank? new-name) + (not (s/valid? ::v/name new-name))) + name + new-name) status-updated? (and (not= new-status nil) (not= status new-status))] (when status-updated? diff --git a/src/status_im/profile/screen.cljs b/src/status_im/profile/screen.cljs index 05016108a7..aa2e61a20a 100644 --- a/src/status_im/profile/screen.cljs +++ b/src/status_im/profile/screen.cljs @@ -3,6 +3,7 @@ (:require [re-frame.core :refer [subscribe dispatch]] [clojure.string :as str] [cljs.spec :as s] + [reagent.core :as r] [status-im.components.react :refer [view text text-input @@ -32,11 +33,7 @@ [view [touchable-highlight {:style st/back-btn-touchable :on-press (fn [] - (dispatch [:set :profile-edit {:edit? false - :name nil - :email nil - :status nil - :photo-path nil}]) + (dispatch [:set-in [:profile-edit :edit?] false]) (dispatch [:navigate-back]))} [view st/back-btn-container [icon :back st/back-btn-icon]]] @@ -77,10 +74,11 @@ (label :t/user-anonymous) username)] [text-input {:style st/status-input + :maxLength 140 :editable edit? :placeholder (label :t/profile-no-status) :on-change-text #(dispatch [:set-in [:profile-edit :status] %]) - :value status}]]) + :default-value status}]]) (defview profile [] [{whisper-identity :whisper-identity @@ -156,70 +154,82 @@ )} [view [text {:style st/report-user-text} (label :t/report-user)]]]]]]) -(defview my-profile [] +(defview my-profile-render [] [{public-key :public-key - address :address - username :name - email :email + address :address + username :name + email :email photo-path :photo-path - phone :phone - status :status - :as account} [:get-current-account] + phone :phone + status :status + :as account} [:get-current-account] {edit? :edit? new-name :name new-email :email new-status :status new-photo-path :photo-path :as profile-edit-data} [:get :profile-edit]] - [scroll-view {:style st/profile} - [status-bar] - [toolbar {:account account - :profile-edit-data profile-edit-data - :edit? edit?}] + [scroll-view {:style st/profile} + [status-bar] + [toolbar {:account account + :profile-edit-data profile-edit-data + :edit? edit?}] - [status-image-view {:account account - :photo-path (or new-photo-path photo-path) - :status (or new-status status) - :edit? edit?}] + [status-image-view {:account account + :photo-path (or new-photo-path photo-path) + :status (or new-status status) + :edit? edit?}] - [scroll-view st/profile-properties-container - [text-field - {:error (if-not (s/valid? ::v/name new-name) - (label :t/error-incorrect-name)) - :error-color "#7099e6" - :editable edit? - :input-style (if edit? - st/profile-input-text - st/profile-input-text-non-editable) - :wrapper-style st/profile-input-wrapper - :value (if (not= username address) - username) - :label (label :t/username) - :on-change-text #(dispatch [:set-in [:profile-edit :name] %])}] + [scroll-view st/profile-properties-container + [text-field + {:error (if-not (s/valid? ::v/name new-name) + (label :t/error-incorrect-name)) + :error-color "#7099e6" + :editable edit? + :input-style (if edit? + st/profile-input-text + st/profile-input-text-non-editable) + :wrapper-style st/profile-input-wrapper + :value (if (not= username address) + username) + :label (label :t/username) + :on-change-text #(dispatch [:set-in [:profile-edit :name] %])}] - [text-field - {:editable false - :input-style st/profile-input-text-non-editable - :wrapper-style st/profile-input-wrapper - :value (if (and phone (not (str/blank? phone))) - (format-phone-number phone)) - :label (label :t/phone-number)}] + [text-field + {:editable false + :input-style st/profile-input-text-non-editable + :wrapper-style st/profile-input-wrapper + :value (if (and phone (not (str/blank? phone))) + (format-phone-number phone)) + :label (label :t/phone-number)}] - [text-field - {:error (if-not (s/valid? ::v/email new-email) - (label :t/error-incorrect-email)) - :error-color "#7099e6" - :editable edit? - :input-style (if edit? - st/profile-input-text - st/profile-input-text-non-editable) - :wrapper-style st/profile-input-wrapper - :value (if (and email (not (str/blank? email))) - email) - :label (label :t/email) - :on-change-text #(dispatch [:set-in [:profile-edit :email] %])}] + [text-field + {:error (if-not (s/valid? ::v/email new-email) + (label :t/error-incorrect-email)) + :error-color "#7099e6" + :editable edit? + :input-style (if edit? + st/profile-input-text + st/profile-input-text-non-editable) + :wrapper-style st/profile-input-wrapper + :value (if (and email (not (str/blank? email))) + email) + :label (label :t/email) + :on-change-text #(dispatch [:set-in [:profile-edit :email] %])}] - [view st/qr-code-container - ;; TODO: this public key should be replaced by address - [qr-code {:value (str "ethereum:" public-key) - :size 220}]]]]) + [view st/qr-code-container + ;; TODO: this public key should be replaced by address + [qr-code {:value (str "ethereum:" public-key) + :size 220}]]]]) + +(defview my-profile [] + [{username :name + email :email} [:get-current-account]] + (r/create-class + {:component-will-mount + (fn [] + (dispatch [:set :profile-edit {:edit? false + :name username + :email email}])) + :reagent-render + my-profile-render}))