Refactored statuses
This commit is contained in:
parent
e66b5c435b
commit
52ddccca96
|
@ -4,7 +4,6 @@
|
|||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.chat.models :as model]
|
||||
[status-im.chat.models.unviewed-messages :as unviewed-messages-model]
|
||||
[status-im.chat.console :as console-chat]
|
||||
[status-im.chat.constants :as chat-const]
|
||||
[status-im.data-store.messages :as msg-store]
|
||||
|
@ -31,7 +30,8 @@
|
|||
(re-frame/reg-cofx
|
||||
:stored-unviewed-messages
|
||||
(fn [cofx _]
|
||||
(assoc cofx :stored-unviewed-messages (messages-store/get-unviewed))))
|
||||
(assoc cofx :stored-unviewed-messages
|
||||
(msg-store/get-unviewed (-> cofx :db :current-public-key)))))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-stored-message
|
||||
|
@ -170,16 +170,16 @@
|
|||
(if account-creation?
|
||||
{:db db
|
||||
:dispatch load-default-contacts-event}
|
||||
(let [chat->unviewed-messages (unviewed-messages-model/index-unviewed-messages stored-unviewed-messages)
|
||||
chat->message-id->request (reduce (fn [acc {:keys [chat-id message-id] :as request}]
|
||||
(let [chat->message-id->request (reduce (fn [acc {:keys [chat-id message-id] :as request}]
|
||||
(assoc-in acc [chat-id message-id] request))
|
||||
{}
|
||||
stored-unanswered-requests)
|
||||
chats (reduce (fn [acc {:keys [chat-id] :as chat}]
|
||||
(assoc acc chat-id (assoc chat
|
||||
:unviewed-messages (get chat->unviewed-messages chat-id)
|
||||
:requests (get chat->message-id->request chat-id)
|
||||
:messages (index-messages (get-stored-messages chat-id)))))
|
||||
(assoc acc chat-id
|
||||
(assoc chat
|
||||
:unviewed-messages (get stored-unviewed-messages chat-id)
|
||||
:requests (get chat->message-id->request chat-id)
|
||||
:messages (index-messages (get-stored-messages chat-id)))))
|
||||
{}
|
||||
all-stored-chats)]
|
||||
(-> db
|
||||
|
@ -190,23 +190,22 @@
|
|||
(handlers/register-handler-fx
|
||||
:send-seen!
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [{:keys [message-id chat-id from]}]]
|
||||
(let [{:keys [web3 current-public-key chats]
|
||||
:contacts/keys [contacts]} db
|
||||
{:keys [group-chat public?]} (get chats chat-id)]
|
||||
(fn [{:keys [db]} [{:keys [chat-id from me message-id]}]]
|
||||
(let [{:keys [web3 chats] :contacts/keys [contacts]} db
|
||||
{:keys [group-chat public? messages]} (get chats chat-id)
|
||||
statuses (assoc (get-in messages [message-id :user-statuses]) me :seen)]
|
||||
(cond-> {:db (-> db
|
||||
(unviewed-messages-model/remove-unviewed-message chat-id message-id)
|
||||
(assoc-in [:chats chat-id :messages message-id :message-status] :seen))
|
||||
:update-message {:message-id message-id
|
||||
:message-status :seen}}
|
||||
(and (not (get-in contacts [chat-id] :dapp?))
|
||||
(not public?))
|
||||
(assoc :protocol-send-seen
|
||||
{:web3 web3
|
||||
:message (cond-> {:from current-public-key
|
||||
:to from
|
||||
:message-id message-id}
|
||||
group-chat (assoc :group-id chat-id))})))))
|
||||
(update-in [:chats chat-id :unviewed-messages] disj message-id)
|
||||
(assoc-in [:chats chat-id :messages message-id :user-statuses] statuses))
|
||||
:update-message {:message-id message-id
|
||||
:user-statuses statuses}}
|
||||
;; for public chats and 1-1 bot/dapp chats, it makes no sense to signalise `:seen` msg
|
||||
(not (or public? (get-in contacts [chat-id] :dapp?)))
|
||||
(assoc :protocol-send-seen {:web3 web3
|
||||
:message (cond-> {:from me
|
||||
:to from
|
||||
:message-id message-id}
|
||||
group-chat (assoc :group-id chat-id))})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-mnemonic
|
||||
|
|
|
@ -44,10 +44,13 @@
|
|||
(sign-up db phone-number message-id)))
|
||||
|
||||
(defn- message-seen [{:keys [db] :as fx} message-id]
|
||||
(-> fx
|
||||
(assoc-in [:db :chats const/console-chat-id :messages message-id :message-status] :seen)
|
||||
(assoc :update-message {:message-id message-id
|
||||
:message-status :seen})))
|
||||
(let [statuses-path [:chats const/console-chat-id :messages message-id :user-statuses]
|
||||
statuses (-> (get-in db statuses-path)
|
||||
(assoc const/console-chat-id :seen))]
|
||||
(-> fx
|
||||
(assoc-in (into [:db] statuses-path) statuses)
|
||||
(assoc :update-message {:message-id message-id
|
||||
:user-statuses statuses}))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:start-listening-confirmation-code-sms
|
||||
|
|
|
@ -79,9 +79,15 @@
|
|||
(dispatch [:prepare-command! chat-id params])))
|
||||
(dispatch [:set-chat-ui-props {:sending-in-progress? false}]))))
|
||||
|
||||
(defn- message-type [{:keys [group-chat public?]}]
|
||||
(cond
|
||||
(and group-chat public?) :public-group-user-message
|
||||
(and group-chat (not public?)) :group-user-message
|
||||
:else :user-message))
|
||||
|
||||
(register-handler :prepare-command!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-public-key network-status] :as db}
|
||||
(fn [{:keys [current-public-key network-status chats] :as db}
|
||||
[_ add-to-chat-id {{:keys [handler-data
|
||||
command]
|
||||
:as content} :command
|
||||
|
@ -92,7 +98,8 @@
|
|||
hidden-params (->> (:params command)
|
||||
(filter :hidden)
|
||||
(map :name))
|
||||
command' (prepare-command current-public-key chat-id clock-value request content)]
|
||||
command' (-> (prepare-command current-public-key chat-id clock-value request content)
|
||||
(assoc :message-type (message-type (get chats chat-id))))]
|
||||
(dispatch [:update-message-overhead! chat-id network-status])
|
||||
(dispatch [:set-chat-ui-props {:sending-in-progress? false}])
|
||||
(dispatch [::send-command! add-to-chat-id (assoc params :command command') hidden-params])
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
[status-im.constants :as constants]
|
||||
[status-im.chat.utils :as chat-utils]
|
||||
[status-im.chat.models :as chat-model]
|
||||
[status-im.chat.models.commands :as commands-model]
|
||||
[status-im.chat.models.unviewed-messages :as unviewed-messages-model]
|
||||
[status-im.chat.models.commands :as commands-model]
|
||||
[status-im.chat.events.requests :as requests-events]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
|
@ -33,8 +32,8 @@
|
|||
(defn- add-message-to-db
|
||||
[db {:keys [message-id] :as message} chat-id]
|
||||
(-> db
|
||||
(chat-utils/add-message-to-db chat-id chat-id message (:new? message))
|
||||
(unviewed-messages-model/add-unviewed-message chat-id message-id)))
|
||||
(update-in [:chats chat-id :unviewed-messages] (fnil conj #{}) message-id)
|
||||
(chat-utils/add-message-to-db chat-id chat-id message (:new? message))))
|
||||
|
||||
(defn receive
|
||||
[{:keys [db message-exists? pop-up-chat? get-last-clock-value now] :as cofx}
|
||||
|
@ -57,21 +56,23 @@
|
|||
command-request? (= content-type constants/content-type-command-request)
|
||||
command (:command content)
|
||||
enriched-message (cond-> (assoc message
|
||||
:chat-id chat-identifier
|
||||
:timestamp (or timestamp now)
|
||||
:show? true
|
||||
:clock-value (clocks/receive
|
||||
clock-value
|
||||
(get-last-clock-value chat-identifier)))
|
||||
(and command command-request?)
|
||||
(assoc-in [:content :content-command-ref]
|
||||
(lookup-response-ref access-scope->commands-responses
|
||||
current-account
|
||||
(get-in fx [:db :chats chat-identifier])
|
||||
contacts
|
||||
command)))]
|
||||
:chat-id chat-identifier
|
||||
:timestamp (or timestamp now)
|
||||
:show? true
|
||||
:clock-value (clocks/receive
|
||||
clock-value
|
||||
(get-last-clock-value chat-identifier)))
|
||||
public-key
|
||||
(assoc :user-statuses {public-key :received})
|
||||
(and command command-request?)
|
||||
(assoc-in [:content :content-command-ref]
|
||||
(lookup-response-ref access-scope->commands-responses
|
||||
current-account
|
||||
(get-in fx [:db :chats chat-identifier])
|
||||
contacts
|
||||
command)))]
|
||||
(cond-> (-> fx
|
||||
(update :db add-message-to-db enriched-message chat-identifier)
|
||||
(assoc :save-message (dissoc enriched-message :new?)))
|
||||
command-request?
|
||||
(requests-events/add-request chat-identifier enriched-message))))))
|
||||
command-request?
|
||||
(requests-events/add-request chat-identifier enriched-message))))))
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
(ns status-im.chat.models.unviewed-messages)
|
||||
|
||||
(defn index-unviewed-messages [unviewed-messages]
|
||||
(into {}
|
||||
(map (fn [[chat-id messages]]
|
||||
[chat-id (into #{} (map :message-id) messages)]))
|
||||
(group-by :chat-id unviewed-messages)))
|
||||
|
||||
(defn add-unviewed-message [db chat-id message-id]
|
||||
(update-in db [:chats chat-id :unviewed-messages] (fnil conj #{}) message-id))
|
||||
|
||||
(defn remove-unviewed-message [db chat-id message-id]
|
||||
(update-in db [:chats chat-id :unviewed-messages] disj message-id))
|
|
@ -10,10 +10,8 @@
|
|||
(s/def :chat/chat-list-ui-props (s/nilable map?))
|
||||
(s/def :chat/layout-height (s/nilable number?)) ; height of chat's view layout
|
||||
(s/def :chat/expandable-view-height-to-value (s/nilable number?))
|
||||
(s/def :chat/message-status (s/nilable map?)) ; TODO janherich: remove later
|
||||
(s/def :chat/selected-participants (s/nilable set?))
|
||||
(s/def :chat/chat-loaded-callbacks (s/nilable map?))
|
||||
(s/def :chat/command-hash-valid? (s/nilable boolean?))
|
||||
(s/def :chat/chat-loaded-callbacks (s/nilable map?))
|
||||
(s/def :chat/public-group-topic (s/nilable string?))
|
||||
(s/def :chat/confirmation-code-sms-listener (s/nilable any?)) ; .addListener result object
|
||||
(s/def :chat/messages (s/nilable map?)) ; messages indexed by message-id
|
||||
|
|
|
@ -61,6 +61,12 @@
|
|||
(fn [[chats current-chat-id]]
|
||||
(get chats current-chat-id)))
|
||||
|
||||
(reg-sub
|
||||
:get-current-chat-message
|
||||
:<- [:get-current-chat]
|
||||
(fn [{:keys [messages]} [_ message-id]]
|
||||
(get messages message-id)))
|
||||
|
||||
(reg-sub
|
||||
:chat
|
||||
:<- [:chats]
|
||||
|
@ -265,7 +271,7 @@
|
|||
(:web-view-extra-js current-chat)))
|
||||
|
||||
(reg-sub
|
||||
:photo-path
|
||||
:get-photo-path
|
||||
:<- [:get-contacts]
|
||||
(fn [contacts [_ id]]
|
||||
(:photo-path (contacts id))))
|
||||
|
|
|
@ -9,5 +9,8 @@
|
|||
:new? (if (nil? new?) true new?))]
|
||||
(update-in db [:chats add-to-chat-id :messages] assoc message-id prepared-message))))
|
||||
|
||||
(defn message-seen-by? [message user-pk]
|
||||
(= :seen (get-in message [:user-statuses user-pk])))
|
||||
|
||||
(defn command-name [{:keys [name]}]
|
||||
(str chat.constants/command-char name))
|
||||
|
|
|
@ -1,72 +1,63 @@
|
|||
(ns status-im.chat.views.input.suggestions
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.ui.components.react :refer [view
|
||||
scroll-view
|
||||
touchable-highlight
|
||||
text
|
||||
icon]]
|
||||
[status-im.data-store.messages :as messages]
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.chat.styles.input.suggestions :as style]
|
||||
[status-im.chat.constants :as const]
|
||||
[status-im.chat.views.input.animations.expandable :refer [expandable-view]]
|
||||
[status-im.chat.views.input.utils :as input-utils]
|
||||
[status-im.i18n :refer [label]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.chat.utils :as chat-utils]))
|
||||
[status-im.chat.views.input.animations.expandable :as expandable]
|
||||
[status-im.chat.utils :as chat.utils]
|
||||
[status-im.i18n :as i18n]))
|
||||
|
||||
(defn suggestion-item [{:keys [on-press name description last?]}]
|
||||
[touchable-highlight {:on-press on-press}
|
||||
[view (style/item-suggestion-container last?)
|
||||
[view {:style style/item-suggestion-name}
|
||||
[text {:style style/item-suggestion-name-text
|
||||
:font :roboto-mono} name]]
|
||||
[text {:style style/item-suggestion-description
|
||||
:number-of-lines 2}
|
||||
[react/touchable-highlight {:on-press on-press}
|
||||
[react/view (style/item-suggestion-container last?)
|
||||
[react/view {:style style/item-suggestion-name}
|
||||
[react/text {:style style/item-suggestion-name-text
|
||||
:font :roboto-mono} name]]
|
||||
[react/text {:style style/item-suggestion-description
|
||||
:number-of-lines 2}
|
||||
description]]])
|
||||
|
||||
(defview response-item [{:keys [name description]
|
||||
{:keys [type message-id]} :request :as command} last?]
|
||||
[{:keys [chat-id]} [:get-current-chat]]
|
||||
{:keys [message-id]} :request :as command} last?]
|
||||
[{{:keys [params]} :content} [:get-current-chat-message message-id]]
|
||||
[suggestion-item
|
||||
{:on-press #(let [{:keys [params]} (messages/get-message-content-by-id message-id)
|
||||
metadata (assoc params :to-message-id message-id)]
|
||||
(dispatch [:select-chat-input-command command metadata]))
|
||||
:name (chat-utils/command-name command)
|
||||
{:on-press #(let [metadata (assoc params :to-message-id message-id)]
|
||||
(re-frame/dispatch [:select-chat-input-command command metadata]))
|
||||
:name (chat.utils/command-name command)
|
||||
:description description
|
||||
:last? last?}])
|
||||
|
||||
(defn command-item [{:keys [name description bot] :as command} last?]
|
||||
[suggestion-item
|
||||
{:on-press #(dispatch [:select-chat-input-command command nil])
|
||||
:name (chat-utils/command-name command)
|
||||
{:on-press #(re-frame/dispatch [:select-chat-input-command command nil])
|
||||
:name (chat.utils/command-name command)
|
||||
:description description
|
||||
:last? last?}])
|
||||
|
||||
(defn item-title [top-padding? s]
|
||||
[view (style/item-title-container top-padding?)
|
||||
[text {:style style/item-title-text}
|
||||
s]])
|
||||
(defn item-title [top-padding? title]
|
||||
[react/view (style/item-title-container top-padding?)
|
||||
[react/text {:style style/item-title-text}
|
||||
title]])
|
||||
|
||||
(defview suggestions-view []
|
||||
[show-suggestions? [:show-suggestions?]
|
||||
responses [:get-available-responses]
|
||||
commands [:get-available-commands]]
|
||||
(when show-suggestions?
|
||||
[expandable-view {:key :suggestions
|
||||
:draggable? false
|
||||
:height 212}
|
||||
[view {:flex 1}
|
||||
[scroll-view {:keyboardShouldPersistTaps :always}
|
||||
[expandable/expandable-view {:key :suggestions
|
||||
:draggable? false
|
||||
:height 212}
|
||||
[react/view {:flex 1}
|
||||
[react/scroll-view {:keyboardShouldPersistTaps :always}
|
||||
(when (seq responses)
|
||||
[view
|
||||
[item-title false (label :t/suggestions-requests)]
|
||||
[react/view
|
||||
[item-title false (i18n/label :t/suggestions-requests)]
|
||||
(for [[i response] (map-indexed vector responses)]
|
||||
^{:key i}
|
||||
[response-item response (= i (dec (count responses)))])])
|
||||
(when (seq commands)
|
||||
[view
|
||||
[item-title (seq responses) (label :t/suggestions-commands)]
|
||||
[react/view
|
||||
[item-title (seq responses) (i18n/label :t/suggestions-commands)]
|
||||
(for [[i command] (map-indexed vector commands)]
|
||||
^{:key i}
|
||||
[command-item command (= i (dec (count commands)))])])]]]))
|
||||
|
|
|
@ -174,71 +174,66 @@
|
|||
[message-content-audio {:content content
|
||||
:content-type content-type}]]])
|
||||
|
||||
(defview group-message-delivery-status [{:keys [message-id group-id message-status user-statuses] :as msg}]
|
||||
(letsubs [chat [:get-current-chat]
|
||||
contacts [:get-contacts]]
|
||||
(let [status (or message-status :sending)
|
||||
participants (:contacts chat)
|
||||
seen-by-everyone? (and (= (count user-statuses) (count participants))
|
||||
(every? (fn [[_ {:keys [status]}]]
|
||||
(= (keyword status) :seen)) user-statuses))]
|
||||
(if (or (zero? (count user-statuses))
|
||||
seen-by-everyone?)
|
||||
[react/view style/delivery-view
|
||||
[react/text {:style style/delivery-text
|
||||
:font :default}
|
||||
(i18n/message-status-label
|
||||
(if seen-by-everyone?
|
||||
:seen-by-everyone
|
||||
status))]]
|
||||
(defn- text-status [status]
|
||||
[react/view style/delivery-view
|
||||
[react/text {:style style/delivery-text
|
||||
:font :default}
|
||||
(i18n/message-status-label status)]])
|
||||
|
||||
(defview group-message-delivery-status [{:keys [message-id group-id current-public-key user-statuses] :as msg}]
|
||||
(letsubs [{participants :contacts} [:get-current-chat]
|
||||
contacts [:get-contacts]]
|
||||
(let [outgoing-status (or (get user-statuses current-public-key) :sending)
|
||||
delivery-statuses (dissoc user-statuses current-public-key)
|
||||
delivery-statuses-count (count delivery-statuses)
|
||||
seen-by-everyone (and (= delivery-statuses-count (count participants))
|
||||
(every? (comp (partial = :seen) second) delivery-statuses)
|
||||
:seen-by-everyone)]
|
||||
(if (or seen-by-everyone (zero? delivery-statuses-count))
|
||||
[text-status (or seen-by-everyone outgoing-status)]
|
||||
[react/touchable-highlight
|
||||
{:on-press (fn []
|
||||
(re-frame/dispatch [:show-message-details {:message-status status
|
||||
:user-statuses user-statuses
|
||||
:participants participants}]))}
|
||||
{:on-press #(re-frame/dispatch [:show-message-details {:message-status outgoing-status
|
||||
:user-statuses delivery-statuses
|
||||
:participants participants}])}
|
||||
[react/view style/delivery-view
|
||||
(for [[_ {:keys [whisper-identity]}] (take 3 user-statuses)]
|
||||
(for [[whisper-identity] (take 3 delivery-statuses)]
|
||||
^{:key whisper-identity}
|
||||
[react/image {:source {:uri (or (get-in contacts [whisper-identity :photo-path])
|
||||
(identicon/identicon whisper-identity))}
|
||||
:style {:width 16
|
||||
:height 16
|
||||
:borderRadius 8}}])
|
||||
(if (> (count user-statuses) 3)
|
||||
(if (> delivery-statuses-count 3)
|
||||
[react/text {:style style/delivery-text
|
||||
:font :default}
|
||||
(str "+ " (- (count user-statuses) 3))])]]))))
|
||||
(str "+ " (- delivery-statuses-count 3))])]]))))
|
||||
|
||||
(defn message-delivery-status
|
||||
[{:keys [message-id chat-id message-status user-statuses content]}]
|
||||
(let [delivery-status (get-in user-statuses [chat-id :status])
|
||||
status (cond (and (not (console/commands-with-delivery-status (:command content)))
|
||||
(= constants/console-chat-id chat-id))
|
||||
[{:keys [message-id chat-id current-public-key user-statuses content]}]
|
||||
(let [outgoing-status (or (get user-statuses current-public-key) :sending)
|
||||
delivery-status (get user-statuses chat-id)
|
||||
status (cond (and (= constants/console-chat-id chat-id)
|
||||
(not (console/commands-with-delivery-status (:command content))))
|
||||
:seen
|
||||
|
||||
:else
|
||||
(or delivery-status message-status :sending))]
|
||||
[react/view style/delivery-view
|
||||
[react/text {:style style/delivery-text
|
||||
:font :default}
|
||||
(i18n/message-status-label status)]]))
|
||||
(or delivery-status outgoing-status))]
|
||||
[text-status status]))
|
||||
|
||||
(defn- photo [from photo-path]
|
||||
[react/view
|
||||
[react/image {:source {:uri (if (string/blank? photo-path)
|
||||
(identicon/identicon from)
|
||||
photo-path)}
|
||||
:style style/photo}]])
|
||||
|
||||
(defview member-photo [from]
|
||||
(letsubs [photo-path [:photo-path from]]
|
||||
[react/view
|
||||
[react/image {:source {:uri (if (string/blank? photo-path)
|
||||
(identicon/identicon from)
|
||||
photo-path)}
|
||||
:style style/photo}]]))
|
||||
(letsubs [photo-path [:get-photo-path from]]
|
||||
(photo from photo-path)))
|
||||
|
||||
(defview my-photo [from]
|
||||
(letsubs [account [:get-current-account]]
|
||||
(let [{:keys [photo-path]} account]
|
||||
[react/view
|
||||
[react/image {:source {:uri (if (string/blank? photo-path)
|
||||
(identicon/identicon from)
|
||||
photo-path)}
|
||||
:style style/photo}]])))
|
||||
(letsubs [{:keys [photo-path]} [:get-current-account]]
|
||||
(photo from photo-path)))
|
||||
|
||||
(defn message-body
|
||||
[{:keys [last-outgoing? message-type same-author? from outgoing] :as message} content]
|
||||
|
@ -291,18 +286,16 @@
|
|||
children)])}))
|
||||
(into [react/view] children)))
|
||||
|
||||
(defn chat-message [{:keys [outgoing message-id chat-id message-status user-statuses
|
||||
from current-public-key] :as message}]
|
||||
(defn chat-message [{:keys [outgoing message-id chat-id from current-public-key] :as message}]
|
||||
(reagent/create-class
|
||||
{:display-name "chat-message"
|
||||
:component-did-mount
|
||||
#(when (and message-id
|
||||
chat-id
|
||||
(not outgoing)
|
||||
(not= :seen message-status)
|
||||
(not= :seen (keyword (get-in user-statuses [current-public-key :status]))))
|
||||
;; send `:seen` signal when we have signed-in user, message not from us and we didn't sent it already
|
||||
#(when (and current-public-key message-id chat-id (not outgoing)
|
||||
(not (chat.utils/message-seen-by? message current-public-key)))
|
||||
(re-frame/dispatch [:send-seen! {:chat-id chat-id
|
||||
:from from
|
||||
:me current-public-key
|
||||
:message-id message-id}]))
|
||||
:reagent-render
|
||||
(fn [{:keys [outgoing group-chat content-type content] :as message}]
|
||||
|
@ -321,4 +314,5 @@
|
|||
[react/view
|
||||
(let [incoming-group (and group-chat (not outgoing))]
|
||||
[message-content message-body (merge message
|
||||
{:incoming-group incoming-group})])]]])}))
|
||||
{:current-public-key current-public-key
|
||||
:incoming-group incoming-group})])]]])}))
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
|
||||
(def default-values
|
||||
{:outgoing false
|
||||
:to nil
|
||||
:preview nil})
|
||||
:to nil})
|
||||
|
||||
(defn exists? [message-id]
|
||||
(data-store/exists? message-id))
|
||||
|
@ -24,17 +23,11 @@
|
|||
[message-id]
|
||||
(data-store/get-by-id message-id))
|
||||
|
||||
(defn get-message-content-by-id [message-id]
|
||||
(when-let [{:keys [content-type content] :as message} (get-by-id message-id)]
|
||||
(when (command-type? content-type)
|
||||
(reader/read-string content))))
|
||||
|
||||
(defn get-by-chat-id
|
||||
([chat-id]
|
||||
(get-by-chat-id chat-id 0))
|
||||
([chat-id from]
|
||||
(->> (data-store/get-by-chat-id chat-id from constants/default-number-of-messages)
|
||||
reverse
|
||||
(keep (fn [{:keys [content-type preview] :as message}]
|
||||
(if (command-type? content-type)
|
||||
(update message :content reader/read-string)
|
||||
|
@ -46,13 +39,6 @@
|
|||
(filter #(= (:content-type %) constants/content-type-log-message))
|
||||
(map #(select-keys % [:content :timestamp]))))
|
||||
|
||||
(defn get-last-outgoing
|
||||
[chat-id number-of-messages]
|
||||
(data-store/get-by-fields {:chat-id chat-id
|
||||
:outgoing true}
|
||||
0
|
||||
number-of-messages))
|
||||
|
||||
(defn get-last-clock-value
|
||||
[chat-id]
|
||||
(if-let [message (data-store/get-last-message chat-id)]
|
||||
|
@ -60,34 +46,46 @@
|
|||
0))
|
||||
|
||||
(defn get-unviewed
|
||||
[]
|
||||
(data-store/get-unviewed))
|
||||
[current-public-key]
|
||||
(into {}
|
||||
(map (fn [[chat-id user-statuses]]
|
||||
[chat-id (into #{} (map :message-id) user-statuses)]))
|
||||
(group-by :chat-id (data-store/get-unviewed current-public-key))))
|
||||
|
||||
(defn- prepare-content [content]
|
||||
(if (string? content)
|
||||
content
|
||||
(pr-str
|
||||
;; TODO janherich: this is ugly and not systematic, define something like `:not-persisent`
|
||||
;; option for command params instead
|
||||
;; option for command params instead
|
||||
(update content :params dissoc :password :password-confirmation))))
|
||||
|
||||
(defn save
|
||||
[{:keys [message-id content] :as message}]
|
||||
(defn- prepare-statuses [{:keys [chat-id message-id] :as message}]
|
||||
(utils/update-if-present message
|
||||
:user-statuses
|
||||
(partial map (fn [[whisper-identity status]]
|
||||
{:whisper-identity whisper-identity
|
||||
:status status
|
||||
:chat-id chat-id
|
||||
:message-id message-id}))))
|
||||
|
||||
(defn- prepare-message [message]
|
||||
(-> message
|
||||
prepare-statuses
|
||||
(utils/update-if-present :content prepare-content)))
|
||||
|
||||
(defn save
|
||||
[{:keys [message-id content from] :as message}]
|
||||
(when-not (data-store/exists? message-id)
|
||||
(let [content' (prepare-content content)
|
||||
message' (merge default-values
|
||||
message
|
||||
{:content content'
|
||||
:timestamp (random/timestamp)})]
|
||||
(data-store/save message'))))
|
||||
(data-store/save (prepare-message (merge default-values
|
||||
message
|
||||
{:from (or from "anonymous")
|
||||
:timestamp (random/timestamp)})))))
|
||||
|
||||
(defn update-message
|
||||
[{:keys [message-id] :as message}]
|
||||
(when (data-store/exists? message-id)
|
||||
(let [message (-> message
|
||||
(utils/update-if-present :user-statuses vals)
|
||||
(utils/update-if-present :content prepare-content))]
|
||||
(data-store/save message))))
|
||||
(when-let [{:keys [chat-id]} (data-store/get-by-id message-id)]
|
||||
(data-store/save (prepare-message (assoc message :chat-id chat-id)))))
|
||||
|
||||
(defn delete-by-chat-id [chat-id]
|
||||
(data-store/delete-by-chat-id chat-id))
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
(data-store/save message')))
|
||||
|
||||
(defn delete
|
||||
[pending-message]
|
||||
(data-store/delete pending-message))
|
||||
[message-id]
|
||||
(data-store/delete message-id))
|
||||
|
||||
(defn delete-all-by-chat-id
|
||||
[chat-id]
|
||||
|
|
|
@ -11,12 +11,18 @@
|
|||
[]
|
||||
(realm/js-object->clj (get-all)))
|
||||
|
||||
(defn- transform-message [message]
|
||||
(update message :user-statuses
|
||||
(partial into {}
|
||||
(map (fn [[_ {:keys [whisper-identity status]}]]
|
||||
[whisper-identity (keyword status)])))))
|
||||
|
||||
(defn get-by-id
|
||||
[message-id]
|
||||
(when-let [message (realm/get-one-by-field-clj @realm/account-realm :message :message-id message-id)]
|
||||
(realm/fix-map message :user-statuses :whisper-identity)))
|
||||
(some-> (realm/get-one-by-field-clj @realm/account-realm :message :message-id message-id)
|
||||
transform-message))
|
||||
|
||||
(defn get-by-chat-id
|
||||
(defn get-by-chat-id
|
||||
([chat-id number-of-messages]
|
||||
(get-by-chat-id chat-id 0 number-of-messages))
|
||||
([chat-id from number-of-messages]
|
||||
|
@ -24,7 +30,7 @@
|
|||
(realm/sorted :timestamp :desc)
|
||||
(realm/page from (+ from number-of-messages))
|
||||
realm/js-object->clj)]
|
||||
(mapv #(realm/fix-map % :user-statuses :whisper-identity) messages))))
|
||||
(mapv transform-message messages))))
|
||||
|
||||
(defn get-by-fields
|
||||
[fields from number-of-messages]
|
||||
|
@ -40,10 +46,10 @@
|
|||
(realm/single-clj)))
|
||||
|
||||
(defn get-unviewed
|
||||
[]
|
||||
[current-public-key]
|
||||
(-> @realm/account-realm
|
||||
(realm/get-by-fields :message :and {:outgoing false
|
||||
:message-status nil})
|
||||
(realm/get-by-fields :user-status :and {:whisper-identity current-public-key
|
||||
:status :received})
|
||||
realm/js-object->clj))
|
||||
|
||||
(defn exists?
|
||||
|
@ -52,8 +58,7 @@
|
|||
|
||||
(defn save
|
||||
[message]
|
||||
(let [message (update message :user-statuses #(if % % []))]
|
||||
(realm/save @realm/account-realm :message message true)))
|
||||
(realm/save @realm/account-realm :message message true))
|
||||
|
||||
(defn delete-by-chat-id
|
||||
[chat-id]
|
||||
|
|
|
@ -23,9 +23,8 @@
|
|||
(realm/save @realm/account-realm :pending-message pending-message true))
|
||||
|
||||
(defn delete
|
||||
[{{:keys [message-id ack-of-message]} :payload}]
|
||||
(let [message-id (or ack-of-message message-id)]
|
||||
(realm/delete @realm/account-realm (get-by-message-id message-id))))
|
||||
[message-id]
|
||||
(realm/delete @realm/account-realm (get-by-message-id message-id)))
|
||||
|
||||
(defn delete-all-by-chat-id
|
||||
[chat-id]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
[status-im.data-store.realm.schemas.account.v1.processed-message :as processed-message]
|
||||
[status-im.data-store.realm.schemas.account.v19.request :as request]
|
||||
[status-im.data-store.realm.schemas.account.v1.tag :as tag]
|
||||
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status]
|
||||
[status-im.data-store.realm.schemas.account.v19.user-status :as user-status]
|
||||
[status-im.data-store.realm.schemas.account.v5.contact-group :as contact-group]
|
||||
[status-im.data-store.realm.schemas.account.v5.group-contact :as group-contact]
|
||||
[status-im.data-store.realm.schemas.account.v8.local-storage :as local-storage]
|
||||
|
@ -101,6 +101,24 @@
|
|||
(log/debug "migrating v19 command/request database, updating: " content " with: " new-props)
|
||||
(aset object "content" (pr-str new-content)))))))
|
||||
|
||||
(defn update-message-statuses [new-realm]
|
||||
(some-> new-realm
|
||||
(.objects "message")
|
||||
(.map (fn [msg _ _]
|
||||
(let [message-id (aget msg "message-id")
|
||||
chat-id (aget msg "chat-id")
|
||||
from (aget msg "from")
|
||||
msg-status (aget msg "message-status")
|
||||
statuses (aget msg "user-statuses")]
|
||||
(when statuses
|
||||
(.map statuses (fn [status _ _]
|
||||
(aset status "message-id" message-id)
|
||||
(aset status "chat-id" chat-id)))
|
||||
(.push statuses (clj->js {"message-id" message-id
|
||||
"chat-id" chat-id
|
||||
"status" (or msg-status "received")
|
||||
"whisper-identity" (or from "anonymous")}))))))))
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating v19 account database: " old-realm new-realm)
|
||||
(remove-contact! new-realm "transactor-personal")
|
||||
|
@ -108,4 +126,5 @@
|
|||
(remove-console-intro-message! new-realm)
|
||||
(update-commands (juxt :bot :command) owner-command->new-props new-realm "command")
|
||||
(update-commands (juxt :command) console-requests->new-props new-realm "command-request")
|
||||
(update-commands (juxt :command (comp count :prefill)) transactor-requests->new-props new-realm "command-request"))
|
||||
(update-commands (juxt :command (comp count :prefill)) transactor-requests->new-props new-realm "command-request")
|
||||
(update-message-statuses new-realm))
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
:indexed true}
|
||||
:outgoing :bool
|
||||
:retry-count {:type :int
|
||||
:default 0}
|
||||
:default 0}
|
||||
:message-type {:type :string
|
||||
:optional true}
|
||||
:message-status {:type :string
|
||||
:optional true}
|
||||
:user-statuses {:type :list
|
||||
:objectType "user-status"}
|
||||
:objectType :user-status}
|
||||
:clock-value {:type :int
|
||||
:default 0}
|
||||
:show? {:type :bool
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v19.user-status)
|
||||
|
||||
(def schema {:name :user-status
|
||||
:properties {:message-id :string
|
||||
:chat-id :string
|
||||
:whisper-identity :string
|
||||
:status :string}})
|
|
@ -11,6 +11,7 @@
|
|||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.protocol.message-cache :as cache]
|
||||
[status-im.chat.utils :as chat.utils]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[taoensso.timbre :as log :refer-macros [debug]]
|
||||
[status-im.native-module.core :as status]
|
||||
|
@ -197,39 +198,15 @@
|
|||
:content (str (or inviter-name from) " " (i18n/label :t/invited) " " (or invitee-name identity))
|
||||
:content-type constants/text-content-type}]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::save-message-status!
|
||||
(fn [{:keys [message-id ack-of-message group-id from status]}]
|
||||
(let [message-id' (or ack-of-message message-id)]
|
||||
(when-let [{:keys [message-status] :as message} (messages/get-by-id message-id')]
|
||||
(when-not (= (keyword message-status) :seen)
|
||||
(let [group? (boolean group-id)
|
||||
message' (-> (if (and group? (not= status :sent))
|
||||
(update-in message
|
||||
[:user-statuses from]
|
||||
(fn [{old-status :status}]
|
||||
{:id (random/id)
|
||||
:whisper-identity from
|
||||
:status (if (= (keyword old-status) :seen)
|
||||
old-status
|
||||
status)}))
|
||||
(assoc message :message-status status))
|
||||
;; we need to dissoc preview because it has been saved before
|
||||
(dissoc :preview))]
|
||||
(messages/update-message message')))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::pending-messages-delete
|
||||
(fn [message]
|
||||
(pending-messages/delete message)))
|
||||
(fn [message-id]
|
||||
(pending-messages/delete message-id)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::pending-messages-save
|
||||
(fn [{:keys [type id pending-message]}]
|
||||
(pending-messages/save pending-message)
|
||||
(when (#{:message :group-message} type)
|
||||
(messages/update-message {:message-id id
|
||||
:delivery-status :pending}))))
|
||||
(fn [pending-message]
|
||||
(pending-messages/save pending-message)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::status-init-jail
|
||||
|
@ -316,9 +293,18 @@
|
|||
:to to
|
||||
:chat-id from}))
|
||||
|
||||
(defn- message-from-self [{:keys [current-public-key]} {:keys [id to group-id]}]
|
||||
{:from to
|
||||
:sent-from current-public-key
|
||||
:payload {:message-id id
|
||||
:group-id group-id}})
|
||||
|
||||
(defn- get-message-id [{:keys [message-id ack-of-message]}]
|
||||
(or ack-of-message message-id))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:incoming-message
|
||||
(fn [_ [_ type {:keys [payload ttl id] :as message}]]
|
||||
:incoming-message
|
||||
(fn [{:keys [db]} [_ type {:keys [payload ttl id] :as message}]]
|
||||
(let [message-id (or id (:message-id payload))]
|
||||
(when-not (cache/exists? message-id type)
|
||||
(let [ttl-s (* 1000 (or ttl 120))
|
||||
|
@ -326,74 +312,56 @@
|
|||
:message-id message-id
|
||||
:type type
|
||||
:ttl (+ (datetime/now-ms) ttl-s)}
|
||||
route-event (case type
|
||||
(:message
|
||||
:group-message
|
||||
:public-group-message) [:chat-received-message/add (transform-protocol-message message)]
|
||||
:ack (if (#{:message :group-message} (:type payload))
|
||||
[:update-message-status message :delivered]
|
||||
[:pending-message-remove message])
|
||||
:seen [:update-message-status message :seen]
|
||||
:group-invitation [:group-chat-invite-received message]
|
||||
:update-group [:update-group-message message]
|
||||
:add-group-identity [:participant-invited-to-group message]
|
||||
:remove-group-identity [:participant-removed-from-group message]
|
||||
:leave-group [:participant-left-group message]
|
||||
:contact-request [:contact-request-received message]
|
||||
:discover [:status-received message]
|
||||
:discoveries-request [:discoveries-request-received message]
|
||||
:discoveries-response [:discoveries-response-received message]
|
||||
:profile [:contact-update-received message]
|
||||
:update-keys [:update-keys-received message]
|
||||
:online [:contact-online-received message]
|
||||
:pending [:pending-message-upsert message]
|
||||
:sent (let [{:keys [to id group-id]} message
|
||||
message' {:from to
|
||||
:payload {:message-id id
|
||||
:group-id group-id}}]
|
||||
[:update-message-status message' :sent])
|
||||
nil)]
|
||||
(when (nil? route-event) (debug "Unknown message type" type))
|
||||
chat-message (#{:message :group-message} (:type payload))
|
||||
route-fx (case type
|
||||
(:message
|
||||
:group-message
|
||||
:public-group-message) {:dispatch [:chat-received-message/add (transform-protocol-message message)]}
|
||||
:pending (cond-> {::pending-messages-save message}
|
||||
chat-message
|
||||
(assoc :dispatch
|
||||
[:update-message-status (message-from-self db message) :pending]))
|
||||
:sent {:dispatch [:update-message-status (message-from-self db message) :sent]}
|
||||
:ack (cond-> {::pending-messages-delete (get-message-id payload)}
|
||||
chat-message
|
||||
(assoc :dispatch [:update-message-status message :delivered]))
|
||||
:seen {:dispatch [:update-message-status message :seen]}
|
||||
:group-invitation {:dispatch [:group-chat-invite-received message]}
|
||||
:update-group {:dispatch [:update-group-message message]}
|
||||
:add-group-identity {:dispatch [:participant-invited-to-group message]}
|
||||
:remove-group-identity {:dispatch [:participant-removed-from-group message]}
|
||||
:leave-group {:dispatch [:participant-left-group message]}
|
||||
:contact-request {:dispatch [:contact-request-received message]}
|
||||
:discover {:dispatch [:status-received message]}
|
||||
:discoveries-request {:dispatch [:discoveries-request-received message]}
|
||||
:discoveries-response {:dispatch [:discoveries-response-received message]}
|
||||
:profile {:dispatch [:contact-update-received message]}
|
||||
:update-keys {:dispatch [:update-keys-received message]}
|
||||
:online {:dispatch [:contact-online-received message]}
|
||||
nil)]
|
||||
(when (nil? route-fx) (debug "Unknown message type" type))
|
||||
(cache/add! processed-message)
|
||||
(merge
|
||||
{::save-processed-messages processed-message}
|
||||
(when route-event {:dispatch route-event})))))))
|
||||
|
||||
(defn update-message-status [db {:keys [message-id ack-of-message group-id from status]}]
|
||||
(let [message-id' (or ack-of-message message-id)
|
||||
update-group-status? (and group-id (not= status :sent))
|
||||
message-path [:chats (or group-id from) :messages message-id']
|
||||
current-status (if update-group-status?
|
||||
(get-in db (into message-path [:user-statuses from :status]))
|
||||
(get-in db (into message-path [:message-status])))]
|
||||
;; for some strange reason, we sometimes receive status update for message we don't have,
|
||||
;; that's why the first condition in if
|
||||
(if (and (get-in db message-path)
|
||||
(not= :seen current-status))
|
||||
(if update-group-status?
|
||||
(assoc-in db (into message-path [:user-statuses from]) {:whisper-identity from
|
||||
:status status})
|
||||
(assoc-in db (into message-path [:message-status]) status))
|
||||
db)))
|
||||
route-fx))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:update-message-status
|
||||
[re-frame/trim-v
|
||||
(re-frame/inject-cofx :get-stored-message)
|
||||
(re-frame/inject-cofx ::chats-is-active?)]
|
||||
(fn [{db :db chats-is-active? :chats-is-active?}
|
||||
[{:keys [from]
|
||||
{:keys [message-id ack-of-message group-id]} :payload
|
||||
:as message}
|
||||
status]]
|
||||
(let [data {:status status
|
||||
:message-id message-id :ack-of-message ack-of-message
|
||||
:group-id group-id :from from}]
|
||||
(merge
|
||||
{::save-message-status! data}
|
||||
(when (= status :delivered)
|
||||
{:dispatch [:pending-message-remove message]})
|
||||
(when chats-is-active?
|
||||
{:db (update-message-status db data)})))))
|
||||
(fn [{:keys [db chats-is-active? get-stored-message]} [{:keys [from sent-from payload]} status]]
|
||||
(let [message-identifier (get-message-id payload)
|
||||
message-db-path [:chats (or (:group-id payload) from) :messages message-identifier]
|
||||
from-id (or sent-from from)
|
||||
message (get-stored-message message-identifier)]
|
||||
;; proceed with updating status if chat is active, and message was not already seen
|
||||
(when (and chats-is-active? (not (chat.utils/message-seen-by? message from-id)))
|
||||
(let [statuses (assoc (:user-statuses message) from-id status)]
|
||||
(cond-> {:update-message {:message-id message-identifier
|
||||
:user-statuses statuses}}
|
||||
(get-in db message-db-path)
|
||||
(assoc :db (assoc-in db (conj message-db-path :user-statuses) statuses))))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:contact-request-received
|
||||
|
@ -423,23 +391,6 @@
|
|||
[:update-chat! chat]
|
||||
[:watch-contact contact]]}))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:pending-message-upsert
|
||||
(fn [{db :db} [_ {:keys [type id to group-id] :as pending-message}]]
|
||||
(let [chat-id (or group-id to)
|
||||
current-status (get-in db [:message-status chat-id id])]
|
||||
(merge
|
||||
{::pending-messages-save {:type type :id id :pending-message pending-message}}
|
||||
(when (and (#{:message :group-message} type) (not= :seen current-status))
|
||||
{:db (assoc-in db [:message-status chat-id id] :pending)})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:pending-message-remove
|
||||
(fn [_ [_ message]]
|
||||
{::pending-messages-delete message}))
|
||||
|
||||
|
||||
|
||||
;;GROUP
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
:gas-price ethereum/default-gas-price})
|
||||
|
||||
;; initial state of app-db
|
||||
(def app-db {:current-public-key ""
|
||||
(def app-db {:current-public-key nil
|
||||
:status-module-initialized? (or platform/ios? js/goog.DEBUG)
|
||||
:keyboard-height 0
|
||||
:accounts/accounts {}
|
||||
|
@ -162,8 +162,7 @@
|
|||
:chat/message-data
|
||||
:chat/message-status
|
||||
:chat/selected-participants
|
||||
:chat/chat-loaded-callbacks
|
||||
:chat/command-hash-valid?
|
||||
:chat/chat-loaded-callbacks
|
||||
:chat/public-group-topic
|
||||
:chat/confirmation-code-sms-listener
|
||||
:chat/messages
|
||||
|
|
Loading…
Reference in New Issue