[Fixes: #12061] Add unread mentions count

Fixes: #2061

This commit adds an unread mentions count in 3 places:

1) Public chats
2) Communities in home
3) Communities chats

The logic is that if you have unread mentions, it will show you the
count of messages with unread mentions, while if you have only unread
messages, you will see a blue dot.

Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Andrea Maria Piana 2021-05-26 10:28:22 +02:00
parent 8926a7ad4e
commit ef13b4d210
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
12 changed files with 70 additions and 104 deletions

View File

@ -143,6 +143,7 @@
(update-in [:chats chat-id] merge (update-in [:chats chat-id] merge
{:last-message nil {:last-message nil
:unviewed-messages-count 0 :unviewed-messages-count 0
:unviewed-mentions-count 0
:deleted-at-clock-value last-message-clock-value}))})) :deleted-at-clock-value last-message-clock-value}))}))
(fx/defn clear-history-handler (fx/defn clear-history-handler

View File

@ -47,7 +47,9 @@
(fx/defn handle-mark-all-read-successful (fx/defn handle-mark-all-read-successful
{:events [::mark-all-read-successful]} {:events [::mark-all-read-successful]}
[{:keys [db]} chat-id] [{:keys [db]} chat-id]
{:db (assoc-in db [:chats chat-id :unviewed-messages-count] 0)}) {:db (update-in db [:chats chat-id] assoc
:unviewed-messages-count 0
:unviewed-mentions-count 0)})
(fx/defn handle-mark-all-read (fx/defn handle-mark-all-read
{:events [:chat.ui/mark-all-read-pressed :chat/mark-all-as-read]} {:events [:chat.ui/mark-all-read-pressed :chat/mark-all-as-read]}

View File

@ -10,6 +10,9 @@
[{:keys [db]} {:keys [chat-id _]}] [{:keys [db]} {:keys [chat-id _]}]
(let [{:keys [loaded-unviewed-messages-ids unviewed-messages-count]} (let [{:keys [loaded-unviewed-messages-ids unviewed-messages-count]}
(get-in db [:chats chat-id])] (get-in db [:chats chat-id])]
;; We currently only use this for private group chats and one-to-ones
;; but this method would have to be changed if we showed unviewed-mentions-count
;; in one to ones and private group chats as well
{:db (update-in db [:chats chat-id] assoc {:db (update-in db [:chats chat-id] assoc
:unviewed-messages-count (subtract-seen-messages :unviewed-messages-count (subtract-seen-messages
unviewed-messages-count unviewed-messages-count

View File

@ -12,6 +12,7 @@
public-key public-key
{:keys [chat-id {:keys [chat-id
unviewed-messages-count unviewed-messages-count
unviewed-mentions-count
last-message]}] last-message]}]
(let [removed-messages-ids (keep (let [removed-messages-ids (keep
(fn [[message-id {:keys [from]}]] (fn [[message-id {:keys [from]}]]
@ -25,6 +26,7 @@
(update-in [:chats chat-id] (update-in [:chats chat-id]
assoc assoc
:unviewed-messages-count unviewed-messages-count :unviewed-messages-count unviewed-messages-count
:unviewed-mentions-count unviewed-mentions-count
:last-message last-message))] :last-message last-message))]
{:db (assoc-in db [:message-lists chat-id] {:db (assoc-in db [:message-lists chat-id]
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))})) (message-list/add-many nil (vals (get-in db [:messages chat-id]))))}))

View File

@ -6,16 +6,6 @@
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[taoensso.timbre :as log])) [taoensso.timbre :as log]))
(defn type->rpc [{:keys [chat-type public? group-chat profile-public-key timeline?] :as chat}]
(if chat-type
(assoc chat :chatType chat-type)
(assoc chat :chatType (cond
profile-public-key constants/profile-chat-type
timeline? constants/timeline-chat-type
public? constants/public-chat-type
group-chat constants/private-group-chat-type
:else constants/one-to-one-chat-type))))
(defn rpc->type [{:keys [chatType name] :as chat}] (defn rpc->type [{:keys [chatType name] :as chat}]
(cond (cond
(or (= constants/public-chat-type chatType) (or (= constants/public-chat-type chatType)
@ -34,15 +24,6 @@
:group-chat true) :group-chat true)
:else (assoc chat :public? false :group-chat false))) :else (assoc chat :public? false :group-chat false)))
(defn- marshal-members [{:keys [admins contacts members-joined chat-type] :as chat}]
(cond-> chat
(= chat-type constants/private-group-chat-type)
(assoc :members (map #(hash-map :id %
:admin (boolean (admins %))
:joined (boolean (members-joined %))) contacts))
:always
(dissoc :admins :contacts :members-joined)))
(defn- unmarshal-members [{:keys [members chatType] :as chat}] (defn- unmarshal-members [{:keys [members chatType] :as chat}]
(cond (cond
(= constants/public-chat-type chatType) (assoc chat (= constants/public-chat-type chatType) (assoc chat
@ -68,26 +49,6 @@
:admins #{} :admins #{}
:members-joined #{}))) :members-joined #{})))
(defn- ->rpc [chat]
(-> chat
marshal-members
(update :last-message messages/->rpc)
type->rpc
(clojure.set/rename-keys {:chat-id :id
:membership-update-events :membershipUpdateEvents
:synced-from :syncedFrom
:synced-to :syncedTo
:unviewed-messages-count :unviewedMessagesCount
:last-message :lastMessage
:community-id :communityId
:deleted-at-clock-value :deletedAtClockValue
:is-active :active
:last-clock-value :lastClockValue
:profile-public-key :profile})
(dissoc :public? :group-chat :messages
:chat-type
:contacts :admins :members-joined)))
(defn <-rpc [chat] (defn <-rpc [chat]
(-> chat (-> chat
rpc->type rpc->type
@ -100,6 +61,7 @@
:deletedAtClockValue :deleted-at-clock-value :deletedAtClockValue :deleted-at-clock-value
:chatType :chat-type :chatType :chat-type
:unviewedMessagesCount :unviewed-messages-count :unviewedMessagesCount :unviewed-messages-count
:unviewedMentionsCount :unviewed-mentions-count
:lastMessage :last-message :lastMessage :last-message
:active :is-active :active :is-active
:lastClockValue :last-clock-value :lastClockValue :last-clock-value

View File

@ -2,47 +2,6 @@
(:require [cljs.test :refer-macros [deftest is testing]] (:require [cljs.test :refer-macros [deftest is testing]]
[status-im.data-store.chats :as chats])) [status-im.data-store.chats :as chats]))
(deftest ->to-rpc
(let [chat {:public? false
:group-chat true
:color "color"
:contacts #{"a" "b" "c" "d"}
:last-clock-value 10
:chat-type 3
:admins #{"a" "b"}
:members-joined #{"a" "c"}
:name "name"
:membership-update-events :events
:unviewed-messages-count 2
:is-active true
:chat-id "chat-id"
:timestamp 2}
expected-chat {:id "chat-id"
:color "color"
:name "name"
:chatType 3
:lastMessage nil
:members #{{:id "a"
:admin true
:joined true}
{:id "b"
:admin true
:joined false}
{:id "c"
:admin false
:joined true}
{:id "d"
:admin false
:joined false}}
:lastClockValue 10
:membershipUpdateEvents :events
:unviewedMessagesCount 2
:active true
:timestamp 2}]
(testing "marshaling chat"
(is (= expected-chat (-> (#'status-im.data-store.chats/->rpc chat)
(update :members #(into #{} %))))))))
(deftest normalize-chat-test (deftest normalize-chat-test
(let [chat {:id "chat-id" (let [chat {:id "chat-id"
:color "color" :color "color"

View File

@ -285,6 +285,18 @@
0 0
chats))) chats)))
(re-frame/reg-sub
:communities/unviewed-counts
(fn [[_ community-id]]
[(re-frame/subscribe [:chats/by-community-id community-id])])
(fn [[chats]]
(reduce (fn [acc {:keys [unviewed-mentions-count unviewed-messages-count]}]
{:unviewed-messages-count (+ (:unviewed-messages-count acc) (or unviewed-messages-count 0))
:unviewed-mentions-count (+ (:unviewed-mentions-count acc) (or unviewed-mentions-count 0))})
{:unviewed-messages-count 0
:unviewed-mentions-count 0}
chats)))
(re-frame/reg-sub (re-frame/reg-sub
:communities/requests-to-join-for-community :communities/requests-to-join-for-community
:<- [:communities/requests-to-join] :<- [:communities/requests-to-join]

View File

@ -49,8 +49,10 @@
(process-next response-js sync-handler) (process-next response-js sync-handler)
(models.chat/ensure-chats (map #(-> % (models.chat/ensure-chats (map #(-> %
(data-store.chats/<-rpc) (data-store.chats/<-rpc)
;;TODO why here? ;; We dissoc this fields as they are handled by status-react and
(dissoc :unviewed-messages-count)) ;; not status-go, as there might be requests in-flight that change
;; this value
(dissoc :unviewed-messages-count :unviewed-mentions-count))
(types/js->clj chats))))) (types/js->clj chats)))))
(seq messages) (seq messages)
@ -118,9 +120,15 @@
(let [chat-id (.-localChatId message-js) (let [chat-id (.-localChatId message-js)
message-type (.-messageType message-js) message-type (.-messageType message-js)
from (.-from message-js) from (.-from message-js)
mentioned (.-mentioned message-js)
profile (models.chat/profile-chat? {:db db} chat-id)
new (.-new message-js) new (.-new message-js)
current (= current-chat-id chat-id) current (= current-chat-id chat-id)
profile (models.chat/profile-chat? {:db db} chat-id) should-update-unviewed? (and (not current)
new
(not profile)
(not (= message-type constants/message-type-private-group-system-message))
(not (= from (multiaccounts.model/current-public-key {:db db}))))
tx-hash (and (.-commandParameters message-js) (.-commandParameters.transactionHash message-js))] tx-hash (and (.-commandParameters message-js) (.-commandParameters.transactionHash message-js))]
(cond-> acc (cond-> acc
current current
@ -130,13 +138,13 @@
(update :statuses conj message-js) (update :statuses conj message-js)
;;update counter ;;update counter
(and (not current) should-update-unviewed?
new
(not profile)
(not (= message-type constants/message-type-private-group-system-message))
(not (= from (multiaccounts.model/current-public-key {:db db}))))
(update-in [:db :chats chat-id :unviewed-messages-count] inc) (update-in [:db :chats chat-id :unviewed-messages-count] inc)
(and should-update-unviewed?
mentioned)
(update-in [:db :chats chat-id :unviewed-mentions-count] inc)
;;conj incoming transaction for :watch-tx ;;conj incoming transaction for :watch-tx
(not (string/blank? tx-hash)) (not (string/blank? tx-hash))
(update :transactions conj tx-hash) (update :transactions conj tx-hash)

View File

@ -124,7 +124,9 @@
(defn community-chat-item [{:keys [chat-id] :as home-item}] (defn community-chat-item [{:keys [chat-id] :as home-item}]
[inner-item/home-list-item [inner-item/home-list-item
home-item ;; We want communities to behave as public chats when it comes to
;; unread indicator
(assoc home-item :public? true)
{:on-press (fn [] {:on-press (fn []
(re-frame/dispatch [:dismiss-keyboard]) (re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]) (re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])

View File

@ -11,6 +11,7 @@
[status-im.ui.components.topbar :as topbar] [status-im.ui.components.topbar :as topbar]
[status-im.ui.components.colors :as colors] [status-im.ui.components.colors :as colors]
[status-im.ui.components.toolbar :as toolbar] [status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.badge :as badge]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.screens.communities.icon :as communities.icon] [status-im.ui.screens.communities.icon :as communities.icon]
[quo.design-system.colors :as quo.colors])) [quo.design-system.colors :as quo.colors]))
@ -20,14 +21,19 @@
(>evt event)) (>evt event))
(defn community-unviewed-count [id] (defn community-unviewed-count [id]
(when-not (zero? (<sub [:communities/unviewed-count id])) (let [{:keys [unviewed-messages-count unviewed-mentions-count]} (<sub [:communities/unviewed-counts id])]
[react/view {:style {:background-color colors/blue (cond
:border-radius 6 (pos? unviewed-mentions-count)
:margin-right 5 [badge/message-counter unviewed-mentions-count]
:margin-top 2
:width 12 (pos? unviewed-messages-count)
:height 12} [react/view {:style {:background-color colors/blue
:accessibility-label :unviewed-messages-public}])) :border-radius 6
:margin-right 5
:margin-top 2
:width 12
:height 12}
:accessibility-label :unviewed-messages-public}])))
(defn community-home-list-item [{:keys [id name last?] :as community}] (defn community-home-list-item [{:keys [id name last?] :as community}]
[react/touchable-opacity {:style (merge {:height 64} [react/touchable-opacity {:style (merge {:height 64}
@ -56,6 +62,7 @@
name]] name]]
[react/view {:flex-direction :row [react/view {:flex-direction :row
:flex 1 :flex 1
:margin-right 15
:justify-content :flex-end :justify-content :flex-end
:align-items :center} :align-items :center}
[community-unviewed-count id]]]]]) [community-unviewed-count id]]]]])

View File

@ -115,12 +115,20 @@
(fn [timestamp] (fn [timestamp]
(string/upper-case (time/to-short-str timestamp))))) (string/upper-case (time/to-short-str timestamp)))))
(defn unviewed-indicator [{:keys [unviewed-messages-count public?]}] (defn unviewed-indicator [{:keys [unviewed-mentions-count
unviewed-messages-count
public?]}]
(when (pos? unviewed-messages-count) (when (pos? unviewed-messages-count)
[react/view {:position :absolute :right 16 :bottom 12} [react/view {:position :absolute :right 16 :bottom 12}
(if public? (cond
(and public? (not (pos? unviewed-mentions-count)))
[react/view {:style styles/public-unread [react/view {:style styles/public-unread
:accessibility-label :unviewed-messages-public}] :accessibility-label :unviewed-messages-public}]
(and public? (pos? unviewed-mentions-count))
[badge/message-counter unviewed-mentions-count]
:else
[badge/message-counter unviewed-messages-count])])) [badge/message-counter unviewed-messages-count])]))
(defn icon-style [] (defn icon-style []

View File

@ -2,7 +2,7 @@
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead", "_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
"owner": "status-im", "owner": "status-im",
"repo": "status-go", "repo": "status-go",
"version": "v0.79.5", "version": "v0.79.6",
"commit-sha1": "dfd46680879954fed29f18863354139d3d2ff34b", "commit-sha1": "c74c9eedfd16ba06d6076b79f87e4401b19ab621",
"src-sha256": "0v5v32zvazcr1fnv8j08pknwz7567i6brhyr51x42al1an9jdkqj" "src-sha256": "1g0z0inr8qp2964xkas4365d8v9shh9c8mwrbhhrkdd1yl6ggy4b"
} }