Reply component in chat input & quoted message redesign

Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
Brian Sztamfater 2022-07-21 18:43:17 -03:00
parent a08c7ff22e
commit 647dfc7e21
No known key found for this signature in database
GPG Key ID: 59EB921E0706B48F
11 changed files with 169 additions and 108 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

View File

@ -16,7 +16,7 @@
[rn/view {:style {:flex-direction :row}}
[rn/view {}
[icons/icon :tiny-icons/tiny-edit {:container-style {:margin-top 5}}]]
[rn/view {:style (styles/reply-content)}
[rn/view {:style (styles/reply-content-old)}
[quo/text {:weight :medium
:number-of-lines 1}
(i18n/label :t/editing-message)]]

View File

@ -9,14 +9,19 @@
[status-im.ethereum.stateofus :as stateofus]
[status-im.ui.screens.chat.components.style :as styles]
[re-frame.core :as re-frame]
[clojure.string :as string]))
[clojure.string :as string]
[quo2.foundations.colors :as quo2.colors :refer [theme-colors]]
[quo2.components.button :as quo2.button]
[quo2.components.text :as quo2.text]
[status-im.ui.screens.chat.photos :as photos]
[status-im.constants :as constants]))
(def ^:private reply-symbol "↪ ")
(defn input-focus [text-input-ref]
(some-> ^js (quo.react/current-ref text-input-ref) .focus))
(defn format-author [contact-name]
(defn format-author-old [contact-name]
(let [author (if (or (= (aget contact-name 0) "@")
;; in case of replies
(= (aget contact-name 1) "@"))
@ -25,10 +30,24 @@
contact-name)]
(i18n/label :replying-to {:author author})))
(defn format-reply-author [from username current-public-key]
(defn format-author [contact-name]
(let [author (if (or (= (aget contact-name 0) "@")
;; in case of replies
(= (aget contact-name 1) "@"))
(or (stateofus/username contact-name)
(subs contact-name 0 81))
contact-name)]
author))
(defn format-reply-author-old [from username current-public-key]
(or (and (= from current-public-key)
(str reply-symbol (i18n/label :t/You)))
(str reply-symbol (format-author username))))
(str reply-symbol (format-author-old username))))
(defn format-reply-author [from username current-public-key]
(or (and (= from current-public-key)
(i18n/label :t/You))
(format-author username)))
(defn get-quoted-text-with-mentions [parsed-text]
(string/join
@ -47,21 +66,62 @@
literal))
parsed-text)))
(defn reply-message [{:keys [from]}]
(defn reply-message-old [{:keys [from]}]
(let [contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])
current-public-key @(re-frame/subscribe [:multiaccount/public-key])]
[rn/view {:style {:flex-direction :row}}
[rn/view {:style (styles/reply-content)}
[rn/view {:style (styles/reply-content-old)}
[quo/text {:weight :medium
:number-of-lines 1
:style {:line-height 18}}
(format-reply-author from contact-name current-public-key)]]
(format-reply-author-old from contact-name current-public-key)]]
[rn/view
[pressable/pressable {:on-press #(re-frame/dispatch [:chat.ui/cancel-message-reply])
:accessibility-label :cancel-message-reply}
[icons/icon :main-icons/close-circle {:container-style (styles/close-button)
:color (:icon-02 @quo.colors/theme)}]]]]))
(defn reply-message [{:keys [from identicon content-type contentType parsed-text content]} in-chat-input?]
(let [contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])
current-public-key @(re-frame/subscribe [:multiaccount/public-key])
content-type (or content-type contentType)]
[rn/view {:style {:flex-direction :row :height 24}}
[rn/view {:style (styles/reply-content)}
[icons/icon :main-icons/connector {:color (theme-colors quo2.colors/neutral-40 quo2.colors/neutral-60)
:container-style {:position :absolute :left 10 :bottom -4 :width 16 :height 16}}]
[rn/view {:style {:position :absolute :left 34 :right 54 :top 3 :flex-direction :row :align-items :center}}
[photos/member-photo from identicon 16]
[quo2.text/text {:weight :semi-bold
:size :paragraph-2
:number-of-lines 1
:style {:margin-left 4}}
(format-reply-author from contact-name current-public-key)]
[quo2.text/text {:number-of-lines 1
:size :label
:weight :regular
:style (merge {:ellipsize-mode :tail
:text-transform :none
:margin-left 4
:margin-top 2}
(when (or (= constants/content-type-image content-type)
(= constants/content-type-sticker content-type)
(= constants/content-type-audio content-type))
{:color (theme-colors quo2.colors/neutral-50 quo2.colors/neutral-40)}))}
(case (or content-type contentType)
constants/content-type-image "Image"
constants/content-type-sticker "Sticker"
constants/content-type-audio "Audio"
(get-quoted-text-with-mentions (or parsed-text (:parsed-text content))))]]]
(when in-chat-input?
[quo2.button/button {:width 24
:size 24
:type :outline
:accessibility-label :reply-cancel-button
:on-press #(re-frame/dispatch [:chat.ui/cancel-message-reply])}
[icons/icon :main-icons/close {:width 16
:height 16
:color (theme-colors quo2.colors/black quo2.colors/neutral-40)}]])]))
(defn send-image [images]
[rn/view {:style (styles/reply-container-image)}
[rn/scroll-view {:horizontal true
@ -86,12 +146,27 @@
(when reply
(js/setTimeout #(input-focus text-input-ref) 250))))
(defn reply-message-wrapper-old [reply]
[rn/view {:style {:padding-horizontal 15
:border-top-width 1
:border-top-color (:ui-01 @quo.colors/theme)
:padding-vertical 8}}
[reply-message-old reply]])
(defn reply-message-wrapper [reply]
[rn/view {:style {:padding-horizontal 15
:border-top-width 1
:border-top-color (:ui-01 @quo.colors/theme)
:padding-vertical 8}}
[reply-message reply]])
[reply-message reply true]])
(defn reply-message-auto-focus-wrapper-old [text-input-ref]
(let [had-reply (atom nil)]
(fn []
(let [reply @(re-frame/subscribe [:chats/reply-message])]
(focus-input-on-reply reply had-reply text-input-ref)
(when reply
[reply-message-wrapper-old reply])))))
(defn reply-message-auto-focus-wrapper [text-input-ref]
(let [had-reply (atom nil)]

View File

@ -87,11 +87,16 @@
(defn reply-container []
{:flex-direction :row})
(defn reply-content []
(defn reply-content-old []
{:padding-vertical 6
:padding-horizontal 10
:flex 1})
(defn reply-content []
{:padding-horizontal 10
:flex 1
:flex-direction :row})
(defn contact-request-content []
{:flex 1
:flex-direction :row

View File

@ -87,27 +87,9 @@
timestamp-str]])))
(defview quoted-message
[_ {:keys [from parsed-text image]} current-public-key public? pinned]
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
[react/view {:style (style/quoted-message-container)}
[react/view {:style style/quoted-message-author-container}
[chat.utils/format-reply-author
from
contact-name
current-public-key
(partial style/quoted-message-author (not pinned))
false]]
(if (and image
;; Disabling images for public-chats
(not public?))
[fast-image/fast-image {:style {:width 56
:height 56
:background-color :black
:border-radius 4}
:source {:uri image}}]
[react/text {:style (style/quoted-message-text)
:number-of-lines 5}
(components.reply/get-quoted-text-with-mentions parsed-text)])]))
[_ reply]
[react/view {:style (style/quoted-message-container)}
[components.reply/reply-message reply false]])
(defn render-inline [message-text content-type acc {:keys [type literal destination]}]
(case type
@ -312,37 +294,40 @@
identicon
from in-popover? timestamp-str]
:as message} content {:keys [modal close-modal]}]
[react/view {:style (style/message-wrapper message)
:pointer-events :box-none
:accessibility-label :chat-item}
[react/view {:style (style/message-body)
:pointer-events :box-none}
[react/view (style/message-author-userpic)
(when last-in-group?
[react/touchable-highlight {:on-press #(do (when modal (close-modal))
(re-frame/dispatch [:chat.ui/show-profile from]))}
[photos/member-photo from identicon]])]
[react/view {:style (style/message-author-wrapper)}
(when last-in-group?
[react/view {:style {:flex-direction :row :align-items :center}}
[react/touchable-opacity {:style style/message-author-touchable
:disabled in-popover?
:on-press #(do (when modal (close-modal))
(re-frame/dispatch [:chat.ui/show-profile from]))}
[message-author-name from {:modal modal}]]
[react/text
{:style (merge
{:padding-left 5
:margin-top 2}
(style/message-timestamp-text))
:accessibility-label :message-timestamp}
timestamp-str]])
(let [response-to (:response-to (:content message))]
[react/view {:style (style/message-wrapper message)
:pointer-events :box-none
:accessibility-label :chat-item}
(when (and (seq response-to) (:quoted-message message))
[quoted-message response-to (:quoted-message message)])
[react/view {:style (style/message-body)
:pointer-events :box-none}
[react/view (style/message-author-userpic)
(when (or (and (seq response-to) (:quoted-message message)) last-in-group?)
[react/touchable-highlight {:on-press #(do (when modal (close-modal))
(re-frame/dispatch [:chat.ui/show-profile from]))}
[photos/member-photo from identicon]])]
[react/view {:style (style/message-author-wrapper)}
(when (or (and (seq response-to) (:quoted-message message)) last-in-group?)
[react/view {:style {:flex-direction :row :align-items :center}}
[react/touchable-opacity {:style style/message-author-touchable
:disabled in-popover?
:on-press #(do (when modal (close-modal))
(re-frame/dispatch [:chat.ui/show-profile from]))}
[message-author-name from {:modal modal}]]
[react/text
{:style (merge
{:padding-left 5
:margin-top 2}
(style/message-timestamp-text))
:accessibility-label :message-timestamp}
timestamp-str]])
;;MESSAGE CONTENT
content
[link-preview/link-preview-wrapper (:links (:content message)) false false]]]
content
[link-preview/link-preview-wrapper (:links (:content message)) false false]]]
; delivery status
[react/view (style/delivery-status)
[message-delivery-status message]]])
[react/view (style/delivery-status)
[message-delivery-status message]]]))
(def image-max-width 260)
(def image-max-height 192)
@ -449,7 +434,7 @@
(defn collapsible-text-message [_ _]
(let [collapsed? (reagent/atom false)
show-timestamp? (reagent/atom false)]
(fn [{:keys [content current-public-key public? pinned in-popover?] :as message} on-long-press modal]
(fn [{:keys [content in-popover?] :as message} on-long-press modal]
[react/touchable-highlight
(when-not modal
{:on-press (fn [_]
@ -466,11 +451,8 @@
[message-timestamp message show-timestamp?]
[react/view {:style (style/message-view message)}
[react/view {:style (style/message-view-content)}
(let [response-to (:response-to content)]
[react/view
(when (and (seq response-to) (:quoted-message message))
[quoted-message response-to (:quoted-message message) current-public-key public? pinned])
[render-parsed-text-with-message-status message (:parsed-text content)]])]]]])))
[react/view
[render-parsed-text-with-message-status message (:parsed-text content)]]]]]])))
(defmethod ->message constants/content-type-text
[message {:keys [on-long-press modal] :as reaction-picker}]
@ -494,39 +476,36 @@
(defmethod ->message constants/content-type-emoji []
(let [show-timestamp? (reagent/atom false)]
(fn [{:keys [content current-public-key outgoing public? pinned in-popover? message-pin-enabled] :as message}
(fn [{:keys [content pinned in-popover? message-pin-enabled] :as message}
{:keys [on-long-press modal]
:as reaction-picker}]
(let [response-to (:response-to content)]
[message-content-wrapper message
[react/touchable-highlight (when-not modal
{:disabled in-popover?
:on-press (fn []
(react/dismiss-keyboard!)
(reset! show-timestamp? true))
:delay-long-press 100
:on-long-press (fn []
(on-long-press
(concat
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
:id :reply
:label (i18n/label :t/message-reply)}
{:on-press #(react/copy-to-clipboard (get content :text))
:id :copy
:label (i18n/label :t/sharing-copy-to-clipboard)}]
(when message-pin-enabled [{:on-press #(pin-message message)
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))})
[react/view style/message-view-wrapper
[message-timestamp message show-timestamp?]
[react/view (style/message-view message)
[react/view {:style (style/message-view-content)}
[react/view {:style (style/style-message-text)}
(when (and (seq response-to) (:quoted-message message))
[quoted-message response-to (:quoted-message message) outgoing current-public-key public? pinned])
[react/text {:style (style/emoji-message message)}
(:text content)]]
[message-status message]]]]]
reaction-picker]))))
[message-content-wrapper message
[react/touchable-highlight (when-not modal
{:disabled in-popover?
:on-press (fn []
(react/dismiss-keyboard!)
(reset! show-timestamp? true))
:delay-long-press 100
:on-long-press (fn []
(on-long-press
(concat
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
:id :reply
:label (i18n/label :t/message-reply)}
{:on-press #(react/copy-to-clipboard (get content :text))
:id :copy
:label (i18n/label :t/sharing-copy-to-clipboard)}]
(when message-pin-enabled [{:on-press #(pin-message message)
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))})
[react/view style/message-view-wrapper
[message-timestamp message show-timestamp?]
[react/view (style/message-view message)
[react/view {:style (style/message-view-content)}
[react/view {:style (style/style-message-text)}
[react/text {:style (style/emoji-message message)}
(:text content)]]
[message-status message]]]]]
reaction-picker])))
(defmethod ->message constants/content-type-sticker
[{:keys [content from outgoing in-popover?]

View File

@ -24,10 +24,15 @@
[memo-photo-rend photo-path size accessibility-label (colors/dark?)])
;; We optionally pass identicon for perfomance reason, so it does not have to be calculated for each message
(defn member-photo [pub-key identicon]
(let [path @(re-frame/subscribe [:chats/photo-path pub-key identicon])]
[photo path {:size style/default-size
:accessibility-label :member-photo}]))
(defn member-photo
([pub-key]
(member-photo pub-key nil))
([pub-key identicon]
(member-photo pub-key identicon style/default-size))
([pub-key identicon size]
(let [path @(re-frame/subscribe [:chats/photo-path pub-key identicon])]
[photo path {:size size
:accessibility-label :member-photo}])))
(defn account-photo [account]
(let [path (multiaccounts/displayed-photo account)]

View File

@ -209,12 +209,9 @@
:text-align-vertical :center})
(defn quoted-message-container []
{:margin-bottom 6
:padding-bottom 6
:border-bottom-color colors/black-transparent
:border-bottom-width 2
:border-bottom-left-radius 2
:border-bottom-right-radius 2})
{:margin-bottom 6
:margin-top 5
:padding-horizontal 15})
(def quoted-message-author-container
{:flex-direction :row

View File

@ -588,7 +588,7 @@
:on-update-inset on-update}
[react/view
[edit/edit-message-auto-focus-wrapper text-input-ref]
[reply/reply-message-auto-focus-wrapper text-input-ref]
[reply/reply-message-auto-focus-wrapper-old text-input-ref]
;; We set the key so we can force a re-render as
;; it does not rely on ratom but just atoms
^{:key (str @components/chat-input-key "chat-input")}