From ef57a5ca3510323d5bb80893847972c9a00181d5 Mon Sep 17 00:00:00 2001 From: Goran Jovic Date: Mon, 15 Jan 2018 17:16:48 +0100 Subject: [PATCH] feature #2906 - new profile screen --- src/status_im/translations/en.cljs | 8 +- src/status_im/ui/components/colors.cljs | 7 +- src/status_im/ui/components/styles.cljs | 10 +- src/status_im/ui/screens/profile/styles.cljs | 148 +++++++----- src/status_im/ui/screens/profile/views.cljs | 228 +++++++++---------- src/status_im/utils/ethereum/tokens.cljs | 6 +- 6 files changed, 226 insertions(+), 181 deletions(-) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 924e5f19e7..00fea83580 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -27,7 +27,9 @@ ;;drawer :switch-users "Switch users" - :logout "Logout" + :logout-title "Log out?" + :logout-are-you-sure "Are you sure you want\nto log out?" + :logout "Log out" :current-network "Current network" ;;home @@ -83,10 +85,13 @@ ;;profile :profile "Profile" :edit-profile "Edit profile" + :main-currency "Main currency" :message "Message" + :notifications "Notifications" :not-specified "Not specified" :public-key "Public key" :phone-number "Phone number" + :share-contact-code "Share my contact code" :update-status "Update your status..." :add-a-status "Add a status..." :status-prompt "Set your status. Using #hastags will help others discover you and talk about what's on your mind" @@ -378,6 +383,7 @@ :process-json "Process JSON" :error-processing-json "Error processing JSON" :rpc-url "RPC URL" + :network "Network" :remove-network "Remove network" :network-settings "Network settings" :offline-messaging-settings "Offline messages settings" diff --git a/src/status_im/ui/components/colors.cljs b/src/status_im/ui/components/colors.cljs index dbe3d62827..6d677f5017 100644 --- a/src/status_im/ui/components/colors.cljs +++ b/src/status_im/ui/components/colors.cljs @@ -1,6 +1,9 @@ (ns status-im.ui.components.colors) (def white "#ffffff") -(def white-light-transparent "rgba(255, 255, 255, 0.1)") ;; Used as icon background color on dark background +(def white-light-transparent "rgba(255, 255, 255, 0.1)") ;; Used as icon background color for a dark foreground (def white-transparent "rgba(255, 255, 255, 0.2)") ;; Used as icon color on dark background -(def blue "#4360df") ;; Used as main wallet color \ No newline at end of file +(def blue "#4360df") ;; Used as main wallet color +(def black "#000000") ;; Used as the default text color +(def gray "#939ba1") ;; Used as a background for a light foreground +(def red "#ff2d55") ;; Used to highlight errors or "dangerous" actions \ No newline at end of file diff --git a/src/status_im/ui/components/styles.cljs b/src/status_im/ui/components/styles.cljs index da5109f30e..810f1d25fb 100644 --- a/src/status_im/ui/components/styles.cljs +++ b/src/status_im/ui/components/styles.cljs @@ -1,4 +1,5 @@ -(ns status-im.ui.components.styles) +(ns status-im.ui.components.styles + (:require [status-im.utils.platform :as platform])) ;; TODO(oskarth): Make a palette of all these colors @@ -157,3 +158,10 @@ (def main-container {:background-color color-white :flex 1}) + +;; TODO(goranjovic): replace all platform conditional uppercase styling with a reference to this var +(def uppercase? + (condp = platform/platform + "android" true + "ios" false + false)) diff --git a/src/status_im/ui/screens/profile/styles.cljs b/src/status_im/ui/screens/profile/styles.cljs index 15514f8780..471d247f3c 100644 --- a/src/status_im/ui/screens/profile/styles.cljs +++ b/src/status_im/ui/screens/profile/styles.cljs @@ -1,32 +1,30 @@ (ns status-im.ui.screens.profile.styles - (:require [status-im.ui.components.styles - :as styles - :refer - [color-black - color-gray4 - color-gray5 - color-light-blue - color-light-gray - color-white - text1-color]] + (:require [status-im.ui.components.styles :as styles] + [status-im.ui.components.colors :as colors] [status-im.utils.platform :as platform]) (:require-macros [status-im.utils.styles :refer [defstyle]])) +(defstyle toolbar-edit-text + {:padding-right 16 + :color colors/blue + :ios {:font-size 15} + :android {:font-size 14}}) + (def profile {:flex 1 - :background-color color-light-gray + :background-color colors/white :flex-direction :column}) (def profile-form - {:background-color color-white + {:background-color colors/white :padding 16}) (def edit-my-profile-form - {:background-color color-white + {:background-color colors/white :flex 1}) (defstyle profile-info-container - {:background-color color-white}) + {:background-color colors/white}) (def profile-info-item-button {:padding 16}) @@ -37,7 +35,7 @@ :padding-top 6}) (defstyle status-prompt-text - {:color color-gray4 + {:color colors/gray :ios {:font-size 14 :line-height 25 :letter-spacing -0.2} @@ -45,14 +43,16 @@ :font-size 12}}) (def profile-status-container - {:background-color color-light-gray + {:background-color colors/gray :margin-top 16 :border-radius 4 :padding 16 :max-height 114}) (def profile-badge - {:flex-direction :row}) + {:flex-direction :column + :justify-content :center + :align-items :center}) (def edit-profile-badge {:flex-direction :row @@ -69,27 +69,27 @@ {:padding-top 25}) (def edit-name-title - {:color color-gray4 + {:color colors/gray :ios {:font-size 13 :letter-spacing -0.1} :android {:font-size 12}}) (defstyle profile-name-text - {:ios {:font-size 17 - :letter-spacing -0.2} - :android {:color color-black - :font-size 16}}) + {:margin-top 8 + :font-size 15 + :text-align :center + :ios {:letter-spacing -0.2} + :android {:color colors/black}}) (def profile-badge-name-container {:flex 1 - :justify-content :center - :padding-left 16}) + :justify-content :center}) (def profile-activity-status-container {:margin-top 4}) (defstyle profile-activity-status-text - {:color color-gray4 + {:color colors/gray :ios {:font-size 14 :line-height 20 :letter-spacing -0.2} @@ -107,24 +107,19 @@ {:flex 1 :padding-right (if options 16 40)}) -(defstyle profile-setting-title - {:color color-gray4 - :ios {:font-size 14 - :letter-spacing -0.2} - :android {:font-size 12}}) +(defstyle profile-settings-title + {:color colors/gray + :margin-left 16 + :margin-top 18 + :margin-bottom 20 + :font-size 14 + :ios {:letter-spacing -0.2}}) (defstyle profile-setting-text {:ios {:font-size 17 :letter-spacing -0.2} :android {:font-size 16 - :color color-black}}) - -(defstyle logout-text - {:padding-left 16 - :color styles/color-red - :ios {:font-size 17 - :letter-spacing -0.2} - :android {:font-size 16}}) + :color colors/black}}) (defstyle profile-setting-spacing {:ios {:height 10} @@ -132,45 +127,48 @@ (def profile-setting-text-empty (merge profile-setting-text - {:color color-gray4})) + {:color colors/gray})) -(def info-item-separator +(def settings-item-separator {:margin-left 16}) -(defstyle network-settings +(defstyle settings-item {:padding-horizontal 16 :flex-direction :row :align-items :center - :background-color color-white - :android {:height 72} - :ios {:height 64}}) + :background-color colors/white + :height 52}) (defstyle offline-messaging-settings {:padding-horizontal 16 :flex-direction :row :align-items :center - :background-color color-white + :background-color colors/white :android {:height 72} :ios {:height 64}}) -(def network-settings-text - (merge {:flex 1} - profile-setting-text)) +(defstyle settings-item-text + {:flex 1 + :font-size 15 + :ios {:letter-spacing -0.2} + :android {:color colors/black}}) -(def offline-messaging-settings-text - (merge {:flex 1} - profile-setting-text)) +(def settings-item-value + {:padding-right 10 + :font-size 15 + :color colors/gray}) + +(defstyle logout-text + (merge settings-item-text + {:color colors/red})) (def edit-line-color (if platform/ios? - (str color-gray5 "80") - color-gray5)) - -(def profile-focus-line-color - color-light-blue) + (str styles/color-gray5 "80") + styles/color-gray5)) (defstyle profile-name-input - {:color text1-color + {:color styles/text1-color :ios {:font-size 17 :padding-bottom 0 :line-height 17 @@ -183,7 +181,7 @@ (defstyle profile-status-input {:line-height 24 ;;TODO doesnt' work for multiline because a bug in the RN - :color text1-color + :color colors/black :padding-left 0 :ios {:font-size 17 :padding-bottom 0 @@ -197,14 +195,14 @@ :padding-bottom 0}}) (defstyle profile-status-text - {:color text1-color + {:color colors/black :line-height 24 :ios {:font-size 17 :letter-spacing -0.2} :android {:font-size 16}}) (defstyle edit-profile-status - {:background-color color-light-gray + {:background-color styles/color-light-gray :border-radius 4 :height 90 :padding-horizontal 16 @@ -218,6 +216,34 @@ (def add-a-status (merge profile-status-text - {:color color-gray4})) + {:color colors/gray})) (def network-info {:background-color :white}) + +(def share-contact-code + {:margin-horizontal 16 + :flex-direction :row + :justify-content :space-between + :align-items :center + :height 42 + :border-radius 8 + :background-color styles/color-blue4-transparent}) + +(def share-contact-code-text-container + {:padding-left 16 + :padding-bottom 1 + :flex 0.9 + :flex-direction :row + :justify-content :center + :align-items :center}) + +(def share-contact-code-text + {:color colors/blue + :font-size 15}) + +(def share-contact-icon-container + {:border-radius 50 + :flex 0.1 + :padding-right 5 + :align-items :center + :justify-content :center}) diff --git a/src/status_im/ui/screens/profile/views.cljs b/src/status_im/ui/screens/profile/views.cljs index 8036128e70..33b772c3d7 100644 --- a/src/status_im/ui/screens/profile/views.cljs +++ b/src/status_im/ui/screens/profile/views.cljs @@ -1,24 +1,24 @@ (ns status-im.ui.screens.profile.views (:require [clojure.string :as string] - [re-frame.core :refer [dispatch]] - [status-im.ui.components.action-button.action-button - :refer - [action-button action-button-disabled action-separator]] - [status-im.ui.components.action-button.styles :refer [actions-list]] - [status-im.ui.components.chat-icon.screen :refer [my-profile-icon]] + [re-frame.core :as re-frame] + [status-im.ui.components.action-button.action-button :as action-button] + [status-im.ui.components.action-button.styles :as action-button.styles] + [status-im.ui.components.chat-icon.screen :as chat-icon.screen] [status-im.ui.components.common.common :as common] - [status-im.ui.components.context-menu :refer [context-menu]] - [status-im.ui.components.list-selection :refer [share-options]] + [status-im.ui.components.context-menu :as context-menu] + [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.react :as react] [status-im.ui.components.icons.vector-icons :as vector-icons] - [status-im.ui.components.status-bar.view :refer [status-bar]] - [status-im.ui.components.styles :refer [color-blue]] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.components.styles :as component.styles] + [status-im.ui.components.colors :as colors] [status-im.ui.components.toolbar.actions :as actions] [status-im.ui.components.toolbar.view :as toolbar] - [status-im.i18n :refer [label]] + [status-im.i18n :as i18n] [status-im.ui.screens.profile.styles :as styles] + [status-im.ui.components.colors :as colors] + [status-im.utils.utils :as utils] [status-im.utils.datetime :as time] - [status-im.utils.utils :refer [hash-tag?]] [status-im.utils.config :as config] [status-im.utils.platform :as platform] [status-im.protocol.core :as protocol] @@ -29,9 +29,11 @@ [toolbar/toolbar {} nil [toolbar/content-title ""] - [toolbar/actions - [(actions/opts [{:value #(dispatch [:my-profile/edit-profile]) - :text (label :t/edit)}])]]]) + [react/touchable-highlight + {:on-press #(re-frame/dispatch [:my-profile/edit-profile])} + [react/view + [react/text {:style styles/toolbar-edit-text + :uppercase? component.styles/uppercase?} (i18n/label :t/edit)]]]]) (defn profile-toolbar [contact] [toolbar/toolbar {} @@ -40,8 +42,8 @@ [toolbar/actions (when (and (not (:pending? contact)) (not (:unremovable? contact))) - [(actions/opts [{:value #(dispatch [:hide-contact contact]) - :text (label :t/remove-from-contacts)}])])]]) + [(actions/opts [{:value #(re-frame/dispatch [:hide-contact contact]) + :text (i18n/label :t/remove-from-contacts)}])])]]) (defn online-text [last-online] (let [last-online-date (time/to-date last-online) @@ -49,12 +51,12 @@ (if (and (pos? last-online) (<= last-online-date now-date)) (time/time-ago last-online-date) - (label :t/active-unknown)))) + (i18n/label :t/active-unknown)))) (defn profile-badge [{:keys [name last-online] :as contact}] [react/view styles/profile-badge - [my-profile-icon {:account contact - :edit? false}] + [chat-icon.screen/my-profile-icon {:account contact + :edit? false}] [react/view styles/profile-badge-name-container [react/text {:style styles/profile-name-text :number-of-lines 1} @@ -65,30 +67,30 @@ (online-text last-online)]])]]) (defn profile-actions [{:keys [pending? whisper-identity dapp?]} chat-id] - [react/view actions-list + [react/view action-button.styles/actions-list (if pending? - [action-button {:label (label :t/add-to-contacts) - :icon :icons/add - :icon-opts {:color :blue} - :on-press #(dispatch [:add-pending-contact chat-id])}] - [action-button-disabled {:label (label :t/in-contacts) :icon :icons/ok}]) - [action-separator] - [action-button {:label (label :t/start-conversation) - :icon :icons/chats - :icon-opts {:color :blue} - :on-press #(dispatch [:profile/send-message whisper-identity])}] + [action-button/action-button {:label (i18n/label :t/add-to-contacts) + :icon :icons/add + :icon-opts {:color :blue} + :on-press #(re-frame/dispatch [:add-pending-contact chat-id])}] + [action-button/action-button-disabled {:label (i18n/label :t/in-contacts) :icon :icons/ok}]) + [action-button/action-separator] + [action-button/action-button {:label (i18n/label :t/start-conversation) + :icon :icons/chats + :icon-opts {:color :blue} + :on-press #(re-frame/dispatch [:profile/send-message whisper-identity])}] (when-not dapp? [react/view - [action-separator] - [action-button {:label (label :t/send-transaction) - :icon :icons/arrow-right - :icon-opts {:color :blue} - :on-press #(dispatch [:profile/send-transaction chat-id whisper-identity])}]])]) + [action-button/action-separator] + [action-button/action-button {:label (i18n/label :t/send-transaction) + :icon :icons/arrow-right + :icon-opts {:color :blue} + :on-press #(re-frame/dispatch [:profile/send-transaction chat-id whisper-identity])}]])]) (defn profile-info-item [{:keys [label value options text-mode empty-value? accessibility-label]}] [react/view styles/profile-setting-item [react/view (styles/profile-info-text-container options) - [react/text {:style styles/profile-setting-title} + [react/text {:style styles/profile-settings-title} label] [react/view styles/profile-setting-spacing] [react/text {:style (if empty-value? @@ -99,27 +101,27 @@ :accessibility-label accessibility-label} value]] (when options - [context-menu + [context-menu/context-menu [vector-icons/icon :icons/options] options nil styles/profile-info-item-button])]) (defn show-qr [contact qr-source qr-value] - #(dispatch [:navigate-to-modal :qr-code-view {:contact contact - :qr-source qr-source - :qr-value qr-value}])) + #(re-frame/dispatch [:navigate-to-modal :qr-code-view {:contact contact + :qr-source qr-source + :qr-value qr-value}])) (defn profile-options [contact k text] (into [] (concat [{:value (show-qr contact k text) - :text (label :t/show-qr)}] + :text (i18n/label :t/show-qr)}] (when text - (share-options text))))) + (list-selection/share-options text))))) (defn profile-info-address-item [{:keys [address] :as contact}] [profile-info-item - {:label (label :t/address) + {:label (i18n/label :t/address) :value address :options (profile-options contact :address address) :text-mode :middle @@ -127,23 +129,23 @@ (defn profile-info-public-key-item [public-key contact] [profile-info-item - {:label (label :t/public-key) + {:label (i18n/label :t/public-key) :value public-key :options (profile-options contact :public-key public-key) :text-mode :middle :accessibility-label :profile-public-key}]) -(defn info-item-separator [] - [common/separator styles/info-item-separator]) +(defn settings-item-separator [] + [common/separator styles/settings-item-separator]) (defn tag-view [tag] - [react/text {:style {:color color-blue} + [react/text {:style {:color colors/blue} :font :medium} (str tag " ")]) (defn colorize-status-hashtags [status] (for [[i status] (map-indexed vector (string/split status #" "))] - (if (hash-tag? status) + (if (utils/hash-tag? status) ^{:key (str "item-" i)} [tag-view status] ^{:key (str "item-" i)} @@ -151,85 +153,82 @@ (defn profile-info-phone-item [phone & [options]] (let [phone-empty? (or (nil? phone) (string/blank? phone)) - phone-text (if phone-empty? - (label :t/not-specified) - phone)] - [profile-info-item {:label (label :t/phone-number) + phone-text (if phone-empty? + (i18n/label :t/not-specified) + phone)] + [profile-info-item {:label (i18n/label :t/phone-number) :value phone-text :options options :empty-value? phone-empty? :accessibility-label :profile-phone-number}])) -(defn network-settings [] - [react/touchable-highlight - {:on-press #(dispatch [:navigate-to :network-settings])} - [react/view styles/network-settings - [react/text {:style styles/network-settings-text} - (label :t/network-settings)] - [vector-icons/icon :icons/forward {:color :gray}]]]) +(defn settings-title [title] + [react/text {:style styles/profile-settings-title} + title]) -(defn offline-messaging-settings [] +(defn settings-item [label-kw value action-fn active?] [react/touchable-highlight - {:on-press #(dispatch [:navigate-to :offline-messaging-settings])} - [react/view styles/offline-messaging-settings - [react/text {:style styles/offline-messaging-settings-text} - (label :t/offline-messaging-settings)] - [vector-icons/icon :icons/forward {:color :gray}]]]) + {:on-press action-fn + :disabled (not active?)} + [react/view styles/settings-item + [react/text {:style styles/settings-item-text} + (i18n/label label-kw)] + [react/text {:style styles/settings-item-value + :uppercase? component.styles/uppercase?} value] + (when active? + [vector-icons/icon :icons/forward {:color colors/gray}])]]) -(defn profile-info [{:keys [whisper-identity status phone] :as contact}] +(defn profile-info [{:keys [whisper-identity phone] :as contact}] [react/view [profile-info-address-item contact] - [info-item-separator] + [settings-item-separator] [profile-info-public-key-item whisper-identity contact] - [info-item-separator] + [settings-item-separator] [profile-info-phone-item phone]]) -(defn save-profile! [] - (when-let [save-event @(re-frame/subscribe [:my-profile.drawer/save-event])] - (re-frame/dispatch [save-event]))) - (defn navigate-to-accounts [] - (save-profile!) ;; TODO(rasom): probably not the best place for this call (protocol/stop-whisper!) (re-frame/dispatch [:navigate-to :accounts])) +(defn handle-logout [] + (utils/show-confirmation (i18n/label :t/logout-title) + (i18n/label :t/logout-are-you-sure) + (i18n/label :t/logout) navigate-to-accounts)) + (defn logout [] [react/view {} [react/touchable-highlight - {:on-press navigate-to-accounts} - [react/view - [react/text {:style styles/logout-text - :font (if platform/android? :medium :default)} - (label :t/logout)]]]]) + {:on-press handle-logout} + [react/view styles/settings-item + [react/text {:style styles/logout-text + :font (if platform/android? :medium :default)} + (i18n/label :t/logout)]]]]) -(defn my-profile-info [{:keys [public-key status phone] :as contact}] +(defn my-profile-settings [{:keys [network networks]}] [react/view - [profile-info-address-item contact] - [info-item-separator] - [profile-info-public-key-item public-key contact] - [info-item-separator] - [profile-info-phone-item - phone - [{:value #(dispatch [:my-profile/update-phone-number]) - :text (label :t/edit)}]] - [info-item-separator] - [network-settings] + [settings-title (i18n/label :t/settings)] + [settings-item :t/main-currency "USD" #() false] + [settings-item-separator] + [settings-item :t/notifications "" #() true] + [settings-item-separator] + [settings-item :t/network (get-in networks [network :name]) + #(re-frame/dispatch [:navigate-to :network-settings]) true] (when config/offline-inbox-enabled? - [info-item-separator]) + [settings-item-separator]) (when config/offline-inbox-enabled? - [offline-messaging-settings]) - [logout]]) + [settings-item :t/offline-messaging-settings "" + #(re-frame/dispatch [:navigate-to :offline-messaging-settings]) true])]) (defn profile-status [status & [edit?]] [react/view styles/profile-status-container (if (or (nil? status) (string/blank? status)) - [react/touchable-highlight {:on-press #(dispatch [:my-profile/edit-profile :edit-status])} + [react/touchable-highlight {:on-press #(re-frame/dispatch [:my-profile/edit-profile :edit-status])} [react/view [react/text {:style styles/add-a-status} - (label :t/add-a-status)]]] + (i18n/label :t/add-a-status)]]] [react/scroll-view - [react/touchable-highlight {:on-press (when edit? #(dispatch [:my-profile/edit-profile :edit-status]))} + [react/touchable-highlight {:on-press (when edit? #(re-frame/dispatch [:my-profile/edit-profile :edit-status]))} [react/view [react/text {:style styles/profile-status-text} (colorize-status-hashtags status)]]]])]) @@ -239,34 +238,35 @@ [common/network-info] [common/separator]]) +(defn share-contact-code [current-account public-key] + [react/touchable-highlight {:on-press (show-qr current-account :public-key public-key)} + [react/view styles/share-contact-code + [react/view styles/share-contact-code-text-container + [react/text {:style styles/share-contact-code-text + :uppercase? component.styles/uppercase?} + (i18n/label :t/share-contact-code)]] + [react/view styles/share-contact-icon-container + [vector-icons/icon :icons/qr {:color colors/blue}]]]]) + (defview my-profile [] - (letsubs [{:keys [status public-key] :as current-account} [:get-current-account]] + (letsubs [{:keys [public-key] :as current-account} [:get-current-account]] [react/view styles/profile [my-profile-toolbar] - [network-info] [react/scroll-view [react/view styles/profile-form - [profile-badge current-account] - [profile-status status true]] - [common/form-spacer] - [react/view actions-list - [action-button {:label (label :t/show-qr) - :icon :icons/qr - :icon-opts {:color :blue} - :on-press (show-qr current-account :public-key public-key)}]] - [common/form-spacer] + [profile-badge current-account]] + [react/view action-button.styles/actions-list + [share-contact-code current-account public-key]] [react/view styles/profile-info-container - [my-profile-info current-account] - [common/bottom-shadow]]]])) + [my-profile-settings current-account]] + [logout]]])) (defview profile [] - (letsubs [{:keys [pending? - status - whisper-identity] + (letsubs [{:keys [status] :as contact} [:contact] - chat-id [:get :current-chat-id]] + chat-id [:get :current-chat-id]] [react/view styles/profile - [status-bar] + [status-bar/status-bar] [profile-toolbar contact] [network-info] [react/scroll-view diff --git a/src/status_im/utils/ethereum/tokens.cljs b/src/status_im/utils/ethereum/tokens.cljs index 2b76f805a8..04fc7d8080 100644 --- a/src/status_im/utils/ethereum/tokens.cljs +++ b/src/status_im/utils/ethereum/tokens.cljs @@ -1,5 +1,4 @@ (ns status-im.utils.ethereum.tokens - (:require [status-im.ui.components.styles :as styles]) (:require-macros [status-im.utils.ethereum.macros :refer [resolve-icons]])) (defn- asset-border [color] @@ -9,7 +8,10 @@ :symbol :ETH :decimals 18 :icon {:source (js/require "./resources/images/assets/ethereum.png") - :style (asset-border styles/color-light-blue-transparent)}}) + ;; TODO(goranjovic) find a better place to set UI info + ;; like colors. Removed the reference to component.styles to + ;; avoid circular dependency between namespaces. + :style (asset-border "#628fe333")}}) (defn ethereum? [k] (= k (:symbol ethereum)))