Skip to content

Commit

Permalink
[#9789] Add a loading indicator and button to username input of start…
Browse files Browse the repository at this point in the history
… new chat
  • Loading branch information
flexsurfer committed Feb 20, 2020
1 parent 81c4d16 commit b98f8de
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 88 deletions.
1 change: 0 additions & 1 deletion src/status_im/contact/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
(spec/def :contacts/contacts (spec/nilable (spec/map-of :global/not-empty-string :contact/contact)))
;;public key of new contact during adding this new contact
(spec/def :contacts/new-identity (spec/nilable map?))
(spec/def :contacts/new-identity-error (spec/nilable string?))
;;on showing this contact's profile (andrey: better to move into profile ns)
(spec/def :contacts/identity (spec/nilable :global/not-empty-string))
(spec/def :contacts/list-ui-props (spec/nilable (spec/keys :opt-un [:contact-list-ui/edit?])))
Expand Down
1 change: 0 additions & 1 deletion src/status_im/subs.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@
;;contacts
(reg-root-key-sub ::contacts :contacts/contacts)
(reg-root-key-sub :contacts/current-contact-identity :contacts/identity)
(reg-root-key-sub :new-identity-error :contacts/new-identity-error)
(reg-root-key-sub :contacts/new-identity :contacts/new-identity)
(reg-root-key-sub :group/selected-contacts :group/selected-contacts)
;;wallet
Expand Down
20 changes: 6 additions & 14 deletions src/status_im/ui/screens/add_new/new_chat/db.cljs
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
(ns status-im.ui.screens.add-new.new-chat.db
(:require [status-im.utils.hex :as hex]
[status-im.ethereum.ens :as ens]
[status-im.utils.platform :as platform]
[status-im.i18n :as i18n]
[cljs.spec.alpha :as spec]
[clojure.string :as string]))
(:require [cljs.spec.alpha :as spec]
[status-im.ethereum.ens :as ens]))

(defn own-public-key?
[{:keys [multiaccount]} public-key]
(= (:public-key multiaccount) public-key))

(defn validate-pub-key [db public-key]
(cond
(or (not (spec/valid? :global/public-key public-key))
(= public-key ens/default-key))
(i18n/label (if platform/desktop?
:t/use-valid-contact-code-desktop
:t/use-valid-contact-code))
(own-public-key? db public-key)
(i18n/label :t/can-not-add-yourself)))
(or
(not (spec/valid? :global/public-key public-key))
(= public-key ens/default-key)
(own-public-key? db public-key)))
48 changes: 34 additions & 14 deletions src/status_im/ui/screens/add_new/new_chat/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
[status-im.ethereum.resolver :as resolver]
[status-im.ui.screens.add-new.new-chat.db :as db]
[status-im.utils.handlers :as handlers]
[status-im.ethereum.stateofus :as stateofus]))
[status-im.ethereum.stateofus :as stateofus]
[status-im.utils.random :as random]))

(defn- ens-name-parse [contact-identity]
(when (string? contact-identity)
Expand All @@ -22,18 +23,37 @@
ens-name (ens-name-parse contact-identity)]
(resolver/pubkey registry ens-name cb))))

;;NOTE we want to handle only last resolve
(def resolve-last-id (atom nil))

(handlers/register-handler-fx
:new-chat/set-new-identity
(fn [{db :db} [_ new-identity new-ens-name]]
(let [is-public-key? (and (string? new-identity)
(string/starts-with? new-identity "0x"))]
(merge {:db (assoc db
:contacts/new-identity {:public-key new-identity
:ens-name (ens-name-parse new-ens-name)}
:contacts/new-identity-error (db/validate-pub-key db new-identity))}
(when (and (not is-public-key?)
(ens/valid-eth-name-prefix? new-identity))
(let [chain (ethereum/chain-keyword db)]
{:resolve-public-key {:chain chain
:contact-identity new-identity
:cb #(re-frame/dispatch [:new-chat/set-new-identity % new-identity])}}))))))
(fn [{db :db} [_ new-identity new-ens-name id]]
(when (or (not id) (= id @resolve-last-id))
(let [is-public-key? (and (string? new-identity)
(string/starts-with? new-identity "0x"))
is-ens? (and (not is-public-key?)
(ens/valid-eth-name-prefix? new-identity))
error? (db/validate-pub-key db new-identity)]
(merge {:db (assoc db
:contacts/new-identity
{:public-key new-identity
:state (cond is-ens?
:searching
(and (string/blank? new-identity) (not new-ens-name))
:empty
error?
:error
:else
:valid)
:ens-name (ens-name-parse new-ens-name)})}
(when is-ens?
(reset! resolve-last-id (random/id))
(let [chain (ethereum/chain-keyword db)]
{:resolve-public-key
{:chain chain
:contact-identity new-identity
:cb #(re-frame/dispatch [:new-chat/set-new-identity
%
new-identity
@resolve-last-id])}})))))))
2 changes: 1 addition & 1 deletion src/status_im/ui/screens/add_new/new_chat/navigation.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

(defmethod navigation/preload-data! :new-chat
[db _]
(dissoc db :contacts/new-identity :contacts/new-identity-error))
(dissoc db :contacts/new-identity))
16 changes: 8 additions & 8 deletions src/status_im/ui/screens/add_new/new_chat/styles.cljs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
(ns status-im.ui.screens.add-new.new-chat.styles
(:require [status-im.ui.components.colors :as colors]))

(def error-message
{:margin-horizontal 14
:margin-top 4
(def message
{:margin-horizontal 16
:align-self :center
:font-size 12
:color colors/red})
:color colors/gray})

(def list-title
{:margin-top 24
:margin-left 16
:font-size 14
:color colors/gray})
{:margin-top 24
:margin-left 16
:font-size 14
:color colors/gray})
105 changes: 71 additions & 34 deletions src/status_im/ui/screens/add_new/new_chat/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,90 @@
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar.view :as toolbar.view]
[status-im.ui.screens.add-new.styles :as add-new.styles]
[status-im.ui.screens.add-new.new-chat.styles :as styles]
[status-im.utils.platform :as platform]
[status-im.ui.components.list-item.views :as list-item]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.topbar :as topbar]))
[status-im.ui.components.topbar :as topbar]
[status-im.utils.debounce :as debounce]
[status-im.utils.utils :as utils]))

(defn- render-row [row _ _]
[list-item/list-item {:title (multiaccounts/displayed-name row)
:icon [chat-icon/contact-icon-contacts-tab row]
:accessories [:chevron]
:on-press #(re-frame/dispatch [:chat.ui/start-chat (:public-key row) {:navigation-reset? true}])}])
[list-item/list-item
{:title (multiaccounts/displayed-name row)
:icon [chat-icon/contact-icon-contacts-tab row]
:accessories [:chevron]
:on-press #(re-frame/dispatch [:chat.ui/start-chat
(:public-key row)
{:navigation-reset? true}])}])

(defn- icon-wrapper [color icon]
[react/view
{:style {:margin-right 16
:margin-top 11
:width 32
:height 32
:border-radius 25
:align-items :center
:justify-content :center
:background-color color}}
icon])

(defn- input-icon
[state]
(case state
:searching
[icon-wrapper colors/gray
[react/activity-indicator {:color colors/white}]]

:valid
[react/touchable-highlight
{:on-press #(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted] 3000)}
[icon-wrapper colors/blue
[vector-icons/icon :main-icons/arrow-right {:color colors/white}]]]

[icon-wrapper colors/gray
[vector-icons/icon :main-icons/arrow-right {:color colors/white}]]))

(views/defview new-chat []
(views/letsubs [contacts [:contacts/active]
new-identity [:contacts/new-identity]
error-message [:new-identity-error]]
{:keys [state ens-name public-key]} [:contacts/new-identity]]
[react/view {:style {:flex 1}}
[topbar/topbar {:title :t/new-chat :modal? true}]
[topbar/topbar
{:title :t/new-chat
:modal? true
:accessories [{:icon :qr
:handler #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed
{:title (i18n/label :t/new-contact)
:handler :contact/qr-code-scanned}])}]}]
[react/view add-new.styles/new-chat-container
[react/view add-new.styles/new-chat-input-container
[react/text-input {:on-change-text #(re-frame/dispatch [:new-chat/set-new-identity %])
:on-submit-editing #(when (and new-identity (not error-message))
(re-frame/dispatch [:contact.ui/contact-code-submitted]))
:placeholder (i18n/label :t/enter-contact-code)
:style add-new.styles/input
;; This input is fine to preserve inputs
;; so its contents will not be erased
;; in onWillBlur navigation event handler
:preserve-input? true
:accessibility-label :enter-contact-code-input
:return-key-type :go}]]
(when-not platform/desktop?
[react/touchable-highlight {:on-press #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed
{:title (i18n/label :t/new-contact)
:handler :contact/qr-code-scanned}])
:style add-new.styles/button-container
:accessibility-label :scan-contact-code-button}
[react/view
[vector-icons/icon :main-icons/camera {:color colors/blue}]]])]
(when error-message
[react/text {:style styles/error-message}
error-message])
(when (seq contacts)
[list-item/list-item {:title :t/contacts :type :section-header}])
[react/text-input
{:on-change-text
#(do
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:new-chat/set-new-identity %] 600))
:on-submit-editing
#(when (= state :valid)
(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted] 3000))
:placeholder (i18n/label :t/enter-contact-code)
:style add-new.styles/input
;; This input is fine to preserve inputs
;; so its contents will not be erased
;; in onWillBlur navigation event handler
:preserve-input? true
:accessibility-label :enter-contact-code-input
:return-key-type :go}]]
[react/view {:width 16}]
[input-icon state]]
[react/text {:style styles/message}
(cond (= state :error)
(i18n/label :t/user-not-found)
(= state :valid)
(str (when ens-name (str ens-name ""))
(utils/get-shortened-address public-key))
:else "")]
[list/flat-list {:data contacts
:key-fn :address
:render-fn render-row
Expand Down
2 changes: 1 addition & 1 deletion src/status_im/ui/screens/browser/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
{:browser? true}
[toolbar.view/nav-button
(actions/close (fn []
(debounce/clear)
(debounce/clear :browser/navigation-state-changed)
(re-frame/dispatch [:navigate-back])
(when error?
(re-frame/dispatch [:browser.ui/remove-browser-pressed browser-id]))))]
Expand Down
1 change: 0 additions & 1 deletion src/status_im/ui/screens/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@

(spec/def ::db (spec/keys :opt [:contacts/contacts
:contacts/new-identity
:contacts/new-identity-error
:contacts/identity
:contacts/ui-props
:contacts/list-ui-props
Expand Down
30 changes: 18 additions & 12 deletions src/status_im/utils/debounce.cljs
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
(ns status-im.utils.debounce
(:require [re-frame.core :as re-frame]))

(def timeout (atom nil))
(def timeout (atom {}))

(defn clear [event-key]
(when-let [event-timeout (get @timeout event-key)]
(js/clearTimeout event-timeout)))

(defn clear-all []
(doseq [[_ v] @timeout]
(js/clearTimeout v)))

(defn debounce-and-dispatch
"Dispatches event only if there were no calls of this function in period of *time* ms"
[event time]
(when @timeout (js/clearTimeout @timeout))
(reset! timeout (js/setTimeout #(re-frame/dispatch event) time)))
(let [event-key (first event)]
(clear event-key)
(swap! timeout assoc event-key (js/setTimeout #(re-frame/dispatch event) time))))

(defn clear []
(when @timeout (js/clearTimeout @timeout)))

(def chill? (atom false))
(def chill (atom {}))

(defn dispatch-and-chill
"Dispateches event and ignores next calls in period of *time* ms"
[event time]
(when-not @chill?
(reset! chill? true)
(js/setTimeout #(reset! chill? false) time)
(re-frame/dispatch event)))

(let [event-key (first event)]
(when-not (get @chill event-key)
(swap! chill assoc event-key true)
(js/setTimeout #(swap! chill assoc event-key false) time)
(re-frame/dispatch event))))
3 changes: 2 additions & 1 deletion translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1172,5 +1172,6 @@
"cant-report-bug": "Can't report a bug",
"mail-should-be-configured": "Mail client should be configured",
"check-on-etherscan": "Check on etherscan",
"transactions-load-more": "Load more"
"transactions-load-more": "Load more",
"user-not-found": "User not found"
}

0 comments on commit b98f8de

Please sign in to comment.