[Fixes: #10471] Parse markdown in chat subheader.

This commit adds parsing of markdown in the chat subheader.

Because of the added complexity performance are impacted but I have
also noticed that on each loading of the chat screen we calculate
alias & identicon through status-go, so that has been changed so that
they are returned from status-go.

Overall performance is now roughly identical, tested loading 150
one-to-one chats.

Another issue that I've spotted is that some `subs` are unnecessarely
recalculated (`active-chats`), when unrelated fields changes. I will
address this in a separate PR that should improve performance.

Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Andrea Maria Piana 2020-05-20 16:27:11 +02:00
parent d0216674da
commit 34755500d5
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
5 changed files with 89 additions and 34 deletions

View File

@ -1,10 +1,10 @@
(ns status-im.chat.db (ns status-im.chat.db
(:require [clojure.set :as clojure.set] (:require [clojure.set :as clojure.set]
[clojure.string :as clojure.string] [clojure.string :as clojure.string]
[status-im.contact.db :as contact.db]
[status-im.group-chats.db :as group-chats.db] [status-im.group-chats.db :as group-chats.db]
[status-im.mailserver.constants :as mailserver.constants] [status-im.mailserver.constants :as mailserver.constants]
[status-im.multiaccounts.core :as multiaccounts] [status-im.multiaccounts.core :as multiaccounts]
[status-im.utils.identicon :as identicon]
[status-im.utils.gfycat.core :as gfycat])) [status-im.utils.gfycat.core :as gfycat]))
(defn group-chat-name (defn group-chat-name
@ -12,7 +12,10 @@
(str (when public? "#") name)) (str (when public? "#") name))
(defn enrich-active-chat (defn enrich-active-chat
[contacts {:keys [chat-id group-chat] :as chat} current-public-key] [contacts {:keys [chat-id
identicon
alias
group-chat] :as chat} current-public-key]
(if group-chat (if group-chat
(let [pending-invite-inviter-name (let [pending-invite-inviter-name
(group-chats.db/get-pending-invite-inviter-name contacts (group-chats.db/get-pending-invite-inviter-name contacts
@ -29,15 +32,25 @@
(assoc :inviter-name inviter-name) (assoc :inviter-name inviter-name)
:always :always
(assoc :chat-name (group-chat-name chat)))) (assoc :chat-name (group-chat-name chat))))
(let [{contact-name :name :as contact} (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 (get contacts chat-id
(contact.db/public-key->new-contact chat-id)) {:public-key chat-id
random-name (gfycat/generate-gfy chat-id)] :identicon photo
:alias alias
:name alias
:system-tags #{}})]
(-> chat (-> chat
(assoc :contact contact (assoc :contact contact
:chat-name (multiaccounts/displayed-name contact) :chat-name (multiaccounts/displayed-name contact)
:name contact-name :name contact-name
:random-name random-name) :identicon photo
:alias alias)
(update :tags clojure.set/union (:tags contact)))))) (update :tags clojure.set/union (:tags contact))))))
(defn active-chats (defn active-chats

View File

@ -4,16 +4,16 @@
(deftest filter-chats (deftest filter-chats
(let [chats {:chat-1 {:name "name1" (let [chats {:chat-1 {:name "name1"
:random-name "random-name1" :alias "alias1"
:tags #{"tag1"}} :tags #{"tag1"}}
:chat-2 {:name "name2" :chat-2 {:name "name2"
:random-name "random-name2" :alias "alias2"
:tags #{"tag2" "tag3"}} :tags #{"tag2" "tag3"}}
:chat-3 {:name "name3" :chat-3 {:name "name3"
:random-name "random-name3" :alias "alias3"
:tags #{}} :tags #{}}
:chat-4 {:name "name4" :chat-4 {:name "name4"
:random-name "random-name4" :alias "alias4"
:tags #{"tag4"}}}] :tags #{"tag4"}}}]
(testing "no search filter" (testing "no search filter"
(is (= (count chats) (is (= (count chats)
@ -33,15 +33,15 @@
chats chats
search.subs/extract-chat-attributes search.subs/extract-chat-attributes
false))))) false)))))
(testing "searching for a specific random-name" (testing "searching for a specific alias"
(is (= 1 (is (= 1
(count (search.subs/apply-filter "random-name1" (count (search.subs/apply-filter "alias4"
chats chats
search.subs/extract-chat-attributes search.subs/extract-chat-attributes
false))))) false)))))
(testing "searching for a partial random-name" (testing "searching for a partial alias"
(is (= 4 (is (= 4
(count (search.subs/apply-filter "random-name" (count (search.subs/apply-filter "alias"
chats chats
search.subs/extract-chat-attributes search.subs/extract-chat-attributes
false))))) false)))))

View File

@ -1786,8 +1786,8 @@
;;SEARCH ============================================================================================================== ;;SEARCH ==============================================================================================================
(defn extract-chat-attributes [chat] (defn extract-chat-attributes [chat]
(let [{:keys [name random-name tags]} (val chat)] (let [{:keys [name alias tags]} (val chat)]
(into [name random-name] tags))) (into [name alias] tags)))
(defn sort-by-timestamp (defn sort-by-timestamp
[coll] [coll]

View File

@ -11,7 +11,60 @@
[status-im.ui.screens.home.styles :as styles] [status-im.ui.screens.home.styles :as styles]
[status-im.utils.contenthash :as contenthash] [status-im.utils.contenthash :as contenthash]
[status-im.utils.core :as utils] [status-im.utils.core :as utils]
[status-im.utils.datetime :as time])) [status-im.utils.datetime :as time])
(: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)))
(defn render-subheader-inline [acc {:keys [type destination literal children]}]
(case type
"paragraph"
(conj acc (reduce
(fn [acc e] (render-subheader-inline acc e))
[react/text-class " "]
children))
"blockquote"
(conj acc (.substring literal 0 (dec (.-length literal))))
"codeblock"
(conj acc (.substring literal 0 (dec (.-length literal))))
"mention"
(conj acc [react/text-class
[mention-element literal]])
"status-tag"
(conj acc [react/text-class
"#"
literal])
"link"
(conj acc destination)
(conj acc literal)))
(def max-length 40)
(defn render-subheader
"Render the chat subheader markdown inline, to a maximum of max-length characters"
[parsed-text]
(:elements
(reduce
(fn [{:keys [elements l] :as acc} {:keys [literal] :as e}]
(if (> l max-length)
(reduced acc)
{:elements (render-subheader-inline elements e)
:l (+ l (count literal))}))
{:length 0
:elements
[react/text-class {:style styles/last-message-text
:number-of-lines 1
:ellipsize-mode :tail
:accessibility-label :chat-message-text}]}
parsed-text)))
(defn message-content-text [{:keys [content content-type]}] (defn message-content-text [{:keys [content content-type]}]
[react/view styles/last-message-container [react/view styles/last-message-container
@ -32,14 +85,7 @@
""] ""]
(:text content) (:text content)
[react/text {:style styles/last-message-text (render-subheader (:parsed-text content)))])
:number-of-lines 1
:ellipsize-mode :tail
:accessibility-label :chat-message-text}
;;TODO (perf) move to event
(-> (:text content)
(subs 0 40)
(string/trim-newline))])])
(defn message-timestamp [timestamp] (defn message-timestamp [timestamp]
(when timestamp (when timestamp
@ -75,12 +121,8 @@
:title-row-accessory [message-timestamp (if (pos? (:whisper-timestamp last-message)) :title-row-accessory [message-timestamp (if (pos? (:whisper-timestamp last-message))
(:whisper-timestamp last-message) (:whisper-timestamp last-message)
timestamp)] timestamp)]
:subtitle :subtitle [message-content-text {:content (:content last-message)
(let [{:keys [tribute-status tribute-label]} (:tribute-to-talk contact)]
(if (not (#{:require :pending} tribute-status))
[message-content-text {:content (:content last-message)
:content-type (:content-type last-message)}] :content-type (:content-type last-message)}]
tribute-label))
:subtitle-row-accessory [unviewed-indicator home-item] :subtitle-row-accessory [unviewed-indicator home-item]
:on-press #(do :on-press #(do
(re-frame/dispatch [:dismiss-keyboard]) (re-frame/dispatch [:dismiss-keyboard])

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.52.4", "version": "v0.53.2",
"commit-sha1": "7bbe9561de16f3bfd9675a8640212cc75410fd75", "commit-sha1": "ee0a83fdc4a19f70fa8d08347ef67c0ca3d67f1e",
"src-sha256": "1s5iv49ck152aq8d0ibr4aja3nf7s4njgmkfx4kn5ds0dy4zq533" "src-sha256": "1jv7cw6a41czhslmqxbqjw2alv9yb0ddpbxyin2l0kdpnxvph965"
} }