feat: autocomplete mentions new ui (#14142)

* feat: autocomplete mentions new ui
This commit is contained in:
Omar Basem 2022-10-13 21:59:19 +04:00 committed by GitHub
parent 7368478033
commit 5492d502fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 83 deletions

View File

@ -6,9 +6,10 @@
[quo.platform :as platform] [quo.platform :as platform]
[quo.components.text :as text] [quo.components.text :as text]
[quo.design-system.colors :as colors] [quo.design-system.colors :as colors]
[quo2.foundations.colors :as quo2.colors]
[status-im.ui.screens.chat.components.style :as styles] [status-im.ui.screens.chat.components.style :as styles]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.utils.handlers :refer [<sub]] [status-im.utils.handlers :refer [<sub >evt]]
[status-im.ui.screens.chat.components.reply :as reply] [status-im.ui.screens.chat.components.reply :as reply]
[status-im.multiaccounts.core :as multiaccounts] [status-im.multiaccounts.core :as multiaccounts]
[status-im.chat.constants :as chat.constants] [status-im.chat.constants :as chat.constants]
@ -331,13 +332,15 @@
[idx item]) [idx item])
@(re-frame/subscribe [:chat/input-with-mentions]))] @(re-frame/subscribe [:chat/input-with-mentions]))]
^{:key (str idx "_" type "_" text)} ^{:key (str idx "_" type "_" text)}
[rn/text (when (= type :mention) {:style {:color "#0DA4C9"}}) [rn/text (when (= type :mention) {:style {:color quo2.colors/primary-50}}) text])
text])
(get @input-texts chat-id))])) (get @input-texts chat-id))]))
(defn mention-item (defn mention-item
[[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref] [[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref]
(let [ens-name? (not= alias name)] (let [ens-name? (not= alias name)]
[rn/touchable-opacity
{:on-press #(re-frame/dispatch [:chat.ui/select-mention text-input-ref user])}
[list-item/list-item [list-item/list-item
(cond-> {:icon [photos/member-photo public-key] (cond-> {:icon [photos/member-photo public-key]
:size :small :size :small
@ -361,17 +364,14 @@
(when ens-name? (when ens-name?
"@") "@")
name])] name])]
:title-text-weight :medium :title-text-weight :medium}
:on-press
(fn []
(re-frame/dispatch [:chat.ui/select-mention text-input-ref user]))}
ens-name? ens-name?
(assoc :subtitle alias))])) (assoc :subtitle alias))]]))
(def chat-toolbar-height (reagent/atom nil)) (def chat-toolbar-height (reagent/atom nil))
(defn autocomplete-mentions [text-input-ref bottom] (defn autocomplete-mentions-old [text-input-ref bottom]
(let [suggestions @(re-frame/subscribe [:chat/mention-suggestions])] (let [suggestions @(re-frame/subscribe [:chat/mention-suggestions])]
(when (seq suggestions) (when (seq suggestions)
(let [height (+ 16 (* 52 (min 4.5 (count suggestions))))] (let [height (+ 16 (* 52 (min 4.5 (count suggestions))))]
@ -389,6 +389,22 @@
:render-data text-input-ref :render-data text-input-ref
:render-fn mention-item}]]])))) :render-fn mention-item}]]]))))
(defn autocomplete-mentions [suggestions]
[:f>
(fn []
(let [animation (reanimated/use-shared-value 0)]
(quo.react/effect! #(do
(reanimated/set-shared-value animation (reanimated/with-timing (if (seq suggestions) 0 200)))))
[reanimated/view {:style (reanimated/apply-animations-to-style
{:transform [{:translateY animation}]}
{:bottom 0 :position :absolute :z-index 5 :max-height 180})}
[list/flat-list
{:keyboardShouldPersistTaps :always
:data suggestions
:key-fn first
:render-fn mention-item
:content-container-style {:padding-bottom 12}}]]))])
(defn on-chat-toolbar-layout [^js ev] (defn on-chat-toolbar-layout [^js ev]
(reset! chat-toolbar-height (-> ev .-nativeEvent .-layout .-height))) (reset! chat-toolbar-height (-> ev .-nativeEvent .-layout .-height)))
@ -475,6 +491,21 @@
(swap! context assoc :state :min) (swap! context assoc :state :min)
min-y))) min-y)))
(defn calculate-y-with-mentions [y max-y max-height chat-id suggestions reply]
(let [input-text (:input-text (get (<sub [:chat/inputs]) chat-id))
num-lines (count (string/split input-text "\n"))
text-height (* num-lines 22)
mentions-height (min 132 (+ 16 (* 46 (- (count suggestions) 1))))
should-translate (if (< (- max-height text-height) mentions-height) true false)
min-value (if-not reply mentions-height (+ mentions-height 44))
; translate value when mentions list appear while at bottom of expanded input sheet
mentions-translate-value (if should-translate (min min-value (- mentions-height (- max-height text-height))) mentions-height)]
(when (or (< y max-y) should-translate) mentions-translate-value)))
(defn get-y-value [context keyboard-shown min-y max-y added-value max-height chat-id suggestions reply]
(let [y (calculate-y context keyboard-shown min-y max-y added-value)]
y (+ y (when (seq suggestions) (calculate-y-with-mentions y max-y max-height chat-id suggestions reply)))))
(defn get-bottom-sheet-gesture [context translate-y text-input-ref keyboard-shown min-y max-y shared-height max-height bg-opacity] (defn get-bottom-sheet-gesture [context translate-y text-input-ref keyboard-shown min-y max-y shared-height max-height bg-opacity]
(-> (gesture/gesture-pan) (-> (gesture/gesture-pan)
(gesture/on-start (gesture/on-start
@ -564,18 +595,17 @@
[:f> [:f>
(fn [] (fn []
(let [reply (<sub [:chats/reply-message]) (let [reply (<sub [:chats/reply-message])
suggestions (<sub [:chat/mention-suggestions])
{window-height :height} (rn/use-window-dimensions) {window-height :height} (rn/use-window-dimensions)
{:keys [keyboard-shown keyboard-height]} (rn/use-keyboard) {:keys [keyboard-shown keyboard-height]} (rn/use-keyboard)
max-y (- window-height (if (> keyboard-height 0) keyboard-height 360) (:top insets)) ; 360 - default height max-y (- window-height (if (> keyboard-height 0) keyboard-height 360) (:top insets)) ; 360 - default height
max-height (- max-y 56 (:bottom insets)) ; 56 - top-bar height max-height (- max-y 56 (:bottom insets)) ; 56 - top-bar height
added-value (if reply 38 0) ; increased height of input box needed when reply added-value (if (and (not (seq suggestions)) reply) 38 0) ; increased height of input box needed when reply
min-y (+ min-y added-value) min-y (+ min-y (when reply 38))
y (calculate-y context keyboard-shown min-y max-y added-value) y (get-y-value context keyboard-shown min-y max-y added-value max-height chat-id suggestions reply)
translate-y (reanimated/use-shared-value 0) translate-y (reanimated/use-shared-value 0)
shared-height (reanimated/use-shared-value min-y) shared-height (reanimated/use-shared-value min-y)
bg-opacity (reanimated/use-shared-value 0) bg-opacity (reanimated/use-shared-value 0)
input-content-change (get-input-content-change context translate-y shared-height max-height input-content-change (get-input-content-change context translate-y shared-height max-height
bg-opacity keyboard-shown min-y max-y) bg-opacity keyboard-shown min-y max-y)
bottom-sheet-gesture (get-bottom-sheet-gesture context translate-y (:text-input-ref refs) keyboard-shown bottom-sheet-gesture (get-bottom-sheet-gesture context translate-y (:text-input-ref refs) keyboard-shown
@ -607,6 +637,7 @@
:refs refs :refs refs
:set-active-panel #()}]]]] :set-active-panel #()}]]]]
;CONTROLS ;CONTROLS
(when-not (seq suggestions)
[rn/view {:style (styles/new-bottom-sheet-controls insets)} [rn/view {:style (styles/new-bottom-sheet-controls insets)}
[quo2.button/button {:icon true :type :outline :size 32} :main-icons2/image] [quo2.button/button {:icon true :type :outline :size 32} :main-icons2/image]
[rn/view {:width 12}] [rn/view {:width 12}]
@ -617,9 +648,10 @@
[quo2.button/button {:icon true :size 32 :accessibility-label :send-message-button [quo2.button/button {:icon true :size 32 :accessibility-label :send-message-button
:on-press #(do (swap! context assoc :clear true) :on-press #(do (swap! context assoc :clear true)
(clear-input chat-id refs) (clear-input chat-id refs)
(re-frame/dispatch [:chat.ui/send-current-message]))} (>evt [:chat.ui/send-current-message]))}
:main-icons2/arrow-up]]] :main-icons2/arrow-up]]])
;black background ;black background
[reanimated/view {:style (reanimated/apply-animations-to-style [reanimated/view {:style (reanimated/apply-animations-to-style
{:opacity bg-opacity} {:opacity bg-opacity}
(styles/new-bottom-sheet-background window-height))}]]))])))]) (styles/new-bottom-sheet-background window-height))}]
[autocomplete-mentions suggestions]]))])))])

View File

@ -143,7 +143,8 @@
:bottom bottom :bottom bottom
:background-color (colors/get-color :ui-background) :background-color (colors/get-color :ui-background)
:border-top-width 1 :border-top-width 1
:border-top-color (colors/get-color :ui-01)}) :border-top-color (colors/get-color :ui-01)
:z-index 3})
(defn new-input-bottom-sheet [window-height] (defn new-input-bottom-sheet [window-height]
(merge {:border-top-left-radius 20 (merge {:border-top-left-radius 20
@ -155,7 +156,7 @@
:height window-height :height window-height
:flex 1 :flex 1
:background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90) :background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90)
:z-index 1000} :z-index 2}
(if platform/ios? (if platform/ios?
{:shadow-radius 16 {:shadow-radius 16
:shadow-opacity 1 :shadow-opacity 1
@ -176,7 +177,7 @@
{:flex-direction :row {:flex-direction :row
:padding-horizontal 20 :padding-horizontal 20
:elevation 2 :elevation 2
:z-index 2000 :z-index 2
:position :absolute :position :absolute
:background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90) :background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90)
;these 3 props play together, we need this magic to hide message text in the safe area ;these 3 props play together, we need this magic to hide message text in the safe area
@ -192,4 +193,4 @@
:bottom 0 :bottom 0
:height window-height :height window-height
:background-color quo2.colors/neutral-95-opa-70 :background-color quo2.colors/neutral-95-opa-70
:z-index 500}) :z-index 1})

View File

@ -12,6 +12,9 @@
[status-im.react-native.resources :as resources] [status-im.react-native.resources :as resources]
[status-im.ui.components.animation :as animation] [status-im.ui.components.animation :as animation]
[status-im.ui.components.fast-image :as fast-image] [status-im.ui.components.fast-image :as fast-image]
[status-im.utils.handlers :refer [>evt]]
[quo2.foundations.colors :as quo2.colors]
[quo2.foundations.typography :as typography]
[status-im.ui.components.icons.icons :as icons] [status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.screens.chat.bottom-sheets.context-drawer :as message-context-drawer] [status-im.ui.screens.chat.bottom-sheets.context-drawer :as message-context-drawer]
@ -131,13 +134,14 @@
destination]) destination])
"mention" "mention"
(conj acc [react/text-class (conj acc
{:style {:color (cond [react/view {:style {:background-color quo2.colors/primary-50-opa-10 :border-radius 6 :padding-horizontal 3}}
(= content-type constants/content-type-system-text) colors/black [react/text-class
:else colors/mention-incoming)} {:style (merge {:color (if (= content-type constants/content-type-system-text) colors/black (:text-04 @colors/theme))}
(if (= content-type constants/content-type-system-text) typography/font-regular typography/font-medium))
:on-press (when-not (= content-type constants/content-type-system-text) :on-press (when-not (= content-type constants/content-type-system-text)
#(re-frame/dispatch [:chat.ui/show-profile literal]))} #(>evt [:chat.ui/show-profile literal]))}
[mention-element literal]]) [mention-element literal]]])
"status-tag" "status-tag"
(conj acc [react/text-class (conj acc [react/text-class
{:style {:color colors/blue {:style {:color colors/blue
@ -706,7 +710,7 @@
[message-content-wrapper message [message-content-wrapper message
[unknown-content-type message]]) [unknown-content-type message]])
(defn chat-message [{:keys [display-photo? pinned pinned-by] :as message}] (defn chat-message [{:keys [display-photo? pinned pinned-by mentioned] :as message}]
(let [reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message) (:chat-id message)]) (let [reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message) (:chat-id message)])
own-reactions (reduce (fn [acc {:keys [emoji-id own]}] own-reactions (reduce (fn [acc {:keys [emoji-id own]}]
(if own (conj acc emoji-id) acc)) (if own (conj acc emoji-id) acc))
@ -733,7 +737,7 @@
(into #{} (js->clj own-reactions)) (into #{} (js->clj own-reactions))
#(on-emoji-press %))}])) #(on-emoji-press %))}]))
on-long-press (atom nil)] on-long-press (atom nil)]
[:<> [react/view {:style (merge (when mentioned {:background-color quo2.colors/primary-50-opa-5 :border-radius 16 :margin-bottom 4}) {:margin-horizontal 8})}
[->message message {:ref on-long-press [->message message {:ref on-long-press
:modal false :modal false
:on-long-press on-open-drawer}] :on-long-press on-open-drawer}]

View File

@ -127,7 +127,7 @@
(defn message-author-userpic [] (defn message-author-userpic []
(merge (merge
{:width (+ 16 photos/default-size)} ;; 16 is for the padding {:width (+ 16 photos/default-size)} ;; 16 is for the padding
{:padding-left 8 {:padding-left 0
:padding-right 8})) :padding-right 8}))
(def delivery-text (def delivery-text
@ -171,21 +171,8 @@
:flex-direction :row-reverse}) :flex-direction :row-reverse})
(defn message-view (defn message-view
[{:keys [content-type mentioned pinned]}] [{:keys [content-type]}]
(merge (merge
{:border-radius 10}
(cond
pinned {:background-color colors/pin-background}
(= content-type constants/content-type-system-text) nil
mentioned {:background-color colors/mentioned-background
:border-color colors/mentioned-border
:border-width 1}
(= content-type constants/content-type-audio) {:background-color colors/blue
:padding-horizontal 12
:padding-top 6}
:else {:background-color colors/white})
(when (= content-type constants/content-type-emoji) (when (= content-type constants/content-type-emoji)
{:flex-direction :row}))) {:flex-direction :row})))

View File

@ -602,7 +602,7 @@
[accessory/view {:y position-y [accessory/view {:y position-y
:on-update-inset on-update} :on-update-inset on-update}
[invitation-bar chat-id]]) [invitation-bar chat-id]])
[components/autocomplete-mentions text-input-ref max-bottom-space] [components/autocomplete-mentions-old text-input-ref max-bottom-space]
(when show-input? (when show-input?
;; NOTE: this only accepts two children ;; NOTE: this only accepts two children
[accessory/view {:y position-y [accessory/view {:y position-y