Top bar stability & animation improvements (#17170)

* Top bar stability improvements

Style updates

Style updates, bugfixes

* Display name update

* Style fix
This commit is contained in:
Alexander 2023-09-07 13:13:16 +02:00 committed by GitHub
parent b645686684
commit c1c8c210e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 193 additions and 165 deletions

View File

@ -9,7 +9,6 @@
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.common.alert.events :as alert] [status-im2.common.alert.events :as alert]
[status-im2.contexts.chat.composer.constants :as comp-constants] [status-im2.contexts.chat.composer.constants :as comp-constants]
[status-im2.contexts.chat.messages.list.view :as messages.list]
[status-im2.common.device-permissions :as device-permissions] [status-im2.common.device-permissions :as device-permissions]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf] [utils.re-frame :as rf]
@ -20,7 +19,9 @@
[{:keys [sending-images? sending-links?]} [{:keys [sending-images? sending-links?]}
{:keys [text-value focused? maximized?]} {:keys [text-value focused? maximized?]}
{:keys [height saved-height last-height opacity background-y container-opacity]} {:keys [height saved-height last-height opacity background-y container-opacity]}
window-height edit] window-height
edit
scroll-to-bottom-fn]
(reanimated/animate height comp-constants/input-height) (reanimated/animate height comp-constants/input-height)
(reanimated/set-shared-value saved-height comp-constants/input-height) (reanimated/set-shared-value saved-height comp-constants/input-height)
(reanimated/set-shared-value last-height comp-constants/input-height) (reanimated/set-shared-value last-height comp-constants/input-height)
@ -38,14 +39,13 @@
(reset! text-value "") (reset! text-value "")
(reset! sending-links? false) (reset! sending-links? false)
(reset! sending-images? false) (reset! sending-images? false)
(when-not (some? edit) (when (and (not (some? edit)) scroll-to-bottom-fn)
(messages.list/scroll-to-bottom))) (scroll-to-bottom-fn)))
(defn f-send-button (defn f-send-button
[props {:keys [text-value] :as state} [props state animations window-height images? btn-opacity scroll-to-bottom-fn z-index edit]
animations window-height images? (let [{:keys [text-value]} state
btn-opacity z-index edit] customization-color (rf/sub [:profile/customization-color])]
(let [customization-color (rf/sub [:profile/customization-color])]
(rn/use-effect (fn [] (rn/use-effect (fn []
(if (or (seq @text-value) images?) (if (or (seq @text-value) images?)
(when (or (not= @z-index 1) (not= (reanimated/get-shared-value btn-opacity) 1)) (when (or (not= @z-index 1) (not= (reanimated/get-shared-value btn-opacity) 1))
@ -64,13 +64,15 @@
:size 32 :size 32
:customization-color customization-color :customization-color customization-color
:accessibility-label :send-message-button :accessibility-label :send-message-button
:on-press #(send-message props state animations window-height edit)} :on-press #(send-message props state animations window-height edit scroll-to-bottom-fn)}
:i/arrow-up]])) :i/arrow-up]]))
(defn send-button (defn send-button
[props {:keys [text-value] :as state} animations window-height images? edit btn-opacity] [props {:keys [text-value] :as state} animations window-height images? edit btn-opacity
scroll-to-bottom-fn]
(let [z-index (reagent/atom (if (and (empty? @text-value) (not images?)) 0 1))] (let [z-index (reagent/atom (if (and (empty? @text-value) (not images?)) 0 1))]
[:f> f-send-button props state animations window-height images? btn-opacity z-index edit])) [:f> f-send-button props state animations window-height images? btn-opacity scroll-to-bottom-fn
z-index edit]))
(defn disabled-audio-button (defn disabled-audio-button
[opacity] [opacity]
@ -214,7 +216,7 @@
:icon :i/format}]) :icon :i/format}])
(defn view (defn view
[props state animations window-height insets {:keys [edit images]}] [props state animations window-height insets scroll-to-bottom-fn {:keys [edit images]}]
(let [send-btn-opacity (reanimated/use-shared-value 0) (let [send-btn-opacity (reanimated/use-shared-value 0)
audio-btn-opacity (reanimated/interpolate send-btn-opacity [0 1] [1 0])] audio-btn-opacity (reanimated/interpolate send-btn-opacity [0 1] [1 0])]
[rn/view {:style style/actions-container} [rn/view {:style style/actions-container}
@ -225,7 +227,8 @@
[image-button props animations insets] [image-button props animations insets]
[reaction-button] [reaction-button]
[format-button]] [format-button]]
[:f> send-button props state animations window-height images edit send-btn-opacity] [:f> send-button props state animations window-height images edit send-btn-opacity
scroll-to-bottom-fn]
(when (and (not edit) (not images)) (when (and (not edit) (not images))
;; TODO(alwx): needs to be replaced with an `audio-button` later. ;; TODO(alwx): needs to be replaced with an `audio-button` later.
;; See https://github.com/status-im/status-mobile/issues/16084 for more details. ;; See https://github.com/status-im/status-mobile/issues/16084 for more details.

View File

@ -6,7 +6,6 @@
[status-im2.config :as config] [status-im2.config :as config]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[status-im2.contexts.chat.composer.style :as style] [status-im2.contexts.chat.composer.style :as style]
[status-im2.contexts.chat.messages.list.view :as messages.list]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -25,16 +24,16 @@
[:f> f-blur-view layout-height focused?]) [:f> f-blur-view layout-height focused?])
(defn- f-shell-button (defn- f-shell-button
[{:keys [focused?]}] [{:keys [focused?]} scroll-to-bottom-fn show-floating-scroll-down-button?]
(let [customization-color (rf/sub [:profile/customization-color]) (let [customization-color (rf/sub [:profile/customization-color])
hide-shell? (or @focused? @messages.list/show-floating-scroll-down-button) hide-shell? (or @focused? @show-floating-scroll-down-button?)
y-shell (reanimated/use-shared-value (if hide-shell? 35 0)) y-shell (reanimated/use-shared-value (if hide-shell? 35 0))
opacity (reanimated/use-shared-value (if hide-shell? 0 1))] opacity (reanimated/use-shared-value (if hide-shell? 0 1))]
(rn/use-effect (rn/use-effect
(fn [] (fn []
(reanimated/animate opacity (if hide-shell? 0 1)) (reanimated/animate opacity (if hide-shell? 0 1))
(reanimated/animate y-shell (if hide-shell? 35 0))) (reanimated/animate y-shell (if hide-shell? 35 0)))
[@focused? @messages.list/show-floating-scroll-down-button]) [@focused? @show-floating-scroll-down-button?])
[:<> [:<>
[reanimated/view [reanimated/view
{:style (style/shell-button y-shell opacity)} {:style (style/shell-button y-shell opacity)}
@ -48,11 +47,11 @@
:label (i18n/label :t/jump-to) :label (i18n/label :t/jump-to)
:style {:align-self :center}}} :style {:align-self :center}}}
{}]] {}]]
(when @messages.list/show-floating-scroll-down-button (when @show-floating-scroll-down-button?
[quo/floating-shell-button [quo/floating-shell-button
{:scroll-to-bottom {:on-press messages.list/scroll-to-bottom}} {:scroll-to-bottom {:on-press scroll-to-bottom-fn}}
style/scroll-to-bottom-button])])) style/scroll-to-bottom-button])]))
(defn shell-button (defn shell-button
[state animations subscriptions] [state scroll-to-bottom-fn show-floating-scroll-down-button?]
[:f> f-shell-button state animations subscriptions]) [:f> f-shell-button state scroll-to-bottom-fn show-floating-scroll-down-button?])

View File

@ -26,7 +26,13 @@
[quo2.theme :as theme])) [quo2.theme :as theme]))
(defn sheet-component (defn sheet-component
[{:keys [insets window-height blur-height opacity background-y]} props state] [{:keys [insets
scroll-to-bottom-fn
show-floating-scroll-down-button?
window-height
blur-height
opacity
background-y]} props state]
(let [{:keys [chat-screen-loaded?] (let [{:keys [chat-screen-loaded?]
:as subscriptions} (utils/init-subs) :as subscriptions} (utils/init-subs)
content-height (reagent/atom (or (:input-content-height content-height (reagent/atom (or (:input-content-height
@ -76,7 +82,7 @@
(:edit subscriptions)]) (:edit subscriptions)])
[rn/view [rn/view
{:style style/composer-sheet-and-jump-to-container} {:style style/composer-sheet-and-jump-to-container}
[sub-view/shell-button state] [sub-view/shell-button state scroll-to-bottom-fn show-floating-scroll-down-button?]
[gesture/gesture-detector [gesture/gesture-detector
{:gesture {:gesture
(drag-gesture/drag-gesture props state animations subscriptions dimensions keyboard-shown)} (drag-gesture/drag-gesture props state animations subscriptions dimensions keyboard-shown)}
@ -127,10 +133,11 @@
[gradients/view props state animations show-bottom-gradient?] [gradients/view props state animations show-bottom-gradient?]
[link-preview/view] [link-preview/view]
[images/images-list]])] [images/images-list]])]
[:f> actions/view props state animations window-height insets subscriptions]]]]])) [:f> actions/view props state animations window-height insets scroll-to-bottom-fn
subscriptions]]]]]))
(defn composer (defn composer
[insets] [{:keys [insets scroll-to-bottom-fn show-floating-scroll-down-button?]}]
(let [window-height (:height (rn/get-window)) (let [window-height (:height (rn/get-window))
opacity (reanimated/use-shared-value 0) opacity (reanimated/use-shared-value 0)
background-y (reanimated/use-shared-value (- window-height)) background-y (reanimated/use-shared-value (- window-height))
@ -138,6 +145,8 @@
(:bottom insets))) (:bottom insets)))
extra-params {:insets insets extra-params {:insets insets
:window-height window-height :window-height window-height
:scroll-to-bottom-fn scroll-to-bottom-fn
:show-floating-scroll-down-button? show-floating-scroll-down-button?
:blur-height blur-height :blur-height blur-height
:opacity opacity :opacity opacity
:background-y background-y} :background-y background-y}

View File

@ -1,5 +1,6 @@
(ns status-im2.contexts.chat.messages.list.view (ns status-im2.contexts.chat.messages.list.view
(:require [oops.core :as oops] (:require
[oops.core :as oops]
[quo2.core :as quo] [quo2.core :as quo]
[quo2.foundations.colors :as colors] [quo2.foundations.colors :as colors]
[react-native.background-timer :as background-timer] [react-native.background-timer :as background-timer]
@ -7,7 +8,6 @@
[react-native.hooks :as hooks] [react-native.hooks :as hooks]
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.ui.screens.chat.group :as chat.group] [status-im.ui.screens.chat.group :as chat.group]
[status-im.ui.screens.chat.message.gap :as message.gap] [status-im.ui.screens.chat.message.gap :as message.gap]
@ -15,9 +15,9 @@
[status-im2.contexts.chat.messages.content.view :as message] [status-im2.contexts.chat.messages.content.view :as message]
[status-im2.contexts.chat.messages.list.state :as state] [status-im2.contexts.chat.messages.list.state :as state]
[status-im2.contexts.chat.messages.list.style :as style] [status-im2.contexts.chat.messages.list.style :as style]
[status-im2.contexts.shell.jump-to.constants :as jump-to.constants]
[status-im2.contexts.chat.composer.constants :as composer.constants] [status-im2.contexts.chat.composer.constants :as composer.constants]
[status-im2.contexts.chat.messages.navigation.style :as navigation.style] [status-im2.contexts.chat.messages.navigation.style :as navigation.style]
[status-im2.contexts.shell.jump-to.constants :as jump-to.constants]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -27,10 +27,11 @@
(defonce ^:const scroll-animation-input-range [50 125]) (defonce ^:const scroll-animation-input-range [50 125])
(defonce ^:const min-message-height 32) (defonce ^:const min-message-height 32)
(defonce extra-keyboard-height (reagent/atom 0))
(defonce messages-list-ref (atom nil)) (defonce messages-list-ref (atom nil))
(defonce messages-view-height (reagent/atom 0)) (defonce messages-view-height (reagent/atom 0))
(defonce messages-view-header-height (reagent/atom 0)) (defonce messages-view-header-height (reagent/atom 0))
(defonce show-floating-scroll-down-button (reagent/atom false)) (defonce show-floating-scroll-down-button? (reagent/atom false))
(defn list-key-fn [{:keys [message-id value]}] (or message-id value)) (defn list-key-fn [{:keys [message-id value]}] (or message-id value))
(defn list-ref [ref] (reset! messages-list-ref ref)) (defn list-ref [ref] (reset! messages-list-ref ref))
@ -48,9 +49,9 @@
threshold-height (* (/ layout-height 100) threshold-height (* (/ layout-height 100)
threshold-percentage-to-show-floating-scroll-down-button) threshold-percentage-to-show-floating-scroll-down-button)
reached-threshold? (> y threshold-height)] reached-threshold? (> y threshold-height)]
(when (not= reached-threshold? @show-floating-scroll-down-button) (when (not= reached-threshold? @show-floating-scroll-down-button?)
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets)) (rn/configure-next (:ease-in-ease-out rn/layout-animation-presets))
(reset! show-floating-scroll-down-button reached-threshold?)))) (reset! show-floating-scroll-down-button? reached-threshold?))))
(defn on-viewable-items-changed (defn on-viewable-items-changed
[e] [e]
@ -296,10 +297,9 @@
:on-viewable-items-changed on-viewable-items-changed :on-viewable-items-changed on-viewable-items-changed
:on-content-size-change (fn [_ y] :on-content-size-change (fn [_ y]
;; NOTE(alwx): here we set the initial value of `scroll-y` ;; NOTE(alwx): here we set the initial value of `scroll-y`
;; which is needed because by default the chat is scrolled to ;; which is needed because by default the chat is
;; the ;; scrolled to the bottom and no initial `on-scroll`
;; bottom ;; event is getting triggered
;; and no initial `on-scroll` event is getting triggered
(let [scroll-y-shared (reanimated/get-shared-value (let [scroll-y-shared (reanimated/get-shared-value
scroll-y) scroll-y)
content-height-shared (reanimated/get-shared-value content-height-shared (reanimated/get-shared-value
@ -360,44 +360,3 @@
[quo/skeleton-list [quo/skeleton-list
{:content :messages {:content :messages
:parent-height content-height}]]))) :parent-height content-height}]])))
(defn f-messages-list
[{:keys [chat cover-bg-color header-comp footer-comp]}]
(let [insets (safe-area/get-insets)
scroll-y (reanimated/use-shared-value 0)
content-height (reanimated/use-shared-value 0)
{:keys [keyboard-height keyboard-shown]} (hooks/use-keyboard)]
(rn/use-effect
(fn []
(if keyboard-shown
(reanimated/set-shared-value scroll-y
(+ (reanimated/get-shared-value scroll-y)
keyboard-height))
(reanimated/set-shared-value scroll-y
(- (reanimated/get-shared-value scroll-y)
keyboard-height))))
[keyboard-shown keyboard-height])
;; Note - Don't pass `behavior :height` to keyboard avoiding view,
;; It breaks composer - https://github.com/status-im/status-mobile/issues/16595
[rn/keyboard-avoiding-view
{:style (style/keyboard-avoiding-container insets)
:keyboard-vertical-offset (- (:bottom insets))}
(when header-comp
[header-comp
{:scroll-y scroll-y}])
[message-list-content-view
{:chat chat
:insets insets
:scroll-y scroll-y
:content-height content-height
:cover-bg-color cover-bg-color
:keyboard-shown? keyboard-shown}]
(when footer-comp
[footer-comp {:insets insets}])]))
(defn messages-list
[props]
[:f> f-messages-list props])

View File

@ -52,8 +52,14 @@
{:opacity animation}) {:opacity animation})
blur-view)) blur-view))
(def navigation-view (defn navigation-view
{:z-index 1}) [loaded?]
{:z-index 1
:top 0
:right 0
:left 0
:position :absolute
:opacity (if loaded? 1 0)})
(def header-container (def header-container
{:position :absolute {:position :absolute

View File

@ -9,28 +9,14 @@
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[status-im2.common.home.actions.view :as actions] [status-im2.common.home.actions.view :as actions]
[status-im2.config :as config] [status-im2.config :as config]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.navigation.style :as style] [status-im2.contexts.chat.messages.navigation.style :as style]
[status-im2.contexts.chat.messages.pin.banner.view :as pin.banner] [status-im2.contexts.chat.messages.pin.banner.view :as pin.banner]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn f-view (defn f-view
[{:keys [scroll-y]}] [{:keys [scroll-y chat chat-screen-loaded? all-loaded? display-name online? photo-path]}]
(let [{:keys [group-chat chat-id chat-name emoji (let [{:keys [group-chat chat-id]} chat
chat-type]
:as chat} (rf/sub [:chats/current-chat-chat-view])
chat-screen-loaded? (rf/sub [:shell/chat-screen-loaded?])
all-loaded? (when chat-screen-loaded?
(rf/sub [:chats/all-loaded? (:chat-id chat)]))
display-name (cond
(= chat-type constants/one-to-one-chat-type)
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
(= chat-type constants/community-chat-type)
(str (when emoji (str emoji " ")) "# " chat-name)
:else (str emoji chat-name))
online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])
opacity-animation (reanimated/interpolate scroll-y opacity-animation (reanimated/interpolate scroll-y
[style/navigation-bar-height [style/navigation-bar-height
(+ style/navigation-bar-height 30)] (+ style/navigation-bar-height 30)]
@ -54,7 +40,7 @@
[0 1] [0 1]
{:extrapolateLeft "clamp" {:extrapolateLeft "clamp"
:extrapolateRight "clamp"})] :extrapolateRight "clamp"})]
[rn/view {:style style/navigation-view} [rn/view {:style (style/navigation-view chat-screen-loaded?)}
[reanimated/view [reanimated/view
{:style (style/animated-background-view all-loaded? opacity-animation nil)}] {:style (style/animated-background-view all-loaded? opacity-animation nil)}]
@ -64,6 +50,7 @@
:blur-type (colors/theme-colors :light :dark) :blur-type (colors/theme-colors :light :dark)
:blur-radius (if platform/ios? 20 10) :blur-radius (if platform/ios? 20 10)
:style {:flex 1}}]] :style {:flex 1}}]]
[rn/view {:style style/header-container} [rn/view {:style style/header-container}
[rn/touchable-opacity [rn/touchable-opacity
{:active-opacity 1 {:active-opacity 1

View File

@ -1,26 +1,91 @@
(ns status-im2.contexts.chat.messages.view (ns status-im2.contexts.chat.messages.view
(:require [status-im2.contexts.chat.composer.view :as composer] (:require
[status-im2.contexts.chat.messages.contact-requests.bottom-drawer :as [react-native.core :as rn]
contact-requests.bottom-drawer] [react-native.hooks :as hooks]
[status-im2.contexts.chat.messages.list.view :as messages.list] [react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.contact-requests.bottom-drawer :as contact-requests.bottom-drawer]
[status-im2.contexts.chat.messages.list.view :as list.view]
[status-im2.contexts.chat.messages.list.style :as style]
[status-im2.contexts.chat.composer.view :as composer.view]
[status-im2.contexts.chat.messages.navigation.view :as messages.navigation] [status-im2.contexts.chat.messages.navigation.view :as messages.navigation]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn chat (defonce extra-keyboard-height (reagent/atom 0))
(defn f-chat
[] []
(let [{:keys [chat-id (let [insets (safe-area/get-insets)
scroll-y (reanimated/use-shared-value 0)
content-height (reanimated/use-shared-value 0)
{:keys [keyboard-height keyboard-shown]} (hooks/use-keyboard)
{:keys [chat-id
contact-request-state contact-request-state
group-chat group-chat
able-to-send-message?] able-to-send-message?
:as current-chat} (rf/sub [:chats/current-chat-chat-view])] chat-type
[messages.list/messages-list chat-name
{:cover-bg-color :turquoise emoji]
:chat current-chat :as chat} (rf/sub [:chats/current-chat-chat-view])
:header-comp (fn [{:keys [scroll-y]}] chat-screen-loaded? (rf/sub [:shell/chat-screen-loaded?])
[messages.navigation/navigation-view {:scroll-y scroll-y}]) all-loaded? (when chat-screen-loaded?
:footer-comp (when (some? able-to-send-message?) (rf/sub [:chats/all-loaded? (:chat-id chat)]))
(fn [{:keys [insets]}] display-name (cond
(if-not able-to-send-message? (= chat-type constants/one-to-one-chat-type)
[contact-requests.bottom-drawer/view chat-id contact-request-state (first (rf/sub
group-chat] [:contacts/contact-two-names-by-identity
[:f> composer/composer insets])))}])) chat-id]))
(= chat-type constants/community-chat-type)
(str (when emoji (str emoji " ")) "# " chat-name)
:else (str emoji chat-name))
online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])]
(rn/use-effect
(fn []
;; If keyboard is shown then adjust `scroll-y`
(when (and keyboard-shown (> keyboard-height 0))
(reanimated/set-shared-value scroll-y
(+ (reanimated/get-shared-value scroll-y)
keyboard-height))
(reset! extra-keyboard-height keyboard-height))
;; If keyboard is not shown then subtract the keyboard height from `scroll-y` value
(when-not keyboard-shown
(reanimated/set-shared-value scroll-y
(- (reanimated/get-shared-value scroll-y)
@extra-keyboard-height))))
[keyboard-shown keyboard-height])
;; Note - Don't pass `behavior :height` to keyboard avoiding view,
;; It breaks composer - https://github.com/status-im/status-mobile/issues/16595
[rn/keyboard-avoiding-view
{:style (style/keyboard-avoiding-container insets)
:keyboard-vertical-offset (- (:bottom insets))}
[list.view/message-list-content-view
{:chat chat
:insets insets
:scroll-y scroll-y
:content-height content-height
:cover-bg-color :turquoise
:keyboard-shown? keyboard-shown}]
[messages.navigation/navigation-view
{:scroll-y scroll-y
:chat chat
:chat-screen-loaded? chat-screen-loaded?
:all-loaded? all-loaded?
:display-name display-name
:online? online?
:photo-path photo-path}]
(if able-to-send-message?
[:f> composer.view/composer
{:insets insets
:scroll-to-bottom-fn list.view/scroll-to-bottom
:show-floating-scroll-down-button? list.view/show-floating-scroll-down-button?}]
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat])]))
(defn chat
[]
[:f> f-chat])