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]
[status-im2.common.alert.events :as alert]
[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]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
@ -20,7 +19,9 @@
[{:keys [sending-images? sending-links?]}
{:keys [text-value focused? maximized?]}
{: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/set-shared-value saved-height comp-constants/input-height)
(reanimated/set-shared-value last-height comp-constants/input-height)
@ -38,14 +39,13 @@
(reset! text-value "")
(reset! sending-links? false)
(reset! sending-images? false)
(when-not (some? edit)
(messages.list/scroll-to-bottom)))
(when (and (not (some? edit)) scroll-to-bottom-fn)
(scroll-to-bottom-fn)))
(defn f-send-button
[props {:keys [text-value] :as state}
animations window-height images?
btn-opacity z-index edit]
(let [customization-color (rf/sub [:profile/customization-color])]
[props state animations window-height images? btn-opacity scroll-to-bottom-fn z-index edit]
(let [{:keys [text-value]} state
customization-color (rf/sub [:profile/customization-color])]
(rn/use-effect (fn []
(if (or (seq @text-value) images?)
(when (or (not= @z-index 1) (not= (reanimated/get-shared-value btn-opacity) 1))
@ -60,17 +60,19 @@
[reanimated/view
{:style (style/send-button btn-opacity @z-index)}
[quo/button
{:icon-only? true
:size 32
{:icon-only? true
:size 32
:customization-color customization-color
: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]]))
(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))]
[: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
[opacity]
@ -214,7 +216,7 @@
:icon :i/format}])
(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)
audio-btn-opacity (reanimated/interpolate send-btn-opacity [0 1] [1 0])]
[rn/view {:style style/actions-container}
@ -225,7 +227,8 @@
[image-button props animations insets]
[reaction-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))
;; TODO(alwx): needs to be replaced with an `audio-button` later.
;; See https://github.com/status-im/status-mobile/issues/16084 for more details.

View File

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

View File

@ -26,7 +26,13 @@
[quo2.theme :as theme]))
(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?]
:as subscriptions} (utils/init-subs)
content-height (reagent/atom (or (:input-content-height
@ -76,7 +82,7 @@
(:edit subscriptions)])
[rn/view
{: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
(drag-gesture/drag-gesture props state animations subscriptions dimensions keyboard-shown)}
@ -127,20 +133,23 @@
[gradients/view props state animations show-bottom-gradient?]
[link-preview/view]
[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
[insets]
[{:keys [insets scroll-to-bottom-fn show-floating-scroll-down-button?]}]
(let [window-height (:height (rn/get-window))
opacity (reanimated/use-shared-value 0)
background-y (reanimated/use-shared-value (- window-height))
blur-height (reanimated/use-shared-value (+ constants/composer-default-height
(:bottom insets)))
extra-params {:insets insets
:window-height window-height
:blur-height blur-height
:opacity opacity
:background-y background-y}
extra-params {:insets insets
: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
:opacity opacity
:background-y background-y}
props (utils/init-props)
state (utils/init-state)]
[rn/view (when platform/ios? {:style {:z-index 1}})

View File

@ -1,25 +1,25 @@
(ns status-im2.contexts.chat.messages.list.view
(:require [oops.core :as oops]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.background-timer :as background-timer]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.ui.screens.chat.group :as chat.group]
[status-im.ui.screens.chat.message.gap :as message.gap]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.content.view :as message]
[status-im2.contexts.chat.messages.list.state :as state]
[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.messages.navigation.style :as navigation.style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(:require
[oops.core :as oops]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.background-timer :as background-timer]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[status-im.ui.screens.chat.group :as chat.group]
[status-im.ui.screens.chat.message.gap :as message.gap]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.content.view :as message]
[status-im2.contexts.chat.messages.list.state :as state]
[status-im2.contexts.chat.messages.list.style :as style]
[status-im2.contexts.chat.composer.constants :as composer.constants]
[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.re-frame :as rf]))
(defonce ^:const threshold-percentage-to-show-floating-scroll-down-button 75)
(defonce ^:const loading-indicator-extra-spacing 250)
@ -27,10 +27,11 @@
(defonce ^:const scroll-animation-input-range [50 125])
(defonce ^:const min-message-height 32)
(defonce extra-keyboard-height (reagent/atom 0))
(defonce messages-list-ref (atom nil))
(defonce messages-view-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-ref [ref] (reset! messages-list-ref ref))
@ -48,9 +49,9 @@
threshold-height (* (/ layout-height 100)
threshold-percentage-to-show-floating-scroll-down-button)
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))
(reset! show-floating-scroll-down-button reached-threshold?))))
(reset! show-floating-scroll-down-button? reached-threshold?))))
(defn on-viewable-items-changed
[e]
@ -296,10 +297,9 @@
:on-viewable-items-changed on-viewable-items-changed
:on-content-size-change (fn [_ y]
;; NOTE(alwx): here we set the initial value of `scroll-y`
;; which is needed because by default the chat is scrolled to
;; the
;; bottom
;; and no initial `on-scroll` event is getting triggered
;; which is needed because by default the chat is
;; scrolled to the bottom and no initial `on-scroll`
;; event is getting triggered
(let [scroll-y-shared (reanimated/get-shared-value
scroll-y)
content-height-shared (reanimated/get-shared-value
@ -360,44 +360,3 @@
[quo/skeleton-list
{:content :messages
: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})
blur-view))
(def navigation-view
{:z-index 1})
(defn navigation-view
[loaded?]
{:z-index 1
:top 0
:right 0
:left 0
:position :absolute
:opacity (if loaded? 1 0)})
(def header-container
{:position :absolute

View File

@ -9,52 +9,38 @@
[react-native.reanimated :as reanimated]
[status-im2.common.home.actions.view :as actions]
[status-im2.config :as config]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.navigation.style :as style]
[status-im2.contexts.chat.messages.pin.banner.view :as pin.banner]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn f-view
[{:keys [scroll-y]}]
(let [{:keys [group-chat chat-id chat-name emoji
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
[style/navigation-bar-height
(+ style/navigation-bar-height 30)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"})
banner-opacity-animation (reanimated/interpolate scroll-y
[(+ style/navigation-bar-height 150)
(+ style/navigation-bar-height 200)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"})
translate-animation (reanimated/interpolate scroll-y
[(+ style/navigation-bar-height 25)
(+ style/navigation-bar-height 100)]
[50 0]
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})
title-opacity-animation (reanimated/interpolate scroll-y
[0 50]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})]
[rn/view {:style style/navigation-view}
[{:keys [scroll-y chat chat-screen-loaded? all-loaded? display-name online? photo-path]}]
(let [{:keys [group-chat chat-id]} chat
opacity-animation (reanimated/interpolate scroll-y
[style/navigation-bar-height
(+ style/navigation-bar-height 30)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"})
banner-opacity-animation (reanimated/interpolate scroll-y
[(+ style/navigation-bar-height 150)
(+ style/navigation-bar-height 200)]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "extend"})
translate-animation (reanimated/interpolate scroll-y
[(+ style/navigation-bar-height 25)
(+ style/navigation-bar-height 100)]
[50 0]
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})
title-opacity-animation (reanimated/interpolate scroll-y
[0 50]
[0 1]
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})]
[rn/view {:style (style/navigation-view chat-screen-loaded?)}
[reanimated/view
{:style (style/animated-background-view all-loaded? opacity-animation nil)}]
@ -64,6 +50,7 @@
:blur-type (colors/theme-colors :light :dark)
:blur-radius (if platform/ios? 20 10)
:style {:flex 1}}]]
[rn/view {:style style/header-container}
[rn/touchable-opacity
{:active-opacity 1

View File

@ -1,26 +1,91 @@
(ns status-im2.contexts.chat.messages.view
(:require [status-im2.contexts.chat.composer.view :as composer]
[status-im2.contexts.chat.messages.contact-requests.bottom-drawer :as
contact-requests.bottom-drawer]
[status-im2.contexts.chat.messages.list.view :as messages.list]
[status-im2.contexts.chat.messages.navigation.view :as messages.navigation]
[utils.re-frame :as rf]))
(:require
[react-native.core :as rn]
[react-native.hooks :as hooks]
[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]
[utils.re-frame :as rf]))
(defonce extra-keyboard-height (reagent/atom 0))
(defn f-chat
[]
(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
group-chat
able-to-send-message?
chat-type
chat-name
emoji]
: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])]
(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
[]
(let [{:keys [chat-id
contact-request-state
group-chat
able-to-send-message?]
:as current-chat} (rf/sub [:chats/current-chat-chat-view])]
[messages.list/messages-list
{:cover-bg-color :turquoise
:chat current-chat
:header-comp (fn [{:keys [scroll-y]}]
[messages.navigation/navigation-view {:scroll-y scroll-y}])
:footer-comp (when (some? able-to-send-message?)
(fn [{:keys [insets]}]
(if-not able-to-send-message?
[contact-requests.bottom-drawer/view chat-id contact-request-state
group-chat]
[:f> composer/composer insets])))}]))
[:f> f-chat])