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/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 af80bbed96..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-20160630_153846-gbf92f5f"] + [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 09290db99e..dea583129e 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -24,7 +24,10 @@ [status-im.components.jail :as j] [status-im.utils.types :refer [json->clj]] [status-im.commands.utils :refer [generate-hiccup]] - status-im.chat.handlers.commands)) + status-im.chat.handlers.commands + status-im.chat.handlers.animation + status-im.chat.handlers.requests + status-im.chat.handlers.unviewed-messages)) (register-handler :set-show-actions (fn [db [_ show-actions]] @@ -140,20 +143,26 @@ (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]) [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 (default-delivery-status current-chat-id) + :outgoing true + :timestamp (time/now-ms)})] (if command (commands/set-chat-command db command) (assoc db :new-message (when-not (str/blank? text) message))))) @@ -167,6 +176,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 @@ -208,12 +218,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]} _] @@ -330,6 +338,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! @@ -343,14 +352,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 @@ -475,6 +492,16 @@ (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! + (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]] + (when-not (console? chat-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 634d2c8bf4..c1a8d722b3 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -182,3 +182,7 @@ (fn [db] (let [current-chat-id (subscribe [:get-current-chat-id])] (reaction (get-in @db [:custom-validation-errors @current-chat-id]))))) + +(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 c7f910e799..3b9b27e3f5 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} + [image {:source (case (or status delivery-status) :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 [_] @@ -203,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 (not 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/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/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/handlers.cljs b/src/status_im/handlers.cljs index ee070f1ceb..3012b78491 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 ------------------------------------------------------------ ;; @@ -90,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 38d7342ae3..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,8 +39,8 @@ message {:chat-id chat-id :content content' - :timestamp (timestamp) - :delivery-status nil})] + :delivery-status delivery-status + :timestamp (timestamp)})] (r/create :msgs message' true)))))) (defn command-type? [type] @@ -50,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 9bb41936e0..1ff462d03a 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] @@ -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]] @@ -102,16 +102,28 @@ (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]] + (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 - (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)) + +(register-handler :msg-seen + [(after (update-message! :seen)) + (after (fn [_ [_ chat-id]] + (dispatch [:remove-unviewed-messages chat-id])))] + (update-message-status :seen)) diff --git a/src/status_im/protocol/protocol_handler.cljs b/src/status_im/protocol/protocol_handler.cljs index cd0d44c812..8f79ed7939 100644 --- a/src/status_im/protocol/protocol_handler.cljs +++ b/src/status_im/protocol/protocol_handler.cljs @@ -22,8 +22,10 @@ (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])) + :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] (dispatch [:group-chat-invite-received from group-id identities group-name])) :new-group-msg (let [{from :from