Refactor compose (#18339)

- Removed show-floating-scroll-down-button? reagent atom
- Created event for scroll-to-bottom-fn
- Renamed chat.ui/close-chat
This commit is contained in:
Parvesh Monu 2024-01-10 13:53:35 +05:30 committed by GitHub
parent 0e4c1b3c17
commit 425ef64901
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 150 additions and 119 deletions

View File

@ -39,7 +39,7 @@ export function interpolateNavigationViewOpacity(props) {
});
}
export function messagesListOnScroll(distanceFromListTop, callback) {
export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callback) {
return function (event) {
'worklet';
const currentY = event.contentOffset.y;
@ -47,7 +47,8 @@ export function messagesListOnScroll(distanceFromListTop, callback) {
const contentSizeY = event.contentSize.height - layoutHeight;
const newDistance = contentSizeY - currentY;
distanceFromListTop.value = newDistance;
runOnJS(callback)(currentY, layoutHeight, newDistance);
chatListScrollY.value = currentY;
runOnJS(callback)(layoutHeight, newDistance);
};
}
@ -64,3 +65,28 @@ export function placeholderZIndex(isCalculationsComplete) {
return isCalculationsComplete.value ? 0 : 2;
});
}
export function scrollDownButtonOpacity(chatListScrollY, isComposerFocused, windowHeight) {
return useDerivedValue(function () {
'worklet';
if (isComposerFocused.value) {
return 0;
} else {
return chatListScrollY.value > windowHeight * 0.75 ? 1 : 0;
}
});
}
export function jumpToButtonOpacity(scrollDownButtonOpacity, isComposerFocused) {
return useDerivedValue(function () {
'worklet';
return withTiming(scrollDownButtonOpacity.value == 1 || isComposerFocused.value ? 0 : 1);
});
}
export function jumpToButtonPosition(scrollDownButtonOpacity, isComposerFocused) {
return useDerivedValue(function () {
'worklet';
return withTiming(scrollDownButtonOpacity.value == 1 || isComposerFocused.value ? 35 : 0);
});
}

View File

@ -95,7 +95,8 @@
:button-text (i18n/label :t/confirm)
:close-button-text (i18n/label :t/cancel)
:on-press (fn []
(hide-sheet-and-dispatch [:chat.ui/close-chat chat-id])
(hide-sheet-and-dispatch [:chat.ui/close-and-remove-chat
chat-id])
(when inside-chat?
(rf/dispatch [:navigate-back])))}])}]))

View File

@ -1,6 +1,7 @@
(ns status-im.contexts.chat.effects
(:require
[react-native.async-storage :as async-storage]
[status-im.contexts.chat.messenger.messages.list.state :as chat.state]
[status-im.contexts.shell.jump-to.constants :as shell.constants]
[utils.re-frame :as rf]))
@ -16,3 +17,9 @@
(when (= stored-key-uid key-uid)
(rf/dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id
shell.constants/open-screen-without-animation])))))))))
(rf/reg-fx :effects.chat/scroll-to-bottom
(fn []
(some-> ^js @chat.state/messages-list-ref
(.scrollToOffset #js
{:animated true}))))

View File

@ -281,7 +281,7 @@
(rf/defn close-and-remove-chat
"Closes the chat and removes it from chat list while retaining history, producing all necessary effects for that"
{:events [:chat.ui/close-chat]}
{:events [:chat.ui/close-and-remove-chat]}
[{:keys [db now] :as cofx} chat-id]
(rf/merge cofx
{:effects/push-notifications-clear-message-notifications [chat-id]
@ -386,7 +386,7 @@
:confirm-button-text (i18n/label :t/delete)
:on-accept #(do
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:chat.ui/close-chat chat-id]))}})
(rf/dispatch [:chat.ui/close-and-remove-chat chat-id]))}})
(rf/defn navigate-to-user-pinned-messages
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
@ -447,3 +447,8 @@
:params [{:id chat-id}]
:on-success #()
:on-error #(log/error "failed to fetch messages for chat" chat-id %)}]})
(rf/defn scroll-to-bottom
{:events [:chat.ui/scroll-to-bottom]}
[_]
{:effects.chat/scroll-to-bottom nil})

View File

@ -20,8 +20,7 @@
{:keys [text-value focused? maximized?]}
{:keys [height saved-height last-height opacity background-y container-opacity]}
window-height
edit
scroll-to-bottom-fn]
edit]
(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)
@ -39,11 +38,11 @@
(reset! text-value "")
(reset! sending-links? false)
(reset! sending-images? false)
(when (and (not (some? edit)) scroll-to-bottom-fn)
(scroll-to-bottom-fn)))
(when-not (some? edit)
(rf/dispatch [:chat.ui/scroll-to-bottom])))
(defn f-send-button
[props state animations window-height images? btn-opacity scroll-to-bottom-fn z-index edit]
[props state animations window-height images? btn-opacity z-index edit]
(let [{:keys [text-value]} state
customization-color (rf/sub [:profile/customization-color])]
(rn/use-effect (fn []
@ -61,19 +60,17 @@
[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 scroll-to-bottom-fn)}
:on-press #(send-message props state animations window-height edit)}
:i/arrow-up]]))
(defn send-button
[props {:keys [text-value] :as state} animations window-height images? edit btn-opacity
scroll-to-bottom-fn]
[props {:keys [text-value] :as state} animations window-height images? edit btn-opacity]
(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 scroll-to-bottom-fn
z-index edit]))
[:f> f-send-button props state animations window-height images? btn-opacity z-index edit]))
(defn disabled-audio-button
[opacity]
@ -231,7 +228,7 @@
:icon :i/format}])
(defn view
[props state animations window-height insets scroll-to-bottom-fn {:keys [edit images]}]
[props state animations window-height insets {: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}
@ -242,8 +239,7 @@
[image-button props animations insets edit]
[reaction-button]
[format-button]]
[:f> send-button props state animations window-height images edit send-btn-opacity
scroll-to-bottom-fn]
[:f> send-button props state animations window-height images edit send-btn-opacity]
(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

@ -16,11 +16,11 @@
(defn focus
"Animate to the `saved-height`, display background-overlay if needed, and set cursor position"
[{:keys [input-ref] :as props}
{:keys [text-value focused? lock-selection? saved-cursor-position]}
{:keys [text-value focused? lock-selection? saved-cursor-position composer-focused?]}
{:keys [height saved-height last-height opacity background-y container-opacity]
:as animations}
{:keys [max-height] :as dimensions}
show-floating-scroll-down-button?]
{:keys [max-height] :as dimensions}]
(reanimated/set-shared-value composer-focused? true)
(reset! focused? true)
(rf/dispatch [:chat.ui/set-input-focused true])
(let [last-height-value (reanimated/get-shared-value last-height)]
@ -35,13 +35,12 @@
(when (and (not-empty @text-value) @input-ref)
(.setNativeProps ^js @input-ref
(clj->js {:selection {:start @saved-cursor-position :end @saved-cursor-position}})))
(kb/handle-refocus-emoji-kb-ios props animations dimensions)
(reset! show-floating-scroll-down-button? false))
(kb/handle-refocus-emoji-kb-ios props animations dimensions))
(defn blur
"Save the current height, minimize the composer, animate-out the background, and save cursor position"
[{:keys [text-value focused? lock-selection? cursor-position saved-cursor-position gradient-z-index
maximized? recording?]}
maximized? recording? composer-focused?]}
{:keys [height saved-height last-height gradient-opacity container-opacity opacity background-y]}
{:keys [content-height max-height window-height]}
{:keys [images link-previews? reply]}]
@ -53,6 +52,7 @@
max-height
content-height
saved-height)]
(reanimated/set-shared-value composer-focused? false)
(reset! focused? false)
(rf/dispatch [:chat.ui/set-input-focused false])
(reanimated/set-shared-value last-height reopen-height)

View File

@ -6,7 +6,8 @@
[react-native.reanimated :as reanimated]
[status-im.contexts.chat.messenger.composer.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.worklets.chat.messages :as worklets]))
(defn bar
[theme]
@ -23,33 +24,33 @@
[:f> f-blur-view props])
(defn- f-shell-button
[{:keys [focused?]} scroll-to-bottom-fn show-floating-scroll-down-button?]
(let [customization-color (rf/sub [:profile/customization-color])
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? @show-floating-scroll-down-button?])
[{:keys [composer-focused?]} chat-list-scroll-y window-height]
(let [customization-color (rf/sub [:profile/customization-color])
scroll-down-button-opacity (worklets/scroll-down-button-opacity
chat-list-scroll-y
composer-focused?
window-height)
jump-to-button-opacity (worklets/jump-to-button-opacity
scroll-down-button-opacity
composer-focused?)
jump-to-button-position (worklets/jump-to-button-position
scroll-down-button-opacity
composer-focused?)]
[:<>
[reanimated/view
{:style (style/shell-button y-shell opacity)}
{:style (style/shell-button jump-to-button-position jump-to-button-opacity)}
[quo/floating-shell-button
{:jump-to
{:on-press (fn []
(rf/dispatch [:shell/navigate-to-jump-to]))
{:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:customization-color customization-color
:label (i18n/label :t/jump-to)
:style {:align-self :center}}}
{}]]
(when (and (not @focused?)
@show-floating-scroll-down-button?)
[quo/floating-shell-button
{:scroll-to-bottom {:on-press scroll-to-bottom-fn}}
style/scroll-to-bottom-button])]))
[quo/floating-shell-button
{:scroll-to-bottom {:on-press #(rf/dispatch [:chat.ui/scroll-to-bottom])}}
style/scroll-to-bottom-button
scroll-down-button-opacity]]))
(defn shell-button
[state scroll-to-bottom-fn show-floating-scroll-down-button?]
[:f> f-shell-button state scroll-to-bottom-fn show-floating-scroll-down-button?])
[state chat-list-scroll-y window-height]
[:f> f-shell-button state chat-list-scroll-y window-height])

View File

@ -193,7 +193,8 @@
:record-permission? (reagent/atom true)
:recording? (reagent/atom false)
:first-level? (reagent/atom true)
:menu-items (reagent/atom selection/first-level-menu-items)})
:menu-items (reagent/atom selection/first-level-menu-items)
:composer-focused? (reanimated/use-shared-value false)})
(defn init-subs
[]

View File

@ -30,8 +30,7 @@
(defn sheet-component
[{:keys [insets
scroll-to-bottom-fn
show-floating-scroll-down-button?
chat-list-scroll-y
window-height
blur-height
opacity
@ -89,7 +88,7 @@
(:edit subscriptions)]
[rn/view
{:style style/composer-sheet-and-jump-to-container}
[sub-view/shell-button state scroll-to-bottom-fn show-floating-scroll-down-button?]
[sub-view/shell-button state chat-list-scroll-y window-height]
[gesture/gesture-detector
{:gesture
(drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
@ -114,42 +113,39 @@
:menu-items @(:menu-items state)
:style (style/input-view state)}
[rn/text-input
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus
#(handler/focus props state animations dimensions show-floating-scroll-down-button?)
:on-blur #(handler/blur state animations dimensions subscriptions)
:on-content-size-change #(handler/content-size-change %
state
animations
dimensions
(or keyboard-shown
(:edit subscriptions)))
:on-scroll #(handler/scroll % props state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % props state)
:on-selection #(selection/on-selection % props state)
:keyboard-appearance (quo.theme/theme-value :light :dark)
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus #(handler/focus props state animations dimensions)
:on-blur #(handler/blur state animations dimensions subscriptions)
:on-content-size-change #(handler/content-size-change %
state
animations
dimensions
(or keyboard-shown
(:edit subscriptions)))
:on-scroll #(handler/scroll % props state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % props state)
:on-selection #(selection/on-selection % props state)
:keyboard-appearance (quo.theme/theme-value :light :dark)
:max-font-size-multiplier 1
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:style (style/input-text props
state
{:max-height max-height
:theme theme})
:max-length constants/max-text-size
:accessibility-label :chat-message-input}]]]
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:style (style/input-text props
state
{:max-height max-height
:theme theme})
:max-length constants/max-text-size
:accessibility-label :chat-message-input}]]]
[:<>
[gradients/view props state animations show-bottom-gradient?]
[link-preview/view]
[images/images-list]]
[:f> actions/view props state animations window-height insets scroll-to-bottom-fn
subscriptions]]]]]))
[:f> actions/view props state animations window-height insets subscriptions]]]]]))
(defn f-composer
[{:keys [insets scroll-to-bottom-fn show-floating-scroll-down-button?
messages-list-on-layout-finished?]}]
[{:keys [insets chat-list-scroll-y messages-list-on-layout-finished?]}]
(let [window-height (:height (rn/get-window))
theme (quo.theme/use-theme-value)
opacity (reanimated/use-shared-value 0)
@ -159,8 +155,7 @@
(:bottom insets)))
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?
:chat-list-scroll-y chat-list-scroll-y
:blur-height blur-height
:opacity opacity
:background-y background-y

View File

@ -1,5 +1,6 @@
(ns status-im.contexts.chat.messenger.messages.list.state)
(defonce messages-list-ref (atom nil))
(defonce first-not-visible-item (atom nil))
(defonce scrolling (atom nil))

View File

@ -23,37 +23,16 @@
[utils.re-frame :as rf]
[utils.worklets.chat.messages :as worklets]))
(defonce ^:const threshold-percentage-to-show-floating-scroll-down-button 75)
(defonce ^:const loading-indicator-extra-spacing 250)
(defonce ^:const loading-indicator-page-loading-height 100)
(defonce ^:const min-message-height 32)
(defonce messages-list-ref (atom nil))
(defn list-key-fn [{:keys [message-id value]}] (or message-id value))
(defn list-ref [ref] (reset! messages-list-ref ref))
(defn scroll-to-bottom
[]
(some-> ^js @messages-list-ref
(.scrollToOffset #js
{:animated true})))
(defn on-scroll-fn
[show-floating-scroll-down-button? distance-atom layout-height-atom]
(fn [y layout-height new-distance]
(let [threshold-height (* (/ layout-height 100)
threshold-percentage-to-show-floating-scroll-down-button)
reached-threshold? (> y threshold-height)]
(when (not= layout-height @layout-height-atom)
(reset! layout-height-atom layout-height))
(reset! distance-atom new-distance)
(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?)))))
(defn list-ref [ref] (reset! state/messages-list-ref ref))
(defn on-viewable-items-changed
[e]
(when @messages-list-ref
(when @state/messages-list-ref
(reset! state/first-not-visible-item
(when-let [last-visible-element (aget (oops/oget e "viewableItems")
(dec (oops/oget e "viewableItems.length")))]
@ -61,7 +40,7 @@
;; Get first not visible element, if it's a datemark/gap
;; we might add messages on receiving as they do not have
;; a clock value, but usually it will be a message
first-not-visible (aget (oops/oget @messages-list-ref "props.data") (inc index))]
first-not-visible (aget (oops/oget @state/messages-list-ref "props.data") (inc index))]
(when (and first-not-visible
(= :message (:type first-not-visible)))
first-not-visible))))))
@ -300,9 +279,16 @@
(reanimated/set-shared-value calculations-complete? true))
(js/setTimeout #(reset! messages-list-on-layout-finished? true) 1000)))
(defn on-scroll-fn
[distance-atom layout-height-atom]
(fn [layout-height new-distance]
(when (not= layout-height @layout-height-atom)
(reset! layout-height-atom layout-height))
(reset! distance-atom new-distance)))
(defn f-messages-list-content
[{:keys [insets distance-from-list-top content-height layout-height cover-bg-color distance-atom
show-floating-scroll-down-button? calculations-complete? messages-list-on-layout-finished?]}]
calculations-complete? messages-list-on-layout-finished? chat-list-scroll-y]}]
(let [theme (quo.theme/use-theme-value)
chat (rf/sub [:chats/current-chat-chat-view])
{:keys [keyboard-shown]} (hooks/use-keyboard)
@ -354,9 +340,8 @@
:on-scroll (reanimated/use-animated-scroll-handler
(worklets/messages-list-on-scroll
distance-from-list-top
(on-scroll-fn show-floating-scroll-down-button?
distance-atom
layout-height)))
chat-list-scroll-y
(on-scroll-fn distance-atom layout-height)))
:style {:background-color (colors/theme-colors colors/white
colors/neutral-95
theme)}

View File

@ -20,9 +20,9 @@
content-height (atom 0)
layout-height (atom 0)
distance-atom (atom 0)
show-floating-scroll-down-button? (reagent/atom false)
messages-list-on-layout-finished? (reagent/atom false)
distance-from-list-top (reanimated/use-shared-value 0)]
distance-from-list-top (reanimated/use-shared-value 0)
chat-list-scroll-y (reanimated/use-shared-value 0)]
[rn/keyboard-avoiding-view
{:style style/keyboard-avoiding-container
:keyboard-vertical-offset (- (:bottom insets))}
@ -36,14 +36,13 @@
:distance-atom distance-atom
:calculations-complete? calculations-complete?
:distance-from-list-top distance-from-list-top
:chat-list-scroll-y chat-list-scroll-y
:messages-list-on-layout-finished? messages-list-on-layout-finished?
:cover-bg-color :turquoise
:show-floating-scroll-down-button? show-floating-scroll-down-button?}]
:cover-bg-color :turquoise}]
[composer.view/composer
{:insets insets
:scroll-to-bottom-fn list.view/scroll-to-bottom
:messages-list-on-layout-finished? messages-list-on-layout-finished?
:show-floating-scroll-down-button? show-floating-scroll-down-button?}]]))
:chat-list-scroll-y chat-list-scroll-y
:messages-list-on-layout-finished? messages-list-on-layout-finished?}]]))
(defn lazy-chat-screen
[calculations-complete?]

View File

@ -23,9 +23,10 @@
[props]
(.interpolateNavigationViewOpacity ^js messages-worklets (clj->js props)))
;;;; Messages List
(defn messages-list-on-scroll
[distance-from-list-top callback]
(.messagesListOnScroll ^js messages-worklets distance-from-list-top callback))
[distance-from-list-top chat-list-scroll-y callback]
(.messagesListOnScroll ^js messages-worklets distance-from-list-top chat-list-scroll-y callback))
;;;; Placeholder
(defn placeholder-opacity
@ -35,3 +36,16 @@
(defn placeholder-z-index
[calculations-complete?]
(.placeholderZIndex ^js messages-worklets calculations-complete?))
;;;; Common
(defn scroll-down-button-opacity
[chat-list-scroll-y composer-focused? window-height]
(.scrollDownButtonOpacity ^js messages-worklets chat-list-scroll-y composer-focused? window-height))
(defn jump-to-button-opacity
[scroll-down-button-opacity-sv composer-focused?]
(.jumpToButtonOpacity ^js messages-worklets scroll-down-button-opacity-sv composer-focused?))
(defn jump-to-button-position
[scroll-down-button-opacity-sv composer-focused?]
(.jumpToButtonPosition ^js messages-worklets scroll-down-button-opacity-sv composer-focused?))