From 0f7143e5bf8e7e2c5e19570d207268e001098108 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Tue, 5 Jul 2016 19:07:34 +0300 Subject: [PATCH 01/10] pending/sent/failed statuses for messages --- project.clj | 2 +- src/status_im/chat/handlers.cljs | 8 +++--- src/status_im/chat/views/message.cljs | 26 ++++++++++--------- src/status_im/contacts/validations.cljs | 1 - src/status_im/protocol/handlers.cljs | 27 +++++++++++--------- src/status_im/protocol/protocol_handler.cljs | 4 +-- 6 files changed, 35 insertions(+), 33 deletions(-) diff --git a/project.clj b/project.clj index af80bbed96..958a23e8bf 100644 --- a/project.clj +++ b/project.clj @@ -10,7 +10,7 @@ [prismatic/schema "1.0.4"] ^{:voom {:repo "git@github.com:status-im/status-lib.git" :branch "master"}} - [status-im/protocol "0.1.1-20160630_153846-gbf92f5f"] + [status-im/protocol "0.1.1-20160705_154931-g96b5c92"] [natal-shell "0.1.6"] [com.andrewmcveigh/cljs-time "0.4.0"]] :plugins [[lein-cljsbuild "1.1.1"] diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 97df9c4281..a21d0f3c63 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -283,12 +283,10 @@ [{:keys [new-message current-chat-id] :as db} _] (when (and new-message (not-console? current-chat-id)) (let [{:keys [group-chat]} (get-in db [:chats current-chat-id]) - content (:content new-message)] + message (select-keys new-message [:content :msg-id])] (if group-chat - (api/send-group-user-msg {:group-id current-chat-id - :content content}) - (api/send-user-msg {:to current-chat-id - :content content}))))) + (api/send-group-user-msg (assoc message :group-id current-chat-id)) + (api/send-user-msg (assoc message :to current-chat-id)))))) (defn save-message-to-realm! [{:keys [new-message current-chat-id]} _] diff --git a/src/status_im/chat/views/message.cljs b/src/status_im/chat/views/message.cljs index c7f910e799..28daa5af59 100644 --- a/src/status_im/chat/views/message.cljs +++ b/src/status_im/chat/views/message.cljs @@ -120,20 +120,23 @@ [message-content-audio {:content content :content-type content-type}]]]) -(defn message-delivery-status [{:keys [delivery-status]}] +(defview message-delivery-status + [{:keys [delivery-status msg-id to] :as m}] + [status [:get-in [:message-status to msg-id]]] [view st/delivery-view [image {:source (case delivery-status - :delivered {:uri :icon_ok_small} :seen {:uri :icon_ok_small} :seen-by-everyone {:uri :icon_ok_small} - :failed res/delivery-failed-icon) + :failed res/delivery-failed-icon + nil) :style st/delivery-image}] [text {:style st/delivery-text} - (case delivery-status - :delivered "Delivered" + (case (or status delivery-status) + :delivered "Sent" :seen "Seen" :seen-by-everyone "Seen by everyone" - :failed "Failed")]]) + :failed "Failed" + "Pending")]]) (defn member-photo [{:keys [photo-path]}] [view st/photo-view @@ -159,12 +162,11 @@ [message-delivery-status {:delivery-status delivery-status}])]]])) (defn message-body - [{:keys [outgoing] :as message} content] - (let [delivery-status :seen] - [view (st/message-body message) - content - (when (and outgoing delivery-status) - [message-delivery-status {:delivery-status delivery-status}])])) + [{:keys [outgoing delivery-status] :as message} content] + [view (st/message-body message) + content + (when outgoing + [message-delivery-status message])]) (defn message-container-animation-logic [{:keys [to-value val callback]}] (fn [_] diff --git a/src/status_im/contacts/validations.cljs b/src/status_im/contacts/validations.cljs index 1e4d517682..5c930a8b3c 100644 --- a/src/status_im/contacts/validations.cljs +++ b/src/status_im/contacts/validations.cljs @@ -3,7 +3,6 @@ [status-im.persistence.realm :as realm])) (defn unique-identity? [identity] - (println identity) (not (realm/exists? :contacts :whisper-identity identity))) (defn valid-length? [identity] diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index 9bb41936e0..55a7530f54 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -4,13 +4,13 @@ (:require [status-im.utils.handlers :as u] [status-im.utils.logging :as log] [status-im.protocol.api :as api] - [re-frame.core :refer [dispatch debug]] + [re-frame.core :refer [dispatch after]] [status-im.utils.handlers :refer [register-handler]] [status-im.models.contacts :as contacts] [status-im.protocol.api :refer [init-protocol]] [status-im.protocol.protocol-handler :refer [make-handler]] [status-im.models.protocol :refer [update-identity - set-initialized]] + set-initialized]] [status-im.constants :refer [text-content-type]] [status-im.models.messages :as messages] [status-im.models.chats :as chats] @@ -102,16 +102,19 @@ (log/debug action msg-id from group-id identity) (participant-invited-to-group-msg group-id identity from msg-id)))) +(defn update-message! [status] + (fn [_ [_ _ msg-id]] + (messages/update-message! {:msg-id msg-id + :delivery-status status}))) + +(defn update-message-status [status] + (fn [db [_ from msg-id]] + (assoc-in db [:message-status from msg-id] status))) + (register-handler :acked-msg - (u/side-effect! - (fn [_ [action from msg-id]] - (log/debug action from msg-id) - (messages/update-message! {:msg-id msg-id - :delivery-status :delivered})))) + (after (update-message! :delivered)) + (update-message-status :delivered)) (register-handler :msg-delivery-failed - (u/side-effect! - (fn [_ [action msg-id]] - (log/debug action msg-id) - (messages/update-message! {:msg-id msg-id - :delivery-status :failed})))) + (after (update-message! :failed)) + (update-message-status :failed)) diff --git a/src/status_im/protocol/protocol_handler.cljs b/src/status_im/protocol/protocol_handler.cljs index cd0d44c812..f684baca87 100644 --- a/src/status_im/protocol/protocol_handler.cljs +++ b/src/status_im/protocol/protocol_handler.cljs @@ -22,8 +22,8 @@ (dispatch [:received-msg (assoc payload :from from :to to)])) :msg-acked (let [{:keys [msg-id from]} event] (dispatch [:acked-msg from msg-id])) - :delivery-failed (let [{:keys [msg-id]} event] - (dispatch [:msg-delivery-failed msg-id])) + :delivery-failed (let [{:keys [msg-id from]} event] + (dispatch [:msg-delivery-failed from msg-id])) :new-group-chat (let [{:keys [from group-id identities group-name]} event] (dispatch [:group-chat-invite-received from group-id identities group-name])) :new-group-msg (let [{from :from From 155626f59a8b4956bf2b5cc46f0fd3ec396214c4 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Wed, 6 Jul 2016 11:55:21 +0300 Subject: [PATCH 02/10] "seen" message --- .../statusim/geth/service/GethService.java | 2 +- project.clj | 2 +- src/status_im/chat/handlers.cljs | 10 ++++- src/status_im/chat/views/message.cljs | 39 ++++++++++++------- src/status_im/protocol/handlers.cljs | 11 +++++- src/status_im/protocol/protocol_handler.cljs | 2 + 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/android/app/src/main/java/com/statusim/geth/service/GethService.java b/android/app/src/main/java/com/statusim/geth/service/GethService.java index 9900b3ef8e..71e15636f8 100644 --- a/android/app/src/main/java/com/statusim/geth/service/GethService.java +++ b/android/app/src/main/java/com/statusim/geth/service/GethService.java @@ -213,7 +213,7 @@ public class GethService extends Service { String address = data.getString("address"); String password = data.getString("password"); // TODO: remove third argument - String result = Statusgo.Login(address, password); + String result = Statusgo.UnlockAccount(address, password, 0); Log.d(TAG, "Unlocked account: " + result); Bundle replyData = new Bundle(); diff --git a/project.clj b/project.clj index 958a23e8bf..ad95b36baa 100644 --- a/project.clj +++ b/project.clj @@ -10,7 +10,7 @@ [prismatic/schema "1.0.4"] ^{:voom {:repo "git@github.com:status-im/status-lib.git" :branch "master"}} - [status-im/protocol "0.1.1-20160705_154931-g96b5c92"] + [status-im/protocol "0.1.1-20160706_085008-ge61756a"] [natal-shell "0.1.6"] [com.andrewmcveigh/cljs-time "0.4.0"]] :plugins [[lein-cljsbuild "1.1.1"] diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index a21d0f3c63..25860a07bb 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -568,6 +568,14 @@ (let [suggestions (get-in db [:command-suggestions current-chat-id]) mode (get-in db [:edit-mode current-chat-id])] (when (and (= :text mode)) (seq suggestions) - (dispatch [:fix-commands-suggestions-height])))))] + (dispatch [:fix-commands-suggestions-height])))))] (fn [db [_ h]] (assoc db :layout-height h))) + + +(register-handler :send-seen! + #_(afetr (fn [_ [_ chat-id message-id]] + (dispatch [:msg-seen chat-id message-id]))) + (debug (u/side-effect! + (fn [_ [_ chat-id message-id]] + (api/send-seen chat-id message-id))))) diff --git a/src/status_im/chat/views/message.cljs b/src/status_im/chat/views/message.cljs index 28daa5af59..01c50c3500 100644 --- a/src/status_im/chat/views/message.cljs +++ b/src/status_im/chat/views/message.cljs @@ -124,7 +124,7 @@ [{:keys [delivery-status msg-id to] :as m}] [status [:get-in [:message-status to msg-id]]] [view st/delivery-view - [image {:source (case delivery-status + [image {:source (case (or status delivery-status) :seen {:uri :icon_ok_small} :seen-by-everyone {:uri :icon_ok_small} :failed res/delivery-failed-icon @@ -205,17 +205,28 @@ (into [view] children))) (defn chat-message - [{:keys [outgoing delivery-status timestamp new-day group-chat] + [{:keys [outgoing delivery-status timestamp new-day group-chat msg-id chat-id] :as message}] - [message-container message - ;; TODO there is no new-day info in message - (when new-day - [message-date timestamp]) - [view - (let [incoming-group (and group-chat (not outgoing))] - [message-content - (if incoming-group - incoming-group-message-body - message-body) - (merge message {:delivery-status (keyword delivery-status) - :incoming-group incoming-group})])]]) + (let [status (subscribe [:get-in [:message-status chat-id msg-id]])] + (r/create-class + {:component-did-mount + (fn [] + (when (and outgoing + (not= :seen delivery-status) + (not= :seen @status)) + (dispatch [:send-seen! chat-id msg-id]))) + :reagent-render + (fn [{:keys [outgoing delivery-status timestamp new-day group-chat] + :as message}] + [message-container message + ;; TODO there is no new-day info in message + (when new-day + [message-date timestamp]) + [view + (let [incoming-group (and group-chat (not outgoing))] + [message-content + (if incoming-group + incoming-group-message-body + message-body) + (merge message {:delivery-status (keyword delivery-status) + :incoming-group incoming-group})])]])}))) diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index 55a7530f54..9221c4b8e4 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -109,7 +109,10 @@ (defn update-message-status [status] (fn [db [_ from msg-id]] - (assoc-in db [:message-status from msg-id] status))) + (let [current-status (get-in db [:message-status from msg-id])] + (if-not (= :seen current-status) + (assoc-in db [:message-status from msg-id] status) + db)))) (register-handler :acked-msg (after (update-message! :delivered)) @@ -118,3 +121,9 @@ (register-handler :msg-delivery-failed (after (update-message! :failed)) (update-message-status :failed)) + +;; todo maybe it is fine to treat as "seen" all messages that are older +;; than current +(register-handler :msg-seen + (after (update-message! :seen)) + (update-message-status :seen)) diff --git a/src/status_im/protocol/protocol_handler.cljs b/src/status_im/protocol/protocol_handler.cljs index f684baca87..8f79ed7939 100644 --- a/src/status_im/protocol/protocol_handler.cljs +++ b/src/status_im/protocol/protocol_handler.cljs @@ -22,6 +22,8 @@ (dispatch [:received-msg (assoc payload :from from :to to)])) :msg-acked (let [{:keys [msg-id from]} event] (dispatch [:acked-msg from msg-id])) + :msg-seen (let [{:keys [msg-id from]} event] + (dispatch [:msg-seen from msg-id])) :delivery-failed (let [{:keys [msg-id from]} event] (dispatch [:msg-delivery-failed from msg-id])) :new-group-chat (let [{:keys [from group-id identities group-name]} event] From 2e790fb00603fe6beda5c73f75afa431ed996e5a Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Wed, 6 Jul 2016 20:17:52 +0300 Subject: [PATCH 03/10] unviewed messages counter --- src/status_im/chat/handlers.cljs | 44 ++++++++++++------- .../chat/handlers/unviewed_messages.cljs | 44 +++++++++++++++++++ src/status_im/chat/subs.cljs | 4 ++ src/status_im/chat/views/message.cljs | 2 +- .../chats_list/views/inner_item.cljs | 7 +-- src/status_im/handlers.cljs | 4 +- src/status_im/models/messages.cljs | 3 +- src/status_im/protocol/handlers.cljs | 6 +-- 8 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 src/status_im/chat/handlers/unviewed_messages.cljs diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 25860a07bb..03a5666043 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -24,7 +24,9 @@ [status-im.utils.logging :as log] [status-im.components.jail :as j] [status-im.utils.types :refer [json->clj]] - [status-im.commands.utils :refer [generate-hiccup]])) + [status-im.commands.utils :refer [generate-hiccup]] + status-im.chat.handlers.requests + status-im.chat.handlers.unviewed-messages)) (register-handler :set-show-actions (fn [db [_ show-actions]] @@ -221,14 +223,15 @@ [command] (suggestions/check-suggestion db (str text " ")) message (check-author-direction db current-chat-id - {:msg-id (random/id) - :chat-id current-chat-id - :content text - :to current-chat-id - :from identity - :content-type text-content-type - :outgoing true - :timestamp (time/now-ms)})] + {:msg-id (random/id) + :chat-id current-chat-id + :content text + :to current-chat-id + :from identity + :content-type text-content-type + :delivery-status :pending + :outgoing true + :timestamp (time/now-ms)})] (if command (commands/set-chat-command db command) (assoc db :new-message (when-not (str/blank? text) message))))) @@ -424,6 +427,7 @@ (assoc db :loaded-chats (chats/chats-list))) (register-handler :initialize-chats + (after #(dispatch [:load-unviewed-messages!])) ((enrich initialize-chats) load-chats!)) (defn store-message! @@ -437,14 +441,22 @@ (defn receive-message [db [_ {chat-id :from :as message}]] - (let [message' (check-author-direction db chat-id message)] + (let [message' (-> db + (check-author-direction chat-id message) + (assoc :delivery-status :pending))] (-> db (add-message-to-db chat-id message') (assoc :new-message message')))) +(defn dispatch-unviewed-message! + [{:keys [new-message]} [_ {chat-id :from}]] + (let [{:keys [msg-id]} new-message] + (dispatch [:add-unviewed-message chat-id msg-id]))) + (register-handler :received-msg [(after store-message!) - (after dispatch-request!)] + (after dispatch-request!) + (after dispatch-unviewed-message!)] receive-message) (register-handler :group-received-msg @@ -574,8 +586,8 @@ (register-handler :send-seen! - #_(afetr (fn [_ [_ chat-id message-id]] - (dispatch [:msg-seen chat-id message-id]))) - (debug (u/side-effect! - (fn [_ [_ chat-id message-id]] - (api/send-seen chat-id message-id))))) + (after (fn [_ [_ chat-id message-id]] + (dispatch [:msg-seen chat-id message-id]))) + (u/side-effect! + (fn [_ [_ chat-id message-id]] + (api/send-seen chat-id message-id)))) diff --git a/src/status_im/chat/handlers/unviewed_messages.cljs b/src/status_im/chat/handlers/unviewed_messages.cljs new file mode 100644 index 0000000000..7dfa9e9df8 --- /dev/null +++ b/src/status_im/chat/handlers/unviewed_messages.cljs @@ -0,0 +1,44 @@ +(ns status-im.chat.handlers.unviewed-messages + (:require [re-frame.core :refer [after enrich path dispatch]] + [status-im.utils.handlers :refer [register-handler]] + [status-im.persistence.realm :as realm])) + +(defn delivered-messages [] + (-> (realm/get-by-fields + :msgs + {:delivery-status :delivered + :outgoing false}) + (realm/collection->map))) + +(defn set-unviewed-messages [db] + (let [messages (->> (::raw-unviewed-messages db) + (group-by :chat-id) + (map (fn [[id messages]] + [id {:messages-ids (map :msg-id messages) + :count (count messages)}])) + (into {}))] + (-> db + (assoc :unviewed-messages messages) + (dissoc ::raw-unviewed-messages)))) + +(defn load-messages! [db] + (let [messages (delivered-messages)] + (assoc db ::raw-unviewed-messages messages))) + +(register-handler ::set-unviewed-messages set-unviewed-messages) + +(register-handler :load-unviewed-messages! + (after #(dispatch [::set-unviewed-messages])) + load-messages!) + +(register-handler :add-unviewed-message + (path :unviewed-messages) + (fn [db [_ chat-id message-id]] + (-> db + (update-in [chat-id :messages-ids] conj message-id) + (update-in [chat-id :count] inc)))) + +(register-handler :remove-unviewed-messages + (path :unviewed-messages) + (fn [db [_ chat-id]] + (dissoc db chat-id))) diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index ae90e45bc0..15fb01f661 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -172,3 +172,7 @@ (fn [_ [_ message-id]] (let [requests (subscribe [:get-requests])] (reaction (not (some #(= message-id (:message-id %)) @requests)))))) + +(register-sub :unviewed-messages-count + (fn [db [_ chat-id]] + (reaction (get-in @db [:unviewed-messages chat-id :count])))) diff --git a/src/status_im/chat/views/message.cljs b/src/status_im/chat/views/message.cljs index 01c50c3500..3b9b27e3f5 100644 --- a/src/status_im/chat/views/message.cljs +++ b/src/status_im/chat/views/message.cljs @@ -211,7 +211,7 @@ (r/create-class {:component-did-mount (fn [] - (when (and outgoing + (when (and (not outgoing) (not= :seen delivery-status) (not= :seen @status)) (dispatch [:send-seen! chat-id msg-id]))) diff --git a/src/status_im/chats_list/views/inner_item.cljs b/src/status_im/chats_list/views/inner_item.cljs index 2803b5d6e4..b8d94902f4 100644 --- a/src/status_im/chats_list/views/inner_item.cljs +++ b/src/status_im/chats_list/views/inner_item.cljs @@ -6,9 +6,10 @@ [status-im.utils.utils :refer [truncate-str]] [status-im.utils.datetime :as time])) -(defn chat-list-item-inner-view +(defview chat-list-item-inner-view [{:keys [chat-id name color new-messages-count online group-chat contacts] :as chat}] + [unviewed-messages [:unviewed-messages-count chat-id]] (let [last-message (first (:messages chat))] [view st/chat-container [view st/chat-icon-container @@ -43,6 +44,6 @@ (when (:timestamp last-message) [text {:style st/datetime-text} (time/to-short-str (:timestamp last-message))])]) - (when (pos? new-messages-count) + (when (pos? unviewed-messages) [view st/new-messages-container - [text {:style st/new-messages-text} new-messages-count]])]])) + [text {:style st/new-messages-text} unviewed-messages]])]])) diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index ee070f1ceb..93e417b149 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -11,7 +11,6 @@ [status-im.utils.handlers :refer [register-handler] :as u] [status-im.models.protocol :as protocol] status-im.chat.handlers - status-im.chat.handlers.animation status-im.group-settings.handlers status-im.navigation.handlers status-im.contacts.handlers @@ -22,8 +21,7 @@ status-im.commands.handlers.jail status-im.qr-scanner.handlers status-im.accounts.handlers - status-im.protocol.handlers - status-im.chat.handlers.requests)) + status-im.protocol.handlers)) ;; -- Middleware ------------------------------------------------------------ ;; diff --git a/src/status_im/models/messages.cljs b/src/status_im/models/messages.cljs index 38d7342ae3..05fddb6ac0 100644 --- a/src/status_im/models/messages.cljs +++ b/src/status_im/models/messages.cljs @@ -38,8 +38,7 @@ message {:chat-id chat-id :content content' - :timestamp (timestamp) - :delivery-status nil})] + :timestamp (timestamp)})] (r/create :msgs message' true)))))) (defn command-type? [type] diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index 9221c4b8e4..0cc9657540 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -122,8 +122,8 @@ (after (update-message! :failed)) (update-message-status :failed)) -;; todo maybe it is fine to treat as "seen" all messages that are older -;; than current (register-handler :msg-seen - (after (update-message! :seen)) + [(after (update-message! :seen)) + (after (fn [_ [_ chat-id]] + (dispatch [:remove-unviewed-messages chat-id])))] (update-message-status :seen)) From d29c6c37115bdf684a00e03e3253a16c10c6007f Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Wed, 6 Jul 2016 20:19:06 +0300 Subject: [PATCH 04/10] fix animation handler --- src/status_im/chat/handlers.cljs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 03a5666043..b5cb7ea5a4 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -25,6 +25,7 @@ [status-im.components.jail :as j] [status-im.utils.types :refer [json->clj]] [status-im.commands.utils :refer [generate-hiccup]] + status-im.chat.handlers.animation status-im.chat.handlers.requests status-im.chat.handlers.unviewed-messages)) From 55a5b96ad7de96708ed1e1bac09f61a87e1ecd6e Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Thu, 7 Jul 2016 11:08:22 +0300 Subject: [PATCH 05/10] fix protocol's initialization on js reloading --- .../com/statusim/geth/module/GethModule.java | 9 +++++++-- src/status_im/chat/handlers.cljs | 4 +++- src/status_im/handlers.cljs | 4 +++- src/status_im/models/messages.cljs | 18 ++++++++++-------- src/status_im/protocol/handlers.cljs | 4 ++-- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/java/com/statusim/geth/module/GethModule.java b/android/app/src/main/java/com/statusim/geth/module/GethModule.java index 058ab03667..d0b2b286c8 100644 --- a/android/app/src/main/java/com/statusim/geth/module/GethModule.java +++ b/android/app/src/main/java/com/statusim/geth/module/GethModule.java @@ -128,7 +128,12 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE } @ReactMethod - public void startNode(Callback callback) { + public void startNode(Callback callback, Callback onAlreadyRunning) { + + if(GethService.isRunning()){ + onAlreadyRunning.invoke(); + return; + } Activity currentActivity = getCurrentActivity(); @@ -216,4 +221,4 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE return UUID.randomUUID().toString(); } -} \ No newline at end of file +} diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index b5cb7ea5a4..72eb4734f3 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -588,7 +588,9 @@ (register-handler :send-seen! (after (fn [_ [_ chat-id message-id]] + (when-not (= "console" chat-id)) (dispatch [:msg-seen chat-id message-id]))) (u/side-effect! (fn [_ [_ chat-id message-id]] - (api/send-seen chat-id message-id)))) + (when-not (= "console" chat-id) + (api/send-seen chat-id message-id))))) diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index 93e417b149..3012b78491 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -88,7 +88,9 @@ (u/side-effect! (fn [db _] (log/debug "Starting node") - (.startNode geth (fn [result] (node-started db result)))))) + (.startNode geth + (fn [result] (node-started db result)) + #(dispatch [:initialize-protocol]))))) (register-handler :crypt-initialized (u/side-effect! diff --git a/src/status_im/models/messages.cljs b/src/status_im/models/messages.cljs index 05fddb6ac0..a595cdcf68 100644 --- a/src/status_im/models/messages.cljs +++ b/src/status_im/models/messages.cljs @@ -26,7 +26,8 @@ (defn save-message ;; todo remove chat-id parameter - [chat-id {:keys [msg-id content] + [chat-id {:keys [delivery-status msg-id content] + :or {delivery-status :pending} :as message}] (when-not (r/exists? :msgs :msg-id msg-id) (r/write @@ -38,6 +39,7 @@ message {:chat-id chat-id :content content' + :delivery-status delivery-status :timestamp (timestamp)})] (r/create :msgs message' true)))))) @@ -49,13 +51,13 @@ (defn get-messages ([chat-id] (get-messages chat-id 0)) ([chat-id from] - (->> (-> (r/get-by-field :msgs :chat-id chat-id) - (r/sorted :timestamp :desc) - (r/page from (+ from c/default-number-of-messages)) - (r/collection->map)) - (into '()) - reverse - (keep (fn [{:keys [content-type] :as message}] + (->> (-> (r/get-by-field :msgs :chat-id chat-id) + (r/sorted :timestamp :desc) + (r/page from (+ from c/default-number-of-messages)) + (r/collection->map)) + (into '()) + reverse + (keep (fn [{:keys [content-type] :as message}] (if (command-type? content-type) (update message :content str-to-map) message)))))) diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index 0cc9657540..1ff462d03a 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -18,8 +18,8 @@ (register-handler :initialize-protocol (u/side-effect! - (fn [db [_ account]] - (init-protocol account (make-handler db))))) + (fn [{:keys [user-identity] :as db} [_ account]] + (init-protocol (or account user-identity) (make-handler db))))) (register-handler :protocol-initialized (fn [db [_ identity]] From 0ddc4608ee800fa38886b12069a88b60c30e3f45 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Thu, 7 Jul 2016 11:16:09 +0300 Subject: [PATCH 06/10] statuses fro console chat --- src/status_im/chat/handlers.cljs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 72eb4734f3..5d745fae7b 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -218,6 +218,11 @@ (fn [db [_ {:keys [chat-id msg-id]}]] (set-message-shown db chat-id msg-id))) +(defn default-delivery-status [chat-id] + (if (console? chat-id) + :seen + :pending)) + (defn prepare-message [{:keys [identity current-chat-id] :as db} _] (let [text (get-in db [:chats current-chat-id :input-text]) @@ -230,7 +235,7 @@ :to current-chat-id :from identity :content-type text-content-type - :delivery-status :pending + :delivery-status (default-delivery-status current-chat-id) :outgoing true :timestamp (time/now-ms)})] (if command @@ -246,6 +251,7 @@ :to chat-id :content content :content-type content-type-command + :delivery-status (default-delivery-status chat-id) :outgoing true :preview preview-string :rendered-preview preview @@ -588,9 +594,9 @@ (register-handler :send-seen! (after (fn [_ [_ chat-id message-id]] - (when-not (= "console" chat-id)) + (when-not (console? chat-id)) (dispatch [:msg-seen chat-id message-id]))) (u/side-effect! (fn [_ [_ chat-id message-id]] - (when-not (= "console" chat-id) + (when-not (console? chat-id) (api/send-seen chat-id message-id))))) From 7c3c3d80086acf86cb851371af676090b696e566 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Thu, 7 Jul 2016 19:09:16 +0300 Subject: [PATCH 07/10] validation handlers & views --- resources/commands.js | 18 +- resources/status.js | 9 +- src/status_im/android/core.cljs | 4 +- src/status_im/chat/handlers.cljs | 103 +--------- src/status_im/chat/handlers/animation.cljs | 2 +- src/status_im/chat/handlers/commands.cljs | 186 ++++++++++++++++++ .../chat/styles/command_validation.cljs | 1 + src/status_im/chat/subs.cljs | 10 + src/status_im/chat/views/command.cljs | 3 +- .../chat/views/command_validation.cljs | 30 +++ src/status_im/chat/views/message_input.cljs | 14 +- src/status_im/chat/views/new_message.cljs | 3 +- src/status_im/models/commands.cljs | 8 +- src/status_im/utils/handlers.cljs | 2 +- 14 files changed, 268 insertions(+), 125 deletions(-) create mode 100644 src/status_im/chat/handlers/commands.cljs create mode 100644 src/status_im/chat/styles/command_validation.cljs create mode 100644 src/status_im/chat/views/command_validation.cljs diff --git a/resources/commands.js b/resources/commands.js index 1191fdd311..7c317eae6e 100644 --- a/resources/commands.js +++ b/resources/commands.js @@ -3,7 +3,7 @@ status.command({ description: "Send location", color: "#9a5dcf", preview: function (params) { - var text = status.components.text( + var text = status.components.text( { style: { marginTop: 5, @@ -138,6 +138,12 @@ status.response({ name: "phone", description: "Send phone number", color: "#5fc48d", + validator: function (params) { + return { + validationHandler: "phone", + parameters: [params.value] + }; + }, params: [{ name: "phone", type: status.types.PHONE, @@ -156,6 +162,16 @@ status.command({ name: "help", description: "Help", color: "#7099e6", + /* Validator example + validator: function (params) { + if (params.value != "3") { + var error = status.components.view( + {backgroundColor: "red"}, + [status.components.text({}, "ooops :(")] + ); + return {errors: [error]} + } + },*/ params: [{ name: "query", type: status.types.TEXT diff --git a/resources/status.js b/resources/status.js index 2eec9a3d44..b9d73021c4 100644 --- a/resources/status.js +++ b/resources/status.js @@ -22,6 +22,7 @@ Command.prototype.create = function (com) { this.name = com.name; this.description = com.description; this.handler = com.handler; + this.validator = com.validator; this.color = com.color; this.icon = com.icon; this.params = com.params || []; @@ -83,13 +84,13 @@ function scrollView(options, elements) { } var status = { - command: function (n, d, h) { + command: function (h) { var command = new Command(); - return command.create(n, d, h); + return command.create(h); }, - response: function (n, d, h) { + response: function (h) { var response = new Response(); - return response.create(n, d, h); + return response.create(h); }, types: { TEXT: 'text', diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index f205c1e497..9288405b76 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -54,11 +54,11 @@ "keyboardDidShow" (fn [e] (let [h (.. e -endCoordinates -height)] - (when-not (= h keyboard-height) + (when-not (= h @keyboard-height) (dispatch [:set :keyboard-height h]))))) (.addListener device-event-emitter "keyboardDidHide" - (when-not (= 0 keyboard-height) + (when-not (= 0 @keyboard-height) #(dispatch [:set :keyboard-height 0])))) :render (fn [] diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 97df9c4281..09290db99e 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -21,10 +21,10 @@ [status-im.utils.phone-number :refer [format-phone-number]] [status-im.utils.datetime :as time] [status-im.components.react :refer [geth]] - [status-im.utils.logging :as log] [status-im.components.jail :as j] [status-im.utils.types :refer [json->clj]] - [status-im.commands.utils :refer [generate-hiccup]])) + [status-im.commands.utils :refer [generate-hiccup]] + status-im.chat.handlers.commands)) (register-handler :set-show-actions (fn [db [_ show-actions]] @@ -53,81 +53,15 @@ (assoc-in [:chats current-chat-id :command-input] {}) (update-in [:chats current-chat-id :input-text] safe-trim)))) -(defn invoke-suggestions-handler! - [{:keys [current-chat-id canceled-command] :as db} _] - (when-not canceled-command - (let [{:keys [command content]} (get-in db [:chats current-chat-id :command-input]) - {:keys [name type]} command - path [(if (= :command type) :commands :responses) - name - :params - 0 - :suggestions] - params {:value content}] - (j/call current-chat-id - path - params - #(dispatch [:suggestions-handler {:command command - :content content - :chat-id current-chat-id} %]))))) - (register-handler :start-cancel-command (u/side-effect! (fn [db _] (dispatch [:animate-cancel-command])))) -(def command-prefix "c ") - -(defn cancel-command! - [{:keys [canceled-command]}] - (when canceled-command - (dispatch [:start-cancel-command]))) - -(register-handler :set-chat-command-content - [(after invoke-suggestions-handler!) - (after cancel-command!)] - (fn [{:keys [current-chat-id] :as db} [_ content]] - (let [starts-as-command? (str/starts-with? content command-prefix) - path [:chats current-chat-id :command-input :command :type] - command? (= :command (get-in db path))] - (as-> db db - (commands/set-chat-command-content db content) - (assoc-in db [:chats current-chat-id :input-text] nil) - (assoc db :canceled-command (and command? (not starts-as-command?))))))) - (defn update-input-text [{:keys [current-chat-id] :as db} text] (assoc-in db [:chats current-chat-id :input-text] text)) -(defn invoke-command-preview! - [{:keys [current-chat-id staged-command]} _] - (let [{:keys [command content]} staged-command - {:keys [name type]} command - path [(if (= :command type) :commands :responses) - name - :preview] - params {:value content}] - (j/call current-chat-id - path - params - #(dispatch [:command-preview current-chat-id %])))) - -(register-handler :stage-command - (after invoke-command-preview!) - (fn [{:keys [current-chat-id] :as db} _] - (let [db (update-input-text db nil) - {:keys [command content to-msg-id]} - (get-in db [:chats current-chat-id :command-input]) - content' (if (= :command (:type command)) - (subs content 2) - content) - command-info {:command command - :content content' - :to-message to-msg-id}] - (-> db - (commands/stage-command command-info) - (assoc :staged-command command-info))))) - (register-handler :set-message-input [] (fn [db [_ input]] (assoc db :message-input input))) @@ -138,15 +72,6 @@ (when-let [message-input (:message-input db)] (.blur message-input))))) -(register-handler :set-response-chat-command - [(after invoke-suggestions-handler!) - (after #(dispatch [:command-edit-mode])) - (after #(dispatch [:set-chat-input-text ""]))] - (fn [db [_ to-msg-id command-key]] - (-> db - (commands/set-response-chat-command to-msg-id command-key) - (assoc :canceled-command false)))) - (defn update-text [{:keys [current-chat-id] :as db} [_ text]] (let [suggestions (get-in db [:command-suggestions current-chat-id])] @@ -322,13 +247,6 @@ params #(dispatch [:command-handler! com %]))))) -(defn handle-commands - [{:keys [new-commands]}] - (doseq [{{content :content} :content - handler :handler} new-commands] - (when handler - (handler content)))) - (register-handler :send-chat-msg (-> prepare-message ((enrich prepare-staged-commans)) @@ -341,21 +259,7 @@ ((after save-commands-to-realm!)) ((after dispatch-responded-requests!)) ;; todo maybe it is better to track if it was handled or not - ((after invoke-commands-handlers!)) - ((after handle-commands)))) - -(register-handler :unstage-command - (fn [db [_ staged-command]] - (commands/unstage-command db staged-command))) - -(register-handler :set-chat-command - [(after invoke-suggestions-handler!) - (after #(dispatch [:command-edit-mode]))] - (fn [{:keys [current-chat-id] :as db} [_ command-key]] - (-> db - (commands/set-chat-command command-key) - (assoc-in [:chats current-chat-id :command-input :content] "c ") - (assoc :disable-input true)))) + ((after invoke-commands-handlers!)))) (register-handler :init-console-chat (fn [db [_]] @@ -552,6 +456,7 @@ (assoc-in db [:edit-mode current-chat-id] mode))) (register-handler :command-edit-mode + (after #(dispatch [:clear-validation-errors])) (edit-mode-handler :command)) (register-handler :text-edit-mode diff --git a/src/status_im/chat/handlers/animation.cljs b/src/status_im/chat/handlers/animation.cljs index c14a22b22d..fde8a8e457 100644 --- a/src/status_im/chat/handlers/animation.cljs +++ b/src/status_im/chat/handlers/animation.cljs @@ -47,7 +47,7 @@ input-height))) (register-handler :animate-show-response - [(after #(dispatch [:command-edit-mode]))] + ;[(after #(dispatch [:command-edit-mode]))] (fn [{:keys [current-chat-id] :as db}] (let [suggestions? (seq (get-in db [:suggestions current-chat-id])) height (if suggestions? diff --git a/src/status_im/chat/handlers/commands.cljs b/src/status_im/chat/handlers/commands.cljs new file mode 100644 index 0000000000..64f5128a9e --- /dev/null +++ b/src/status_im/chat/handlers/commands.cljs @@ -0,0 +1,186 @@ +(ns status-im.chat.handlers.commands + (:require [re-frame.core :refer [enrich after dispatch]] + [status-im.utils.handlers :refer [register-handler] :as u] + [status-im.components.jail :as j] + [status-im.models.commands :as commands] + [clojure.string :as str] + [status-im.commands.utils :as cu] + [status-im.utils.phone-number :as pn])) + +(def command-prefix "c ") + +(defn invoke-suggestions-handler! + [{:keys [current-chat-id canceled-command] :as db} _] + (when-not canceled-command + (let [{:keys [command content]} (get-in db [:chats current-chat-id :command-input]) + {:keys [name type]} command + path [(if (= :command type) :commands :responses) + name + :params + 0 + :suggestions] + params {:value content}] + (j/call current-chat-id + path + params + #(dispatch [:suggestions-handler {:command command + :content content + :chat-id current-chat-id} %]))))) + +(defn cancel-command! + [{:keys [canceled-command]}] + (when canceled-command + (dispatch [:start-cancel-command]))) + +(register-handler :set-chat-command-content + [(after invoke-suggestions-handler!) + (after cancel-command!) + (after #(dispatch [:clear-validation-errors]))] + (fn [{:keys [current-chat-id] :as db} [_ content]] + (let [starts-as-command? (str/starts-with? content command-prefix) + path [:chats current-chat-id :command-input :command :type] + command? (= :command (get-in db path))] + (as-> db db + (commands/set-chat-command-content db content) + (assoc-in db [:chats current-chat-id :input-text] nil) + (assoc db :canceled-command (and command? (not starts-as-command?))))))) + +(defn invoke-command-preview! + [{:keys [staged-command]} [_ chat-id]] + (let [{:keys [command content]} staged-command + {:keys [name type]} command + path [(if (= :command type) :commands :responses) + name + :preview] + params {:value content}] + (j/call chat-id + path + params + #(dispatch [:command-preview chat-id %])))) + +(defn content-by-command + [{:keys [type]} content] + (if (= :command type) + (subs content 2) + content)) + +(defn command-input + ([{:keys [current-chat-id] :as db}] + (command-input db current-chat-id)) + ([db chat-id] + (get-in db [:chats chat-id :command-input]))) + + +(register-handler ::validate! + (u/side-effect! + (fn [_ [_ {:keys [chat-id]} {:keys [error result]}]] + ;; todo handle error + (when-not error + (let [{:keys [errors validationHandler parameters]} result] + (cond errors + (dispatch [::add-validation-errors chat-id errors]) + + validationHandler + (dispatch [::validation-handler! + chat-id + validationHandler + parameters]) + + :else (dispatch [::finish-command-staging chat-id]))))))) + +(defn start-validate! [db] + (let [{:keys [content command chat-id] :as data} (::command db) + {:keys [name type]} command + path [(if (= :command type) :commands :responses) + name + :validator] + params {:value content}] + (j/call chat-id + path + params + #(dispatch [::validate! data %])))) + +(register-handler :stage-command + (after start-validate!) + (fn [{:keys [current-chat-id] :as db}] + (let [{:keys [command content]} (command-input db) + content' (content-by-command command content)] + (-> db + (assoc ::command {:content content' + :command command + :chat-id current-chat-id}) + (assoc-in [:disable-staging current-chat-id] true))))) + +(register-handler ::finish-command-staging + [(after #(dispatch [:start-cancel-command])) + (after invoke-command-preview!)] + (fn [db [_ chat-id]] + (let [db (assoc-in db [:chats chat-id :input-text] nil) + {:keys [command content to-msg-id]} (command-input db) + content' (content-by-command command content) + command-info {:command command + :content content' + :to-message to-msg-id}] + (-> db + (commands/stage-command command-info) + (assoc :staged-command command-info) + (assoc-in [:disable-staging chat-id] true))))) + +(register-handler :unstage-command + (fn [db [_ staged-command]] + (commands/unstage-command db staged-command))) + +(defn set-chat-command + [{:keys [current-chat-id] :as db} [_ command-key]] + (-> db + (commands/set-chat-command command-key) + (assoc-in [:chats current-chat-id :command-input :content] command-prefix) + (assoc :disable-input true))) + +(register-handler :set-chat-command + [(after invoke-suggestions-handler!) + (after #(dispatch [:command-edit-mode]))] + set-chat-command) + +(defn set-response-command [db [_ to-msg-id command-key]] + (-> db + (commands/set-response-chat-command to-msg-id command-key) + (assoc :canceled-command false))) + +(register-handler :set-response-chat-command + [(after invoke-suggestions-handler!) + (after #(dispatch [:command-edit-mode])) + (after #(dispatch [:set-chat-input-text ""]))] + set-response-command) + +(register-handler ::add-validation-errors + (fn [db [_ chat-id errors]] + (assoc-in db [:custom-validation-errors chat-id] + (map cu/generate-hiccup errors)))) + +(register-handler :clear-validation-errors + (fn [db] + (dissoc db :validation-errors :custom-validation-errors))) + +(def validation-handlers + {:phone (fn [chat-id [number]] + (if (pn/valid-mobile-number? number) + (dispatch [::finish-command-staging chat-id]) + (dispatch [::set-validation-error + chat-id + {:title "Phobe number" + :description "Wrong phone number"}])))}) + +(defn validator [name] + (validation-handlers (keyword name))) + +(register-handler ::validation-handler! + (u/side-effect! + (fn [_ [_ chat-id name params]] + (when-let [handler (validator name)] + (handler chat-id params))))) + + +(register-handler ::set-validation-error + (fn [db [_ chat-id error]] + (assoc-in db [:validation-errors chat-id] [error]))) diff --git a/src/status_im/chat/styles/command_validation.cljs b/src/status_im/chat/styles/command_validation.cljs new file mode 100644 index 0000000000..b38e8cc820 --- /dev/null +++ b/src/status_im/chat/styles/command_validation.cljs @@ -0,0 +1 @@ +(ns status-im.chat.styles.command-validation) diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index ae90e45bc0..634d2c8bf4 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -172,3 +172,13 @@ (fn [_ [_ message-id]] (let [requests (subscribe [:get-requests])] (reaction (not (some #(= message-id (:message-id %)) @requests)))))) + +(register-sub :validation-errors + (fn [db] + (let [current-chat-id (subscribe [:get-current-chat-id])] + (reaction (get-in @db [:validation-errors @current-chat-id]))))) + +(register-sub :custom-validation-errors + (fn [db] + (let [current-chat-id (subscribe [:get-current-chat-id])] + (reaction (get-in @db [:custom-validation-errors @current-chat-id]))))) diff --git a/src/status_im/chat/views/command.cljs b/src/status_im/chat/views/command.cljs index 49f5135b7e..3264e5d597 100644 --- a/src/status_im/chat/views/command.cljs +++ b/src/status_im/chat/views/command.cljs @@ -15,8 +15,7 @@ (dispatch [:set-chat-command-content message])) (defn send-command [] - (dispatch [:stage-command]) - (cancel-command-input)) + (dispatch [:stage-command])) (defn valid? [message validator] (if validator diff --git a/src/status_im/chat/views/command_validation.cljs b/src/status_im/chat/views/command_validation.cljs new file mode 100644 index 0000000000..4294e61ce2 --- /dev/null +++ b/src/status_im/chat/views/command_validation.cljs @@ -0,0 +1,30 @@ +(ns status-im.chat.views.command-validation + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [status-im.components.react :as c] + [status-im.chat.styles.command-validation :as st] + [status-im.utils.listview :as lw])) + +(defn error [{:keys [title description]}] + (c/list-item + [c/view + [c/text title] + [c/text description]])) + +(defn errors-list [errors] + [c/list-view {:renderRow error + :keyboardShouldPersistTaps true + :dataSource (lw/to-datasource errors)}]) + +(defview errors [] + [errors [:validation-errors] + custom-errors [:custom-validation-errors] + command? [:command?]] + (when (and command? + (or (seq errors) + (seq custom-errors))) + [c/scroll-view {:background-color :red} + (cond (seq custom-errors) + (vec (concat [c/view] custom-errors)) + + (seq errors) + [errors-list errors])])) diff --git a/src/status_im/chat/views/message_input.cljs b/src/status_im/chat/views/message_input.cljs index c96b36f22e..e45349b28f 100644 --- a/src/status_im/chat/views/message_input.cljs +++ b/src/status_im/chat/views/message_input.cljs @@ -2,6 +2,7 @@ (:require-macros [status-im.utils.views :refer [defview]]) (:require [re-frame.core :refer [subscribe]] [status-im.components.react :refer [view + text animated-view icon touchable-highlight @@ -10,7 +11,8 @@ [status-im.chat.views.command :as command] [status-im.chat.styles.message-input :as st] [status-im.chat.styles.plain-message :as st-message] - [status-im.chat.styles.response :as st-response])) + [status-im.chat.styles.response :as st-response] + [status-im.chat.views.command-validation :as cv])) (defn send-button [{:keys [on-press accessibility-label]}] [touchable-highlight {:on-press on-press @@ -48,20 +50,20 @@ input-options) (if command? input-command input-message)]) -(defview plain-message-input-view [{:keys [input-options validator]}] +(defview plain-message-input-view [{:keys [input-options]}] [command? [:command?] {:keys [type] :as command} [:get-chat-command] input-command [:get-chat-command-content] - valid-plain-message? [:valid-plain-message?] - valid-command? [:valid-command? validator]] + valid-plain-message? [:valid-plain-message?]] [view st/input-container + [cv/errors] [view st/input-view [plain-message/commands-button] [message-input-container - [message-input input-options validator]] + [message-input input-options]] ;; TODO emoticons: not implemented [plain-message/smile-button] - (when (if command? valid-command? valid-plain-message?) + (when (or command? valid-plain-message?) (let [on-press (if command? command/send-command plain-message/send)] diff --git a/src/status_im/chat/views/new_message.cljs b/src/status_im/chat/views/new_message.cljs index 54bb81f2d7..84576ef5a3 100644 --- a/src/status_im/chat/views/new_message.cljs +++ b/src/status_im/chat/views/new_message.cljs @@ -18,8 +18,7 @@ (defn get-options [{:keys [type placeholder]} command-type] (let [options (case (keyword type) - :phone {:input-options {:keyboardType :phone-pad} - :validator valid-mobile-number?} + :phone {:input-options {:keyboardType :phone-pad}} :password {:input-options {:secureTextEntry true}} :number {:input-options {:keyboardType :numeric}} ;; todo maybe nil is fine for now :) diff --git a/src/status_im/models/commands.cljs b/src/status_im/models/commands.cljs index 1ebb70dccb..d7380a04c4 100644 --- a/src/status_im/models/commands.cljs +++ b/src/status_im/models/commands.cljs @@ -1,11 +1,5 @@ (ns status-im.models.commands - (:require [clojure.string :refer [join split]] - [clojure.walk :refer [stringify-keys keywordize-keys]] - [re-frame.core :refer [subscribe dispatch]] - [status-im.db :as db] - [status-im.components.animation :as anim] - [status-im.components.styles :refer [color-blue color-dark-mint]] - [status-im.i18n :refer [label]])) + (:require [status-im.db :as db])) (defn get-commands [{:keys [current-chat-id] :as db}] (or (get-in db [:chats current-chat-id :commands]) {})) diff --git a/src/status_im/utils/handlers.cljs b/src/status_im/utils/handlers.cljs index 083196375e..4d2777e335 100644 --- a/src/status_im/utils/handlers.cljs +++ b/src/status_im/utils/handlers.cljs @@ -11,4 +11,4 @@ (defn register-handler ([name handler] (register-handler name nil handler)) ([name middleware handler] - (re-core/register-handler name [#_debug middleware] handler))) + (re-core/register-handler name [debug middleware] handler))) From 4e5838391c21832046894d06f7dcca1939434ba5 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Fri, 8 Jul 2016 11:30:42 +0300 Subject: [PATCH 08/10] validation messages styles --- src/status_im/chat/handlers/commands.cljs | 7 +++--- .../chat/styles/command_validation.cljs | 17 ++++++++++++- .../chat/views/command_validation.cljs | 25 ++++++++++--------- src/status_im/chat/views/message_input.cljs | 2 +- src/status_im/components/react.cljs | 6 ++++- src/status_im/translations/en.cljs | 2 ++ 6 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/status_im/chat/handlers/commands.cljs b/src/status_im/chat/handlers/commands.cljs index 64f5128a9e..5c0caf390f 100644 --- a/src/status_im/chat/handlers/commands.cljs +++ b/src/status_im/chat/handlers/commands.cljs @@ -5,7 +5,8 @@ [status-im.models.commands :as commands] [clojure.string :as str] [status-im.commands.utils :as cu] - [status-im.utils.phone-number :as pn])) + [status-im.utils.phone-number :as pn] + [status-im.i18n :as i18n])) (def command-prefix "c ") @@ -168,8 +169,8 @@ (dispatch [::finish-command-staging chat-id]) (dispatch [::set-validation-error chat-id - {:title "Phobe number" - :description "Wrong phone number"}])))}) + {:title (i18n/label :t/phone-number) + :description (i18n/label :t/invalid-phone)}])))}) (defn validator [name] (validation-handlers (keyword name))) diff --git a/src/status_im/chat/styles/command_validation.cljs b/src/status_im/chat/styles/command_validation.cljs index b38e8cc820..fc4f75b999 100644 --- a/src/status_im/chat/styles/command_validation.cljs +++ b/src/status_im/chat/styles/command_validation.cljs @@ -1 +1,16 @@ -(ns status-im.chat.styles.command-validation) +(ns status-im.chat.styles.command-validation + (:require [status-im.components.styles :as st])) + +(def messages-container + {:background-color :red + :height 61 + :padding-left 16 + :padding-top 14}) + +(def title + {:color :white + :font-size 12 + :font-family st/font}) + +(def description + (assoc title :opacity 0.69)) diff --git a/src/status_im/chat/views/command_validation.cljs b/src/status_im/chat/views/command_validation.cljs index 4294e61ce2..1c36b91ceb 100644 --- a/src/status_im/chat/views/command_validation.cljs +++ b/src/status_im/chat/views/command_validation.cljs @@ -4,27 +4,28 @@ [status-im.chat.styles.command-validation :as st] [status-im.utils.listview :as lw])) -(defn error [{:keys [title description]}] +(defn message [{:keys [title description]}] (c/list-item [c/view - [c/text title] - [c/text description]])) + [c/text st/title title] + [c/text st/description description]])) -(defn errors-list [errors] - [c/list-view {:renderRow error +(defn messages-list [errors] + [c/list-view {:renderRow message :keyboardShouldPersistTaps true - :dataSource (lw/to-datasource errors)}]) + :dataSource (lw/to-datasource errors) + :style st/messages-container}]) -(defview errors [] - [errors [:validation-errors] +(defview validation-messages [] + [validation-messages [:validation-errors] custom-errors [:custom-validation-errors] command? [:command?]] (when (and command? - (or (seq errors) + (or (seq validation-messages) (seq custom-errors))) - [c/scroll-view {:background-color :red} + [c/scroll-view (cond (seq custom-errors) (vec (concat [c/view] custom-errors)) - (seq errors) - [errors-list errors])])) + (seq validation-messages) + [messages-list validation-messages])])) diff --git a/src/status_im/chat/views/message_input.cljs b/src/status_im/chat/views/message_input.cljs index e45349b28f..87f08c5ad2 100644 --- a/src/status_im/chat/views/message_input.cljs +++ b/src/status_im/chat/views/message_input.cljs @@ -56,7 +56,7 @@ input-command [:get-chat-command-content] valid-plain-message? [:valid-plain-message?]] [view st/input-container - [cv/errors] + [cv/validation-messages] [view st/input-view [plain-message/commands-button] [message-input-container diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index f180f463c2..ff9f87ef6a 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -17,7 +17,11 @@ (def app-registry (get-react-property "AppRegistry")) (def navigator (get-class "Navigator")) -(def text (get-class "Text")) +(def text-class (get-class "Text")) +(defn text + ([s] [text-class s]) + ([{:keys [style] :as opts} s] + [text-class (if style opts {:style opts}) s])) (def view (get-class "View")) (def image (get-class "Image")) (def touchable-highlight-class (get-class "TouchableHighlight")) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index c667275426..e86d4fbc9b 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -136,4 +136,6 @@ ;users :add-account "Add account" + ;validation + :invalid-phone "Invalid phone number" }) From 3718541b8c0844d76e2fc12944ef494e9cef9c1f Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Fri, 8 Jul 2016 12:26:46 +0300 Subject: [PATCH 09/10] validation errors position --- src/status_im/chat/handlers/animation.cljs | 14 ++++++++++---- src/status_im/chat/handlers/commands.cljs | 1 + src/status_im/chat/styles/command_validation.cljs | 5 +++-- src/status_im/chat/views/command_validation.cljs | 15 +++++++-------- src/status_im/chat/views/message_input.cljs | 4 +--- src/status_im/chat/views/response.cljs | 7 ++++--- src/status_im/utils/handlers.cljs | 2 +- 7 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/status_im/chat/handlers/animation.cljs b/src/status_im/chat/handlers/animation.cljs index fde8a8e457..1bb6913651 100644 --- a/src/status_im/chat/handlers/animation.cljs +++ b/src/status_im/chat/handlers/animation.cljs @@ -41,10 +41,16 @@ (defn get-minimum-height [{:keys [current-chat-id] :as db}] (let [path [:chats current-chat-id :command-input :command :type] - type (get-in db path)] - (if (= :response type) - minimum-suggestion-height - input-height))) + type (get-in db path) + errors (get-in db [:validation-errors current-chat-id]) + custom-errors (get-in db [:custom-validation-errors current-chat-id]) + validation-height (if (or (seq errors) (seq custom-errors)) + request-info-height + 0)] + (+ validation-height + (if (= :response type) + minimum-suggestion-height + input-height)))) (register-handler :animate-show-response ;[(after #(dispatch [:command-edit-mode]))] diff --git a/src/status_im/chat/handlers/commands.cljs b/src/status_im/chat/handlers/commands.cljs index 5c0caf390f..f1ca4f1945 100644 --- a/src/status_im/chat/handlers/commands.cljs +++ b/src/status_im/chat/handlers/commands.cljs @@ -183,5 +183,6 @@ (register-handler ::set-validation-error + (after #(dispatch [:fix-response-height])) (fn [db [_ chat-id error]] (assoc-in db [:validation-errors chat-id] [error]))) diff --git a/src/status_im/chat/styles/command_validation.cljs b/src/status_im/chat/styles/command_validation.cljs index fc4f75b999..2ffb23cc84 100644 --- a/src/status_im/chat/styles/command_validation.cljs +++ b/src/status_im/chat/styles/command_validation.cljs @@ -1,9 +1,10 @@ (ns status-im.chat.styles.command-validation - (:require [status-im.components.styles :as st])) + (:require [status-im.components.styles :as st] + [status-im.chat.constants :as constants])) (def messages-container {:background-color :red - :height 61 + :height constants/request-info-height :padding-left 16 :padding-top 14}) diff --git a/src/status_im/chat/views/command_validation.cljs b/src/status_im/chat/views/command_validation.cljs index 1c36b91ceb..6d7a705bd5 100644 --- a/src/status_im/chat/views/command_validation.cljs +++ b/src/status_im/chat/views/command_validation.cljs @@ -20,12 +20,11 @@ [validation-messages [:validation-errors] custom-errors [:custom-validation-errors] command? [:command?]] - (when (and command? - (or (seq validation-messages) - (seq custom-errors))) - [c/scroll-view - (cond (seq custom-errors) - (vec (concat [c/view] custom-errors)) + [c/view + (cond (seq custom-errors) + (vec (concat [c/view] custom-errors)) - (seq validation-messages) - [messages-list validation-messages])])) + (seq validation-messages) + [messages-list validation-messages] + + :else nil)]) diff --git a/src/status_im/chat/views/message_input.cljs b/src/status_im/chat/views/message_input.cljs index 87f08c5ad2..81ea2dd4a7 100644 --- a/src/status_im/chat/views/message_input.cljs +++ b/src/status_im/chat/views/message_input.cljs @@ -11,8 +11,7 @@ [status-im.chat.views.command :as command] [status-im.chat.styles.message-input :as st] [status-im.chat.styles.plain-message :as st-message] - [status-im.chat.styles.response :as st-response] - [status-im.chat.views.command-validation :as cv])) + [status-im.chat.styles.response :as st-response])) (defn send-button [{:keys [on-press accessibility-label]}] [touchable-highlight {:on-press on-press @@ -56,7 +55,6 @@ input-command [:get-chat-command-content] valid-plain-message? [:valid-plain-message?]] [view st/input-container - [cv/validation-messages] [view st/input-view [plain-message/commands-button] [message-input-container diff --git a/src/status_im/chat/views/response.cljs b/src/status_im/chat/views/response.cljs index a0d8e876bc..6e016f5e00 100644 --- a/src/status_im/chat/views/response.cljs +++ b/src/status_im/chat/views/response.cljs @@ -15,7 +15,8 @@ [status-im.chat.styles.dragdown :as ddst] [status-im.components.animation :as anim] [status-im.chat.suggestions-responder :as resp] - [status-im.chat.constants :as c])) + [status-im.chat.constants :as c] + [status-im.chat.views.command-validation :as cv])) (defn drag-icon [] [view st/drag-container @@ -83,8 +84,7 @@ (defview placeholder [] [suggestions [:get-content-suggestions]] - (when (seq suggestions) - [view st/input-placeholder])) + [view st/input-placeholder]) (defview response-suggestions-view [] [suggestions [:get-content-suggestions]] @@ -95,4 +95,5 @@ [container response-height [request-info response-height] [response-suggestions-view] + [cv/validation-messages] [placeholder]])) diff --git a/src/status_im/utils/handlers.cljs b/src/status_im/utils/handlers.cljs index 4d2777e335..083196375e 100644 --- a/src/status_im/utils/handlers.cljs +++ b/src/status_im/utils/handlers.cljs @@ -11,4 +11,4 @@ (defn register-handler ([name handler] (register-handler name nil handler)) ([name middleware handler] - (re-core/register-handler name [debug middleware] handler))) + (re-core/register-handler name [#_debug middleware] handler))) From 65772e3438230aef52466e9bf596dc5943e2cac3 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Fri, 8 Jul 2016 18:30:16 +0300 Subject: [PATCH 10/10] separate animations values for different chats --- src/status_im/chat/handlers/animation.cljs | 30 ++++++++++++---------- src/status_im/chat/subs.cljs | 12 +++++++++ src/status_im/chat/views/response.cljs | 4 +-- src/status_im/chat/views/suggestions.cljs | 2 +- src/status_im/db.cljs | 3 +-- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/status_im/chat/handlers/animation.cljs b/src/status_im/chat/handlers/animation.cljs index 1bb6913651..0a92615c7d 100644 --- a/src/status_im/chat/handlers/animation.cljs +++ b/src/status_im/chat/handlers/animation.cljs @@ -3,6 +3,7 @@ [status-im.utils.handlers :refer [register-handler]] [status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.chat.constants :refer [input-height request-info-height + suggestions-header-height minimum-command-suggestions-height response-height-normal minimum-suggestion-height]] [status-im.constants :refer [response-input-hiding-duration]])) @@ -15,27 +16,28 @@ ([name middleware handler] (register-handler name [(path :animations) middleware] handler))) -(animation-handler :animate-cancel-command +(register-handler :animate-cancel-command (after #(dispatch [:text-edit-mode])) - (fn [db _] - (assoc db :to-response-height input-height))) + (fn [{:keys [current-chat-id] :as db} _] + (assoc-in db [:animations :to-response-height current-chat-id] input-height))) (def response-height (+ input-height response-height-normal)) -(defn update-response-height [db] - (assoc-in db [:animations :to-response-height] response-height)) +(defn update-response-height + [{:keys [current-chat-id] :as db}] + (assoc-in db [:animations :to-response-height current-chat-id] response-height)) (register-handler :animate-command-suggestions - (fn [{:keys [current-chat-id] :as db} _] - (let [suggestions? (seq (get-in db [:command-suggestions current-chat-id])) - current (get-in db [:animations :command-suggestions-height]) + (fn [{chat-id :current-chat-id :as db} _] + (let [suggestions? (seq (get-in db [:command-suggestions chat-id])) + current (get-in db [:animations :command-suggestions-height chat-id]) height (if suggestions? middle-height input-height) changed? (if (and suggestions? (not (nil? current)) (not= input-height current)) identity inc)] (-> db - (update :animations assoc :command-suggestions-height height) + (assoc-in [:animations :command-suggestions-height chat-id] height) (update-in [:animations :commands-height-changed] changed?))))) (defn get-minimum-height @@ -50,7 +52,9 @@ (+ validation-height (if (= :response type) minimum-suggestion-height - input-height)))) + (if (zero? validation-height) + input-height + (+ input-height suggestions-header-height)))))) (register-handler :animate-show-response ;[(after #(dispatch [:command-edit-mode]))] @@ -59,7 +63,7 @@ height (if suggestions? middle-height (get-minimum-height db))] - (assoc-in db [:animations :to-response-height] height)))) + (assoc-in db [:animations :to-response-height current-chat-id] height)))) (defn fix-height [height-key height-signal-key suggestions-key minimum] @@ -70,7 +74,7 @@ under-middle-position? (<= current middle-height) over-middle-position? (not under-middle-position?) suggestions (get-in db [suggestions-key current-chat-id]) - old-fixed (get-in db [:animations height-key]) + old-fixed (get-in db [:animations height-key current-chat-id]) new-fixed (cond (not suggestions) (minimum db) @@ -95,7 +99,7 @@ (and under-middle-position? moving-down?) (minimum db))] (-> db - (assoc-in [:animations height-key] new-fixed) + (assoc-in [:animations height-key current-chat-id] new-fixed) (update-in [:animations height-signal-key] inc))))) (defn commands-min-height diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index c1a8d722b3..edef877e45 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -186,3 +186,15 @@ (register-sub :unviewed-messages-count (fn [db [_ chat-id]] (reaction (get-in @db [:unviewed-messages chat-id :count])))) + +(register-sub :command-suggestions-height + (fn [db] + (let [chat-id (subscribe [:get-current-chat-id])] + (reaction + (get-in @db [:animations :command-suggestions-height @chat-id]))))) + +(register-sub :response-height + (fn [db] + (let [chat-id (subscribe [:get-current-chat-id])] + (reaction + (get-in @db [:animations :to-response-height @chat-id]))))) diff --git a/src/status_im/chat/views/response.cljs b/src/status_im/chat/views/response.cljs index 6e016f5e00..1e7d9d7d3d 100644 --- a/src/status_im/chat/views/response.cljs +++ b/src/status_im/chat/views/response.cljs @@ -59,14 +59,14 @@ [icon :drag_down ddst/drag-down-icon]])))) (defn container-animation-logic [{:keys [to-value val]}] - (let [to-value @to-value] + (when-let [to-value @to-value] (when-not (= to-value (.-_value val)) (anim/start (anim/spring val {:toValue to-value}))))) (defn container [response-height & children] (let [;; todo to-response-height, cur-response-height must be specific ;; for each chat - to-response-height (subscribe [:animations :to-response-height]) + to-response-height (subscribe [:response-height]) changed (subscribe [:animations :response-height-changed]) context {:to-value to-response-height :val response-height} diff --git a/src/status_im/chat/views/suggestions.cljs b/src/status_im/chat/views/suggestions.cljs index 909641d829..5a97ed7e3d 100644 --- a/src/status_im/chat/views/suggestions.cljs +++ b/src/status_im/chat/views/suggestions.cljs @@ -104,7 +104,7 @@ (defn container [h & elements] (let [;; todo to-response-height, cur-response-height must be specific ;; for each chat - to-response-height (subscribe [:animations :command-suggestions-height]) + to-response-height (subscribe [:command-suggestions-height]) changed (subscribe [:animations :commands-height-changed]) context {:to-value to-response-height :val h} diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index 9d1cc6fa5d..503ca17a99 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -38,8 +38,7 @@ :whisper-identity "" :phone-number ""} :disable-group-creation false - :animations {:to-response-height 0.1 - ;; todo clear this + :animations {;; todo clear this :tabs-bar-value (anim/create-value 0)}}) (def protocol-initialized-path [:protocol-initialized])