Costmetic refactoring according to refactoring guidelines
This commit is contained in:
parent
6dafd137dc
commit
69a84c8315
|
@ -45,8 +45,8 @@
|
|||
(let [o (orientation->keyword (.getInitialOrientation react/orientation))]
|
||||
(dispatch [:set :orientation o]))
|
||||
(.addOrientationListener
|
||||
react/orientation
|
||||
#(dispatch [:set :orientation (orientation->keyword %)]))
|
||||
react/orientation
|
||||
#(dispatch [:set :orientation (orientation->keyword %)]))
|
||||
(.lockToPortrait react/orientation)
|
||||
(.addListener react/keyboard
|
||||
"keyboardDidShow"
|
||||
|
@ -74,4 +74,4 @@
|
|||
(.registerComponent react/app-registry "StatusIm" #(reagent/reactify-component app-root))
|
||||
(status/set-soft-input-mode status/adjust-resize)
|
||||
(init-back-button-handler!)
|
||||
(dispatch-sync [:initialize-app]))
|
||||
(dispatch-sync [:initialize-app]))
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
dismiss-keyboard!]]
|
||||
[status-im.components.status-view.view :as status-view]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.profile.validations :as v]
|
||||
[status-im.ui.screens.profile.db :as profile.db]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.utils.listview :as lw]
|
||||
|
@ -54,13 +54,13 @@
|
|||
[view {:style st/name-input-wrapper}
|
||||
[text-input
|
||||
{:placeholder placeholder
|
||||
:style (st/name-input-text (s/valid? ::v/name (or new-name current-name)))
|
||||
:style (st/name-input-text (s/valid? ::profile.db/name (or new-name current-name)))
|
||||
: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? ::v/name new-name)
|
||||
(when (s/valid? ::profile.db/name new-name)
|
||||
(rf/dispatch [:account-update {:name (utils/clean-text new-name)}])))}]]))
|
||||
|
||||
(defview status-input []
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
(let [o (orientation->keyword (.getInitialOrientation react/orientation))]
|
||||
(dispatch [:set :orientation o]))
|
||||
(.addOrientationListener
|
||||
react/orientation
|
||||
#(dispatch [:set :orientation (orientation->keyword %)]))
|
||||
react/orientation
|
||||
#(dispatch [:set :orientation (orientation->keyword %)]))
|
||||
(.lockToPortrait react/orientation)
|
||||
(.addListener react/keyboard
|
||||
"keyboardWillShow"
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
(ns status-im.profile.edit.screen
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [cljs.spec.alpha :as s]
|
||||
[clojure.string :as str]
|
||||
[reagent.core :as r]
|
||||
[re-frame.core :refer [dispatch]]
|
||||
[status-im.profile.styles :as st]
|
||||
[status-im.components.text-input-with-label.view :refer [text-input-with-label]]
|
||||
[status-im.components.styles :refer [color-blue color-gray5]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar-new.view :refer [toolbar]]
|
||||
[status-im.components.toolbar-new.actions :as act]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.profile.screen :refer [colorize-status-hashtags]]
|
||||
[status-im.components.sticky-button :refer [sticky-button]]
|
||||
[status-im.components.camera :as camera]
|
||||
[status-im.components.chat-icon.screen :refer [my-profile-icon]]
|
||||
[status-im.components.context-menu :refer [context-menu]]
|
||||
[status-im.profile.validations :as v]
|
||||
[status-im.components.react :refer [view
|
||||
scroll-view
|
||||
keyboard-avoiding-view
|
||||
text
|
||||
touchable-highlight
|
||||
text-input]]
|
||||
[status-im.utils.utils :as utils :refer [clean-text]]
|
||||
[status-im.utils.platform :refer [ios?]]))
|
||||
|
||||
(defn edit-my-profile-toolbartoolbar []
|
||||
[toolbar {:title (label :t/edit-profile)
|
||||
:actions [{:image :blank}]}])
|
||||
|
||||
(defview profile-name-input []
|
||||
[new-profile-name [:get-in [:profile-edit :name]]]
|
||||
[view
|
||||
[text-input-with-label {:label (label :t/name)
|
||||
:default-value new-profile-name
|
||||
:on-change-text #(dispatch [:set-in [:profile-edit :name] %])}]])
|
||||
|
||||
(def profile-icon-options
|
||||
[{:text (label :t/image-source-gallery)
|
||||
:value #(dispatch [:open-image-picker])}
|
||||
{: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-bage [contact]
|
||||
[view st/edit-profile-bage
|
||||
[view st/edit-profile-icon-container
|
||||
[context-menu
|
||||
[my-profile-icon {:account contact
|
||||
:edit? true}]
|
||||
profile-icon-options
|
||||
st/context-menu-custom-styles]]
|
||||
[view st/edit-profile-name-container
|
||||
[profile-name-input]]])
|
||||
|
||||
(defn edit-profile-status [{:keys [status edit-status?]}]
|
||||
(let [input-ref (r/atom nil)]
|
||||
[view st/edit-profile-status
|
||||
[scroll-view
|
||||
(if edit-status?
|
||||
[text-input
|
||||
{:ref #(reset! input-ref %)
|
||||
:auto-focus edit-status?
|
||||
:multiline true
|
||||
:max-length 140
|
||||
:placeholder (label :t/status)
|
||||
:style st/profile-status-input
|
||||
:on-change-text #(dispatch [:set-in [:profile-edit :status] (clean-text %)])
|
||||
:on-blur #(dispatch [:set-in [:profile-edit :edit-status?] false])
|
||||
:blur-on-submit true
|
||||
:on-submit-editing #(.blur @input-ref)
|
||||
:default-value status}]
|
||||
[touchable-highlight {:on-press #(dispatch [:set-in [:profile-edit :edit-status?] true])}
|
||||
[view
|
||||
(if (str/blank? status)
|
||||
[text {:style st/add-a-status}
|
||||
(label :t/status)]
|
||||
[text {:style st/profile-status-text}
|
||||
(colorize-status-hashtags status)])]])]]))
|
||||
|
||||
(defn status-prompt [{:keys [status]}]
|
||||
(when (or (nil? status) (str/blank? status))
|
||||
[view st/status-prompt
|
||||
[text {:style st/status-prompt-text}
|
||||
(colorize-status-hashtags (label :t/status-prompt))]]))
|
||||
|
||||
(defview edit-my-profile []
|
||||
[current-account [:get-current-account]
|
||||
changed-account [:get :profile-edit]]
|
||||
{:component-will-unmount #(dispatch [:set-in [:profile-edit :edit-status?] false])}
|
||||
(let [profile-edit-data-valid? (s/valid? ::v/profile changed-account)
|
||||
profile-edit-data-changed? (or (not= (:name current-account) (:name changed-account))
|
||||
(not= (:status current-account) (:status changed-account))
|
||||
(not= (:photo-path current-account) (:photo-path changed-account)))]
|
||||
[keyboard-avoiding-view {:style st/profile}
|
||||
[status-bar]
|
||||
[edit-my-profile-toolbartoolbar]
|
||||
[view st/edit-my-profile-form
|
||||
[edit-profile-bage 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]))])]))
|
|
@ -1,62 +0,0 @@
|
|||
(ns status-im.profile.handlers
|
||||
(:require [re-frame.core :refer [subscribe dispatch after]]
|
||||
[status-im.utils.handlers :refer [register-handler get-hashtags] :as u]
|
||||
[status-im.components.react :refer [show-image-picker]]
|
||||
[status-im.utils.image-processing :refer [img->base64]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
[status-im.ui.screens.navigation :as nav]))
|
||||
|
||||
(defn message-user [identity]
|
||||
(when identity
|
||||
(dispatch [:navigation-replace :chat identity])))
|
||||
|
||||
(register-handler :open-image-picker
|
||||
(u/side-effect!
|
||||
(fn [_ _]
|
||||
(show-image-picker
|
||||
(fn [image]
|
||||
(let [path (get (js->clj image) "path")
|
||||
_ (log/debug path)
|
||||
on-success (fn [base64]
|
||||
(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)))))))
|
||||
|
||||
(register-handler :phone-number-change-requested
|
||||
;; 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.
|
||||
(u/side-effect!
|
||||
(fn [db _]
|
||||
(dispatch [:navigate-to :chat console-chat-id])
|
||||
(js/setTimeout #(dispatch [:select-chat-input-command {:name "phone"}]) 500))))
|
||||
|
||||
(register-handler :open-chat-with-the-send-transaction
|
||||
(u/side-effect!
|
||||
(fn [db [_ chat-id]]
|
||||
(dispatch [:clear-seq-arguments])
|
||||
(dispatch [:navigate-to :chat chat-id])
|
||||
(js/setTimeout #(dispatch [:select-chat-input-command {:name "send"}]) 500))))
|
||||
|
||||
(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 [_ _]
|
||||
(dispatch [:navigate-to :edit-my-profile]))
|
||||
|
||||
(register-handler :open-edit-my-profile
|
||||
(u/handlers->
|
||||
prepare-edit-profile
|
||||
open-edit-profile))
|
||||
|
||||
(defmethod nav/preload-data! :qr-code-view
|
||||
[{:keys [current-account-id] :as db} [_ _ {:keys [contact qr-source amount?]}]]
|
||||
(assoc db :qr-modal {:contact (or contact
|
||||
(get-in db [:accounts current-account-id]))
|
||||
:qr-source qr-source
|
||||
:amount? amount?}))
|
|
@ -1,5 +0,0 @@
|
|||
(ns status-im.profile.photo-capture.styles)
|
||||
|
||||
(def container
|
||||
{:flex 1
|
||||
:background-color :white})
|
|
@ -1,58 +0,0 @@
|
|||
(ns status-im.profile.qr-code.screen
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [status-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight
|
||||
get-dimensions]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.styles :refer [icon-close]]
|
||||
[status-im.components.qr-code :refer [qr-code]]
|
||||
[re-frame.core :refer [dispatch subscribe]]
|
||||
[status-im.profile.qr-code.styles :as st]
|
||||
[status-im.i18n :refer [label]]
|
||||
[clojure.string :as s]))
|
||||
|
||||
(defview qr-code-view []
|
||||
[{:keys [photo-path address name] :as contact} [:get-in [:qr-modal :contact]]
|
||||
{:keys [qr-source amount? dimensions]} [:get :qr-modal]
|
||||
{:keys [amount]} [:get :contacts/click-params]]
|
||||
[view st/wallet-qr-code
|
||||
[status-bar {:type :modal}]
|
||||
[view st/account-toolbar
|
||||
[view st/wallet-account-container
|
||||
[view st/qr-photo-container
|
||||
[view st/account-photo-container
|
||||
[image {:source {:uri (if (s/blank? photo-path) :avatar photo-path)}
|
||||
:style st/photo-image}]]]
|
||||
[view st/name-container
|
||||
[text {:style st/name-text
|
||||
:number-of-lines 1} name]]
|
||||
[view st/online-container
|
||||
[touchable-highlight {:onPress #(dispatch [:navigate-back])}
|
||||
[view st/online-image-container
|
||||
[icon :close_white]]]]]]
|
||||
[view {:style st/qr-code
|
||||
:on-layout #(let [layout (.. % -nativeEvent -layout)]
|
||||
(dispatch [:set-in [:qr-modal :dimensions] {:width (.-width layout)
|
||||
:height (.-height layout)}]))}
|
||||
(when (:width dimensions)
|
||||
[view {:style (st/qr-code-container dimensions)}
|
||||
[qr-code {:value (if amount?
|
||||
(prn-str {:address (get contact qr-source)
|
||||
:amount amount})
|
||||
(str "ethereum:" (get contact qr-source)))
|
||||
:size (- (min (:width dimensions)
|
||||
(:height dimensions))
|
||||
80)}]])]
|
||||
[view st/footer
|
||||
[view st/wallet-info
|
||||
[text {:style st/wallet-name-text} (label :t/main-wallet)]
|
||||
[text {:style st/wallet-address-text} address]]
|
||||
|
||||
[touchable-highlight {:onPress #(dispatch [:navigate-back])}
|
||||
[view st/done-button
|
||||
[text {:style st/done-button-text} (label :t/done)]]]]])
|
||||
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
(ns status-im.profile.screen
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[clojure.string :as str]
|
||||
[reagent.core :as r]
|
||||
[status-im.ui.screens.contacts.styles :as cst]
|
||||
[status-im.components.common.common :refer [separator
|
||||
form-spacer
|
||||
top-shadow
|
||||
bottom-shadow]]
|
||||
[status-im.components.styles :refer [color-blue color-gray5]]
|
||||
[status-im.components.context-menu :refer [context-menu]]
|
||||
[status-im.components.action-button.action-button :refer [action-button
|
||||
action-button-disabled
|
||||
action-separator]]
|
||||
[status-im.components.action-button.styles :refer [actions-list]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
text-input
|
||||
image
|
||||
icon
|
||||
scroll-view
|
||||
touchable-highlight]]
|
||||
[status-im.components.chat-icon.screen :refer [my-profile-icon]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar-new.view :refer [toolbar]]
|
||||
[status-im.components.toolbar-new.actions :as act]
|
||||
[status-im.components.list-selection :refer [share-options]]
|
||||
[status-im.utils.platform :refer [platform-specific android?]]
|
||||
[status-im.profile.handlers :refer [message-user]]
|
||||
[status-im.profile.styles :as st]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.utils :refer [hash-tag?]]))
|
||||
|
||||
|
||||
(defn my-profile-toolbar []
|
||||
[toolbar {:actions [(act/opts [{:value #(dispatch [:open-edit-my-profile])
|
||||
:text (label :t/edit)}])]}])
|
||||
|
||||
(defn profile-toolbar [contact]
|
||||
[toolbar
|
||||
(when (and (not (:pending? contact))
|
||||
(not (:unremovable? contact)))
|
||||
{:actions [(act/opts [{:value #(dispatch [:hide-contact contact])
|
||||
:text (label :t/remove-from-contacts)}])]})])
|
||||
|
||||
(defn online-text [last-online]
|
||||
(let [last-online-date (time/to-date last-online)
|
||||
now-date (time/now)]
|
||||
(if (and (pos? last-online)
|
||||
(<= last-online-date now-date))
|
||||
(time/time-ago last-online-date)
|
||||
(label :t/active-unknown))))
|
||||
|
||||
(defn profile-badge [{:keys [name last-online] :as contact}]
|
||||
[view st/profile-bage
|
||||
[my-profile-icon {:account contact
|
||||
:edit? false}]
|
||||
[view st/profile-badge-name-container
|
||||
[text {:style st/profile-name-text
|
||||
:number-of-lines 1}
|
||||
name]
|
||||
(when-not (nil? last-online)
|
||||
[view st/profile-activity-status-container
|
||||
[text {:style st/profile-activity-status-text}
|
||||
(online-text last-online)]])]])
|
||||
|
||||
(defn profile-actions [{:keys [pending? whisper-identity dapp?]} chat-id]
|
||||
[view actions-list
|
||||
(if pending?
|
||||
[action-button (label :t/add-to-contacts)
|
||||
:add_blue
|
||||
#(dispatch [:add-pending-contact chat-id])]
|
||||
[action-button-disabled (label :t/in-contacts)
|
||||
:ok_dark])
|
||||
[action-separator]
|
||||
[action-button (label :t/start-conversation)
|
||||
:chats_blue
|
||||
#(message-user whisper-identity)]
|
||||
(when-not dapp?
|
||||
[view
|
||||
[action-separator]
|
||||
[action-button (label :t/send-transaction)
|
||||
:arrow_right_blue
|
||||
#(dispatch [:open-chat-with-the-send-transaction chat-id])]])])
|
||||
|
||||
(defn profile-info-item [{:keys [label value options text-mode empty-value?]}]
|
||||
[view st/profile-setting-item
|
||||
[view (st/profile-info-text-container options)
|
||||
[text {:style st/profile-setting-title}
|
||||
label]
|
||||
[view st/profile-setting-spacing]
|
||||
[text {:style (if empty-value?
|
||||
st/profile-setting-text-empty
|
||||
st/profile-setting-text)
|
||||
:number-of-lines 1
|
||||
:ellipsizeMode text-mode}
|
||||
value]]
|
||||
(when options
|
||||
[context-menu
|
||||
[icon :options_gray]
|
||||
options
|
||||
nil
|
||||
st/profile-info-item-button])])
|
||||
|
||||
(defn show-qr [contact qr-source]
|
||||
#(dispatch [:navigate-to-modal :qr-code-view {:contact contact
|
||||
:qr-source qr-source}]))
|
||||
|
||||
(defn profile-options [contact k text]
|
||||
(into []
|
||||
(concat [{:value (show-qr contact k)
|
||||
:text (label :t/show-qr)}]
|
||||
(when text
|
||||
(share-options text)))))
|
||||
|
||||
(defn profile-info-address-item [{:keys [address] :as contact}]
|
||||
[profile-info-item
|
||||
{:label (label :t/address)
|
||||
:value address
|
||||
:options (profile-options contact :address address)
|
||||
:text-mode :middle}])
|
||||
|
||||
(defn profile-info-public-key-item [public-key contact]
|
||||
[profile-info-item
|
||||
{:label (label :t/public-key)
|
||||
:value public-key
|
||||
:options (profile-options contact :public-key public-key)
|
||||
:text-mode :middle}])
|
||||
|
||||
(defn info-item-separator []
|
||||
[separator st/info-item-separator])
|
||||
|
||||
(defn tag-view [tag]
|
||||
[text {:style {:color color-blue}
|
||||
:font :medium}
|
||||
(str tag " ")])
|
||||
|
||||
(defn colorize-status-hashtags [status]
|
||||
(for [[i status] (map-indexed vector (str/split status #" "))]
|
||||
(if (hash-tag? status)
|
||||
^{:key (str "item-" i)}
|
||||
[tag-view status]
|
||||
^{:key (str "item-" i)}
|
||||
(str status " "))))
|
||||
|
||||
(defn profile-info-phone-item [phone & [options]]
|
||||
(let [phone-empty? (or (nil? phone) (str/blank? phone))
|
||||
phone-text (if phone-empty?
|
||||
(label :t/not-specified)
|
||||
phone)]
|
||||
[profile-info-item {:label (label :t/phone-number)
|
||||
:value phone-text
|
||||
:options options
|
||||
:empty-value? phone-empty?}]))
|
||||
|
||||
(defn profile-info [{:keys [whisper-identity status phone] :as contact}]
|
||||
[view
|
||||
[profile-info-address-item contact]
|
||||
[info-item-separator]
|
||||
[profile-info-public-key-item whisper-identity contact]
|
||||
[info-item-separator]
|
||||
[profile-info-phone-item phone]])
|
||||
|
||||
(defn my-profile-info [{:keys [public-key status phone] :as contact}]
|
||||
[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 [:phone-number-change-requested])
|
||||
: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?]]
|
||||
[view st/profile-status-container
|
||||
(if (or (nil? status) (str/blank? status))
|
||||
[touchable-highlight {:on-press profile-status-on-press}
|
||||
[view
|
||||
[text {:style st/add-a-status}
|
||||
(label :t/add-a-status)]]]
|
||||
[scroll-view
|
||||
[touchable-highlight {:on-press (when edit? profile-status-on-press)}
|
||||
[view
|
||||
[text {:style st/profile-status-text}
|
||||
(colorize-status-hashtags status)]]]])])
|
||||
|
||||
(defview my-profile []
|
||||
[{:keys [status] :as current-account} [:get-current-account]]
|
||||
[view st/profile
|
||||
[status-bar]
|
||||
[my-profile-toolbar]
|
||||
[scroll-view
|
||||
[view st/profile-form
|
||||
[profile-badge current-account]
|
||||
[profile-status status true]]
|
||||
[form-spacer]
|
||||
[view actions-list
|
||||
[action-button (label :t/show-qr)
|
||||
:q_r_blue
|
||||
(show-qr current-account :public-key)]]
|
||||
[form-spacer]
|
||||
[view st/profile-info-container
|
||||
[my-profile-info current-account]
|
||||
[bottom-shadow]]]])
|
||||
|
||||
(defview profile []
|
||||
[{:keys [pending?
|
||||
status
|
||||
whisper-identity]
|
||||
:as contact} [:contact]
|
||||
chat-id [:get :current-chat-id]]
|
||||
[view st/profile
|
||||
[status-bar]
|
||||
[profile-toolbar contact]
|
||||
[scroll-view
|
||||
[view st/profile-form
|
||||
[profile-badge contact]
|
||||
(when (and (not (nil? status)) (not (str/blank? status)))
|
||||
[profile-status status])]
|
||||
[form-spacer]
|
||||
[profile-actions contact chat-id]
|
||||
[form-spacer]
|
||||
[view st/profile-info-container
|
||||
[profile-info contact]
|
||||
[bottom-shadow]]]])
|
|
@ -1,5 +0,0 @@
|
|||
(ns status-im.profile.specs
|
||||
(:require [cljs.spec.alpha :as s]))
|
||||
|
||||
;EDIT PROFILE
|
||||
(s/def :profile/profile-edit (s/nilable map?))
|
|
@ -1,25 +0,0 @@
|
|||
(ns status-im.profile.validations
|
||||
(:require [cljs.spec.alpha :as s]
|
||||
[status-im.constants :refer [console-chat-id wallet-chat-id]]
|
||||
[status-im.chat.constants :as chat-consts]
|
||||
[clojure.string :as str]
|
||||
[status-im.utils.homoglyph :as h]))
|
||||
|
||||
(defn correct-name? [username]
|
||||
(when-let [username (some-> username (str/trim))]
|
||||
(every? false?
|
||||
[(str/blank? username)
|
||||
(h/matches username console-chat-id)
|
||||
(h/matches username wallet-chat-id)
|
||||
(str/includes? username chat-consts/command-char)
|
||||
(str/includes? username chat-consts/bot-char)])))
|
||||
|
||||
(defn correct-email? [email]
|
||||
(let [pattern #"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"]
|
||||
(or (str/blank? email)
|
||||
(and (string? email) (re-matches pattern email)))))
|
||||
|
||||
(s/def ::name correct-name?)
|
||||
(s/def ::email correct-email?)
|
||||
|
||||
(s/def ::profile (s/keys :req-un [::name]))
|
|
@ -9,7 +9,7 @@
|
|||
status-im.ui.screens.group.db
|
||||
status-im.chat.specs
|
||||
status-im.chat.new-public-chat.db
|
||||
status-im.profile.specs
|
||||
status-im.ui.screens.profile.db
|
||||
status-im.transactions.specs
|
||||
status-im.ui.screens.discover.db))
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
|||
:sync-state :done
|
||||
:network :testnet})
|
||||
|
||||
|
||||
;;;;GLOBAL
|
||||
|
||||
;;public key of current logged in account
|
||||
|
|
|
@ -1,39 +1,37 @@
|
|||
(ns status-im.ui.screens.events
|
||||
(:require
|
||||
status-im.chat.handlers
|
||||
status-im.ui.screens.group.chat-settings.events
|
||||
status-im.ui.screens.navigation
|
||||
status-im.ui.screens.contacts.events
|
||||
status-im.ui.screens.discover.events
|
||||
status-im.ui.screens.group.events
|
||||
status-im.profile.handlers
|
||||
status-im.commands.handlers.loading
|
||||
status-im.commands.handlers.jail
|
||||
status-im.ui.screens.qr-scanner.events
|
||||
status-im.ui.screens.accounts.events
|
||||
status-im.protocol.handlers
|
||||
status-im.transactions.handlers
|
||||
status-im.network.handlers
|
||||
status-im.debug.handlers
|
||||
status-im.bots.handlers
|
||||
(:require status-im.bots.handlers
|
||||
status-im.chat.handlers
|
||||
status-im.commands.handlers.jail
|
||||
status-im.commands.handlers.loading
|
||||
status-im.debug.handlers
|
||||
status-im.network.handlers
|
||||
status-im.protocol.handlers
|
||||
status-im.transactions.handlers
|
||||
status-im.ui.screens.accounts.events
|
||||
status-im.ui.screens.contacts.events
|
||||
status-im.ui.screens.discover.events
|
||||
status-im.ui.screens.group.chat-settings.events
|
||||
status-im.ui.screens.group.events
|
||||
status-im.ui.screens.navigation
|
||||
status-im.ui.screens.profile.events
|
||||
status-im.ui.screens.qr-scanner.events
|
||||
|
||||
[re-frame.core :refer [dispatch reg-fx]]
|
||||
[status-im.utils.handlers :refer [register-handler-db register-handler-fx]]
|
||||
[status-im.ui.screens.db :refer [app-db]]
|
||||
[status-im.data-store.core :as data-store]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.crypt :as crypt]
|
||||
[status-im.components.status :as status]
|
||||
[status-im.components.permissions :as permissions]
|
||||
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
[status-im.utils.instabug :as inst]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.js-dependencies :as dependencies]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.i18n :as i18n]))
|
||||
[re-frame.core :refer [dispatch reg-fx]]
|
||||
[status-im.components.status :as status]
|
||||
[status-im.components.permissions :as permissions]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
[status-im.data-store.core :as data-store]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.js-dependencies :as dependencies]
|
||||
[status-im.ui.screens.db :refer [app-db]]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.crypt :as crypt]
|
||||
[status-im.utils.handlers :refer [register-handler-db register-handler-fx]]
|
||||
[status-im.utils.instabug :as inst]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.utils.utils :as utils]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
;;;; COFX
|
||||
|
||||
|
@ -48,33 +46,33 @@
|
|||
::initialize-crypt-fx
|
||||
(fn []
|
||||
(crypt/gen-random-bytes
|
||||
1024
|
||||
(fn [{:keys [error buffer]}]
|
||||
(if error
|
||||
(log/error "Failed to generate random bytes to initialize sjcl crypto")
|
||||
(->> (.toString buffer "hex")
|
||||
(.toBits (.. dependencies/eccjs -sjcl -codec -hex))
|
||||
(.addEntropy (.. dependencies/eccjs -sjcl -random))))))))
|
||||
1024
|
||||
(fn [{:keys [error buffer]}]
|
||||
(if error
|
||||
(log/error "Failed to generate random bytes to initialize sjcl crypto")
|
||||
(->> (.toString buffer "hex")
|
||||
(.toBits (.. dependencies/eccjs -sjcl -codec -hex))
|
||||
(.addEntropy (.. dependencies/eccjs -sjcl -random))))))))
|
||||
|
||||
(defn node-started [result]
|
||||
(log/debug "Started Node"))
|
||||
|
||||
(defn move-to-internal-storage []
|
||||
(status/move-to-internal-storage
|
||||
(fn []
|
||||
(status/start-node node-started))))
|
||||
(fn []
|
||||
(status/start-node node-started))))
|
||||
|
||||
(reg-fx
|
||||
::initialize-geth-fx
|
||||
(fn []
|
||||
(status/should-move-to-internal-storage?
|
||||
(fn [should-move?]
|
||||
(if should-move?
|
||||
(dispatch [:request-permissions
|
||||
[:read-external-storage]
|
||||
#(move-to-internal-storage)
|
||||
#(dispatch [:move-to-internal-failure-message])])
|
||||
(status/start-node node-started))))))
|
||||
(fn [should-move?]
|
||||
(if should-move?
|
||||
(dispatch [:request-permissions
|
||||
[:read-external-storage]
|
||||
#(move-to-internal-storage)
|
||||
#(dispatch [:move-to-internal-failure-message])])
|
||||
(status/start-node node-started))))))
|
||||
|
||||
(reg-fx
|
||||
::status-module-initialized-fx
|
||||
|
@ -101,8 +99,8 @@
|
|||
(fn []
|
||||
(when config/testfairy-enabled?
|
||||
(utils/show-popup
|
||||
(i18n/label :testfairy-title)
|
||||
(i18n/label :testfairy-message)))))
|
||||
(i18n/label :testfairy-title)
|
||||
(i18n/label :testfairy-message)))))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
|
@ -133,12 +131,12 @@
|
|||
network-status network _]} :db} _]
|
||||
{::init-store nil
|
||||
:db (assoc app-db
|
||||
:current-account-id nil
|
||||
:contacts/contacts {}
|
||||
:network-status network-status
|
||||
:status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?)
|
||||
:status-node-started? status-node-started?
|
||||
:network (or network :testnet))}))
|
||||
:current-account-id nil
|
||||
:contacts/contacts {}
|
||||
:network-status network-status
|
||||
:status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?)
|
||||
:status-node-started? status-node-started?
|
||||
:network (or network :testnet))}))
|
||||
|
||||
(register-handler-db
|
||||
:initialize-account-db
|
||||
|
@ -174,14 +172,14 @@
|
|||
:chat
|
||||
:accounts)]
|
||||
(merge
|
||||
{:db (assoc db :view-id view
|
||||
:navigation-stack (list view))}
|
||||
(when (or (empty? accounts) open-console?)
|
||||
{:dispatch-n (concat
|
||||
[[:init-console-chat]
|
||||
[:load-commands!]]
|
||||
(when open-console?
|
||||
[[:navigate-to :chat console-chat-id]]))})))))
|
||||
{:db (assoc db :view-id view
|
||||
:navigation-stack (list view))}
|
||||
(when (or (empty? accounts) open-console?)
|
||||
{:dispatch-n (concat
|
||||
[[:init-console-chat]
|
||||
[:load-commands!]]
|
||||
(when open-console?
|
||||
[[:navigate-to :chat console-chat-id]]))})))))
|
||||
|
||||
(register-handler-fx
|
||||
:initialize-crypt
|
||||
|
@ -247,19 +245,19 @@
|
|||
(fn []
|
||||
(let [watch-id (atom nil)]
|
||||
(.getCurrentPosition
|
||||
navigator.geolocation
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
(clj->js {:enableHighAccuracy true :timeout 20000 :maximumAge 1000}))
|
||||
navigator.geolocation
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
(clj->js {:enableHighAccuracy true :timeout 20000 :maximumAge 1000}))
|
||||
(when platform/android?
|
||||
(reset! watch-id
|
||||
(.watchPosition
|
||||
navigator.geolocation
|
||||
#(do
|
||||
(.clearWatch
|
||||
navigator.geolocation
|
||||
@watch-id)
|
||||
(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])))))))]}))
|
||||
navigator.geolocation
|
||||
#(do
|
||||
(.clearWatch
|
||||
navigator.geolocation
|
||||
@watch-id)
|
||||
(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])))))))]}))
|
||||
|
||||
(register-handler-db
|
||||
:update-geolocation
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
(ns status-im.ui.screens.profile.db
|
||||
(:require [cljs.spec.alpha :as spec]
|
||||
[clojure.string :as string]
|
||||
[status-im.chat.constants :as chat.constants]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.homoglyph :as homoglyph]))
|
||||
|
||||
(defn correct-name? [username]
|
||||
(when-let [username (some-> username (string/trim))]
|
||||
(every? false?
|
||||
[(string/blank? username)
|
||||
(homoglyph/matches username constants/console-chat-id)
|
||||
(homoglyph/matches username constants/wallet-chat-id)
|
||||
(string/includes? username chat.constants/command-char)
|
||||
(string/includes? username chat.constants/bot-char)])))
|
||||
|
||||
(defn correct-email? [email]
|
||||
(let [pattern #"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"]
|
||||
(or (string/blank? email)
|
||||
(and (string? email) (re-matches pattern email)))))
|
||||
|
||||
(spec/def ::name correct-name?)
|
||||
(spec/def ::email correct-email?)
|
||||
|
||||
(spec/def ::profile (spec/keys :req-un [::name]))
|
||||
|
||||
;; EDIT PROFILE
|
||||
(spec/def :profile/profile-edit (spec/nilable map?))
|
|
@ -0,0 +1,106 @@
|
|||
(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.components.camera :as camera]
|
||||
[status-im.components.chat-icon.screen :refer [my-profile-icon]]
|
||||
[status-im.components.context-menu :refer [context-menu]]
|
||||
[status-im.components.react :as react]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.sticky-button :refer [sticky-button]]
|
||||
[status-im.components.text-input-with-label.view :refer [text-input-with-label]]
|
||||
[status-im.components.toolbar-new.view :refer [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 {:title (label :t/edit-profile)
|
||||
:actions [{:image :blank}]}])
|
||||
|
||||
(defview profile-name-input []
|
||||
(letsubs [new-profile-name [:get-in [: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] %])}]]))
|
||||
|
||||
(def profile-icon-options
|
||||
[{:text (label :t/image-source-gallery)
|
||||
:value #(dispatch [:open-image-picker])}
|
||||
{: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-bage [contact]
|
||||
[react/view styles/edit-profile-bage
|
||||
[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]]])
|
||||
|
||||
(defn edit-profile-status [{:keys [status edit-status?]}]
|
||||
(let [input-ref (reagent/atom nil)]
|
||||
[react/view styles/edit-profile-status
|
||||
[react/scroll-view
|
||||
(if edit-status?
|
||||
[react/text-input
|
||||
{:ref #(reset! input-ref %)
|
||||
:auto-focus edit-status?
|
||||
:multiline true
|
||||
: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])
|
||||
: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/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 :profile-edit]]
|
||||
{:component-will-unmount #(dispatch [:set-in [: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))
|
||||
(not= (:photo-path current-account) (:photo-path changed-account)))]
|
||||
[react/keyboard-avoiding-view {:style styles/profile}
|
||||
[status-bar]
|
||||
[edit-my-profile-toolbar]
|
||||
[react/view styles/edit-my-profile-form
|
||||
[edit-profile-bage 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]))])])))
|
|
@ -0,0 +1,58 @@
|
|||
(ns status-im.ui.screens.profile.events
|
||||
(:require [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]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[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
|
||||
: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)))))))
|
||||
|
||||
(handlers/register-handler
|
||||
:phone-number-change-requested
|
||||
;; 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))))
|
||||
|
||||
(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))))
|
||||
|
||||
(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))
|
|
@ -0,0 +1,9 @@
|
|||
(ns status-im.ui.screens.profile.navigation
|
||||
(:require [status-im.ui.screens.navigation :as navigation]))
|
||||
|
||||
(defmethod navigation/preload-data! :qr-code-view
|
||||
[{:keys [current-account-id] :as db} [_ _ {:keys [contact qr-source amount?]}]]
|
||||
(assoc db :qr-modal {:contact (or contact
|
||||
(get-in db [:accounts current-account-id]))
|
||||
:qr-source qr-source
|
||||
:amount? amount?}))
|
|
@ -0,0 +1,5 @@
|
|||
(ns status-im.ui.screens.profile.photo-capture.styles)
|
||||
|
||||
(def container
|
||||
{:flex 1
|
||||
:background-color :white})
|
|
@ -1,28 +1,21 @@
|
|||
(ns status-im.profile.photo-capture.screen
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[clojure.walk :refer [keywordize-keys]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
touchable-highlight]]
|
||||
[status-im.components.camera :refer [camera
|
||||
aspects
|
||||
capture-targets]]
|
||||
[status-im.components.styles :refer [icon-back]]
|
||||
[status-im.components.icons.custom-icons :refer [ion-icon]]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar.view :refer [toolbar]]
|
||||
[status-im.components.toolbar.actions :as act]
|
||||
[status-im.components.toolbar.styles :refer [toolbar-background1]]
|
||||
[status-im.utils.image-processing :refer [img->base64]]
|
||||
[status-im.profile.photo-capture.styles :as st]
|
||||
[status-im.i18n :refer [label]]
|
||||
(ns status-im.ui.screens.profile.photo-capture.views
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[reagent.core :as r]
|
||||
[status-im.components.camera :refer [aspects camera capture-targets]]
|
||||
[status-im.components.icons.custom-icons :refer [ion-icon]]
|
||||
[status-im.components.react :as react]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.toolbar.actions :as actions]
|
||||
[status-im.components.toolbar.styles :refer [toolbar-background1]]
|
||||
[status-im.components.toolbar.view :refer [toolbar]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.ui.screens.profile.photo-capture.styles :as styles]
|
||||
[status-im.utils.image-processing :refer [img->base64]]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn image-captured [data]
|
||||
(let [path (.-path data)
|
||||
_ (log/debug "Captured image: " path)
|
||||
_ (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)])
|
||||
|
@ -33,10 +26,10 @@
|
|||
|
||||
(defn profile-photo-capture []
|
||||
(let [camera-ref (r/atom nil)]
|
||||
[view st/container
|
||||
[react/view styles/container
|
||||
[status-bar]
|
||||
[toolbar {:title (label :t/image-source-title)
|
||||
:nav-action (act/back #(dispatch [:navigate-back]))
|
||||
:nav-action (actions/back #(dispatch [:navigate-back]))
|
||||
:background-color toolbar-background1}]
|
||||
[camera {:style {:flex 1}
|
||||
:aspect (:fill aspects)
|
||||
|
@ -44,14 +37,14 @@
|
|||
:captureTarget (:disk capture-targets)
|
||||
:type "front"
|
||||
:ref #(reset! camera-ref %)}]
|
||||
[view {:style {:padding 10
|
||||
:background-color toolbar-background1}}
|
||||
[touchable-highlight {:style {:align-self "center"}
|
||||
:on-press (fn []
|
||||
(let [camera @camera-ref]
|
||||
(-> (.capture camera)
|
||||
(.then image-captured)
|
||||
(.catch #(log/debug "Error capturing image: " %)))))}
|
||||
[view
|
||||
[react/view {:style {:padding 10
|
||||
:background-color toolbar-background1}}
|
||||
[react/touchable-highlight {:style {:align-self "center"}
|
||||
:on-press (fn []
|
||||
(let [camera @camera-ref]
|
||||
(-> (.capture camera)
|
||||
(.then image-captured)
|
||||
(.catch #(log/debug "Error capturing image: " %)))))}
|
||||
[react/view
|
||||
[ion-icon {:name :md-camera
|
||||
:style {:font-size 36}}]]]]]))
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.profile.qr-code.styles
|
||||
(:require [status-im.components.styles :refer [color-white]]
|
||||
[status-im.components.react :as r]))
|
||||
(ns status-im.ui.screens.profile.qr-code.styles
|
||||
(:require [status-im.components.styles :refer [color-white]]))
|
||||
|
||||
(def photo-container
|
||||
{:flex 0.2
|
|
@ -0,0 +1,50 @@
|
|||
(ns status-im.ui.screens.profile.qr-code.views
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :refer [dispatch]]
|
||||
[status-im.components.qr-code :refer [qr-code]]
|
||||
[status-im.components.react :as react]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.ui.screens.profile.qr-code.styles :as styles])
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
(defview qr-code-view []
|
||||
(letsubs [{:keys [photo-path address name] :as contact} [:get-in [:qr-modal :contact]]
|
||||
{:keys [qr-source amount? dimensions]} [:get :qr-modal]
|
||||
{:keys [amount]} [:get :contacts/click-params]]
|
||||
[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
|
||||
[react/icon :close_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 (if amount?
|
||||
(prn-str {:address (get contact qr-source)
|
||||
:amount amount})
|
||||
(str "ethereum:" (get contact qr-source)))
|
||||
:size (- (min (:width dimensions)
|
||||
(:height dimensions))
|
||||
80)}]])]
|
||||
[react/view styles/footer
|
||||
[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/touchable-highlight {:onPress #(dispatch [:navigate-back])}
|
||||
[react/view styles/done-button
|
||||
[react/text {:style styles/done-button-text} (label :t/done)]]]]]))
|
|
@ -1,14 +1,15 @@
|
|||
(ns status-im.profile.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
||||
(:require [status-im.components.styles :refer [color-white
|
||||
color-black
|
||||
color-gray4
|
||||
color-gray5
|
||||
color-light-gray
|
||||
color-light-blue
|
||||
color-light-blue-transparent
|
||||
text1-color]]
|
||||
[status-im.utils.platform :as p]))
|
||||
(ns status-im.ui.screens.profile.styles
|
||||
(:require [status-im.components.styles
|
||||
:refer
|
||||
[color-black
|
||||
color-gray4
|
||||
color-gray5
|
||||
color-light-blue
|
||||
color-light-gray
|
||||
color-white
|
||||
text1-color]]
|
||||
[status-im.utils.platform :as platform])
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]]))
|
||||
|
||||
(def profile
|
||||
{:flex 1
|
||||
|
@ -129,7 +130,7 @@
|
|||
{:margin-left 16})
|
||||
|
||||
(def edit-line-color
|
||||
(if p/ios?
|
||||
(if platform/ios?
|
||||
(str color-gray5 "80")
|
||||
color-gray5))
|
||||
|
||||
|
@ -137,7 +138,7 @@
|
|||
color-light-blue)
|
||||
|
||||
(def profile-focus-line-height
|
||||
(get-in p/platform-specific [:component-styles :text-field-focus-line-height]))
|
||||
(get-in platform/platform-specific [:component-styles :text-field-focus-line-height]))
|
||||
|
||||
(defstyle profile-name-input
|
||||
{:color text1-color
|
||||
|
@ -189,4 +190,3 @@
|
|||
(def add-a-status
|
||||
(merge profile-status-text
|
||||
{:color color-gray4}))
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
(ns status-im.ui.screens.profile.views
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :refer [dispatch]]
|
||||
[status-im.components.action-button.action-button
|
||||
:refer
|
||||
[action-button action-button-disabled action-separator]]
|
||||
[status-im.components.action-button.styles :refer [actions-list]]
|
||||
[status-im.components.chat-icon.screen :refer [my-profile-icon]]
|
||||
[status-im.components.common.common
|
||||
:refer
|
||||
[bottom-shadow form-spacer separator]]
|
||||
[status-im.components.context-menu :refer [context-menu]]
|
||||
[status-im.components.list-selection :refer [share-options]]
|
||||
[status-im.components.react :as react]
|
||||
[status-im.components.status-bar :refer [status-bar]]
|
||||
[status-im.components.styles :refer [color-blue]]
|
||||
[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])
|
||||
:text (label :t/edit)}])]}])
|
||||
|
||||
(defn profile-toolbar [contact]
|
||||
[toolbar
|
||||
(when (and (not (:pending? contact))
|
||||
(not (:unremovable? contact)))
|
||||
{:actions [(actions/opts [{:value #(dispatch [:hide-contact contact])
|
||||
:text (label :t/remove-from-contacts)}])]})])
|
||||
|
||||
(defn online-text [last-online]
|
||||
(let [last-online-date (time/to-date last-online)
|
||||
now-date (time/now)]
|
||||
(if (and (pos? last-online)
|
||||
(<= last-online-date now-date))
|
||||
(time/time-ago last-online-date)
|
||||
(label :t/active-unknown))))
|
||||
|
||||
(defn profile-badge [{:keys [name last-online] :as contact}]
|
||||
[react/view styles/profile-bage
|
||||
[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}
|
||||
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 actions-list
|
||||
(if pending?
|
||||
[action-button (label :t/add-to-contacts)
|
||||
:add_blue
|
||||
#(dispatch [:add-pending-contact chat-id])]
|
||||
[action-button-disabled (label :t/in-contacts)
|
||||
:ok_dark])
|
||||
[action-separator]
|
||||
[action-button (label :t/start-conversation)
|
||||
:chats_blue
|
||||
#(message-user 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])]])])
|
||||
|
||||
(defn profile-info-item [{:keys [label value options text-mode empty-value?]}]
|
||||
[react/view styles/profile-setting-item
|
||||
[react/view (styles/profile-info-text-container options)
|
||||
[react/text {:style styles/profile-setting-title}
|
||||
label]
|
||||
[react/view styles/profile-setting-spacing]
|
||||
[react/text {:style (if empty-value?
|
||||
styles/profile-setting-text-empty
|
||||
styles/profile-setting-text)
|
||||
:number-of-lines 1
|
||||
:ellipsizeMode text-mode}
|
||||
value]]
|
||||
(when options
|
||||
[context-menu
|
||||
[react/icon :options_gray]
|
||||
options
|
||||
nil
|
||||
styles/profile-info-item-button])])
|
||||
|
||||
(defn show-qr [contact qr-source]
|
||||
#(dispatch [:navigate-to-modal :qr-code-view {:contact contact
|
||||
:qr-source qr-source}]))
|
||||
|
||||
(defn profile-options [contact k text]
|
||||
(into []
|
||||
(concat [{:value (show-qr contact k)
|
||||
:text (label :t/show-qr)}]
|
||||
(when text
|
||||
(share-options text)))))
|
||||
|
||||
(defn profile-info-address-item [{:keys [address] :as contact}]
|
||||
[profile-info-item
|
||||
{:label (label :t/address)
|
||||
:value address
|
||||
:options (profile-options contact :address address)
|
||||
:text-mode :middle}])
|
||||
|
||||
(defn profile-info-public-key-item [public-key contact]
|
||||
[profile-info-item
|
||||
{:label (label :t/public-key)
|
||||
:value public-key
|
||||
:options (profile-options contact :public-key public-key)
|
||||
:text-mode :middle}])
|
||||
|
||||
(defn info-item-separator []
|
||||
[separator styles/info-item-separator])
|
||||
|
||||
(defn tag-view [tag]
|
||||
[react/text {:style {:color color-blue}
|
||||
:font :medium}
|
||||
(str tag " ")])
|
||||
|
||||
(defn colorize-status-hashtags [status]
|
||||
(for [[i status] (map-indexed vector (string/split status #" "))]
|
||||
(if (hash-tag? status)
|
||||
^{:key (str "item-" i)}
|
||||
[tag-view status]
|
||||
^{:key (str "item-" i)}
|
||||
(str status " "))))
|
||||
|
||||
(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)
|
||||
:value phone-text
|
||||
:options options
|
||||
:empty-value? phone-empty?}]))
|
||||
|
||||
(defn profile-info [{:keys [whisper-identity status phone] :as contact}]
|
||||
[react/view
|
||||
[profile-info-address-item contact]
|
||||
[info-item-separator]
|
||||
[profile-info-public-key-item whisper-identity contact]
|
||||
[info-item-separator]
|
||||
[profile-info-phone-item phone]])
|
||||
|
||||
(defn my-profile-info [{:keys [public-key status phone] :as contact}]
|
||||
[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 [:phone-number-change-requested])
|
||||
: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/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/view
|
||||
[react/text {:style styles/profile-status-text}
|
||||
(colorize-status-hashtags status)]]]])])
|
||||
|
||||
(defview my-profile []
|
||||
(letsubs [{:keys [status] :as current-account} [:get-current-account]]
|
||||
[react/view styles/profile
|
||||
[status-bar]
|
||||
[my-profile-toolbar]
|
||||
[react/scroll-view
|
||||
[react/view styles/profile-form
|
||||
[profile-badge current-account]
|
||||
[profile-status status true]]
|
||||
[form-spacer]
|
||||
[react/view actions-list
|
||||
[action-button (label :t/show-qr)
|
||||
:q_r_blue
|
||||
(show-qr current-account :public-key)]]
|
||||
[form-spacer]
|
||||
[react/view styles/profile-info-container
|
||||
[my-profile-info current-account]
|
||||
[bottom-shadow]]]]))
|
||||
|
||||
(defview profile []
|
||||
(letsubs [{:keys [pending?
|
||||
status
|
||||
whisper-identity]
|
||||
:as contact} [:contact]
|
||||
chat-id [:get :current-chat-id]]
|
||||
[react/view styles/profile
|
||||
[status-bar]
|
||||
[profile-toolbar contact]
|
||||
[react/scroll-view
|
||||
[react/view styles/profile-form
|
||||
[profile-badge contact]
|
||||
(when (and (not (nil? status)) (not (string/blank? status)))
|
||||
[profile-status status])]
|
||||
[form-spacer]
|
||||
[profile-actions contact chat-id]
|
||||
[form-spacer]
|
||||
[react/view styles/profile-info-container
|
||||
[profile-info contact]
|
||||
[bottom-shadow]]]]))
|
|
@ -37,10 +37,10 @@
|
|||
add-participants-toggle-list]]
|
||||
[status-im.ui.screens.group.reorder.views :refer [reorder-groups]]
|
||||
|
||||
[status-im.profile.screen :refer [profile my-profile]]
|
||||
[status-im.profile.edit.screen :refer [edit-my-profile]]
|
||||
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
|
||||
[status-im.profile.qr-code.screen :refer [qr-code-view]]
|
||||
[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.photo-capture.views :refer [profile-photo-capture]]
|
||||
[status-im.ui.screens.profile.qr-code.views :refer [qr-code-view]]
|
||||
[status-im.ui.screens.wallet.send.views :refer [send-transaction]]))
|
||||
;;[status-im.ui.screens.wallet.receive.views :refer [receive-transaction]]
|
||||
|
||||
|
@ -103,4 +103,4 @@
|
|||
:transaction-details transaction-details
|
||||
:confirmation-success confirmation-success
|
||||
:contact-list-modal contact-list-modal)]
|
||||
[component])]])]])))))
|
||||
[component])]])]])))))
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
(ns status-im.utils.handlers
|
||||
(:require [re-frame.core :refer [reg-event-db reg-event-fx]]
|
||||
(:require [cljs.spec.alpha :as spec]
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :refer [reg-event-db reg-event-fx]]
|
||||
[re-frame.interceptor :refer [->interceptor get-coeffect get-effect]]
|
||||
[clojure.string :as str]
|
||||
[taoensso.timbre :as log]
|
||||
[cljs.spec.alpha :as s])
|
||||
[taoensso.timbre :as log])
|
||||
(:require-macros status-im.utils.handlers))
|
||||
|
||||
(defn side-effect!
|
||||
|
@ -16,24 +16,24 @@
|
|||
(def debug-handlers-names
|
||||
"Interceptor which logs debug information to js/console for each event."
|
||||
(->interceptor
|
||||
:id :debug-handlers-names
|
||||
:before (fn debug-handlers-names-before
|
||||
[context]
|
||||
(log/debug "Handling re-frame event: " (first (get-coeffect context :event)))
|
||||
context)))
|
||||
:id :debug-handlers-names
|
||||
:before (fn debug-handlers-names-before
|
||||
[context]
|
||||
(log/debug "Handling re-frame event: " (first (get-coeffect context :event)))
|
||||
context)))
|
||||
|
||||
(def check-spec
|
||||
"throw an exception if db doesn't match the spec"
|
||||
(->interceptor
|
||||
:id check-spec
|
||||
:after
|
||||
(fn check-handler
|
||||
[context]
|
||||
(let [new-db (get-effect context :db)
|
||||
v (get-coeffect context :event)]
|
||||
(when (and new-db (not (s/valid? :status-im.ui.screens.db/db new-db)))
|
||||
(throw (ex-info (str "spec check failed on: " (first v) "\n " (s/explain-str :status-im.ui.screens.db/db new-db)) {})))
|
||||
context))))
|
||||
:id check-spec
|
||||
:after
|
||||
(fn check-handler
|
||||
[context]
|
||||
(let [new-db (get-effect context :db)
|
||||
v (get-coeffect context :event)]
|
||||
(when (and new-db (not (spec/valid? :status-im.ui.screens.db/db new-db)))
|
||||
(throw (ex-info (str "spec check failed on: " (first v) "\n " (spec/explain-str :status-im.ui.screens.db/db new-db)) {})))
|
||||
context))))
|
||||
|
||||
(defn register-handler
|
||||
([name handler] (register-handler name nil handler))
|
||||
|
@ -52,7 +52,7 @@
|
|||
|
||||
(defn get-hashtags [status]
|
||||
(if status
|
||||
(let [hashtags (map #(str/lower-case (subs % 1))
|
||||
(let [hashtags (map #(string/lower-case (subs % 1))
|
||||
(re-seq #"#[^ !?,;:.]+" status))]
|
||||
(set (or hashtags [])))
|
||||
#{}))
|
||||
|
|
Loading…
Reference in New Issue