diff --git a/android/app/src/main/res/drawable-hdpi/icon_arrow_right_gray.png b/android/app/src/main/res/drawable-hdpi/icon_arrow_right_gray.png new file mode 100644 index 0000000000..e14ee1c07b Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/icon_arrow_right_gray.png differ diff --git a/android/app/src/main/res/drawable-mdpi/icon_arrow_right_gray.png b/android/app/src/main/res/drawable-mdpi/icon_arrow_right_gray.png new file mode 100644 index 0000000000..84d63cba19 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/icon_arrow_right_gray.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/icon_arrow_right_gray.png b/android/app/src/main/res/drawable-xhdpi/icon_arrow_right_gray.png new file mode 100644 index 0000000000..0d73c2ebb3 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/icon_arrow_right_gray.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_arrow_right_gray.png b/android/app/src/main/res/drawable-xxhdpi/icon_arrow_right_gray.png new file mode 100644 index 0000000000..12de7f81b5 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/icon_arrow_right_gray.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_arrow_right_gray.png b/android/app/src/main/res/drawable-xxxhdpi/icon_arrow_right_gray.png new file mode 100644 index 0000000000..f43ee037de Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/icon_arrow_right_gray.png differ diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_right_gray.imageset/Contents.json b/ios/StatusIm/Images.xcassets/icon_arrow_right_gray.imageset/Contents.json new file mode 100644 index 0000000000..fc3b9b2484 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/icon_arrow_right_gray.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_arrow_right_gray.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/StatusIm/Images.xcassets/icon_arrow_right_gray.imageset/icon_arrow_right_gray.png b/ios/StatusIm/Images.xcassets/icon_arrow_right_gray.imageset/icon_arrow_right_gray.png new file mode 100644 index 0000000000..0d73c2ebb3 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/icon_arrow_right_gray.imageset/icon_arrow_right_gray.png differ diff --git a/src/status_im/components/drawer/styles.cljs b/src/status_im/components/drawer/styles.cljs index 24e95b4d5b..6c7b776c59 100644 --- a/src/status_im/components/drawer/styles.cljs +++ b/src/status_im/components/drawer/styles.cljs @@ -1,92 +1,166 @@ (ns status-im.components.drawer.styles - (:require [status-im.components.styles :refer [color-white - text1-color - text2-color - text3-color - color-red]] - [status-im.utils.platform :as p])) + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) + (:require [status-im.components.styles :as common])) -(def drawer-menu +(def drawer {:flex 1 - :background-color color-white - :flex-direction :column}) + :background-color common/color-white + :justify-content :space-between}) + +;; profile + +(def upper-container + {:margin 16 + :margin-top 0}) + +(def profile-container + {:padding 16 + :border-radius 8 + :background-color common/color-light-blue4}) (def user-photo-container - {:margin-top 40 - :align-items :center - :justify-content :center}) - -(def user-photo - {:border-radius 32 - :width 64 - :height 64}) - -(def name-container - {:margin-top (if p/ios? -13 -19) - :margin-bottom -16 - :margin-left 16 - :margin-right 16}) + {:height 52 + :width 52}) (def name-input-wrapper - {}) + {:margin-top 24 + :padding 0 + :height 20}) -(defn name-input-text [valid?] - {:color (if valid? text1-color - color-red) - :text-align :center}) +(defnstyle name-input-text [valid?] + {:line-height 24 + :height 20 + :padding 0 + :color (if valid? common/color-black common/color-red) + :android {:font-size 16} + :ios {:font-size 17}}) (def status-container - {:margin-left 16 - :margin-right 16 - :flex-direction :row - :margin-top 5 - :justify-content :center}) + {:flex-direction :row + :margin-top 3}) -(def status-view - {:min-height 56 - :width 200 - :font-size 14 - :text-align :center +(defstyle status-input-view + {:min-height 67 + :width 236 + :font-size 15 + :line-height 21 + :padding-left 0 + :padding-top 5 + :padding-bottom 0 + :margin-bottom 0 :text-align-vertical :top - :color text2-color}) + :color common/color-black}) -(def status-input - (merge status-view - {:padding-left 4 - :padding-top (if p/ios? 0 5)})) +(defnstyle status-view [placeholder?] + (merge status-input-view + {:color (if placeholder? common/color-gray common/color-black) + :min-height 0 + :ios {:padding-top 10}})) -(def status-text - (merge status-view - {:padding-left 0 - :padding-top 5})) +(def options-button + {:position :absolute + :top 16 + :right 16}) -(def menu-items-container - {:flex 1 - :margin-top 20 - :align-items :stretch - :flex-direction :column}) +;; network -(def menu-item-touchable - {:height 48 - :paddingLeft 16 - :paddingTop 14}) +(def network-label-container + {:margin-top 16}) -(def menu-item-text - {:font-size 14 - :line-height 21 - :color text1-color}) +(defstyle network-label + {:color common/color-gray4 + :android {:font-size 12} + :ios {:font-size 14}}) -(def name-text - {:color text1-color +(def network-title + {:color common/color-gray6 :font-size 16}) -(def switch-users-container - {:padding-vertical 36 - :align-items :center}) +;; transactions -(def switch-users-text - {:font-size 14 - :line-height 21 - :color text3-color}) +(def transactions-list-separator + {:margin-left 48}) -(def feedback {:text-align :center}) +(def empty-transactions-title-container + {:margin-bottom 32 + :align-items :center}) + +(defstyle transactions-title-container + {:margin-left 16 + :android {:margin-bottom 16} + :ios {:margin-bottom 8}}) + +(defstyle transactions-title + {:color common/color-gray4 + :android {:font-size 12} + :ios {:font-size 14}}) + +(def transaction + {:padding 16 + :flex-direction :row}) + +(defstyle transaction-icon + {:width 24 + :height 24 + :margin-right 8 + :android {:margin-top 2}}) + +(def transaction-info + {:width 180}) + +(def transaction-value-container + {:flex-direction :row}) + +(def transaction-value + {:font-size 20 + :line-height 22 + :color common/color-black}) + +(def transaction-unit + {:font-size 20 + :line-height 22 + :color common/color-gray + :margin-left 8}) + +(def transaction-details-container + {:margin-top 8 + :flex-direction :row}) + +(defstyle transaction-to + {:line-height 16 + :color common/color-gray4 + :android {:font-size 12} + :ios {:font-size 14}}) + +(defstyle transaction-recipient + {:line-height 16 + :margin-left 4 + :color common/color-black + :flex-shrink 1 + :android {:font-size 12} + :ios {:font-size 14}}) + +(defstyle transaction-time + {:line-height 16 + :color common/color-gray4 + :margin-left 8 + :android {:font-size 12} + :ios {:font-size 14}}) + +(def transaction-picture + {:margin-top 3 + :margin-left 16 + :min-width 40 + :min-height 40}) + +(def view-all-transactions-button + {:height 52 + :justify-content :center + :align-items :center + :border-top-width 1 + :border-top-color common/color-light-gray2}) + +(defstyle view-all-transactions-text + {:color common/color-light-blue + :android {:font-size 14} + :ios {:font-size 17}}) diff --git a/src/status_im/components/drawer/view.cljs b/src/status_im/components/drawer/view.cljs index 9977df928a..ef304f3eac 100644 --- a/src/status_im/components/drawer/view.cljs +++ b/src/status_im/components/drawer/view.cljs @@ -1,130 +1,176 @@ (ns status-im.components.drawer.view (:require-macros [status-im.utils.views :refer [defview]]) - (:require [reagent.core :as r] - [re-frame.core :refer [subscribe dispatch dispatch-sync]] + (:require [cljs.spec :as s] [clojure.string :as str] - [cljs.spec :as s] + [reagent.core :as r] + [re-frame.core :as rf] + [status-im.accessibility-ids :as id] + [status-im.components.chat-icon.screen :as ci] + [status-im.components.common.common :as common] + [status-im.components.context-menu :as context-menu] + [status-im.components.drawer.styles :as st] [status-im.components.react :refer [view text text-input - image + icon + list-item + list-view drawer-layout touchable-without-feedback - touchable-opacity]] - [status-im.components.text-field.view :refer [text-field]] - [status-im.components.status-view.view :refer [status-view]] - [status-im.components.drawer.styles :as st] + touchable-highlight + touchable-opacity + dismiss-keyboard!]] + [status-im.components.status-view.view :as status-view] + [status-im.i18n :as i18n] [status-im.profile.validations :as v] - [status-im.utils.gfycat.core :refer [generate-gfy]] - [status-im.utils.utils :refer [clean-text]] - [status-im.i18n :refer [label]] - [status-im.accessibility-ids :as id] - [status-im.components.react :refer [dismiss-keyboard!]] - [clojure.string :as str] - [status-im.components.chat-icon.screen :as ci])) + [status-im.utils.datetime :as time] + [status-im.utils.gfycat.core :as gfycat] + [status-im.utils.listview :as lw] + [status-im.utils.platform :as platform] + [status-im.utils.utils :as utils])) (defonce drawer-atom (atom)) - -(defn open-drawer [] - (.openDrawer @drawer-atom)) - -(defn close-drawer [] - (.closeDrawer @drawer-atom)) - -(defn menu-item [{:keys [name handler]}] - [touchable-opacity {:style st/menu-item-touchable - :onPress (fn [] - (close-drawer) - (handler))} - [text {:style st/menu-item-text - :font :default} - name]]) +(defn open-drawer [] (.openDrawer @drawer-atom)) +(defn close-drawer [] (.closeDrawer @drawer-atom)) (defn- update-status [new-status] (when-not (str/blank? new-status) - (dispatch [:check-status-change new-status]) - (dispatch [:account-update {:status new-status}]) - (dispatch [:set-in [:profile-edit :status] new-status]))) + (rf/dispatch [:check-status-change new-status]) + (rf/dispatch [:account-update {:status new-status}]) + (rf/dispatch [:set-in [:profile-edit :status] new-status]))) -(defn drawer-menu [] - (let - [account (subscribe [:get-current-account]) - profile (subscribe [:get :profile-edit]) - keyboard-height (subscribe [:get :keyboard-height]) - placeholder (generate-gfy) - status-edit? (r/atom false) - status-text (r/atom nil)] +(defview profile-picture [] + [account [:get-current-account]] + [touchable-opacity {:on-press #(rf/dispatch [:navigate-to :my-profile]) + :style st/user-photo-container} + [view + [ci/chat-icon (:photo-path account) {:size 52}]]]) + +(defview name-input [placeholder] + [account [:get-current-account] + new-name [:get-in [:profile-edit :name]]] + (let [current-name (:name account)] + [view {:style st/name-input-wrapper} + [text-input + {:placeholder placeholder + :style (st/name-input-text (s/valid? ::v/name (or new-name current-name))) + :font (if platform/ios? :medium :default) + :default-value (or new-name current-name) + :on-change-text #(rf/dispatch [:set-in [:profile-edit :name] %]) + :on-end-editing #(do + (rf/dispatch [:set-in [:profile-edit :name] nil]) + (when (s/valid? ::v/name new-name) + (rf/dispatch [:account-update {:name (utils/clean-text new-name)}])))}]])) + +(defview status-input [] + [account [:get-current-account] + status-edit? (r/atom false) + status-text (r/atom nil)] + (let [status (:status account) + placeholder (i18n/label :t/update-status)] + [view st/status-container + (if @status-edit? + [text-input {:style st/status-input-view + :multiline true + :auto-focus true + :focus @status-edit? + :max-length 140 + :accessibility-label id/drawer-status-input + :placeholder placeholder + :default-value status + :on-blur #(do + (reset! status-edit? false) + (update-status @status-text)) + :on-change-text #(let [new-status (utils/clean-text %)] + (reset! status-text new-status) + (if (str/includes? % "\n") + (do + (reset! status-edit? false) + (update-status new-status)) + (rf/dispatch [:set-in [:profile-edit :status] new-status])))}] + [status-view/status-view {:style (st/status-view (str/blank? status)) + :on-press #(reset! status-edit? true) + :number-of-lines 3 + :status (if (str/blank? status) placeholder status)}])])) + +(defview transaction-list-item [{:keys [to value timestamp] :as transaction}] + [recipient [:contact-by-address to]] + (let [eth-value (.fromWei js/Web3.prototype value "ether") + value (i18n/label-number eth-value) + recipient-name (or (:name recipient) to)] + [touchable-highlight {:on-press #(rf/dispatch [:navigate-to-modal :transaction-details transaction])} + [view {:style st/transaction} + [icon :arrow_right_gray st/transaction-icon] + [view {:style st/transaction-info} + [view {:style st/transaction-value-container} + [text {:style st/transaction-value :font :medium} value] + [text {:style st/transaction-unit} "ETH"]] + [view {:style st/transaction-details-container} + [text {:style st/transaction-to} (i18n/label :t/to)] + [text {:style st/transaction-recipient :number-of-lines 1} recipient-name] + [text {:style st/transaction-time} (time/format-date "dd MMM hh:mm" (time/to-date timestamp))]]] + [view {:style st/transaction-picture} + (when recipient + [ci/chat-icon (:photo-path recipient) {:size 40}])]]])) + +(defn render-separator-fn [transactions-count] + (fn [_ row-id _] + (when (< row-id (dec transactions-count)) + (list-item + ^{:key row-id} + [common/separator {} st/transactions-list-separator])))) + +(defview unsigned-transactions [] + [all-transactions [:transactions]] + (let [transactions (take 2 (sort-by :timestamp > all-transactions))] + (if (empty? transactions) + [view {:style st/empty-transactions-title-container} + [text {:style st/transactions-title} (i18n/label :t/no-unsigned-transactions)]] + + [view + [view {:style st/transactions-title-container} + [text {:style st/transactions-title} (i18n/label :t/unsigned-transactions)]] + [list-view {:dataSource (lw/to-datasource transactions) + :renderSeparator (render-separator-fn (count transactions)) + :renderRow (fn [row _ _] (list-item [transaction-list-item row]))}] + [touchable-opacity {:style st/view-all-transactions-button + :on-press #(rf/dispatch [:navigate-to-modal :unsigned-transactions])} + [text {:style st/view-all-transactions-text + :font (if platform/android? :medium :default) + :uppercase? platform/android?} + (i18n/label :t/view-all)]]]))) + +(defn current-network [] + [view {:style st/network-label-container} + [text {:style st/network-label} (i18n/label :t/current-network)] + [text {:style st/network-title} "Ropsten"]]) + +(defn options-btn [] + (let [options [{:value (fn [] + (close-drawer) + (rf/dispatch [:set-in [:profile-edit :name] nil]) + (rf/dispatch [:navigate-to :accounts])) + :text (i18n/label :t/switch-users)}]] + [view {:style st/options-button} + [context-menu/context-menu [icon :options_gray] options]])) + +(defn drawer [] + (let [placeholder (gfycat/generate-gfy)] (fn [] - (let [{:keys [name photo-path status]} @account - {new-name :name} @profile] - [view st/drawer-menu - [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 - [ci/chat-icon photo-path {:size 64}]]] - [view st/name-container - [text-field - {:line-color :white - :focus-line-color :white - :placeholder placeholder - :editable true - :input-style (st/name-input-text (s/valid? ::v/name (or new-name name))) - :wrapper-style st/name-input-wrapper - :value (or new-name name) - :on-change-text #(dispatch [:set-in [:profile-edit :name] %]) - :on-end-editing #(do - (dispatch [:set-in [:profile-edit :name] nil]) - (when (s/valid? ::v/name new-name) - (dispatch [:account-update {:name (clean-text new-name)}])))}]] - [view st/status-container - (if @status-edit? - [text-input {:style st/status-input - :editable true - :multiline true - :auto-focus true - :focus status-edit? - :max-length 140 - :accessibility-label id/drawer-status-input - :placeholder (label :t/profile-no-status) - :default-value status - :on-blur #(do - (reset! status-edit? false) - (update-status @status-text)) - :on-change-text #(let [status (clean-text %)] - (reset! status-text status) - (if (str/includes? % "\n") - (do - (reset! status-edit? false) - (update-status status)) - (dispatch [:set-in [:profile-edit :status] status])))}] - [status-view {:style st/status-text - :on-press #(reset! status-edit? true) - :number-of-lines 3 - :status status}])] - [view st/menu-items-container - [menu-item {:name (label :t/profile) - :handler #(dispatch [:navigate-to :my-profile])}] - [menu-item {:name (label :t/discover) - :handler #(dispatch [:navigate-to-tab :discover])}] - [menu-item {:name (label :t/contacts) - :handler #(dispatch [:navigate-to-tab :contact-list])}]] - (when (zero? @keyboard-height) - [text {:style st/feedback - :font :default} (label :t/feedback)]) - (when (zero? @keyboard-height) - [view st/switch-users-container - [touchable-opacity {:onPress (fn [] - (close-drawer) - (dispatch [:set-in [:profile-edit :name] nil]) - (dispatch [:navigate-to :accounts]))} - [text {:style st/switch-users-text - :font :default} - (label :t/switch-users)]]])]]])))) + [touchable-without-feedback {:on-press #(dismiss-keyboard!)} + [view st/drawer + [view st/upper-container + [view st/profile-container + [profile-picture] + [name-input placeholder] + [status-input] + [options-btn]] + [current-network]] + [unsigned-transactions]]]))) (defn drawer-view [items] - [drawer-layout {:drawerWidth 260 - :renderNavigationView #(r/as-element [drawer-menu]) + [drawer-layout {:drawerWidth 300 + :renderNavigationView #(r/as-element [drawer]) :onDrawerSlide dismiss-keyboard! :ref (fn [drawer] (reset! drawer-atom drawer))} diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index e5a49755da..7aea39f364 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -21,6 +21,7 @@ (def color-light-blue-transparent "#628fe333") (def color-light-blue2 "#eff3fc") (def color-light-blue3 "#a0bcf0") +(def color-light-blue4 "#f1f4f5") (def color-dark-blue-1 "#252c4a") (def color-dark-blue-2 "#1f253f") (def color-dark-blue-3 "#191f37") diff --git a/src/status_im/transactions/handlers.cljs b/src/status_im/transactions/handlers.cljs index 29353b02b2..c73f21c41d 100644 --- a/src/status_im/transactions/handlers.cljs +++ b/src/status_im/transactions/handlers.cljs @@ -2,6 +2,7 @@ (:require [re-frame.core :refer [after dispatch debug enrich]] [status-im.utils.handlers :refer [register-handler]] [status-im.navigation.handlers :as nav] + [status-im.utils.datetime :as time] [status-im.utils.handlers :as u] [status-im.utils.types :as t] [status-im.utils.hex :refer [valid-hex? normalize-hex]] @@ -134,6 +135,7 @@ :data data :gas (.toDecimal js/Web3.prototype gas) :gas-price (.toDecimal js/Web3.prototype gasPrice) + :timestamp (time/now-ms) :message-id message_id}] (assoc-in db [:transactions-queue id] transaction)) db)))) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 0e0a01e6d8..458b3ffeeb 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -22,6 +22,8 @@ :faq "FAQ" :switch-users "Switch users" :feedback "Got feedback?\nShake your phone!" + :view-all "View all" + :current-network "Current network" ;chat :is-typing "is typing" @@ -81,7 +83,7 @@ :public-key "Public key" :phone-number "Phone number" :email "Email" - :profile-no-status "No status" + :update-status "Update your status..." :add-a-status "Add a status..." :status-prompt "Create a status to help people know about the things you are offering. You can use #hashtags too." :add-to-contacts "Add to contacts" @@ -292,6 +294,7 @@ :zero "No transactions confirmed"} :transaction "Transaction" :unsigned-transactions "Unsigned transactions" + :no-unsigned-transactions "No unsigned transactions" :enter-password-transactions {:one "Confirm transaction by entering your password" :other "Confirm transactions by entering your password"} :status "Status"