feature #3052 and #3054 - edit profile and qr code viewer

This commit is contained in:
Goran Jovic 2018-01-15 17:16:48 +01:00 committed by Goran Jović
parent 6c72b6d5db
commit 5ecdb174e2
20 changed files with 398 additions and 426 deletions

View File

@ -6,7 +6,7 @@
[status-im.chat.views.input.web-view :as chat-web-view]
[status-im.chat.views.input.validation-messages :as chat-validation-messages]
[status-im.chat.views.api.choose-contact :as choose-contact]
[status-im.ui.components.qr-code :as qr]
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
[status-im.ui.components.chat-preview :as chat-preview]
[status-im.chat.views.api.geolocation.views :as geolocation]
[status-im.utils.handlers :refer [register-handler]]
@ -25,7 +25,7 @@
:text-input components/text-input
:chat-preview-text chat-preview/text
:image components/image
:qr-code qr/qr-code
:qr-code qr-code-viewer/qr-code
:linking components/linking
:slider components/slider
:scroll-view components/scroll-view

View File

@ -103,7 +103,7 @@
:mainnet-text "Youre on the Mainnet. Real ETH will be sent"
;;make_photo
:image-source-title "Profile image"
:image-source-title "Edit picture"
:image-source-make-photo "Capture"
:image-source-gallery "Select from gallery"
@ -183,6 +183,7 @@
:choose-from-contacts "Choose from contacts"
:no-contacts "No contacts yet"
:show-qr "Show QR code"
:qr-code-public-key-hint "Share this code to \nstart chatting"
:enter-address "Enter address"
:more "more"

View File

@ -1,121 +1,118 @@
(ns status-im.ui.components.chat-icon.screen
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.ui.components.react :refer [view
text
image]]
[status-im.ui.components.chat-icon.styles :as st]
[status-im.ui.components.styles :refer [default-chat-color]]
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [status-im.ui.components.react :as react]
[status-im.ui.components.chat-icon.styles :as styles]
[status-im.ui.components.styles :as components.styles]
[status-im.react-native.resources :as resources]
[status-im.constants :refer [console-chat-id]]
[clojure.string :as s]))
[clojure.string :as string]
[status-im.i18n :as i18n]))
(defn default-chat-icon [name styles]
[view (:default-chat-icon styles)
[text {:style (:default-chat-icon-text styles)}
[react/view (:default-chat-icon styles)
[react/text {:style (:default-chat-icon-text styles)}
(first name)]])
(defn chat-icon [photo-path {:keys [size accessibility-label]}]
(let [photo (if (s/starts-with? photo-path "contacts://")
(->> (s/replace photo-path #"contacts://" "")
(let [photo (if (string/starts-with? photo-path "contacts://")
(->> (string/replace photo-path #"contacts://" "")
(keyword)
(get resources/contacts))
{:uri photo-path})]
[image {:source photo
:style (st/image-style size)
:accessibility-label (or accessibility-label :chat-icon)}]))
[react/image {:source photo
:style (styles/image-style size)
:accessibility-label (or accessibility-label :chat-icon)}]))
(defn dapp-badge [{:keys [online-view-wrapper online-view online-dot-left online-dot-right]}]
[view online-view-wrapper
[view online-view
[view
[view online-dot-left]
[view online-dot-right]]]])
[react/view online-view-wrapper
[react/view online-view
[react/view
[react/view online-dot-left]
[react/view online-dot-right]]]])
(defview pending-contact-badge
[chat-id {:keys [pending-wrapper pending-outer-circle pending-inner-circle]}]
[pending-contact? [:get-in [:contacts/contacts chat-id :pending?]]]
(when pending-contact?
[view pending-wrapper
[view pending-outer-circle
[view pending-inner-circle]]]))
(letsubs [pending-contact? [:get-in [:contacts/contacts chat-id :pending?]]]
(when pending-contact?
[react/view pending-wrapper
[react/view pending-outer-circle
[react/view pending-inner-circle]]])))
(defview chat-icon-view [chat-id group-chat name online styles & [hide-dapp?]]
[photo-path [:get-chat-photo chat-id]
dapp? [:get-in [:contacts/contacts chat-id :dapp?]]]
[view (:container styles)
(if-not (s/blank? photo-path)
[chat-icon photo-path styles]
[default-chat-icon name styles])
(when (and dapp? (not hide-dapp?))
[dapp-badge styles])
[pending-contact-badge chat-id styles]])
(defview chat-icon-view [chat-id _group-chat name _online styles & [hide-dapp?]]
(letsubs [photo-path [:get-chat-photo chat-id]
dapp? [:get-in [:contacts/contacts chat-id :dapp?]]]
[react/view (:container styles)
(if-not (string/blank? photo-path)
[chat-icon photo-path styles]
[default-chat-icon name styles])
(when (and dapp? (not hide-dapp?))
[dapp-badge styles])
[pending-contact-badge chat-id 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-wrapper st/online-view-wrapper
:online-view st/online-view
:online-dot-left st/online-dot-left
:online-dot-right st/online-dot-right
:pending-wrapper st/pending-wrapper
:pending-outer-circle st/pending-outer-circle
:pending-inner-circle st/pending-inner-circle
{:container styles/container-chat-list
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:pending-wrapper styles/pending-wrapper
:pending-outer-circle styles/pending-outer-circle
:pending-inner-circle styles/pending-inner-circle
:size 40
: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}])
:chat-icon styles/chat-icon-chat-list
:default-chat-icon (styles/default-chat-icon-chat-list color)
:default-chat-icon-text styles/default-chat-icon-text}])
(defn chat-icon-view-action [chat-id group-chat name color online]
(defn chat-icon-view-action [chat-id group-chat name _color online]
^{:key chat-id}
[chat-icon-view chat-id group-chat name online
{:container st/container-chat-list
:online-view-wrapper st/online-view-wrapper
:online-view st/online-view
:online-dot-left st/online-dot-left
:online-dot-right st/online-dot-right
{:container styles/container-chat-list
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:size 40
:chat-icon st/chat-icon-chat-list
:default-chat-icon (st/default-chat-icon-chat-list default-chat-color)
:default-chat-icon-text st/default-chat-icon-text}])
:chat-icon styles/chat-icon-chat-list
:default-chat-icon (styles/default-chat-icon-chat-list components.styles/default-chat-color)
:default-chat-icon-text styles/default-chat-icon-text}])
(defn chat-icon-view-menu-item [chat-id group-chat name color online]
^{:key chat-id}
[chat-icon-view chat-id group-chat name online
{:container st/container-menu-item
:online-view-wrapper st/online-view-menu-wrapper
: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
:pending-wrapper st/pending-view-menu-wrapper
:pending-outer-circle st/pending-outer-circle
:pending-inner-circle st/pending-inner-circle
{:container styles/container-menu-item
:online-view-wrapper styles/online-view-menu-wrapper
:online-view styles/online-view-menu-item
:online-dot-left styles/online-dot-left-menu-item
:online-dot-right styles/online-dot-right-menu-item
:pending-wrapper styles/pending-view-menu-wrapper
:pending-outer-circle styles/pending-outer-circle
:pending-inner-circle styles/pending-inner-circle
:size 24
:chat-icon st/chat-icon-menu-item
:default-chat-icon (st/default-chat-icon-view-action color)
:default-chat-icon-text st/default-chat-icon-text}
:chat-icon styles/chat-icon-menu-item
:default-chat-icon (styles/default-chat-icon-view-action color)
:default-chat-icon-text styles/default-chat-icon-text}
true])
(defn chat-icon-message-status [chat-id group-chat name color online]
^{:key chat-id}
[chat-icon-view chat-id group-chat name online
{:container st/container-message-status
:online-view-wrapper st/online-view-wrapper
:online-view st/online-view
:online-dot-left st/online-dot-left
:online-dot-right st/online-dot-right
:pending-wrapper st/pending-wrapper
:pending-outer-circle st/pending-outer-circle
:pending-inner-circle st/pending-inner-circle
{:container styles/container-message-status
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:pending-wrapper styles/pending-wrapper
:pending-outer-circle styles/pending-outer-circle
:pending-inner-circle styles/pending-inner-circle
:size 64
:chat-icon st/chat-icon-message-status
:default-chat-icon (st/default-chat-icon-message-status color)
:default-chat-icon-text st/message-status-icon-text}])
:chat-icon styles/chat-icon-message-status
:default-chat-icon (styles/default-chat-icon-message-status color)
:default-chat-icon-text styles/message-status-icon-text}])
(defn contact-icon-view [{:keys [photo-path name dapp?]} {:keys [container] :as styles}]
(let [photo-path photo-path]
[view container
(if-not (s/blank? photo-path)
[react/view container
(if-not (string/blank? photo-path)
[chat-icon photo-path styles]
[default-chat-icon name styles])
(when dapp?
@ -123,32 +120,32 @@
(defn contact-icon-contacts-tab [contact]
[contact-icon-view contact
{:container st/container-chat-list
:online-view-wrapper st/online-view-wrapper
:online-view st/online-view
:online-dot-left st/online-dot-left
:online-dot-right st/online-dot-right
{:container styles/container-chat-list
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
:online-dot-left styles/online-dot-left
:online-dot-right styles/online-dot-right
:size 40
:chat-icon st/chat-icon-chat-list
:default-chat-icon (st/default-chat-icon-chat-list default-chat-color)
:default-chat-icon-text st/default-chat-icon-text}])
:chat-icon styles/chat-icon-chat-list
:default-chat-icon (styles/default-chat-icon-chat-list components.styles/default-chat-color)
:default-chat-icon-text styles/default-chat-icon-text}])
(defn profile-icon-view [photo-path name color edit? size]
(let [styles {:container {:width size :height size}
:online-view st/online-view-profile
:online-dot-left st/online-dot-left-profile
:online-dot-right st/online-dot-right-profile
:online-view styles/online-view-profile
:online-dot-left styles/online-dot-left-profile
:online-dot-right styles/online-dot-right-profile
:size size
: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)
:chat-icon styles/chat-icon-profile
:default-chat-icon (styles/default-chat-icon-profile color)
:default-chat-icon-text styles/default-chat-icon-text}]
[react/view (:container styles)
(when edit?
[view (st/profile-icon-mask size)])
[react/view (styles/profile-icon-mask size)])
(when edit?
[view (st/profile-icon-edit-text-containter size)
[text {:style st/profile-icon-edit-text}
"Edit"]])
[react/view (styles/profile-icon-edit-text-containter size)
[react/text {:style styles/profile-icon-edit-text}
(i18n/label :t/edit)]])
(if (and photo-path (seq photo-path))
[chat-icon photo-path styles]
[default-chat-icon name styles])]))
@ -157,6 +154,6 @@
(defn my-profile-icon [{{:keys [photo-path name]} :account
edit? :edit?}]
(let [color default-chat-color
size (if edit? 70 56)]
(let [color components.styles/default-chat-color
size 56]
[profile-icon-view photo-path name color edit? size]))

View File

@ -6,4 +6,5 @@
(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
(def red "#ff2d55") ;; Used to highlight errors or "dangerous" actions
(def light-gray "#eef2f5") ;; Used as a background or shadow

View File

@ -6,7 +6,8 @@
[status-im.ui.components.common.styles :as styles]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.platform :as platform]
[status-im.i18n :as i18n]))
[status-im.i18n :as i18n]
[re-frame.core :as re-frame]))
(defn top-shadow []
(when platform/android?
@ -72,3 +73,15 @@
(if (ethereum/testnet? network-id)
(i18n/label :t/testnet-text {:testnet (get-in ethereum/chains [(ethereum/chain-id->chain-keyword network-id) :name] "Unknown")})
(i18n/label :t/mainnet-text))]]]))
(defn icon-or-label
"Renders a touchable icon on Android or a label or iOS."
[action-opts label-kw label-style icon-id icon-opts]
[react/touchable-highlight action-opts
(if platform/ios?
[react/view
[react/text {:style (merge styles/label-action-text label-style)}
(i18n/label label-kw)]]
[react/view styles/icon-action
[vector-icons/icon icon-id icon-opts]])])

View File

@ -1,6 +1,7 @@
(ns status-im.ui.components.common.styles
(:require-macros [status-im.utils.styles :refer [defstyle]])
(:require [status-im.ui.components.styles :as styles]))
(:require [status-im.ui.components.styles :as styles]
[status-im.ui.components.colors :as colors]))
(def gradient-top
{:flexDirection :row
@ -101,4 +102,17 @@
:border-radius (/ 40 2)
:background-color styles/color-green-4
:align-items :center
:justify-content :center})
:justify-content :center})
(defstyle label-action-text
{:padding-right 16
:color colors/blue
:ios {:font-size 15}
:android {:font-size 14}})
(def icon-action
{:width 40
:height 40
:margin-right 4
:align-items :center
:justify-content :center})

View File

@ -39,8 +39,9 @@
(def list-selection-fn (:list-selection-fn platform-specific))
(defn open-ios-menu [options]
(defn open-ios-menu [title options]
(list-selection-fn {:options options
:title title
:callback (fn [index]
(when (< index (count options))
(when-let [handler (:value (nth options index))]
@ -50,7 +51,7 @@
(defn context-menu [trigger options & custom-styles trigger-style]
(if ios?
[rn/touchable-highlight {:style trigger-style
:on-press #(open-ios-menu options)}
:on-press #(open-ios-menu nil options)}
[rn/view
trigger]]
[menu {:onSelect #(when % (do (%) nil))}
@ -61,3 +62,9 @@
[menu-option {:value value}
[rn/text {:style (merge (context-menu-text destructive?) style)}
(:text option)]])]]))
(defn modal-menu [trigger style title options]
[rn/touchable-highlight {:style style
:on-press #(open-ios-menu title options)}
[rn/view
trigger]])

View File

@ -1,8 +0,0 @@
(ns status-im.ui.components.qr-code
(:require [reagent.core :as r]
[status-im.react-native.js-dependencies :as rn-dependencies]))
(defn qr-code [props]
(r/create-element
rn-dependencies/qr-code
(clj->js (merge {:inverted true} props))))

View File

@ -0,0 +1,97 @@
(ns status-im.ui.components.qr-code-viewer.styles
(:require [status-im.ui.components.colors :as colors])
(:require-macros [status-im.utils.styles :refer [defstyle]]))
(def qr-code-hint
{:color colors/gray
:padding-bottom 24
:text-align :center})
(def qr-code-padding
15)
(defn qr-code-container [dimensions]
{:background-color colors/white
:width (:width dimensions)
:align-items :center
:justify-content :center
:padding qr-code-padding
:border-radius 8})
(def toolbar-done-text-ios
{:color colors/blue
:letter-spacing -0.2
:font-size 17})
(defstyle name-container
{:flex 0.6
:flex-direction :column
:ios {:align-items :center}
:android {:margin-left 15}})
(defstyle name-text
{:color colors/black
:font-size 17
:ios {:letter-spacing -0.2}})
(def address-text
{:color colors/white
:font-size 12})
(def toolbar-action-container
{:flex 0.2
:flex-direction :column
:align-items :center
:justify-content :center})
(def toolbar-action-icon-container
{:width 40
:height 40
:margin-right 16
:align-items :center
:justify-content :center})
(def wallet-qr-code
{:flex-grow 1
:flex-direction :column})
(def account-toolbar
{:background-color colors/white})
(def toolbar-contents
{:flex-grow 1
:flex-direction :row
:height 55
:align-items :center
:justify-content :center})
(def qr-code
{:background-color colors/light-gray
:flex-grow 1
:align-items :center
:justify-content :center})
(def footer
{:background-color colors/light-gray
:flex-direction :row
:justify-content :center
:padding-bottom 50})
(def wallet-info
{:align-items :center
:padding-bottom 20})
(def hash-value-type
{:color colors/black
:padding-bottom 5})
(def hash-value-text
{:color colors/black
:margin-horizontal 60
:text-align :center
:font-size 15
:letter-spacing -0.2
:line-height 20})
(def done-button-text
{:color colors/white})

View File

@ -0,0 +1,59 @@
(ns status-im.ui.components.qr-code-viewer.views
(:require [re-frame.core :as re-frame]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.qr-code-viewer.styles :as styles]
[status-im.ui.components.common.common :as common]
[status-im.ui.components.common.styles :as common.styles]
[status-im.utils.platform :as platform]
[status-im.i18n :as i18n]
[status-im.react-native.js-dependencies :as rn-dependencies]
[reagent.core :as r])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn qr-code [props]
(r/create-element
rn-dependencies/qr-code
(clj->js (merge {:inverted true} props))))
(defn qr-viewer-toolbar [name qr-value]
[react/view styles/account-toolbar
[react/view styles/toolbar-contents
[react/view styles/toolbar-action-container
[common/icon-or-label {:on-press #(re-frame/dispatch [:navigate-back])}
:t/done styles/toolbar-done-text-ios :icons/close {:color :black}]]
[react/view styles/name-container
[react/text {:style styles/name-text
:number-of-lines 1} name]]
[react/view styles/toolbar-action-container
[react/touchable-highlight {:on-press #(list-selection/open-share {:message qr-value})}
[react/view styles/toolbar-action-icon-container
[vector-icons/icon :icons/share {:color :black}]]]]]])
(defn qr-viewer-body [qr-value dimensions]
[react/view {:style styles/qr-code
:on-layout #(let [layout (.. % -nativeEvent -layout)]
(re-frame/dispatch [:set-in [:qr-modal :dimensions] {:width (* 0.7 (.-width layout))
:height (.-height layout)}]))}
[react/text {:style styles/qr-code-hint} (i18n/label :t/qr-code-public-key-hint)]
(when (:width dimensions)
[react/view {:style (styles/qr-code-container dimensions)}
[qr-code {:value qr-value
:size (- (min (:width dimensions)
(:height dimensions))
(* 2 styles/qr-code-padding))}]])])
(defn qr-viewer-footer [qr-value]
[react/view styles/footer
[react/view styles/wallet-info
[react/text {:style styles/hash-value-text} qr-value]]])
(defview qr-viewer []
(letsubs [{:keys [qr-value dimensions contact]} [:get :qr-modal]]
[react/view styles/wallet-qr-code
[status-bar/status-bar {:type :modal}]
[qr-viewer-toolbar (:name contact) qr-value]
[qr-viewer-body qr-value dimensions]
[qr-viewer-footer qr-value]]))

View File

@ -48,7 +48,8 @@
:networks/networks constants/default-networks
:inbox/wnode constants/default-wnode
:inbox/topic constants/inbox-topic
:inbox/password constants/inbox-password})
:inbox/password constants/inbox-password
:my-profile/editing? false})
;;;;GLOBAL
@ -123,6 +124,7 @@
:my-profile/drawer
:my-profile/profile
:my-profile/default-name
:my-profile/editing?
:networks/selected-network
:networks/networks
:node/after-start

View File

@ -1,104 +0,0 @@
(ns status-im.ui.screens.profile.edit.views
(:require [cljs.spec.alpha :as spec]
[clojure.string :as string]
[re-frame.core :refer [dispatch]]
[reagent.core :as reagent]
[status-im.ui.components.camera :as camera]
[status-im.ui.components.chat-icon.screen :refer [my-profile-icon]]
[status-im.ui.components.context-menu :refer [context-menu]]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :refer [status-bar]]
[status-im.ui.components.sticky-button :refer [sticky-button]]
[status-im.ui.components.text-input-with-label.view :refer [text-input-with-label]]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.i18n :refer [label]]
[status-im.ui.screens.profile.db :as db]
[status-im.ui.screens.profile.events :as profile.events]
[status-im.ui.screens.profile.styles :as styles]
[status-im.ui.screens.profile.views :refer [colorize-status-hashtags]]
[status-im.utils.utils :as utils :refer [clean-text]])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn edit-my-profile-toolbar []
[toolbar/toolbar {}
toolbar/default-nav-back
[toolbar/content-title (label :t/edit-profile)]])
(defview profile-name-input []
(letsubs [profile-name [:my-profile/get :name]
placeholder [:get :my-profile/default-name]]
[react/view
[text-input-with-label
{:label (label :t/name)
:default-value profile-name
:on-focus #(dispatch [:my-profile/edit-profile])
:on-change-text #(dispatch [:my-profile/update-name %])}]]))
(def profile-icon-options
[{:text (label :t/image-source-gallery)
:value #(dispatch [:my-profile/update-picture])}
{:text (label :t/image-source-make-photo)
:value (fn []
(dispatch [:request-permissions
[:camera :write-external-storage]
(fn []
(camera/request-access
#(if %
(dispatch [:navigate-to :profile-photo-capture])
(utils/show-popup (label :t/error)
(label :t/camera-access-error)))))]))}])
(defn edit-profile-badge [contact]
[react/view styles/edit-profile-badge
[react/view styles/edit-profile-icon-container
[context-menu
[my-profile-icon {:account contact
:edit? true}]
profile-icon-options
styles/context-menu-custom-styles]]
[react/view styles/edit-profile-name-container
[profile-name-input]]])
(defview edit-profile-status []
(letsubs [edit-status? [:my-profile/get :edit-status?]
status [:my-profile/get :status]]
[react/view styles/edit-profile-status
[react/scroll-view
(if edit-status?
[react/text-input
{:auto-focus (if edit-status? true false)
:multiline true
:max-length 140
:placeholder (label :t/status)
:style styles/profile-status-input
:on-change-text #(dispatch [:my-profile/update-status %])
:default-value status}]
[react/touchable-highlight {:on-press #(dispatch [:my-profile/edit-profile :status])}
[react/view
(if (string/blank? status)
[react/text {:style styles/add-a-status}
(label :t/status)]
[react/text {:style styles/profile-status-text}
(colorize-status-hashtags status)])]])]]))
(defn status-prompt [{:keys [status]}]
(when (or (nil? status) (string/blank? status))
[react/view styles/status-prompt
[react/text {:style styles/status-prompt-text}
(colorize-status-hashtags (label :t/status-prompt))]]))
(defview edit-my-profile []
(letsubs [current-account [:get-current-account]
changed-account [:get :my-profile/profile]
profile-changed? [:my-profile/changed?]
valid-name? [:my-profile/valid-name?]]
[react/keyboard-avoiding-view {:style styles/profile}
[status-bar]
[edit-my-profile-toolbar]
[react/scroll-view styles/edit-my-profile-form
[edit-profile-badge changed-account]
[edit-profile-status]
[status-prompt changed-account]]
(when (and valid-name? profile-changed?)
[sticky-button (label :t/save) #(dispatch [:my-profile/save-profile])])]))

View File

@ -82,8 +82,7 @@
(assoc-in [:my-profile/profile :edit-status?] edit-status?)
(update-in [:my-profile/profile]
#(merge (select-keys (get-current-account db) db/account-profile-keys) %)))]
{:db new-db
:dispatch [:navigate-to :edit-my-profile]})))
{:db new-db})))
(defn valid-name? [name]
(spec/valid? :profile/name name))
@ -139,7 +138,7 @@
(get-in db [:accounts/accounts current-account-id :name]))))
(defn clear-profile [fx]
(update fx :db dissoc :my-profile/profile :my-profile/drawer :my-profile/default-name))
(update fx :db dissoc :my-profile/profile :my-profile/drawer :my-profile/default-name :my-profile/editing?))
(handlers/register-handler-fx
:my-profile.drawer/save-name
@ -172,6 +171,11 @@
(status-change {:old-status old-status
:status status}))))))
(handlers/register-handler-fx
:my-profile/start-editing-profile
(fn [{:keys [db]} []]
{:db (assoc db :my-profile/editing? true)}))
(handlers/register-handler-fx
:my-profile/save-profile
(fn [{:keys [db now]} _]
@ -179,10 +183,11 @@
{old-status :status} (get accounts current-account-id)
{:keys [status photo-path]} (:my-profile/profile db)
cleaned-name (clean-name db :my-profile/profile)
cleaned-edit {:name cleaned-name
:status status
:photo-path photo-path
:last-updated now}]
cleaned-edit (merge {:name cleaned-name
:status status
:last-updated now}
(if photo-path
{:photo-path photo-path}))]
(-> (clear-profile {:db db})
(accounts-events/account-update cleaned-edit)
(status-change {:old-status old-status

View File

@ -1,9 +1,12 @@
(ns status-im.ui.screens.profile.navigation
(:require [status-im.ui.screens.navigation :as navigation]))
(defmethod navigation/preload-data! :qr-code-view
;;TODO(goranjovic) - replace this with an atomic navigation event that calls functions, not dispatch
;; possibly use the generic event, see https://github.com/status-im/status-react/issues/2987
(defmethod navigation/preload-data! :qr-viewer
[{:accounts/keys [current-account-id] :as db} [_ _ {:keys [contact qr-source qr-value]}]]
(update db :qr-modal #(merge % {:contact (or contact
(get-in db [:accounts/accounts current-account-id]))
:qr-source qr-source
:qr-value qr-value})))

View File

@ -1,103 +0,0 @@
(ns status-im.ui.screens.profile.qr-code.styles
(:require [status-im.ui.components.styles :refer [color-white]]))
(def photo-container
{:flex 0.2
:flexDirection :column
:alignItems :center
:justifyContent :center})
(def account-photo-container
{:flex 1
:width 36
:height 36
:alignItems :center
:justifyContent :center})
(def qr-photo-container
(merge photo-container
{:margin-left 8
:margin-right 4}))
(defn qr-code-container [dimensions]
{:background-color "white"
:width (:width dimensions)
:align-items :center
:justify-content :center
:padding 40})
(def photo-image
{:width 36
:height 36
:border-radius 18})
(def name-container
{:flex 1
:flexDirection :column})
(def name-text
{:color color-white
:fontSize 16})
(def address-text
{:color color-white
:fontSize 12})
(def online-container
{:flex 0.2
:flexDirection :column
:alignItems :center
:justifyContent :center})
(def online-image-container
{:width 40
:height 40
:margin-right 4
:align-items :center
:justify-content :center})
(def wallet-qr-code
{:flex-grow 1
:flex-direction :column})
(def account-toolbar
{:background-color "#2f3031"})
(def wallet-account-container
{:flex-grow 1
:flexDirection :row
:height 69
:alignItems :center
:justifyContent :center})
(def qr-code
{:background-color "#2f3031"
:flex-grow 1
:align-items :center
:justify-content :center})
(def footer
{:background-color "#2f3031"})
(def wallet-info
{:align-items :center
:padding-bottom 20
:padding-top 20})
(def wallet-name-text
{:color color-white
:padding-bottom 5})
(def wallet-address-text
{:color "#999999"})
(def done-button
{:flex-grow 1
:flex-direction :column
:align-items :center
:justify-content :center
:height 51
:background-color "#7597e4"})
(def done-button-text
{:color color-white})

View File

@ -1,51 +0,0 @@
(ns status-im.ui.screens.profile.qr-code.views
(:require [clojure.string :as string]
[re-frame.core :refer [dispatch]]
[status-im.ui.components.qr-code :refer [qr-code]]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vi]
[status-im.ui.components.status-bar.view :refer [status-bar]]
[status-im.i18n :refer [label]]
[status-im.ui.screens.profile.qr-code.styles :as styles]
[status-im.utils.money :as money])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defview qr-code-view []
(letsubs [{:keys [photo-path address name]} [:get-in [:qr-modal :contact]]
{:keys [qr-source qr-value dimensions]} [:get :qr-modal]
chain-id [:get-network-id]]
[react/view styles/wallet-qr-code
[status-bar {:type :modal}]
[react/view styles/account-toolbar
[react/view styles/wallet-account-container
[react/view styles/qr-photo-container
[react/view styles/account-photo-container
[react/image {:source {:uri (if (string/blank? photo-path) :avatar photo-path)}
:style styles/photo-image}]]]
[react/view styles/name-container
[react/text {:style styles/name-text
:number-of-lines 1} name]]
[react/view styles/online-container
[react/touchable-highlight {:onPress #(dispatch [:navigate-back])}
[react/view styles/online-image-container
[vi/icon :icons/close {:color :white}]]]]]]
[react/view {:style styles/qr-code
:on-layout #(let [layout (.. % -nativeEvent -layout)]
(dispatch [:set-in [:qr-modal :dimensions] {:width (.-width layout)
:height (.-height layout)}]))}
(when (:width dimensions)
[react/view {:style (styles/qr-code-container dimensions)}
[qr-code {:value qr-value
:size (- (min (:width dimensions)
(:height dimensions))
80)}]])]
[react/view styles/footer
(if (= :address qr-source)
[react/view styles/wallet-info
[react/text {:style styles/wallet-name-text} (label :t/main-wallet)]
[react/text {:style styles/wallet-address-text} address]]
[react/view styles/wallet-info
[react/text {:style styles/wallet-name-text} (label :t/public-key)]])
[react/touchable-highlight {:onPress #(dispatch [:navigate-back])}
[react/view styles/done-button
[react/text {:style styles/done-button-text} (label :t/done)]]]]]))

View File

@ -4,12 +4,6 @@
[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 colors/white
@ -19,10 +13,6 @@
{:background-color colors/white
:padding 16})
(def edit-my-profile-form
{:background-color colors/white
:flex 1})
(defstyle profile-info-container
{:background-color colors/white})
@ -54,20 +44,9 @@
:justify-content :center
:align-items :center})
(def edit-profile-badge
{:flex-direction :row
:padding-left 24})
(def context-menu-custom-styles
{:optionsContainer {:margin-top 78}})
(def edit-profile-name-container
{:flex 1
:padding-top 30})
(def edit-profile-icon-container
{:padding-top 25})
(def edit-name-title
{:color colors/gray
:ios {:font-size 13
@ -75,10 +54,18 @@
:android {:font-size 12}})
(defstyle profile-name-text
{:margin-top 8
:font-size 15
{:padding-vertical 14
:font-size 15
:text-align :center
:ios {:letter-spacing -0.2}
:android {:color colors/black}})
(defstyle profile-name-input-text
{:font-size 15
:text-align :center
:ios {:letter-spacing -0.2}
:ios {:letter-spacing -0.2
:height 46
:width 800}
:android {:color colors/black}})
(def profile-badge-name-container

View File

@ -5,6 +5,7 @@
[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.common.styles :as common.styles]
[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]
@ -22,7 +23,8 @@
[status-im.utils.config :as config]
[status-im.utils.platform :as platform]
[status-im.protocol.core :as protocol]
[re-frame.core :as re-frame])
[re-frame.core :as re-frame]
[status-im.ui.components.camera :as camera])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn my-profile-toolbar []
@ -30,11 +32,18 @@
nil
[toolbar/content-title ""]
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:my-profile/edit-profile])}
{:on-press #(re-frame/dispatch [:my-profile/start-editing-profile])}
[react/view
[react/text {:style styles/toolbar-edit-text
[react/text {:style common.styles/label-action-text
:uppercase? component.styles/uppercase?} (i18n/label :t/edit)]]]])
(defn my-profile-edit-toolbar []
[toolbar/toolbar {}
nil
[toolbar/content-title ""]
[common/icon-or-label {:on-press #(re-frame/dispatch [:my-profile/save-profile])}
:t/done {} :icons/ok {:color colors/blue}]])
(defn profile-toolbar [contact]
[toolbar/toolbar {}
toolbar/default-nav-back
@ -66,6 +75,45 @@
[react/text {:style styles/profile-activity-status-text}
(online-text last-online)]])]])
(defn profile-name-input [name]
[react/view
[react/text-input
{:style styles/profile-name-input-text
:placeholder ""
:default-value name
:auto-focus true
:on-focus #(re-frame/dispatch [:my-profile/edit-profile])
:on-change-text #(re-frame/dispatch [:my-profile/update-name %])}]])
(def profile-icon-options
[{:text (i18n/label :t/image-source-gallery)
:value #(re-frame/dispatch [:my-profile/update-picture])}
{:text (i18n/label :t/image-source-make-photo)
:value (fn []
(re-frame/dispatch [:request-permissions
[:camera :write-external-storage]
(fn []
(camera/request-access
#(if %
(re-frame/dispatch [:navigate-to :profile-photo-capture])
(utils/show-popup (i18n/label :t/error)
(i18n/label :t/camera-access-error)))))]))}])
(defn profile-badge-edit [{:keys [name last-online] :as account}]
[react/view styles/profile-badge
[context-menu/modal-menu
[chat-icon.screen/my-profile-icon {:account account
:edit? true}]
{} (i18n/label :t/image-source-title)
profile-icon-options]
[react/view styles/profile-badge-name-container
[profile-name-input name]
(when-not (nil? last-online)
[react/view styles/profile-activity-status-container
[react/text {:style styles/profile-activity-status-text}
(online-text last-online)]])]])
(defn profile-actions [{:keys [pending? whisper-identity dapp?]} chat-id]
[react/view action-button.styles/actions-list
(if pending?
@ -108,9 +156,9 @@
styles/profile-info-item-button])])
(defn show-qr [contact qr-source qr-value]
#(re-frame/dispatch [:navigate-to-modal :qr-code-view {:contact contact
:qr-source qr-source
:qr-value qr-value}]))
#(re-frame/dispatch [:navigate-to :qr-viewer {:contact contact
:qr-source qr-source
:qr-value qr-value}]))
(defn profile-options [contact k text]
(into []
@ -249,12 +297,18 @@
[vector-icons/icon :icons/qr {:color colors/blue}]]]])
(defview my-profile []
(letsubs [{:keys [public-key] :as current-account} [:get-current-account]]
(letsubs [{:keys [public-key] :as current-account} [:get-current-account]
editing? [:get :my-profile/editing?]
changed-account [:get :my-profile/profile]]
[react/view styles/profile
[my-profile-toolbar]
(if editing?
[my-profile-edit-toolbar]
[my-profile-toolbar])
[react/scroll-view
[react/view styles/profile-form
[profile-badge current-account]]
(if editing?
[profile-badge-edit (merge current-account changed-account)]
[profile-badge current-account])]
[react/view action-button.styles/actions-list
[share-contact-code current-account public-key]]
[react/view styles/profile-info-container

View File

@ -29,10 +29,9 @@
add-participants-toggle-list]]
[status-im.ui.screens.group.reorder.views :refer [reorder-groups]]
[status-im.ui.screens.profile.views :refer [profile my-profile]]
[status-im.ui.screens.profile.edit.views :refer [edit-my-profile]]
[status-im.ui.screens.profile.views :as profile]
[status-im.ui.screens.profile.photo-capture.views :refer [profile-photo-capture]]
[status-im.ui.screens.profile.qr-code.views :refer [qr-code-view]]
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
[status-im.ui.screens.wallet.send.views :refer [send-transaction send-transaction-modal]]
[status-im.ui.screens.wallet.choose-recipient.views :refer [choose-recipient]]
@ -91,8 +90,7 @@
:new-contact new-contact
:qr-scanner qr-scanner
:chat chat
:profile profile
:edit-my-profile edit-my-profile
:profile profile/profile
:discover-all-recent discover-recent/discover-all-recent
:discover-all-popular-hashtags discover-popular/discover-all-popular-hashtags
:discover-search-results discover-search/discover-search-results
@ -107,6 +105,7 @@
:paste-json-text paste-json-text
:add-rpc-url add-rpc-url
:network-details network-details
:qr-viewer qr-code-viewer/qr-viewer
(throw (str "Unknown view: " current-view)))]
[(if android? menu-context view) common-styles/flex
[view common-styles/flex
@ -118,7 +117,6 @@
:on-request-close #(dispatch [:navigate-back])}
(let [component (case modal-view
:qr-scanner qr-scanner
:qr-code-view qr-code-view
:recover-modal recover-modal
:contact-list-modal contact-list-modal
:wallet-transactions-filter wallet-transactions/filter-history

View File

@ -2,7 +2,7 @@
(:require-macros [status-im.utils.views :as views])
(:require [re-frame.core :as re-frame]
[status-im.ui.components.react :as react]
[status-im.ui.components.qr-code :as components.qr-code]
[status-im.ui.components.qr-code-viewer.views :as components.qr-code-viewer]
[status-im.ui.components.toolbar.actions :as actions]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.status-bar.view :as status-bar]
@ -37,7 +37,7 @@
(views/defview qr-code [amount symbol]
(views/letsubs [account [:get-current-account]
chain-id [:get-network-id]]
[components.qr-code/qr-code
[components.qr-code-viewer/qr-code
(let [address (ethereum/normalized-address (:address account))
params {:chain-id chain-id :value amount :symbol (or symbol :ETH)}]
{:value (generate-value address params)