Improve chat loading performance

This commit does a few things:

Move collections top level

Move `messages`,`message-lists`,`pagination-info` from nested in
`chats` to top level at the db.
The reason for this change is that if any of the `messages` fields
change, any `sub` that relies on `chat` will be recomputed, which is
unnecessary.

Move chat-name to events

`chat-name` was computed dynamically, while it is now only calculated
when loading chat the first time around.

Remove `enrich-chats`

Enrich chats was doing a lot of work, and many subscriptions were
relying on it.
Not all the computations were necessary, for example it would always
calculate the name of who invited the user to a group chat, regardless
of whether it was actually used in the view.
This commit changes that behavior so that we use smaller subscriptions
to calculate such fields.
In general we should move computations to events, if that's not
desirable (there are some cases where we might not want to do that), we
should have "bottom/leaf heavy" subscriptions as opposed to "top heavy",
especially if they are to be shared, so only when (and if) we load that
particular view, the subscription is triggered, while others can be
re-used.

I have compared performance with current release, and there's a
noticeable difference. Opening a chat is faster (messages are loaded
faster), and clicking on the home view on a chat is more responsing
(the animation on-press is much quicker).
This commit is contained in:
Andrea Maria Piana 2020-05-27 16:29:33 +02:00
parent 5f7c795567
commit f69ae44d50
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
29 changed files with 554 additions and 650 deletions

View File

@ -1,69 +1,11 @@
(ns status-im.chat.db
(:require [clojure.set :as clojure.set]
[clojure.string :as clojure.string]
[status-im.group-chats.db :as group-chats.db]
[status-im.mailserver.constants :as mailserver.constants]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.utils.identicon :as identicon]
[status-im.utils.gfycat.core :as gfycat]))
(:require [clojure.string :as clojure.string]
[status-im.mailserver.constants :as mailserver.constants]))
(defn group-chat-name
[{:keys [public? name]}]
(str (when public? "#") name))
(defn enrich-active-chat
[contacts {:keys [chat-id
identicon
alias
group-chat] :as chat} current-public-key]
(if group-chat
(let [pending-invite-inviter-name
(group-chats.db/get-pending-invite-inviter-name contacts
chat
current-public-key)
inviter-name
(group-chats.db/get-inviter-name contacts
chat
current-public-key)]
(cond-> chat
pending-invite-inviter-name
(assoc :pending-invite-inviter-name pending-invite-inviter-name)
inviter-name
(assoc :inviter-name inviter-name)
:always
(assoc :chat-name (group-chat-name chat))))
(let [photo (if (seq identicon)
identicon
(identicon/identicon chat-id))
alias (if (seq alias)
alias
(gfycat/generate-gfy chat-id))
{contact-name :name :as contact}
(get contacts chat-id
{:public-key chat-id
:identicon photo
:alias alias
:name alias
:system-tags #{}})]
(-> chat
(assoc :contact contact
:chat-name (multiaccounts/displayed-name contact)
:name contact-name
:identicon photo
:alias alias)
(update :tags clojure.set/union (:tags contact))))))
(defn active-chats
[contacts chats {:keys [public-key]}]
(reduce-kv (fn [acc chat-id {:keys [is-active] :as chat}]
(if is-active
(assoc acc
chat-id
(enrich-active-chat contacts chat public-key))
acc))
{}
chats))
(defn datemark? [{:keys [type]}]
(= type :datemark))

View File

@ -1,7 +1,5 @@
(ns status-im.chat.db-test
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]
[status-im.chat.db :as db]))
(deftest group-chat-name
@ -41,18 +39,6 @@
(is (= {:type :datemark
:value "Dec 31, 1999"} d2)))))
(deftest active-chats-test
(with-redefs [gfycat/generate-gfy (constantly "generated")
identicon/identicon (constantly "generated")]
(let [active-chat-1 {:is-active true :chat-id "1"}
active-chat-2 {:is-active true :chat-id "2"}
chats {"1" active-chat-1
"2" active-chat-2
"3" {:is-active false :chat-id "3"}}]
(testing "it returns only chats with is-active"
(is (= #{"1" "2"}
(set (keys (db/active-chats {} chats {})))))))))
(deftest add-gaps
(testing "empty state"
(is (empty?

View File

@ -4,7 +4,6 @@
[status-im.transport.filters.core :as transport.filters]
[status-im.contact.core :as contact.core]
[status-im.waku.core :as waku]
[status-im.contact.db :as contact.db]
[status-im.data-store.chats :as chats-store]
[status-im.data-store.messages :as messages-store]
[status-im.ethereum.json-rpc :as json-rpc]
@ -92,8 +91,7 @@
:is-active true
:timestamp now
:contacts #{chat-id}
:last-clock-value 0
:messages {}}))
:last-clock-value 0}))
(fx/defn ensure-chat
"Add chat to db and update"
@ -165,6 +163,7 @@
{:chat-id topic
:is-active true
:name topic
:chat-name (str "#" topic)
:group-chat true
:contacts #{}
:public? true
@ -175,20 +174,20 @@
(fx/defn clear-history
"Clears history of the particular chat"
[{:keys [db] :as cofx} chat-id]
(let [{:keys [messages
last-message
(let [{:keys [last-message
deleted-at-clock-value]} (get-in db [:chats chat-id])
last-message-clock-value (or (:clock-value last-message)
deleted-at-clock-value
(utils.clocks/send 0))]
(fx/merge
cofx
{:db (update-in db [:chats chat-id] merge
{:messages {}
:message-list nil
:last-message nil
:unviewed-messages-count 0
:deleted-at-clock-value last-message-clock-value})}
{:db (-> db
(assoc-in [:messages chat-id] {})
(update-in [:message-lists] dissoc chat-id)
(update-in [:chats chat-id] merge
{:last-message nil
:unviewed-messages-count 0
:deleted-at-clock-value last-message-clock-value}))}
(messages-store/delete-messages-by-chat-id chat-id)
#(chats-store/save-chat % (get-in % [:db :chats chat-id])))))
@ -218,13 +217,9 @@
{:db
(-> db
(dissoc :loaded-chat-id)
(update-in [:chats current-chat-id]
assoc
:all-loaded? false
:cursor nil
:messages-initialized? false
:messages {}
:message-list nil))}))
(update :messages dissoc current-chat-id)
(update :message-lists dissoc current-chat-id)
(update :pagination-info dissoc current-chat-id))}))
(fx/defn preload-chat-data
"Takes chat-id and coeffects map, returns effects necessary when navigating to chat"
@ -241,8 +236,6 @@
(transport.filters/load-chat chat-id))
(when platform/desktop?
(message-seen/mark-messages-seen chat-id))
(when (and (one-to-one-chat? cofx chat-id) (not (contact.db/contact-exists? db chat-id)))
(contact.core/create-contact chat-id))
(loading/load-messages))))
(fx/defn navigate-to-chat

View File

@ -24,10 +24,7 @@
[{:keys [db] :as cofx} new-chats]
(let [old-chats (:chats db)
chats (reduce (fn [acc {:keys [chat-id] :as chat}]
(assoc acc chat-id
(assoc chat
:messages-initialized? false
:messages {})))
(assoc acc chat-id chat))
{}
new-chats)
chats (merge old-chats chats)]
@ -52,12 +49,11 @@
acc))
{}
(get-in db [:chats chat-id :messages]))]
{:db (update-in db [:chats chat-id]
assoc
:messages new-messages
:all-loaded? false
:message-list (message-list/add-many nil (vals new-messages))
:cursor (clock-value->cursor last-element-clock-value))}))))))
{:db (-> db
(assoc-in [:messages chat-id] new-messages)
(assoc-in [:pagination-info chat-id] {:all-loaded? false
:cursor (clock-value->cursor last-element-clock-value)})
(assoc-in [:message-lists chat-id] (message-list/add-many nil (vals new-messages))))}))))))
(fx/defn initialize-chats
"Initialize persisted chats on startup"
@ -70,7 +66,7 @@
[{:keys [db]} current-chat-id _ err]
(log/error "failed loading messages" current-chat-id err)
(when current-chat-id
{:db (assoc-in db [:chats current-chat-id :loading-messages?] false)}))
{:db (assoc-in db [:pagination-info current-chat-id :loading-messages?] false)}))
(fx/defn messages-loaded
"Loads more messages for current chat"
@ -81,10 +77,10 @@
{:keys [cursor messages]}]
(when-not (or (nil? current-chat-id)
(not= chat-id current-chat-id)
(and (get-in db [:chats current-chat-id :messages-initialized?])
(and (get-in db [:pagination-info current-chat-id :messages-initialized?])
(not= session-id
(get-in db [:chats current-chat-id :messages-initialized?]))))
(let [already-loaded-messages (get-in db [:chats current-chat-id :messages])
(get-in db [:pagination-info current-chat-id :messages-initialized?]))))
(let [already-loaded-messages (get-in db [:messages current-chat-id])
loaded-unviewed-messages-ids (get-in db [:chats current-chat-id :loaded-unviewed-messages-ids] #{})
;; We remove those messages that are already loaded, as we might get some duplicates
{:keys [all-messages
@ -111,23 +107,23 @@
messages)]
(fx/merge cofx
{:db (-> db
(assoc-in [:chats current-chat-id :cursor-clock-value] (when (seq cursor) (cursor->clock-value cursor)))
(assoc-in [:pagination-info current-chat-id :cursor-clock-value] (when (seq cursor) (cursor->clock-value cursor)))
(assoc-in [:chats current-chat-id :loaded-unviewed-messages-ids] unviewed-message-ids)
(assoc-in [:chats current-chat-id :loading-messages?] false)
(assoc-in [:chats current-chat-id :messages] all-messages)
(update-in [:chats current-chat-id :message-list] message-list/add-many new-messages)
(assoc-in [:chats current-chat-id :cursor] cursor)
(assoc-in [:chats current-chat-id :all-loaded?]
(assoc-in [:pagination-info current-chat-id :loading-messages?] false)
(assoc-in [:messages current-chat-id] all-messages)
(update-in [:message-lists current-chat-id] message-list/add-many new-messages)
(assoc-in [:pagination-info current-chat-id :cursor] cursor)
(assoc-in [:pagination-info current-chat-id :all-loaded?]
(empty? cursor)))}
(message-seen/mark-messages-seen current-chat-id)))))
(fx/defn load-more-messages
[{:keys [db] :as cofx}]
(when-let [current-chat-id (:current-chat-id db)]
(when-let [session-id (get-in db [:chats current-chat-id :messages-initialized?])]
(when-not (or (get-in db [:chats current-chat-id :all-loaded?])
(get-in db [:chats current-chat-id :loading-messages?]))
(let [cursor (get-in db [:chats current-chat-id :cursor])
(when-let [session-id (get-in db [:pagination-info current-chat-id :messages-initialized?])]
(when-not (or (get-in db [:pagination-info current-chat-id :all-loaded?])
(get-in db [:pagination-info current-chat-id :loading-messages?]))
(let [cursor (get-in db [:pagination-info current-chat-id :cursor])
load-messages-fx (data-store.messages/messages-by-chat-id-rpc
(waku/enabled? cofx)
current-chat-id
@ -142,7 +138,7 @@
(fx/defn load-messages
[{:keys [db now] :as cofx}]
(when-let [current-chat-id (:current-chat-id db)]
(if-not (get-in db [:chats current-chat-id :messages-initialized?])
(if-not (get-in db [:pagination-info current-chat-id :messages-initialized?])
(do
; reset chat first-not-visible-items state
(chat.state/reset)
@ -151,7 +147,7 @@
;; We keep track of whether there's a loaded chat
;; which will be reset only if we hit home
(assoc :loaded-chat-id current-chat-id)
(assoc-in [:chats current-chat-id :messages-initialized?] now))}
(assoc-in [:pagination-info current-chat-id :messages-initialized?] now))}
(message-seen/mark-messages-seen current-chat-id)
(load-more-messages)))
;; We mark messages as seen in case we received them while on a different tab

View File

@ -28,8 +28,8 @@
(fx/defn rebuild-message-list
[{:keys [db]} chat-id]
{:db (assoc-in db [:chats chat-id :message-list]
(message-list/add-many nil (vals (get-in db [:chats chat-id :messages]))))})
{:db (assoc-in db [:message-lists chat-id]
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))})
(fx/defn hidden-message-marked-as-seen
{:events [::hidden-message-marked-as-seen]}
@ -42,7 +42,7 @@
"Hide chat message, rebuild message-list"
[{:keys [db] :as cofx} chat-id {:keys [seen message-id]}]
(fx/merge cofx
{:db (update-in db [:chats chat-id :messages] dissoc message-id)}
{:db (update-in db [:messages chat-id] dissoc message-id)}
(data-store.messages/mark-messages-seen chat-id [message-id] #(re-frame/dispatch [::hidden-message-marked-as-seen %1 %2 %3]))
(rebuild-message-list chat-id)))
@ -52,7 +52,7 @@
:keys [seen-by-user?]}]
(let [current-public-key (multiaccounts.model/current-public-key cofx)
message-to-be-removed (when replace
(get-in db [:chats chat-id :messages replace]))
(get-in db [:messages chat-id replace]))
prepared-message (prepare-message message seen-by-user?)]
(fx/merge cofx
(when message-to-be-removed
@ -62,8 +62,8 @@
;; We should not be always adding to the list, as it does not make sense
;; if the chat has not been initialized, but run into
;; some troubles disabling it, so next time
(update-in [:chats chat-id :messages] assoc message-id prepared-message)
(update-in [:chats chat-id :message-list] message-list/add prepared-message))
(update-in [:messages chat-id] assoc message-id prepared-message)
(update-in [:message-lists chat-id] message-list/add prepared-message))
(and (not seen-by-user?)
(not= from current-public-key))
(update-in [:chats chat-id :loaded-unviewed-messages-ids]
@ -94,7 +94,7 @@
(defn- message-loaded?
[{:keys [db]} {:keys [chat-id message-id]}]
(get-in db [:chats chat-id :messages message-id]))
(get-in db [:messages chat-id message-id]))
(defn- earlier-than-deleted-at?
[{:keys [db]} {:keys [chat-id clock-value]}]
@ -145,7 +145,7 @@
;; If the message is already loaded, it means it's an update, that
;; happens when a message that was missing a reply had the reply
;; coming through, in which case we just insert the new message
{:db (assoc-in db [:chats chat-id :messages message-id] message-with-chat-id)}
{:db (assoc-in db [:messages chat-id message-id] message-with-chat-id)}
(fx/merge cofx
(add-received-message message-with-chat-id)
(update-unviewed-count message-with-chat-id)
@ -202,7 +202,7 @@
[{:keys [db] :as cofx} chat-id message-id status]
(fx/merge cofx
{:db (assoc-in db
[:chats chat-id :messages message-id :outgoing-status]
[:messages chat-id message-id :outgoing-status]
status)}
(data-store.messages/update-outgoing-status message-id status)))
@ -219,7 +219,7 @@
"Deletes chat message, rebuild message-list"
[{:keys [db] :as cofx} chat-id message-id]
(fx/merge cofx
{:db (update-in db [:chats chat-id :messages] dissoc message-id)}
{:db (update-in db [:messages chat-id] dissoc message-id)}
(data-store.messages/delete-message message-id)
(rebuild-message-list chat-id)))
@ -229,4 +229,4 @@
(fx/defn toggle-expand-message
[{:keys [db]} chat-id message-id]
{:db (update-in db [:chats chat-id :messages message-id :expanded?] not)})
{:db (update-in db [:messages chat-id message-id :expanded?] not)})

View File

@ -41,12 +41,11 @@
(when (seq loaded-unviewed-ids)
(fx/merge cofx
{:db (reduce (fn [acc message-id]
(assoc-in acc [:chats chat-id :messages
message-id :seen]
(assoc-in acc [:messages chat-id message-id :seen]
true))
db
loaded-unviewed-ids)}
(messages-store/mark-messages-seen chat-id loaded-unviewed-ids nil)
(update-chats-unviewed-messages-count {:chat-id chat-id})
(when platform/desktop?
(update-dock-badge-label))))))
(update-dock-badge-label))))))

View File

@ -94,7 +94,8 @@
:clock-value 1
:chat-id "a"}))))
(testing "it returns true when it's already in the loaded message"
(is (#'status-im.chat.models.message/message-loaded? {:db {:chats {"a" {:messages {"message-id" {}}}}}}
(is (#'status-im.chat.models.message/message-loaded? {:db
{:messages {"a" {"message-id" {}}}}}
{:message-id "message-id"
:from "a"
:clock-value 1
@ -124,7 +125,8 @@
:view-id :chat
:loaded-chat-id "chat-id"
:current-chat-id "chat-id"
:chats {"chat-id" {:messages {}}}}]
:messages {"chat-id" {}}
:chats {"chat-id" {}}}]
(testing "a message coming from you!"
(let [actual (message/receive-one {:db db}
{:from "me"
@ -136,7 +138,7 @@
:outgoing true
:content "b"
:clock-value 1})
message (get-in actual [:db :chats "chat-id" :messages "id"])]
message (get-in actual [:db :messages "chat-id" "id"])]
(testing "it adds the message"
(is message))))))
@ -170,7 +172,7 @@
:whisper-timestamp 0
:timestamp 0}]
(testing "a valid message"
(is (get-in (message/receive-one cofx valid-message) [:db :chats "chat-id" :messages "1"])))
(is (get-in (message/receive-one cofx valid-message) [:db :messages "chat-id" "1"])))
(testing "a message from someone not in the list of participants"
(is (not (message/receive-one cofx bad-from-message))))
(testing "a message with non existing chat-id"
@ -199,7 +201,7 @@
:whisper-timestamp 0
:timestamp 0}]
(testing "a valid message"
(is (get-in (message/receive-one cofx valid-message) [:db :chats "chat-id" :messages "1"])))
(is (get-in (message/receive-one cofx valid-message) [:db :messages "chat-id" "1"])))
(testing "a message with non existing chat-id"
(is (not (message/receive-one cofx bad-chat-id-message))))))
@ -235,37 +237,39 @@
:whisper-timestamp 0
:timestamp 0}]
(testing "a valid message"
(is (get-in (message/receive-one cofx valid-message) [:db :chats "matching" :messages "1"])))
(is (get-in (message/receive-one cofx valid-message) [:db :messages "matching" "1"])))
(testing "our own message"
(is (get-in (message/receive-one cofx own-message) [:db :chats "matching" :messages "1"])))
(is (get-in (message/receive-one cofx own-message) [:db :messages "matching" "1"])))
(testing "a message with non matching chat-id"
(is (not (get-in (message/receive-one cofx bad-chat-id-message) [:db :chats "not-matching" :messages "1"])))))))
(is (not (get-in (message/receive-one cofx bad-chat-id-message) [:db :messages "not-matching" "1"])))))))
(deftest delete-message
(with-redefs [time/day-relative (constantly "day-relative")
time/timestamp->time (constantly "timestamp")]
(let [cofx1 {:db {:chats {"chat-id" {:messages {0 {:message-id 0
:content "a"
:clock-value 0
:whisper-timestamp 0
:timestamp 0}
1 {:message-id 1
:content "b"
:clock-value 1
:whisper-timestamp 1
:timestamp 1}}
:message-list [{:something :something}]}}}}
cofx2 {:db {:chats {"chat-id" {:messages {0 {:message-id 0
:content "a"
:clock-value 0
:whisper-timestamp 1
:timestamp 1}}
:message-list [{:something :something}]}}}}
(let [cofx1 {:db {:messages {"chat-id" {0 {:message-id 0
:content "a"
:clock-value 0
:whisper-timestamp 0
:timestamp 0}
1 {:message-id 1
:content "b"
:clock-value 1
:whisper-timestamp 1
:timestamp 1}}}
:message-lists {"chat-id" [{:something :something}]}
:chats {"chat-id" {}}}}
cofx2 {:db {:messages {"chat-id" {0 {:message-id 0
:content "a"
:clock-value 0
:whisper-timestamp 1
:timestamp 1}}}
:message-list {"chat-id" [{:something :something}]}
:chats {"chat-id" {}}}}
fx1 (message/delete-message cofx1 "chat-id" 1)
fx2 (message/delete-message cofx2 "chat-id" 0)]
(testing "Deleting message deletes it along with all references"
(is (= '(0)
(keys (get-in fx1 [:db :chats "chat-id" :messages]))))
(keys (get-in fx1 [:db :messages "chat-id"]))))
(is (= [{:one-to-one? false
:message-id 0
:whisper-timestamp 0
@ -284,8 +288,8 @@
:display-username? true
:outgoing false}]
(models.message-list/->seq
(get-in fx1 [:db :chats "chat-id" :message-list]))))
(get-in fx1 [:db :message-lists "chat-id"]))))
(is (= {}
(get-in fx2 [:db :chats "chat-id" :messages])))
(get-in fx2 [:db :messages "chat-id"])))
(is (= nil
(get-in fx2 [:db :chats "chat-id" :message-list])))))))
(get-in fx2 [:db :message-lists "chat-id"])))))))

View File

@ -65,15 +65,15 @@
(deftest clear-history-test
(let [chat-id "1"
cofx {:db {:chats {chat-id {:message-list [{:something "a"}]
:last-message {:clock-value 10}
cofx {:db {:message-lists {chat-id [{:something "a"}]}
:chats {chat-id {:last-message {:clock-value 10}
:unviewed-messages-count 1}}}}]
(testing "it deletes all the messages"
(let [actual (chat/clear-history cofx chat-id)]
(is (= {} (get-in actual [:db :chats chat-id :messages])))))
(is (= {} (get-in actual [:db :messages chat-id])))))
(testing "it deletes all the message groups"
(let [actual (chat/clear-history cofx chat-id)]
(is (= nil (get-in actual [:db :chats chat-id :message-list])))))
(is (= nil (get-in actual [:db :message-lists chat-id])))))
(testing "it deletes unviewed messages set"
(let [actual (chat/clear-history cofx chat-id)]
(is (= 0 (get-in actual [:db :chats chat-id :unviewed-messages-count])))))
@ -103,13 +103,13 @@
(deftest remove-chat-test
(let [chat-id "1"
cofx {:db {:chats {chat-id {:last-message {:clock-value 10}
:messages {"1" {:clock-value 1}
"2" {:clock-value 10}
"3" {:clock-value 2}}}}}}]
cofx {:db {:messages {chat-id {"1" {:clock-value 1}
"2" {:clock-value 10}
"3" {:clock-value 2}}}
:chats {chat-id {:last-message {:clock-value 10}}}}}]
(testing "it deletes all the messages"
(let [actual (chat/remove-chat cofx chat-id)]
(is (= {} (get-in actual [:db :chats chat-id :messages])))))
(is (= {} (get-in actual [:db :messages chat-id])))))
(testing "it sets a deleted-at-clock-value equal to the last message clock-value"
(let [actual (chat/remove-chat cofx chat-id)]
(is (= 10 (get-in actual [:db :chats chat-id :deleted-at-clock-value])))))
@ -147,9 +147,10 @@
(def test-db
{:multiaccount {:public-key "me"}
:messages {"status" {"4" {} "5" {} "6" {}}}
:chats {"status" {:public? true
:group-chat true
:messages {"4" {} "5" {} "6" {}}
:loaded-unviewed-messages-ids #{"6" "5" "4"}}
"opened" {:loaded-unviewed-messages-ids #{}}
"1-1" {:loaded-unviewed-messages-ids #{"6" "5" "4"}}}})

View File

@ -16,10 +16,16 @@
group-chat private-group-chat-type
:else one-to-one-chat-type)))
(defn rpc->type [{:keys [chatType] :as chat}]
(defn rpc->type [{:keys [chatType name] :as chat}]
(cond
(= public-chat-type chatType) (assoc chat :public? true :group-chat true)
(= private-group-chat-type chatType) (assoc chat :public? false :group-chat true)
(= public-chat-type chatType) (assoc chat
:chat-name (str "#" name)
:public? true
:group-chat true)
(= private-group-chat-type chatType) (assoc chat
:chat-name name
:public? false
:group-chat true)
:else (assoc chat :public? false :group-chat false)))
(defn- marshal-members [{:keys [admins contacts members-joined chatType] :as chat}]
@ -68,11 +74,10 @@
:deleted-at-clock-value :deletedAtClockValue
:is-active :active
:last-clock-value :lastClockValue})
(dissoc :message-list :gaps-loaded? :pagination-info
:public? :group-chat :messages
(dissoc :public? :group-chat :messages
:might-have-join-time-messages?
:loaded-unviewed-messages-ids
:messages-initialized? :contacts :admins :members-joined)))
:contacts :admins :members-joined)))
(defn <-rpc [chat]
(-> chat

View File

@ -5,7 +5,6 @@
(deftest ->to-rpc
(let [chat {:public? false
:group-chat true
:message-list []
:color "color"
:contacts #{"a" "b" "c" "d"}
:last-clock-value 10
@ -13,15 +12,11 @@
:members-joined #{"a" "c"}
:name "name"
:membership-update-events :events
:gaps-loaded? true
:unviewed-messages-count 2
:is-active true
:messages {}
:pagination-info {}
:chat-id "chat-id"
:loaded-unviewed-messages-ids []
:timestamp 2
:messages-initialized? true}
:timestamp 2}
expected-chat {:id "chat-id"
:color "color"
:name "name"
@ -73,6 +68,7 @@
expected-chat {:public? false
:group-chat true
:color "color"
:chat-name "name"
:contacts #{"a" "b" "c" "d"}
:last-clock-value 10
:last-message nil

View File

@ -519,7 +519,7 @@
(handlers/register-handler-fx
:chat.ui/resend-message
(fn [{:keys [db] :as cofx} [_ chat-id message-id]]
(let [message (get-in db [:chats chat-id :messages message-id])]
(let [message (get-in db [:messages chat-id message-id])]
(fx/merge
cofx
(transport.message/set-message-envelope-hash chat-id message-id (:message-type message) 1)

View File

@ -1,5 +1,4 @@
(ns status-im.group-chats.db
(:require [status-im.multiaccounts.core :as multiaccounts]))
(ns status-im.group-chats.db)
(def members-added-type 3)
@ -23,21 +22,3 @@
(defn group-chat? [chat]
(and (:group-chat chat) (not (:public? chat))))
(defn get-pending-invite-inviter-name
"when the chat is a private group chat in which the user has been
invited and didn't accept the invitation yet, return inviter-name"
[contacts chat my-public-key]
(when (and (group-chat? chat)
(invited? my-public-key chat)
(not (joined? my-public-key chat)))
(let [inviter-pk (get-inviter-pk my-public-key chat)]
(multiaccounts/displayed-name (or (get contacts inviter-pk) {:public-key inviter-pk})))))
(defn get-inviter-name
"when the chat is a private group chat in which the user has been
invited and didn't accept the invitation yet, return inviter-name"
[contacts chat my-public-key]
(when (group-chat? chat)
(let [inviter-pk (get-inviter-pk my-public-key chat)]
(multiaccounts/displayed-name (or (get contacts inviter-pk) {:public-key inviter-pk})))))

View File

@ -1171,7 +1171,7 @@
{})))
(fx/defn load-gaps-fx [{:keys [db] :as cofx} chat-id]
(when-not (get-in db [:chats chat-id :gaps-loaded?])
(when-not (get-in db [:gaps-loaded? chat-id])
(let [success-fn #(re-frame/dispatch [::gaps-loaded %1 %2])]
(data-store.mailservers/load-gaps cofx chat-id success-fn))))
@ -1190,7 +1190,7 @@
cofx
{:db
(-> db
(assoc-in [:chats chat-id :gaps-loaded?] true)
(assoc-in [:gaps-loaded? chat-id] true)
(assoc-in [:mailserver/gaps chat-id] gaps))}
(data-store.mailservers/delete-gaps outdated-gaps))))

View File

@ -389,13 +389,11 @@
{:multiaccount {:public-key "me"}
:chats
{"chat-id-1" {:is-active true
:messages {}
:might-have-join-time-messages? true
:group-chat true
:public? true
:chat-id "chat-id-1"}
"chat-id-2" {:is-active true
:messages {}
:group-chat true
:public? true
:chat-id "chat-id-2"}}}})
@ -405,14 +403,12 @@
{:multiaccount {:public-key "me"}
:chats
{"chat-id-1" {:is-active true
:messages {}
:join-time-mail-request-id "a"
:might-have-join-time-messages? true
:group-chat true
:public? true
:chat-id "chat-id-1"}
"chat-id-2" {:is-active true
:messages {}
:group-chat true
:public? true
:chat-id "chat-id-2"}}}})
@ -422,26 +418,22 @@
{:multiaccount {:public-key "me"}
:chats
{"chat-id-1" {:is-active true
:messages {}
:join-time-mail-request-id "a"
:might-have-join-time-messages? true
:group-chat true
:public? true
:chat-id "chat-id-1"}
"chat-id-2" {:is-active true
:messages {}
:join-time-mail-request-id "a"
:might-have-join-time-messages? true
:group-chat true
:public? true
:chat-id "chat-id-2"}
"chat-id-3" {:is-active true
:messages {}
:group-chat true
:public? true
:chat-id "chat-id-3"}
"chat-id-4" {:is-active true
:messages {}
:join-time-mail-request-id "a"
:might-have-join-time-messages? true
:group-chat true

View File

@ -37,7 +37,6 @@
[status-im.utils.money :as money]
[status-im.utils.platform :as platform]
[status-im.utils.security :as security]
[status-im.utils.universal-links.core :as links]
[status-im.wallet.db :as wallet.db]
[status-im.wallet.utils :as wallet.utils]
status-im.ui.screens.keycard.subs
@ -185,6 +184,10 @@
(reg-root-key-sub :multiaccounts/loading :multiaccounts/loading)
(reg-root-key-sub ::messages :messages)
(reg-root-key-sub ::message-lists :message-lists)
(reg-root-key-sub ::pagination-info :pagination-info)
;;GENERAL ==============================================================================================================
(re-frame/reg-sub
@ -450,6 +453,21 @@
(fn [{:keys [public-key]}]
public-key))
(re-frame/reg-sub
:multiaccount/preferred-name
:<- [:multiaccount]
(fn [{:keys [preferred-name]}]
preferred-name))
(re-frame/reg-sub
:multiaccount/my-name
:<- [:multiaccount/public-key]
:<- [:multiaccount/preferred-name]
(fn [[identity preferred-name]]
(if preferred-name
(stateofus/username (str "@" preferred-name))
(gfycat/generate-gfy identity))))
(re-frame/reg-sub
:multiaccount/default-account
:<- [:multiaccount/accounts]
@ -608,77 +626,24 @@
(re-frame/reg-sub
:chats/active-chats
:<- [:contacts/contacts]
:<- [::chats]
:<- [:multiaccount]
(fn [[contacts chats multiaccount]]
(chat.db/active-chats contacts chats multiaccount)))
(fn [chats]
(reduce-kv (fn [acc id {:keys [is-active] :as chat}]
(if is-active
(assoc acc id chat)
acc))
{}
chats)))
;; TODO: this is no useful without tribute to talk
#_(defn enrich-current-one-to-one-chat
[{:keys [contact] :as current-chat} my-public-key ttt-settings
chain-keyword prices currency]
(let [{:keys [tribute-to-talk]} contact
{:keys [disabled? snt-amount message]} tribute-to-talk
whitelisted-by? (whitelist/whitelisted-by? contact)
loading? (and (not whitelisted-by?)
(not tribute-to-talk))
show-input? (or whitelisted-by?
disabled?)
token (case chain-keyword
:mainnet :SNT
:STT)
tribute-status (if loading?
:loading
(tribute-to-talk.db/tribute-status contact))
tribute-label (tribute-to-talk.db/status-label tribute-status snt-amount)]
(cond-> (assoc current-chat
:tribute-to-talk/tribute-status tribute-status
:tribute-to-talk/tribute-label tribute-label)
(#{:required :pending :paid} tribute-status)
(assoc :tribute-to-talk/snt-amount
(tribute-to-talk.db/from-wei snt-amount)
:tribute-to-talk/message
message
:tribute-to-talk/fiat-amount (if snt-amount
(money/fiat-amount-value
snt-amount
token
(-> currency :code keyword)
prices)
"0")
:tribute-to-talk/fiat-currency (:code currency)
:tribute-to-talk/token (str " " (name token)))
(tribute-to-talk.db/enabled? ttt-settings)
(assoc :tribute-to-talk/received? (tribute-to-talk.db/tribute-received?
contact))
(= tribute-status :required)
(assoc :tribute-to-talk/on-share-my-profile
#(re-frame/dispatch
[:profile/share-profile-link my-public-key]))
show-input?
(assoc :show-input? true))))
(defn enrich-current-chat
[{:keys [messages chat-id might-have-join-time-messages?] :as chat} ranges]
(assoc chat
:range
(get ranges chat-id)
:intro-status
(if might-have-join-time-messages?
:loading
(if (empty? messages)
:empty
:messages))))
(re-frame/reg-sub
::chat
:<- [::chats]
(fn [chats [_ chat-id]]
(get chats chat-id)))
(re-frame/reg-sub
:chats/current-raw-chat
:<- [:chats/active-chats]
:<- [::chats]
:<- [:chats/current-chat-id]
(fn [[chats current-chat-id]]
(get chats current-chat-id)))
@ -694,15 +659,10 @@
:chats/current-chat
:<- [:chats/current-raw-chat]
:<- [:multiaccount/public-key]
:<- [:mailserver/ranges]
(fn [[{:keys [group-chat chat-id messages] :as current-chat}
my-public-key ranges]]
(fn [[{:keys [group-chat] :as current-chat}
my-public-key]]
(when current-chat
(cond-> (enrich-current-chat current-chat ranges)
(empty? messages)
(assoc :universal-link
(links/generate-link :public-chat :external chat-id))
(cond-> current-chat
(chat.models/public-chat? current-chat)
(assoc :show-input? true)
@ -727,17 +687,12 @@
(fn [current-chat]
(chat.models/public-chat? current-chat)))
(re-frame/reg-sub
:chats/current-chat-message
:<- [:chats/current-chat]
(fn [{:keys [messages]} [_ message-id]]
(get messages message-id)))
(re-frame/reg-sub
:chats/current-chat-messages
:<- [:chats/current-chat]
(fn [{:keys [messages]}]
(or messages {})))
:<- [::messages]
:<- [:chats/current-chat-id]
(fn [[messages chat-id]]
(get messages chat-id {})))
(re-frame/reg-sub
:chats/messages-gaps
@ -746,6 +701,12 @@
(fn [[gaps chat-id]]
(sort-by :from (vals (get gaps chat-id)))))
(re-frame/reg-sub
:mailserver/ranges-by-chat-id
:<- [:mailserver/ranges]
(fn [ranges [_ chat-id]]
(get ranges chat-id)))
(re-frame/reg-sub
:chats/range
:<- [:mailserver/ranges]
@ -755,27 +716,23 @@
(re-frame/reg-sub
:chats/all-loaded?
:<- [:chats/current-chat]
(fn [chat]
(:all-loaded? chat)))
:<- [::pagination-info]
:<- [:chats/current-chat-id]
(fn [[pagination-info chat-id]]
(get-in pagination-info [chat-id :all-loaded?])))
(re-frame/reg-sub
:chats/public?
:<- [:chats/current-chat]
:<- [:chats/current-raw-chat]
(fn [chat]
(:public? chat)))
(re-frame/reg-sub
:chats/message-list
:<- [:chats/current-chat]
(fn [chat]
(:message-list chat)))
(re-frame/reg-sub
:chats/messages
:<- [:chats/current-chat]
(fn [chat]
(:messages chat)))
:<- [::message-lists]
:<- [:chats/current-chat-id]
(fn [[message-lists chat-id]]
(get message-lists chat-id)))
(defn hydrate-messages
"Pull data from messages and add it to the sorted list"
@ -786,10 +743,16 @@
%)
message-list))
(re-frame/reg-sub
:chats/current-chat-no-messages?
:<- [:chats/current-chat-messages]
(fn [messages]
(empty? messages)))
(re-frame/reg-sub
:chats/current-chat-messages-stream
:<- [:chats/message-list]
:<- [:chats/messages]
:<- [:chats/current-chat-messages]
:<- [:chats/messages-gaps]
:<- [:chats/range]
:<- [:chats/all-loaded?]
@ -801,17 +764,6 @@
(hydrate-messages messages)
(chat.db/add-gaps messages-gaps range all-loaded? public?))))
(re-frame/reg-sub
:chats/current-chat-intro-status
:<- [:chats/current-chat]
:<- [:chats/current-chat-messages]
(fn [[{:keys [might-have-join-time-messages?]} messages]]
(if might-have-join-time-messages?
:loading
(if (empty? messages)
:empty
:messages))))
(re-frame/reg-sub
:chats/photo-path
:<- [:contacts/contacts]
@ -826,9 +778,15 @@
:chats/unread-messages-number
:<- [:chats/active-chats]
(fn [chats _]
(let [grouped-chats (group-by :public? (vals chats))]
{:public (apply + (map :unviewed-messages-count (get grouped-chats true)))
:other (apply + (map :unviewed-messages-count (get grouped-chats false)))})))
(reduce-kv (fn [{:keys [public other]} _ {:keys [unviewed-messages-count public?]}]
(if public?
{:public (+ public unviewed-messages-count)
:other other}
{:other (+ other unviewed-messages-count)
:public public}))
{:public 0
:other 0}
chats)))
(re-frame/reg-sub
:chats/cooldown-enabled?
@ -886,13 +844,13 @@
(filter-contacts selected-contacts active-contacts)))
(re-frame/reg-sub
:group-chat/chat-joined?
:<- [:multiaccount/public-key]
:<- [:chats/active-chats]
(fn [[my-public-key chats] [_ chat-id]]
(let [current-chat (get chats chat-id)]
(and (chat.models/group-chat? current-chat)
(group-chats.db/joined? my-public-key current-chat)))))
:group-chat/inviter-info
(fn [[_ chat-id] _]
[(re-frame/subscribe [::chat chat-id])
(re-frame/subscribe [:multiaccount/public-key])])
(fn [[chat my-public-key]]
{:joined? (group-chats.db/joined? my-public-key chat)
:inviter-pk (group-chats.db/get-inviter-pk my-public-key chat)}))
(re-frame/reg-sub
:chats/transaction-status
@ -1631,21 +1589,40 @@
contact.db/public-key->new-contact
contact.db/enrich-contact))))
(re-frame/reg-sub
:contacts/contact-by-identity
:<- [::contacts]
(fn [contacts [_ identity]]
(get contacts identity)))
(re-frame/reg-sub
:contacts/contact-added?
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-by-identity identity])])
(fn [[contact] _]
(contact.db/added? contact)))
(re-frame/reg-sub
:contacts/raw-contact-name-by-identity
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-by-identity identity])])
(fn [[db-contact] _]
(if (and (:ens-verified db-contact) (seq (:name db-contact)))
(stateofus/username (str "@" (:name db-contact)))
(:alias db-contact))))
(re-frame/reg-sub
:contacts/contact-name-by-identity
:<- [:contacts/contacts]
:<- [:multiaccount]
(fn [[contacts current-multiaccount] [_ identity]]
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/raw-contact-name-by-identity identity])
(re-frame/subscribe [:multiaccount])])
(fn [[contact-name current-multiaccount] [_ identity]]
(let [me? (= (:public-key current-multiaccount) identity)]
(if me?
{:ens-name (:preferred-name current-multiaccount)
:alias (gfycat/generate-gfy identity)}
(let [contact (or (contacts identity)
(contact.db/public-key->new-contact identity))]
{:ens-name (when (:ens-verified contact)
(:name contact))
:alias (or (:alias contact)
(gfycat/generate-gfy identity))})))))
(or (:preferred-name current-multiaccount)
(gfycat/generate-gfy identity))
(or contact-name
(gfycat/generate-gfy identity))))))
(re-frame/reg-sub
:messages/quote-info
@ -1694,17 +1671,6 @@
(fn [[chat all-contacts] [_ query-fn]]
(contact.db/query-chat-contacts chat all-contacts query-fn)))
(re-frame/reg-sub
:contacts/chat-photo
(fn [[_ chat-id] _]
[(re-frame/subscribe [:chats/chat chat-id])
(re-frame/subscribe [:contacts/contacts-by-chat filter chat-id])])
(fn [[chat contacts] [_ _]]
(when (and chat (not (:group-chat chat)))
(if (pos? (count contacts))
(multiaccounts/displayed-photo (first contacts))
(multiaccounts/displayed-photo chat)))))
(re-frame/reg-sub
:contacts/contact-by-address
:<- [:contacts/contacts]

View File

@ -60,7 +60,8 @@
(let [chat-id "chat-id"
from "from"
message-id "message-id"
initial-cofx {:db {:chats {chat-id {:messages {message-id {:from from}}}}}}]
initial-cofx {:db {:messages {chat-id {message-id {:from from}}}
:chats {chat-id {}}}}]
(testing "a single envelope message"
(let [cofx (message/set-message-envelope-hash initial-cofx chat-id message-id :message-type 1)]
@ -72,12 +73,12 @@
(is (= :sent
(get-in
(message/update-envelope-status cofx message-id :sent)
[:db :chats chat-id :messages message-id :outgoing-status]))))
[:db :messages chat-id message-id :outgoing-status]))))
(testing "the message is not sent"
(is (= :not-sent
(get-in
(message/update-envelope-status cofx message-id :not-sent)
[:db :chats chat-id :messages message-id :outgoing-status]))))))
[:db :messages chat-id message-id :outgoing-status]))))))
(testing "multi envelope message"
(testing "only inserts"
(let [cofx (fx/merge
@ -103,7 +104,7 @@
(is (= :sent
(get-in
cofx
[:db :chats chat-id :messages message-id :outgoing-status]))))))
[:db :messages chat-id message-id :outgoing-status]))))))
(testing "order of events is reversed"
(let [cofx (fx/merge
initial-cofx
@ -119,7 +120,7 @@
(is (= :sent
(get-in
cofx
[:db :chats chat-id :messages message-id :outgoing-status]))))))
[:db :messages chat-id message-id :outgoing-status]))))))
(testing "message not sent"
(let [cofx (fx/merge
initial-cofx
@ -135,4 +136,4 @@
(is (= :not-sent
(get-in
cofx
[:db :chats chat-id :messages message-id :outgoing-status])))))))))
[:db :messages chat-id message-id :outgoing-status])))))))))

View File

@ -91,7 +91,7 @@
[{:keys [db] :as cofx} message-id status]
(if-let [{:keys [chat-id]}
(get-in db [:transport/message-envelopes message-id])]
(when-let [{:keys [from]} (get-in db [:chats chat-id :messages message-id])]
(when-let [{:keys [from]} (get-in db [:messages chat-id message-id])]
(check-confirmations cofx status chat-id message-id))
;; We don't have a message-envelope for this, might be that the confirmation
;; came too early
@ -118,4 +118,4 @@
:message-type message-type})
(update-in [:transport/message-ids->confirmations message-id]
#(or % {:pending-confirmations messages-count})))})]
(apply fx/merge cofx (conj check-confirmations-fx add-envelope-data))))
(apply fx/merge cofx (conj check-confirmations-fx add-envelope-data))))

View File

@ -8,8 +8,6 @@
[status-im.ui.screens.chat.photos :as photos]
[status-im.utils.platform :as platform]))
;;TODO REWORK THIS NAMESPACE
(defn default-chat-icon [name styles]
(when-not (string/blank? name)
[react/view (:default-chat-icon styles)
@ -32,15 +30,16 @@
[react/view online-dot-right]]]])
(defn chat-icon-view
[contact group-chat name _online styles]
[chat-id group-chat name styles]
[react/view (:container styles)
(if-not group-chat
[photos/photo (multiaccounts/displayed-photo contact) styles]
[default-chat-icon name styles])])
(if group-chat
[default-chat-icon name styles]
(let [photo-path @(re-frame.core/subscribe [:chats/photo-path chat-id])]
[photos/photo photo-path styles]))])
(defn chat-icon-view-toolbar
[contact group-chat name color online]
[chat-icon-view contact group-chat name online
[chat-id group-chat name color]
[chat-icon-view chat-id group-chat name
{:container styles/container-chat-toolbar
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
@ -52,8 +51,8 @@
:default-chat-icon-text (styles/default-chat-icon-text 36)}])
(defn chat-icon-view-chat-list
[contact group-chat name color online]
[chat-icon-view contact group-chat name online
[chat-id group-chat name color]
[chat-icon-view chat-id group-chat name
{:container styles/container-chat-list
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
@ -65,8 +64,8 @@
:default-chat-icon-text (styles/default-chat-icon-text 40)}])
(defn chat-icon-view-chat-sheet
[contact group-chat name color online]
[chat-icon-view contact group-chat name online
[chat-id group-chat name color]
[chat-icon-view chat-id group-chat name
{:container styles/container-chat-list
:online-view-wrapper styles/online-view-wrapper
:online-view styles/online-view
@ -116,11 +115,12 @@
:default-chat-icon (styles/default-chat-icon-profile colors/default-chat-color size)
:default-chat-icon-text (styles/default-chat-icon-text size)}])
(defn chat-intro-icon-view [icon-text chat-id styles]
(let [photo-path (re-frame.core/subscribe [:contacts/chat-photo chat-id])]
(if-not (string/blank? @photo-path)
[photos/photo @photo-path styles]
[default-chat-icon icon-text styles])))
(defn chat-intro-icon-view [icon-text chat-id group-chat styles]
(if group-chat
[default-chat-icon icon-text styles]
(let [photo-path @(re-frame.core/subscribe [:chats/photo-path chat-id])]
(if-not (string/blank? photo-path)
[photos/photo photo-path styles]))))
(defn profile-icon-view [photo-path name color edit? size override-styles]
(let [styles (merge {:container {:width size :height size}

View File

@ -2,10 +2,12 @@
(:require [re-frame.core :as re-frame]
[status-im.ui.components.button :as button]
[status-im.ui.components.react :as react]
[status-im.utils.universal-links.core :as links]
[status-im.ui.screens.chat.styles.main :as style]
[status-im.i18n :as i18n]
[status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.colors :as colors]))
[status-im.ui.components.colors :as colors])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn join-chat-button [chat-id]
[button/button
@ -20,15 +22,16 @@
[react/text {:style style/decline-chat}
(i18n/label :t/group-chat-decline-invitation)]])
(defn group-chat-footer
(defview group-chat-footer
[chat-id]
[react/view {:style style/group-chat-join-footer}
[react/view {:style style/group-chat-join-container}
[join-chat-button chat-id]
[decline-chat chat-id]]])
(letsubs [{:keys [joined?]} [:group-chat/inviter-info chat-id]]
(when-not joined?
[react/view {:style style/group-chat-join-footer}
[react/view {:style style/group-chat-join-container}
[join-chat-button chat-id]
[decline-chat chat-id]]])))
(defn group-chat-description-loading
[]
(def group-chat-description-loading
[react/view {:style (merge style/intro-header-description-container
{:margin-bottom 36
:height 44})}
@ -38,48 +41,72 @@
:size :small
:color colors/gray}]])
(defview no-messages-group-chat-description-container [chat-id]
(letsubs [{:keys [highest-request-to lowest-request-from]}
[:mailserver/ranges-by-chat-id chat-id]]
[react/nested-text {:style (merge style/intro-header-description
{:margin-bottom 36})}
(let [quiet-hours (quot (- highest-request-to lowest-request-from)
(* 60 60))
quiet-time (if (<= quiet-hours 24)
(i18n/label :t/quiet-hours
{:quiet-hours quiet-hours})
(i18n/label :t/quiet-days
{:quiet-days (quot quiet-hours 24)}))]
(i18n/label :t/empty-chat-description-public
{:quiet-hours quiet-time}))
[{:style {:color colors/blue}
:on-press #(list-selection/open-share
{:message
(i18n/label
:t/share-public-chat-text {:link (links/generate-link :public-chat :external chat-id)})})}
(i18n/label :t/empty-chat-description-public-share-this)]]))
(defview pending-invitation-description
[inviter-pk chat-name]
(letsubs [inviter-name [:contacts/contact-name-by-identity inviter-pk]]
[react/nested-text {:style style/intro-header-description}
[{:style {:color colors/black}} inviter-name]
(i18n/label :t/join-group-chat-description
{:username ""
:group-name chat-name})]))
(defview joined-group-chat-description
[inviter-pk chat-name]
(letsubs [inviter-name [:contacts/contact-name-by-identity inviter-pk]]
[react/nested-text {:style style/intro-header-description}
(i18n/label :t/joined-group-chat-description
{:username ""
:group-name chat-name})
[{:style {:color colors/black}} inviter-name]]))
(defn created-group-chat-description [chat-name]
[react/text {:style style/intro-header-description}
(i18n/label :t/created-group-chat-description
{:group-name chat-name})])
(defview group-chat-inviter-description-container [chat-id chat-name]
(letsubs [{:keys [joined? inviter-pk]}
[:group-chat/inviter-info chat-id]]
(cond
(not joined?)
[pending-invitation-description inviter-pk chat-name]
inviter-pk
[joined-group-chat-description inviter-pk chat-name]
:else
[created-group-chat-description chat-name])))
(defn group-chat-description-container
[{:keys [pending-invite-inviter-name inviter-name chat-name public?
universal-link range intro-status]}]
(let [{:keys [lowest-request-from highest-request-to]} range]
(case intro-status
:loading
[group-chat-description-loading]
[{:keys [public?
chat-id
chat-name
loading-messages?
no-messages?]}]
(cond loading-messages?
group-chat-description-loading
:empty
(when public?
[react/nested-text {:style (merge style/intro-header-description
{:margin-bottom 36})}
(let [quiet-hours (quot (- highest-request-to lowest-request-from)
(* 60 60))
quiet-time (if (<= quiet-hours 24)
(i18n/label :t/quiet-hours
{:quiet-hours quiet-hours})
(i18n/label :t/quiet-days
{:quiet-days (quot quiet-hours 24)}))]
(i18n/label :t/empty-chat-description-public
{:quiet-hours quiet-time}))
[{:style {:color colors/blue}
:on-press #(list-selection/open-share
{:message
(i18n/label
:t/share-public-chat-text {:link universal-link})})}
(i18n/label :t/empty-chat-description-public-share-this)]])
(and no-messages? public?)
[no-messages-group-chat-description-container chat-id]
:messages
(when (not public?)
(if pending-invite-inviter-name
[react/nested-text {:style style/intro-header-description}
[{:style {:color colors/black}} pending-invite-inviter-name]
(i18n/label :t/join-group-chat-description
{:username ""
:group-name chat-name})]
(if (not= inviter-name "Unknown")
[react/nested-text {:style style/intro-header-description}
(i18n/label :t/joined-group-chat-description
{:username ""
:group-name chat-name})
[{:style {:color colors/black}} inviter-name]]
[react/text {:style style/intro-header-description}
(i18n/label :t/created-group-chat-description
{:group-name chat-name})]))))))
(not public?)
[group-chat-inviter-description-container chat-id chat-name]))

View File

@ -33,21 +33,6 @@
:placeholder-text-color colors/gray
:auto-capitalize :sentences}])
(defview reply-message [from alias content]
(letsubs [{:keys [ens-name]} [:contacts/contact-name-by-identity from]
current-public-key [:multiaccount/public-key]]
[react/scroll-view {:style style/reply-message-content}
[react/view {:style style/reply-message-to-container}
(chat-utils/format-reply-author from alias ens-name current-public-key style/reply-message-author)]
(if (:image content)
[react/image {:style {:width 56
:height 56
:background-color :black
:border-radius 4}
:source {:uri (:image content)}}]
[react/text {:style (assoc (message-style/style-message-text false) :font-size 14)
:number-of-lines 3} (:text content)])]))
(defn close-button [on-press]
[react/touchable-highlight
{:style style/cancel-reply-highlight
@ -58,12 +43,6 @@
:height 19
:color colors/white}]])
(defn reply-message-view [{:keys [content from alias]}]
[react/view {:style style/reply-message}
[photos/member-photo from]
[reply-message from alias content]
[close-button #(re-frame/dispatch [:chat.ui/cancel-message-reply])]])
(defn send-image-view [{:keys [uri]}]
[react/view {:style style/reply-message}
[react/image {:style {:width 56 :height 56
@ -71,6 +50,29 @@
:source {:uri uri}}]
[close-button #(re-frame/dispatch [:chat.ui/cancel-sending-image])]])
(defview reply-message [from message-text image]
(letsubs [contact-name [:contacts/contact-name-by-identity from]
current-public-key [:multiaccount/public-key]]
[react/scroll-view {:style style/reply-message-content}
[react/view {:style style/reply-message-to-container}
(chat-utils/format-reply-author from contact-name current-public-key style/reply-message-author)]
(if image
[react/image {:style {:width 56
:height 56
:background-color :black
:border-radius 4}
:source {:uri image}}]
[react/text {:style (assoc (message-style/style-message-text false) :font-size 14)
:number-of-lines 3} message-text])]))
(defview reply-message-view []
(letsubs [{:keys [content from] :as message} [:chats/reply-message]]
(when message
[react/view {:style style/reply-message}
[photos/member-photo from]
[reply-message from (:text content) (:image content)]
[close-button #(re-frame/dispatch [:chat.ui/cancel-message-reply])]])))
(defview container []
(letsubs [mainnet? [:mainnet?]
input-text [:chats/current-chat-input-text]

View File

@ -21,15 +21,15 @@
(views/defview gap
[{:keys [gaps first-gap?]} idx list-ref]
(views/letsubs [{:keys [range intro-status]} [:chats/current-chat]
(views/letsubs [range [:chats/range]
{:keys [might-have-join-time-messages?]} [:chats/current-raw-chat]
in-progress? [:chats/fetching-gap-in-progress?
(if first-gap?
[:first-gap]
(:ids gaps))]
connected? [:mailserver/connected?]]
(let [ids (:ids gaps)
intro-loading? (= intro-status :loading)]
(when-not (and first-gap? intro-loading?)
(let [ids (:ids gaps)]
(when-not (and first-gap? might-have-join-time-messages?)
[react/view {:style style/gap-container}
[react/touchable-highlight
{:on-press (when (and connected? (not in-progress?))

View File

@ -18,8 +18,8 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defview mention-element [from]
(letsubs [{:keys [ens-name alias]} [:contacts/contact-name-by-identity from]]
(if ens-name (str "@" ens-name) alias)))
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
contact-name))
(defn message-timestamp
([message]
@ -38,14 +38,13 @@
appender])
(defview quoted-message
[_ {:keys [from text image]} outgoing current-public-key public?]
(letsubs [{:keys [ens-name alias]} [:contacts/contact-name-by-identity from]]
[_ {:keys [from text]} outgoing current-public-key public?]
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
[react/view {:style (style/quoted-message-container outgoing)}
[react/view {:style style/quoted-message-author-container}
[chat.utils/format-reply-author
from
alias
ens-name
contact-name
current-public-key
(partial style/quoted-message-author outgoing)]]
(if (and image
@ -239,8 +238,8 @@
nil)))
(defview message-author-name [from alias]
(letsubs [{:keys [ens-name]} [:contacts/contact-name-by-identity from]]
(chat.utils/format-author alias style/message-author-name-container ens-name)))
(letsubs [contact-name [:contacts/raw-contact-name-by-identity from]]
(chat.utils/format-author (or contact-name alias) style/message-author-name-container)))
(defn message-content-wrapper
"Author, userpic and delivery wrapper"
@ -261,7 +260,6 @@
(when display-username?
[react/touchable-opacity {:style style/message-author-touchable
:on-press #(re-frame/dispatch [:chat.ui/show-profile from])}
;;TODO (perf) move to event
[message-author-name from alias]])
;;MESSAGE CONTENT
content]]

View File

@ -4,7 +4,6 @@
[status-im.ui.components.react :as react]
[status-im.ui.components.list-selection :as list-selection]
[status-im.utils.universal-links.core :as universal-links]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.colors :as colors]
[status-im.utils.platform :as platform]
@ -27,40 +26,42 @@
:color colors/gray}}
(i18n/label helper)]])
(defn chat-actions [{:keys [chat-id contact chat-name]}]
[react/view
[list-item/list-item
{:theme :action
:icon (multiaccounts/displayed-photo contact)
:title [view-profile {:name chat-name
:helper :t/view-profile}]
:accessibility-label :view-chat-details-button
:accessories [:chevron]
:on-press #(hide-sheet-and-dispatch [:chat.ui/show-profile chat-id])}]
[list-item/list-item
{:theme :action
:title :t/mark-all-read
:accessibility-label :mark-all-read-button
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [:chat.ui/mark-all-read-pressed chat-id])}]
[list-item/list-item
{:theme :action
:title :t/clear-history
:accessibility-label :clear-history-button
:icon :main-icons/close
:on-press #(hide-sheet-and-dispatch [:chat.ui/clear-history-pressed chat-id])}]
[list-item/list-item
{:theme :action
:title :t/fetch-history
:accessibility-label :fetch-history-button
:icon :main-icons/arrow-down
:on-press #(hide-sheet-and-dispatch [:chat.ui/fetch-history-pressed chat-id])}]
[list-item/list-item
{:theme :action-destructive
:title :t/delete-chat
:accessibility-label :delete-chat-button
:icon :main-icons/delete
:on-press #(hide-sheet-and-dispatch [:chat.ui/remove-chat-pressed chat-id])}]])
(defn one-to-one-chat-actions [{:keys [chat-id]}]
(let [photo @(re-frame/subscribe [:chats/photo-path chat-id])
contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity chat-id])]
[react/view
[list-item/list-item
{:theme :action
:icon photo
:title [view-profile {:name contact-name
:helper :t/view-profile}]
:accessibility-label :view-chat-details-button
:accessories [:chevron]
:on-press #(hide-sheet-and-dispatch [:chat.ui/show-profile chat-id])}]
[list-item/list-item
{:theme :action
:title :t/mark-all-read
:accessibility-label :mark-all-read-button
:icon :main-icons/check
:on-press #(hide-sheet-and-dispatch [:chat.ui/mark-all-read-pressed chat-id])}]
[list-item/list-item
{:theme :action
:title :t/clear-history
:accessibility-label :clear-history-button
:icon :main-icons/close
:on-press #(hide-sheet-and-dispatch [:chat.ui/clear-history-pressed chat-id])}]
[list-item/list-item
{:theme :action
:title :t/fetch-history
:accessibility-label :fetch-history-button
:icon :main-icons/arrow-down
:on-press #(hide-sheet-and-dispatch [:chat.ui/fetch-history-pressed chat-id])}]
[list-item/list-item
{:theme :action-destructive
:title :t/delete-chat
:accessibility-label :delete-chat-button
:icon :main-icons/delete
:on-press #(hide-sheet-and-dispatch [:chat.ui/remove-chat-pressed chat-id])}]]))
(defn public-chat-actions [{:keys [chat-id]}]
(let [link (universal-links/generate-link :public-chat :external chat-id)
@ -101,15 +102,15 @@
:on-press #(hide-sheet-and-dispatch [:chat.ui/remove-chat-pressed chat-id])}]]))
(defn group-chat-actions []
(fn [{:keys [chat-id contact group-chat chat-name color online]}]
(let [joined @(re-frame/subscribe [:group-chat/chat-joined? chat-id])]
(fn [{:keys [chat-id group-chat chat-name color]}]
(let [{:keys [joined?]} @(re-frame/subscribe [:group-chat/inviter-info chat-id])]
[react/view
[list-item/list-item
{:theme :action
:title [view-profile {:name chat-name
:helper :t/group-info}]
:icon [chat-icon/chat-icon-view-chat-sheet
contact group-chat chat-name color online]
chat-id group-chat chat-name color]
:accessories [:chevron]
:on-press #(hide-sheet-and-dispatch [:show-group-chat-profile chat-id])}]
[list-item/list-item
@ -130,7 +131,7 @@
:accessibility-label :fetch-history-button
:icon :main-icons/arrow-down
:on-press #(hide-sheet-and-dispatch [:chat.ui/fetch-history-pressed chat-id])}]
(when joined
(when joined?
[list-item/list-item
{:theme :action
:title :t/leave-chat
@ -143,7 +144,7 @@
(cond
public? [public-chat-actions current-chat]
group-chat [group-chat-actions current-chat]
:else [chat-actions current-chat]))
:else [one-to-one-chat-actions current-chat]))
(defn options [chat-id message-id]
(fn []
@ -162,16 +163,16 @@
:accessibility-label :delete-transaction-button
:on-press #(hide-sheet-and-dispatch [:chat.ui/delete-message chat-id message-id])}]]))
(defn message-long-press [{:keys [content identicon from outgoing] :as message}]
(defn message-long-press [{:keys [content from outgoing] :as message}]
(fn []
(let [{:keys [ens-name alias]} @(re-frame/subscribe [:contacts/contact-name-by-identity from])]
(let [photo @(re-frame/subscribe [:chats/photo-path from])
contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])]
[react/view
(when-not outgoing
[list-item/list-item
{:theme :action
:icon (multiaccounts/displayed-photo {:identicon identicon
:public-key from})
:title [view-profile {:name (or ens-name alias)
:icon photo
:title [view-profile {:name contact-name
:helper :t/view-profile}]
:accessibility-label :view-chat-details-button
:accessories [:chevron]
@ -197,15 +198,15 @@
(re-frame/dispatch [:bottom-sheet/hide-sheet])
(list-selection/open-share {:message (:text content)}))}])])))
(defn sticker-long-press [{:keys [from identicon]}]
(defn sticker-long-press [{:keys [from]}]
(fn []
(let [{:keys [ens-name alias]} @(re-frame/subscribe [:contacts/contact-name-by-identity from])]
(let [photo @(re-frame/subscribe [:chats/photo-path from])
contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])]
[react/view
[list-item/list-item
{:theme :action
:icon (multiaccounts/displayed-photo {:identicon identicon
:public-key from})
:title [view-profile {:name (or ens-name alias)
:icon photo
:title [view-profile {:name contact-name
:helper :t/view-profile}]
:accessibility-label :view-chat-details-button
:accessories [:chevron]

View File

@ -47,8 +47,8 @@
:margin-right 6})
(defn intro-header-container
[status no-messages]
(if (or no-messages (= status (or :loading :empty)))
[loading-messages? no-messages?]
(if (or loading-messages? no-messages?)
{:flex 1
:flex-direction :column
:justify-content :center
@ -143,4 +143,4 @@
(def tribute-received-note
{:font-size 13
:line-height 18
:text-align :center})
:text-align :center})

View File

@ -5,64 +5,48 @@
[status-im.ui.screens.chat.styles.main :as st])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn- in-progress-text [{:keys [highestBlock currentBlock startBlock]}]
(let [total (- highestBlock startBlock)
ready (- currentBlock startBlock)
percentage (if (zero? ready)
0
(->> (/ ready total)
(* 100)
(.round js/Math)))]
(str (i18n/label :t/sync-in-progress) " " percentage "% " currentBlock)))
(defview last-activity [{:keys [sync-state accessibility-label]}]
(letsubs [state [:sync-data]]
[react/text {:style st/last-activity-text
:accessibility-label accessibility-label}
(case sync-state
:in-progress (in-progress-text state)
:synced (i18n/label :t/sync-synced))]))
(defn- group-last-activity [{:keys [contacts sync-state public?]}]
(if (or (= sync-state :in-progress)
(= sync-state :synced))
[last-activity {:sync-state sync-state}]
[react/view {:flex-direction :row}
[react/text {:style st/toolbar-subtitle}
(if public?
(i18n/label :t/public-group-status)
(let [cnt (count contacts)]
(if (zero? cnt)
(i18n/label :members-active-none)
(i18n/label-pluralize cnt :t/members-active))))]]))
(defn- contact-indicator [{:keys [added?]}]
(defn- group-last-activity [{:keys [contacts public?]}]
[react/view {:flex-direction :row}
[react/text {:style st/toolbar-subtitle}
(if added?
(i18n/label :chat-is-a-contact)
(i18n/label :chat-is-not-a-contact))]])
(if public?
(i18n/label :t/public-group-status)
(let [cnt (count contacts)]
(if (zero? cnt)
(i18n/label :members-active-none)
(i18n/label-pluralize cnt :t/members-active))))]])
(defview one-to-one-name [from]
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
contact-name))
(defview contact-indicator [contact-id]
(letsubs [added? [:contacts/contact-added? contact-id]]
[react/view {:flex-direction :row}
[react/text {:style st/toolbar-subtitle}
(if added?
(i18n/label :chat-is-a-contact)
(i18n/label :chat-is-not-a-contact))]]))
(defview toolbar-content-view []
(letsubs [{:keys [group-chat color online contacts chat-name contact public?]}
[:chats/current-chat]
sync-state [:sync-state]]
(let [has-subtitle? (or group-chat (not= :done sync-state))]
[react/view {:style st/toolbar-container}
[react/view {:margin-right 10}
[chat-icon.screen/chat-icon-view-toolbar contact group-chat chat-name color online]]
[react/view {:style st/chat-name-view}
[react/text {:style st/chat-name-text
:number-of-lines 1
:accessibility-label :chat-name-text}
chat-name]
(when contact
[contact-indicator contact])
(if group-chat
[group-last-activity {:contacts contacts
:public? public?
:sync-state sync-state}]
(when has-subtitle?
[last-activity {:sync-state sync-state
:accessibility-label :last-seen-text}]))]])))
(letsubs [{:keys [group-chat
color
chat-id
contacts
chat-name
public?]}
[:chats/current-chat]]
[react/view {:style st/toolbar-container}
[react/view {:margin-right 10}
[chat-icon.screen/chat-icon-view-toolbar chat-id group-chat chat-name color]]
[react/view {:style st/chat-name-view}
[react/text {:style st/chat-name-text
:number-of-lines 1
:accessibility-label :chat-name-text}
(if group-chat
chat-name
[one-to-one-name chat-id])]
(when-not group-chat
[contact-indicator chat-id])
(when group-chat
[group-last-activity {:contacts contacts
:public? public?}])]]))

View File

@ -4,30 +4,26 @@
[status-im.ui.components.react :as react]
[status-im.ui.components.colors :as colors]))
(defn format-author [alias style name]
(defn format-author [contact-name style]
(let [additional-styles (style false)]
(if name
(let [name (subs name 0 80)]
(if (= (aget contact-name 0) "@")
(let [trimmed-name (subs contact-name 0 81)]
[react/text {:number-of-lines 2
:style (merge {:color colors/blue
:font-size 13
:line-height 18
:font-weight "500"} additional-styles)}
(str "@" (or (stateofus/username name) name))])
(or (stateofus/username trimmed-name) trimmed-name)])
[react/text {:style (merge {:color colors/gray
:font-size 12
:line-height 18
:font-weight "400"} additional-styles)}
alias])))
contact-name])))
(def ^:private reply-symbol "↪ ")
(defn format-reply-author [from alias username current-public-key style]
(let [reply-name (or (some->> username
(str "@")
(str reply-symbol))
(str reply-symbol alias))]
(or (and (= from current-public-key)
[react/text {:style (style true)}
(str reply-symbol (i18n/label :t/You))])
(format-author (subs reply-name 0 80) style false))))
(defn format-reply-author [from username current-public-key style]
(or (and (= from current-public-key)
[react/text {:style (style true)}
(str reply-symbol (i18n/label :t/You))])
(format-author username style)))

View File

@ -1,8 +1,6 @@
(ns status-im.ui.screens.chat.views
(:require [re-frame.core :as re-frame]
[status-im.contact.db :as contact.db]
[status-im.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.connectivity.view :as connectivity]
@ -41,56 +39,86 @@
[sheets/actions current-chat])
:height 256}])}]}])
(defn add-contact-bar
[public-key]
[react/touchable-highlight
{:on-press
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
:accessibility-label :add-to-contacts-button}
[react/view {:style (style/add-contact)}
[vector-icons/icon :main-icons/add
{:color colors/blue}]
[react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]])
(defview add-contact-bar [public-key]
(letsubs [added? [:contacts/contact-added? public-key]]
(when-not added?
[react/touchable-highlight
{:on-press
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
:accessibility-label :add-to-contacts-button}
[react/view {:style (style/add-contact)}
[vector-icons/icon :main-icons/add
{:color colors/blue}]
[react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]])))
(defn intro-header
[contact]
(defn intro-header [name]
[react/text {:style (assoc style/intro-header-description
:margin-bottom 32)}
(str
(i18n/label :t/empty-chat-description-one-to-one)
(multiaccounts/displayed-name contact))])
name)])
(defn chat-intro [{:keys [chat-id
chat-name
group-chat
contact-name
public?
color
loading-messages?
no-messages?]}]
[react/view (style/intro-header-container loading-messages? no-messages?)
;; Icon section
[react/view {:style {:margin-top 42
:margin-bottom 24}}
[chat-icon.screen/chat-intro-icon-view
chat-name chat-id group-chat
{:default-chat-icon (style/intro-header-icon 120 color)
:default-chat-icon-text style/intro-header-icon-text
:size 120}]]
;; Chat title section
[react/text {:style (style/intro-header-chat-name)} (if group-chat chat-name contact-name)]
;; Description section
(if group-chat
[chat.group/group-chat-description-container {:chat-id chat-id
:loading-messages? loading-messages?
:chat-name chat-name
:public? public?
:no-messages? no-messages?}]
[react/text {:style (assoc style/intro-header-description
:margin-bottom 32)}
(str
(i18n/label :t/empty-chat-description-one-to-one)
contact-name)])])
(defview chat-intro-one-to-one [{:keys [chat-id] :as opts}]
(letsubs [contact-name [:contacts/contact-name-by-identity chat-id]]
(chat-intro (assoc opts :contact-name contact-name))))
(defn chat-intro-header-container
[{:keys [group-chat name pending-invite-inviter-name color chat-id chat-name
public? contact intro-status] :as chat}
[{:keys [group-chat
might-have-join-time-messages?
color chat-id chat-name
public?]}
no-messages]
(let [icon-text (if public? chat-id name)
intro-name (if public? chat-name (multiaccounts/displayed-name contact))]
(when (or pending-invite-inviter-name
(not= (get-in contact [:tribute-to-talk :snt-amount]) 0))
[react/touchable-without-feedback
{:style {:flex 1
:align-items :flex-start}
:on-press (fn [_]
(re-frame/dispatch
[:chat.ui/set-chat-ui-props {:input-bottom-sheet nil}])
(react/dismiss-keyboard!))}
[react/view (style/intro-header-container intro-status no-messages)
;; Icon section
[react/view {:style {:margin-top 42
:margin-bottom 24}}
[chat-icon.screen/chat-intro-icon-view
icon-text chat-id
{:default-chat-icon (style/intro-header-icon 120 color)
:default-chat-icon-text style/intro-header-icon-text
:size 120}]]
;; Chat title section
[react/text {:style (style/intro-header-chat-name)}
(if group-chat chat-name intro-name)]
;; Description section
(if group-chat
[chat.group/group-chat-description-container chat]
[intro-header contact])]])))
[react/touchable-without-feedback
{:style {:flex 1
:align-items :flex-start}
:on-press (fn [_]
(re-frame/dispatch
[:chat.ui/set-chat-ui-props {:input-bottom-sheet nil}])
(react/dismiss-keyboard!))}
(let [opts
{:chat-id chat-id
:group-chat group-chat
:chat-name chat-name
:public? public?
:color color
:loading-messages? might-have-join-time-messages?
:no-messages? no-messages}]
(if group-chat
[chat-intro opts]
[chat-intro-one-to-one opts]))])
(defonce messages-list-ref (atom nil))
@ -110,15 +138,16 @@
(debounce/debounce-and-dispatch [:chat.ui/message-visibility-changed e] 5000))
(defview messages-view
[{:keys [public? group-chat chat-id pending-invite-inviter-name] :as chat}]
[{:keys [group-chat chat-id public?] :as chat}]
(letsubs [messages [:chats/current-chat-messages-stream]
no-messages? [:chats/current-chat-no-messages?]
current-public-key [:multiaccount/public-key]]
[list/flat-list
{:key-fn #(or (:message-id %) (:value %))
:ref #(reset! messages-list-ref %)
:header (when pending-invite-inviter-name
:header (when (and group-chat (not public?))
[chat.group/group-chat-footer chat-id])
:footer [chat-intro-header-container chat (empty? messages)]
:footer [chat-intro-header-container chat no-messages?]
:data messages
:inverted true
:render-fn (fn [{:keys [outgoing type] :as message} idx]
@ -154,14 +183,13 @@
[empty-bottom-sheet])))
(defview chat []
(letsubs [{:keys [chat-id show-input? group-chat contact] :as current-chat}
(letsubs [{:keys [chat-id show-input? group-chat] :as current-chat}
[:chats/current-chat]]
[react/view {:style {:flex 1}}
[connectivity/connectivity
[topbar current-chat]
[react/view {:style {:flex 1}}
;;TODO contact.db/added? looks weird here, move to events
(when (and (not group-chat) (not (contact.db/added? contact)))
(when-not group-chat
[add-contact-bar chat-id])
[messages-view current-chat]]]
(when show-input?

View File

@ -18,7 +18,9 @@
[status-im.ui.components.radio :as radio]
[status-im.ui.components.react :as react]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.chat.utils :as chat.utils]
[status-im.ui.screens.chat.message.message :as message]
[status-im.ui.screens.chat.styles.message.message :as message.style]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.profile.components.views :as profile.components]
[status-im.utils.debounce :as debounce])
@ -624,7 +626,11 @@
[name-item {:name name :hide-chevron? true :action action}]]
[radio/radio (= name preferred-name)]]]))]]]])
(defn- registered [names {:keys [preferred-name public-key] :as account} _]
(views/defview my-name []
(views/letsubs [contact-name [:multiaccount/my-name]]
(chat.utils/format-author contact-name message.style/message-author-name-container)))
(defn- registered [names {:keys [preferred-name] :as account} _]
[react/view {:style {:flex 1}}
[react/scroll-view
[react/view {:style {:margin-top 8}}
@ -663,7 +669,7 @@
:timestamp-str "9:41 AM"}]
[react/view
[react/view {:padding-left 72}
[message/message-author-name public-key]]
[my-name]]
[react/view {:flex-direction :row}
[react/view {:padding-left 16 :padding-right 8 :padding-top 4}
[photos/photo (multiaccounts/displayed-photo account) {:size 36}]]

View File

@ -15,8 +15,8 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defview mention-element [from]
(letsubs [{:keys [ens-name alias]} [:contacts/contact-name-by-identity from]]
(if ens-name (str "@" ens-name) alias)))
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
contact-name))
(defn render-subheader-inline [acc {:keys [type destination literal children]}]
(case type
@ -108,20 +108,20 @@
(defn home-list-item [[_ home-item]]
(let [{:keys [chat-id chat-name color online group-chat
public? contact timestamp last-message]}
public? timestamp last-message]}
home-item
private-group? (and group-chat (not public?))
public-group? (and group-chat public?)
;;TODO (perf) move to event
truncated-chat-name (utils/truncate-str chat-name 30)]
public-group? (and group-chat public?)]
[list-item/list-item
{:icon [chat-icon.screen/chat-icon-view-chat-list
contact group-chat truncated-chat-name color online false]
chat-id group-chat chat-name color online false]
:title-prefix (cond
private-group? :main-icons/tiny-group
public-group? :main-icons/tiny-public
:else nil)
:title truncated-chat-name
:title (if group-chat
(utils/truncate-str chat-name 30)
@(re-frame/subscribe [:contacts/contact-name-by-identity chat-id]))
:title-accessibility-label :chat-name-text
:title-row-accessory [message-timestamp (if (pos? (:whisper-timestamp last-message))
(:whisper-timestamp last-message)