fix #1571 Feature/profile refactoring

Second step of refactoring guidelines to fix #1571

- use fx and cofx
- specs
- simplify event chain
This commit is contained in:
Eric Dvorsak 2017-08-13 00:19:13 +02:00 committed by Roman Volosovskyi
parent d63d411c53
commit cb48195383
8 changed files with 132 additions and 112 deletions

View File

@ -34,12 +34,6 @@
(defn open-drawer [] (.openDrawer @drawer-atom))
(defn close-drawer [] (.closeDrawer @drawer-atom))
(defn- update-status [new-status]
(when-not (str/blank? 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])))
(defview profile-picture []
[account [:get-current-account]]
[touchable-opacity {:on-press #(rf/dispatch [:navigate-to :my-profile])
@ -49,27 +43,25 @@
(defview name-input []
[account [:get-current-account]
new-name [:get-in [:profile-edit :name]]]
(let [current-name (:name account)
public-key (:public-key account)]
[view {:style st/name-input-wrapper}
name-text (r/atom nil)]
(let [previous-name (:name account)]
[view st/name-input-wrapper
[text-input
{:placeholder (gfycat/generate-gfy public-key)
:style (st/name-input-text (s/valid? ::profile.db/name (or new-name current-name)))
:style (st/name-input-text (s/valid? ::profile.db/name @name-text))
:font :medium
: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? ::profile.db/name new-name)
(rf/dispatch [:account-update {:name (utils/clean-text new-name)}])))}]]))
:default-value (or @name-text previous-name)
:on-change-text #(reset! name-text %)
:on-end-editing #(if (s/valid? ::profile.db/name @name-text)
(rf/dispatch [:account-update {:name (utils/clean-text @name-text)}])
(reset! name-text previous-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)]
(let [placeholder (i18n/label :t/update-status)
previous-status (:status account)]
[view st/status-container
(if @status-edit?
[text-input {:style st/status-input-view
@ -79,21 +71,21 @@
: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))
:default-value previous-status
: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))
(when (str/includes? % "\n")
(reset! status-edit? false)
(rf/dispatch [:my-profile/update-status new-status])))
:on-blur #(do (reset! status-edit? false)
(rf/dispatch [:my-profile/update-status @status-text]))}]
[status-view/status-view {:style (st/status-view (str/blank? previous-status))
:on-press #(reset! status-edit? true)
:number-of-lines 3
:status (if (str/blank? status) placeholder status)}])]))
:status (if (str/blank? previous-status)
placeholder
previous-status)}])]))
(defview transaction-list-item [{:keys [to value timestamp] :as transaction}]
[recipient [:contact-by-address to]]
@ -152,7 +144,6 @@
[touchable-highlight
{:on-press (fn []
(close-drawer)
(rf/dispatch [:set-in [:profile-edit :name] nil])
(rf/dispatch [:navigate-to :my-profile]))}
[view [icon :options_gray]]]])
@ -161,7 +152,6 @@
[touchable-highlight
{:on-press (fn []
(close-drawer)
(rf/dispatch [:set-in [:profile-edit :name] nil])
(rf/dispatch [:navigate-to :accounts]))}
[view
[text {:style st/switch-account-text

View File

@ -27,7 +27,7 @@
:current-chat-id console-chat-id
:loading-allowed true
:selected-participants #{}
:profile-edit {:edit? false
:my-profile/edit {:edit? false
:name nil
:email nil
:status nil
@ -97,7 +97,8 @@
:group/contact-group-id
:group/group-type
:group/selected-contacts
:group/groups-order]
:group/groups-order
:my-profile/edit]
:opt-un
[::current-public-key
::modal
@ -158,7 +159,6 @@
:chat/raw-unviewed-messages
:chat/bot-db
:chat/geolocation
:profile/profile-edit
:transactions/transactions
:transactions/transactions-queue
:transactions/selected-transaction

View File

@ -1,4 +1,5 @@
(ns status-im.ui.screens.profile.db
(:require-macros [status-im.utils.db :refer [allowed-keys]])
(:require [cljs.spec.alpha :as spec]
[clojure.string :as string]
[status-im.chat.constants :as chat.constants]
@ -19,10 +20,26 @@
(or (string/blank? email)
(and (string? email) (re-matches pattern email)))))
(spec/def ::name correct-name?)
(spec/def ::email correct-email?)
(defn base64-encoded-image-path? [photo-path]
(or (string/starts-with? photo-path "data:image/jpeg;base64,")
(string/starts-with? photo-path "data:image/png;base64,")))
(spec/def :profile/name (spec/nilable correct-name?))
(spec/def ::profile (spec/keys :req-un [:profile/name]))
(spec/def ::name (spec/or :name correct-name?
:empty-string string/blank?))
(spec/def ::email (spec/nilable correct-email?))
(spec/def ::edit? boolean?)
(spec/def ::status (spec/nilable string?))
(spec/def ::photo-path (spec/nilable base64-encoded-image-path?))
(spec/def ::edit-status? boolean?)
(spec/def ::profile (spec/keys :req-un [::name]))
;; EDIT PROFILE
(spec/def :profile/profile-edit (spec/nilable map?))
(spec/def :my-profile/edit (allowed-keys
:req-un [::email ::edit? ::name ::status ::photo-path]
:opt-un [::edit-status?]))

View File

@ -24,15 +24,15 @@
:actions [{:image :blank}]}])
(defview profile-name-input []
(letsubs [new-profile-name [:get-in [:profile-edit :name]]]
(letsubs [new-profile-name [:get-in [:my-profile/edit :name]]]
[react/view
[text-input-with-label {:label (label :t/name)
:default-value new-profile-name
:on-change-text #(dispatch [:set-in [:profile-edit :name] %])}]]))
:on-change-text #(dispatch [:set-in [:my-profile/edit :name] %])}]]))
(def profile-icon-options
[{:text (label :t/image-source-gallery)
:value #(dispatch [:open-image-picker])}
:value #(dispatch [:my-profile/update-picture])}
{:text (label :t/image-source-make-photo)
:value (fn []
(dispatch [:request-permissions
@ -43,8 +43,8 @@
(utils/show-popup (label :t/error)
(label :t/camera-access-error)))))]))}])
(defn edit-profile-bage [contact]
[react/view styles/edit-profile-bage
(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
@ -66,12 +66,12 @@
:max-length 140
:placeholder (label :t/status)
:style styles/profile-status-input
:on-change-text #(dispatch [:set-in [:profile-edit :status] (clean-text %)])
:on-blur #(dispatch [:set-in [:profile-edit :edit-status?] false])
:on-change-text #(dispatch [:set-in [:my-profile/edit :status] (clean-text %)])
:on-blur #(dispatch [:set-in [:my-profile/edit :edit-status?] false])
:blur-on-submit true
:on-submit-editing #(.blur @input-ref)
:default-value status}]
[react/touchable-highlight {:on-press #(dispatch [:set-in [:profile-edit :edit-status?] true])}
[react/touchable-highlight {:on-press #(dispatch [:set-in [:my-profile/edit :edit-status?] true])}
[react/view
(if (string/blank? status)
[react/text {:style styles/add-a-status}
@ -87,8 +87,8 @@
(defview edit-my-profile []
(letsubs [current-account [:get-current-account]
changed-account [:get :profile-edit]]
{:component-will-unmount #(dispatch [:set-in [:profile-edit :edit-status?] false])}
changed-account [:get :my-profile/edit]]
{:component-will-unmount #(dispatch [:set-in [:my-profile/edit :edit-status?] false])}
(let [profile-edit-data-valid? (spec/valid? ::db/profile changed-account)
profile-edit-data-changed? (or (not= (:name current-account) (:name changed-account))
(not= (:status current-account) (:status changed-account))
@ -97,10 +97,8 @@
[status-bar]
[edit-my-profile-toolbar]
[react/view styles/edit-my-profile-form
[edit-profile-bage changed-account]
[edit-profile-badge changed-account]
[edit-profile-status changed-account]
[status-prompt changed-account]]
(when (and profile-edit-data-changed? profile-edit-data-valid?)
[sticky-button (label :t/save) #(do
(dispatch [:check-status-change (:status changed-account)])
(dispatch [:account-update changed-account]))])])))
[sticky-button (label :t/save) #(dispatch [:my-profile/save-changes])])])))

View File

@ -1,5 +1,6 @@
(ns status-im.ui.screens.profile.events
(:require [re-frame.core :as re-frame :refer [reg-fx]]
(:require [clojure.string :as string]
[re-frame.core :as re-frame :refer [reg-fx]]
[status-im.components.react :refer [show-image-picker]]
[status-im.constants :refer [console-chat-id]]
[status-im.ui.screens.profile.navigation]
@ -7,52 +8,71 @@
[status-im.utils.image-processing :refer [img->base64]]
[taoensso.timbre :as log]))
(defn message-user [identity]
(when identity
(re-frame/dispatch [:navigation-replace :chat identity])))
(handlers/register-handler
(reg-fx
:open-image-picker
(handlers/side-effect!
(fn [_ _]
(show-image-picker
(fn [image]
(let [path (get (js->clj image) "path")
_ (log/debug path)
on-success (fn [base64]
(re-frame/dispatch [:set-in [:profile-edit :photo-path] (str "data:image/jpeg;base64," base64)]))
on-error (fn [type error]
(.log js/console type error))]
(img->base64 path on-success on-error)))))))
;; the image picker is only used here for now, this effect can be use in other scenarios as well
(fn [callback-event]
(show-image-picker
(fn [image]
(let [path (get (js->clj image) "path")
_ (log/debug path)
on-success (fn [base64]
(re-frame/dispatch [callback-event base64]))
on-error (fn [type error]
(.log js/console type error))]
(img->base64 path on-success on-error))))))
(handlers/register-handler
:phone-number-change-requested
(handlers/register-handler-fx
:profile/send-transaction
(fn [_ [_ chat-id]]
{:dispatch-n [[:clear-seq-arguments]
[:navigate-to :chat chat-id]
;; TODO https://github.com/status-im/status-react/issues/1621
[:select-chat-input-command {:name "send"}]]}))
(handlers/register-handler-fx
:profile/send-message
(fn [_ [_ identity]]
(when identity
{:dispatch [:navigation-replace :chat identity]})))
(handlers/register-handler-fx
:my-profile/edit
(fn [{:keys [db]} [_ edit-type edit-value]]
(let [current-account-id (:current-account-id db)
current-account (select-keys (get-in db [:accounts current-account-id])
[:name :photo-path :status])
new-db (-> db
(update-in [:my-profile/edit] merge current-account)
(assoc-in [:my-profile/edit :edit-status?] (= edit-type :status true)))]
{:db new-db
:dispatch [:navigate-to :edit-my-profile]})))
(handlers/register-handler-fx
:my-profile/update-status
(fn [_ [_ new-status]]
(when-not (string/blank? new-status)
{:dispatch-n [[:check-status-change new-status]
[:account-update {:status new-status}]]})))
(handlers/register-handler-fx
:my-profile/update-phone-number
;; Switch user to the console issuing the !phone command automatically to let him change his phone number.
;; We allow to change phone number only from console because this requires entering SMS verification code.
(handlers/side-effect!
(fn [db _]
(re-frame/dispatch [:navigate-to :chat console-chat-id])
(js/setTimeout #(re-frame/dispatch [:select-chat-input-command {:name "phone"}]) 500))))
(fn [_ _]
{:dispatch-n [[:navigate-to :chat console-chat-id]
[:select-chat-input-command {:name "phone"}]]}))
(handlers/register-handler
:open-chat-with-the-send-transaction
(handlers/side-effect!
(fn [db [_ chat-id]]
(re-frame/dispatch [:clear-seq-arguments])
(re-frame/dispatch [:navigate-to :chat chat-id])
(js/setTimeout #(re-frame/dispatch [:select-chat-input-command {:name "send"}]) 500))))
(handlers/register-handler-fx
:my-profile/update-picture
(fn [{:keys [db]} [this-event base64-image]]
(if base64-image
{:db (assoc-in db [:my-profile/edit :photo-path] (str "data:image/jpeg;base64," base64-image))}
{:open-image-picker this-event})))
(defn prepare-edit-profile
[{:keys [current-account-id] :as db} _]
(let [current-account (select-keys (get-in db [:accounts current-account-id])
[:name :photo-path :status])]
(update-in db [:profile-edit] merge current-account)))
(defn open-edit-profile [_ _]
(re-frame/dispatch [:navigate-to :edit-my-profile]))
(handlers/register-handler
:open-edit-my-profile
(handlers/handlers->
prepare-edit-profile
open-edit-profile))
(handlers/register-handler-fx
:my-profile/save-changes
(fn [{:keys [db]} _]
(let [{:keys [:my-profile/edit]} db]
{:dispatch-n [[:check-status-change (:status edit)]
[:account-update edit]]})))

View File

@ -18,7 +18,7 @@
_ (log/debug "Captured image: " path)
on-success (fn [base64]
(log/debug "Captured success: " base64)
(dispatch [:set-in [:profile-edit :photo-path] (str "data:image/jpeg;base64," base64)])
(dispatch [:set-in [:my-profile/edit :photo-path] (str "data:image/jpeg;base64," base64)])
(dispatch [:navigate-back]))
on-error (fn [type error]
(log/debug type error))]

View File

@ -50,10 +50,10 @@
:padding 16
:max-height 114})
(def profile-bage
(def profile-badge
{:flex-direction :row})
(def edit-profile-bage
(def edit-profile-badge
{:flex-direction :row
:padding-left 24})

View File

@ -17,14 +17,13 @@
[status-im.components.toolbar-new.actions :as actions]
[status-im.components.toolbar-new.view :refer [toolbar]]
[status-im.i18n :refer [label]]
[status-im.ui.screens.profile.events :as profile.event :refer [message-user]]
[status-im.ui.screens.profile.styles :as styles]
[status-im.utils.datetime :as time]
[status-im.utils.utils :refer [hash-tag?]])
(:require-macros [status-im.utils.views :refer [defview]]))
(defn my-profile-toolbar []
[toolbar {:actions [(actions/opts [{:value #(dispatch [:open-edit-my-profile])
[toolbar {:actions [(actions/opts [{:value #(dispatch [:my-profile/edit])
:text (label :t/edit)}])]}])
(defn profile-toolbar [contact]
@ -43,7 +42,7 @@
(label :t/active-unknown))))
(defn profile-badge [{:keys [name last-online] :as contact}]
[react/view styles/profile-bage
[react/view styles/profile-badge
[my-profile-icon {:account contact
:edit? false}]
[react/view styles/profile-badge-name-container
@ -66,13 +65,13 @@
[action-separator]
[action-button (label :t/start-conversation)
:chats_blue
#(message-user whisper-identity)]
#(dispatch [:profile/send-message whisper-identity])]
(when-not dapp?
[react/view
[action-separator]
[action-button (label :t/send-transaction)
:arrow_right_blue
#(dispatch [:open-chat-with-the-send-transaction chat-id])]])])
#(dispatch [:profile/send-transaction chat-id])]])])
(defn profile-info-item [{:keys [label value options text-mode empty-value?]}]
[react/view styles/profile-setting-item
@ -160,22 +159,18 @@
[info-item-separator]
[profile-info-phone-item
phone
[{:value #(dispatch [:phone-number-change-requested])
[{:value #(dispatch [:my-profile/change-phone-number])
:text (label :t/edit)}]]])
(defn- profile-status-on-press []
(dispatch [:set-in [:profile-edit :edit-status?] true])
(dispatch [:open-edit-my-profile]))
(defn profile-status [status & [edit?]]
[react/view styles/profile-status-container
(if (or (nil? status) (string/blank? status))
[react/touchable-highlight {:on-press profile-status-on-press}
[react/touchable-highlight {:on-press #(dispatch [:my-profile/edit :status])}
[react/view
[react/text {:style styles/add-a-status}
(label :t/add-a-status)]]]
[react/scroll-view
[react/touchable-highlight {:on-press (when edit? profile-status-on-press)}
[react/touchable-highlight {:on-press (when edit? #(dispatch [:my-profile/edit :status]))}
[react/view
[react/text {:style styles/profile-status-text}
(colorize-status-hashtags status)]]]])])