From b189f59950807b2359c818a9b051140550a00362 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Thu, 8 Feb 2024 14:49:09 -0300 Subject: [PATCH] fix: NavBottomFAB position (#5555) --- .../MessageComposer/MessageComposer.tsx | 2 + .../components/ComposerInput.tsx | 2 +- .../components/Toolbar/Default.tsx | 2 +- .../components/Toolbar/Markdown.tsx | 2 +- app/containers/MessageComposer/emitter.ts | 14 ---- .../hooks/useKeyboardListener.ts | 13 +++- app/lib/methods/helpers/emitter.ts | 20 ++++++ app/lib/methods/helpers/events.ts | 3 + app/lib/methods/helpers/index.ts | 1 + .../RoomView/List/components/NavBottomFAB.tsx | 65 +++++++------------ app/views/RoomView/List/constants.ts | 2 + app/views/RoomView/List/hooks/index.ts | 1 + .../List/hooks/useNavBottomStyle/index.ts | 1 + .../useNavBottomStyle.android.ts | 8 +++ .../useNavBottomStyle/useNavBottomStyle.ts | 36 ++++++++++ app/views/RoomView/List/hooks/useScroll.ts | 6 +- 16 files changed, 115 insertions(+), 63 deletions(-) delete mode 100644 app/containers/MessageComposer/emitter.ts create mode 100644 app/lib/methods/helpers/emitter.ts create mode 100644 app/views/RoomView/List/hooks/useNavBottomStyle/index.ts create mode 100644 app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.android.ts create mode 100644 app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.ts diff --git a/app/containers/MessageComposer/MessageComposer.tsx b/app/containers/MessageComposer/MessageComposer.tsx index 56b25d8f4..00337588b 100644 --- a/app/containers/MessageComposer/MessageComposer.tsx +++ b/app/containers/MessageComposer/MessageComposer.tsx @@ -30,6 +30,7 @@ import log from '../../lib/methods/helpers/log'; import { prepareQuoteMessage } from './helpers'; import { RecordAudio } from './components/RecordAudio'; import { useKeyboardListener } from './hooks'; +import { emitter } from '../../lib/methods/helpers/emitter'; const styles = StyleSheet.create({ container: { @@ -193,6 +194,7 @@ export const MessageComposer = ({ const onHeightChanged = (height: number) => { setTrackingViewHeight(height); + emitter.emit(`setComposerHeight${tmid ? 'Thread' : ''}`, height); }; const backgroundColor = action === 'edit' ? colors.statusBackgroundWarning2 : colors.surfaceLight; diff --git a/app/containers/MessageComposer/components/ComposerInput.tsx b/app/containers/MessageComposer/components/ComposerInput.tsx index 36013f210..1d05f9563 100644 --- a/app/containers/MessageComposer/components/ComposerInput.tsx +++ b/app/containers/MessageComposer/components/ComposerInput.tsx @@ -16,7 +16,7 @@ import { getRoomTitle, parseJson } from '../../../lib/methods/helpers'; import { MAX_HEIGHT, MIN_HEIGHT, NO_CANNED_RESPONSES, MARKDOWN_STYLES } from '../constants'; import database from '../../../lib/database'; import Navigation from '../../../lib/navigation/appNavigation'; -import { emitter } from '../emitter'; +import { emitter } from '../../../lib/methods/helpers/emitter'; import { useRoomContext } from '../../../views/RoomView/context'; import { getMessageById } from '../../../lib/database/services/Message'; import { generateTriggerId } from '../../../lib/methods'; diff --git a/app/containers/MessageComposer/components/Toolbar/Default.tsx b/app/containers/MessageComposer/components/Toolbar/Default.tsx index b16c369db..961002098 100644 --- a/app/containers/MessageComposer/components/Toolbar/Default.tsx +++ b/app/containers/MessageComposer/components/Toolbar/Default.tsx @@ -3,7 +3,7 @@ import React, { ReactElement } from 'react'; import { ActionsButton, BaseButton } from '..'; import { useMessageComposerApi } from '../../context'; import { Gap } from '../Gap'; -import { emitter } from '../../emitter'; +import { emitter } from '../../../../lib/methods/helpers/emitter'; import { useRoomContext } from '../../../../views/RoomView/context'; export const Default = (): ReactElement | null => { diff --git a/app/containers/MessageComposer/components/Toolbar/Markdown.tsx b/app/containers/MessageComposer/components/Toolbar/Markdown.tsx index 1c1e946a4..bcecfb8bb 100644 --- a/app/containers/MessageComposer/components/Toolbar/Markdown.tsx +++ b/app/containers/MessageComposer/components/Toolbar/Markdown.tsx @@ -4,7 +4,7 @@ import { BaseButton } from '..'; import { useMessageComposerApi } from '../../context'; import { Gap } from '../Gap'; import { TMarkdownStyle } from '../../interfaces'; -import { emitter } from '../../emitter'; +import { emitter } from '../../../../lib/methods/helpers/emitter'; export const Markdown = (): ReactElement => { const { setMarkdownToolbar } = useMessageComposerApi(); diff --git a/app/containers/MessageComposer/emitter.ts b/app/containers/MessageComposer/emitter.ts deleted file mode 100644 index e3e1f5132..000000000 --- a/app/containers/MessageComposer/emitter.ts +++ /dev/null @@ -1,14 +0,0 @@ -import mitt from 'mitt'; - -import { TMarkdownStyle } from './interfaces'; - -type Events = { - toolbarMention: undefined; - addMarkdown: { - style: TMarkdownStyle; - }; -}; - -export const emitter = mitt(); - -emitter.on('*', (type, e) => console.log(type, e)); diff --git a/app/containers/MessageComposer/hooks/useKeyboardListener.ts b/app/containers/MessageComposer/hooks/useKeyboardListener.ts index eb7e3b0ca..f8575d07c 100644 --- a/app/containers/MessageComposer/hooks/useKeyboardListener.ts +++ b/app/containers/MessageComposer/hooks/useKeyboardListener.ts @@ -1,26 +1,37 @@ import { MutableRefObject, useEffect } from 'react'; import { Keyboard } from 'react-native'; +import { useIsFocused } from '@react-navigation/native'; import { useMessageComposerApi } from '../context'; import { ITrackingView } from '../interfaces'; +import { TKeyEmitterEvent, emitter } from '../../../lib/methods/helpers/emitter'; +import { useRoomContext } from '../../../views/RoomView/context'; export const useKeyboardListener = (ref: MutableRefObject) => { const { setKeyboardHeight } = useMessageComposerApi(); + const { tmid } = useRoomContext(); + const isFocused = useIsFocused(); useEffect(() => { + if (!isFocused) { + return; + } + const keyboardEvent: TKeyEmitterEvent = `setKeyboardHeight${tmid ? 'Thread' : ''}`; const showListener = Keyboard.addListener('keyboardWillShow', async () => { if (ref?.current) { const props = await ref.current.getNativeProps(); setKeyboardHeight(props.keyboardHeight); + emitter.emit(keyboardEvent, props.keyboardHeight); } }); const hideListener = Keyboard.addListener('keyboardWillHide', () => { setKeyboardHeight(0); + emitter.emit(keyboardEvent, 0); }); return () => { showListener.remove(); hideListener.remove(); }; - }, [ref, setKeyboardHeight]); + }, [ref, setKeyboardHeight, tmid, isFocused]); }; diff --git a/app/lib/methods/helpers/emitter.ts b/app/lib/methods/helpers/emitter.ts new file mode 100644 index 000000000..ba8f7b21c --- /dev/null +++ b/app/lib/methods/helpers/emitter.ts @@ -0,0 +1,20 @@ +import mitt from 'mitt'; + +import { TMarkdownStyle } from '../../../containers/MessageComposer/interfaces'; + +export type TEmitterEvents = { + toolbarMention: undefined; + addMarkdown: { + style: TMarkdownStyle; + }; + setKeyboardHeight: number; + setKeyboardHeightThread: number; + setComposerHeight: number; + setComposerHeightThread: number; +}; + +export type TKeyEmitterEvent = keyof TEmitterEvents; + +export const emitter = mitt(); + +emitter.on('*', (type, e) => console.log(type, e)); diff --git a/app/lib/methods/helpers/events.ts b/app/lib/methods/helpers/events.ts index ff3ff3e65..234453133 100644 --- a/app/lib/methods/helpers/events.ts +++ b/app/lib/methods/helpers/events.ts @@ -42,6 +42,9 @@ class EventEmitter { } } + /** + * @deprecated use lib/methods/helpers/emitter.ts + */ emit(event: string, ...args: TEventEmitterEmmitArgs[]) { if (typeof this.events[event] === 'object') { this.events[event].forEach((listener: Function) => { diff --git a/app/lib/methods/helpers/index.ts b/app/lib/methods/helpers/index.ts index 611fe6aad..65ae74993 100644 --- a/app/lib/methods/helpers/index.ts +++ b/app/lib/methods/helpers/index.ts @@ -16,4 +16,5 @@ export * from './isValidEmail'; export * from './random'; export * from './image'; export * from './askAndroidMediaPermissions'; +export * from './emitter'; export * from './parseJson'; diff --git a/app/views/RoomView/List/components/NavBottomFAB.tsx b/app/views/RoomView/List/components/NavBottomFAB.tsx index a0d9a65c6..7673b697c 100644 --- a/app/views/RoomView/List/components/NavBottomFAB.tsx +++ b/app/views/RoomView/List/components/NavBottomFAB.tsx @@ -1,14 +1,16 @@ -import React from 'react'; -import { StyleSheet, View, Platform } from 'react-native'; +import React, { memo } from 'react'; +import { StyleSheet, View } from 'react-native'; import { CustomIcon } from '../../../../containers/CustomIcon'; import { useTheme } from '../../../../theme'; import Touch from '../../../../containers/Touch'; +import { useNavBottomStyle } from '../hooks'; +import { EDGE_DISTANCE } from '../constants'; const styles = StyleSheet.create({ container: { position: 'absolute', - right: 15 + right: EDGE_DISTANCE }, button: { borderRadius: 25 @@ -23,46 +25,25 @@ const styles = StyleSheet.create({ } }); -const NavBottomFAB = ({ - visible, - onPress, - isThread -}: { - visible: boolean; - onPress: Function; - isThread: boolean; -}): React.ReactElement | null => { - const { colors } = useTheme(); +const NavBottomFAB = memo( + ({ visible, onPress, isThread }: { visible: boolean; onPress: Function; isThread: boolean }): React.ReactElement | null => { + const { colors } = useTheme(); + const positionStyle = useNavBottomStyle(isThread); - if (!visible) { - return null; + if (!visible) { + return null; + } + + return ( + + onPress()} style={[styles.button, { backgroundColor: colors.backgroundColor }]}> + + + + + + ); } - - return ( - - onPress()} style={[styles.button, { backgroundColor: colors.backgroundColor }]}> - - - - - - ); -}; +); export default NavBottomFAB; diff --git a/app/views/RoomView/List/constants.ts b/app/views/RoomView/List/constants.ts index 30aafb545..863e8953a 100644 --- a/app/views/RoomView/List/constants.ts +++ b/app/views/RoomView/List/constants.ts @@ -5,3 +5,5 @@ export const VIEWABILITY_CONFIG = { }; export const SCROLL_LIMIT = 200; + +export const EDGE_DISTANCE = 15; diff --git a/app/views/RoomView/List/hooks/index.ts b/app/views/RoomView/List/hooks/index.ts index 0e9e991f8..65f094110 100644 --- a/app/views/RoomView/List/hooks/index.ts +++ b/app/views/RoomView/List/hooks/index.ts @@ -1,2 +1,3 @@ +export * from './useNavBottomStyle'; export * from './useMessages'; export * from './useScroll'; diff --git a/app/views/RoomView/List/hooks/useNavBottomStyle/index.ts b/app/views/RoomView/List/hooks/useNavBottomStyle/index.ts new file mode 100644 index 000000000..086222689 --- /dev/null +++ b/app/views/RoomView/List/hooks/useNavBottomStyle/index.ts @@ -0,0 +1 @@ +export * from './useNavBottomStyle'; diff --git a/app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.android.ts b/app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.android.ts new file mode 100644 index 000000000..2e6251809 --- /dev/null +++ b/app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.android.ts @@ -0,0 +1,8 @@ +import { ViewStyle } from 'react-native'; + +import { EDGE_DISTANCE } from '../../constants'; + +export const useNavBottomStyle = (): ViewStyle => ({ + top: EDGE_DISTANCE, + scaleY: -1 +}); diff --git a/app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.ts b/app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.ts new file mode 100644 index 000000000..91371651a --- /dev/null +++ b/app/views/RoomView/List/hooks/useNavBottomStyle/useNavBottomStyle.ts @@ -0,0 +1,36 @@ +import { useEffect, useState } from 'react'; +import { ViewStyle } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +import { TKeyEmitterEvent, emitter } from '../../../../../lib/methods/helpers'; +import { EDGE_DISTANCE } from '../../constants'; + +export const useNavBottomStyle = (isThread: boolean): ViewStyle => { + const [keyboardHeight, setKeyboardHeight] = useState(0); + const [composerHeight, setComposerHeight] = useState(0); + const { bottom } = useSafeAreaInsets(); + + useEffect(() => { + const keyboardEvent: TKeyEmitterEvent = `setKeyboardHeight${isThread ? 'Thread' : ''}`; + const composerEvent: TKeyEmitterEvent = `setComposerHeight${isThread ? 'Thread' : ''}`; + emitter.on(keyboardEvent, height => { + if (height !== keyboardHeight) { + setKeyboardHeight(height); + } + }); + emitter.on(composerEvent, height => { + if (height !== composerHeight) { + setComposerHeight(height); + } + }); + + return () => { + emitter.off(keyboardEvent); + emitter.off(composerEvent); + }; + }, [isThread, keyboardHeight, composerHeight]); + + return { + bottom: keyboardHeight + composerHeight + (keyboardHeight ? 0 : bottom) + EDGE_DISTANCE + }; +}; diff --git a/app/views/RoomView/List/hooks/useScroll.ts b/app/views/RoomView/List/hooks/useScroll.ts index 5f6551b5a..7e332d1b8 100644 --- a/app/views/RoomView/List/hooks/useScroll.ts +++ b/app/views/RoomView/List/hooks/useScroll.ts @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { ViewToken, ViewabilityConfigCallbackPairs } from 'react-native'; import { IListContainerRef, IListProps, TListRef, TMessagesIdsRef } from '../definitions'; @@ -20,9 +20,9 @@ export const useScroll = ({ listRef, messagesIds }: { listRef: TListRef; message [] ); - const jumpToBottom = () => { + const jumpToBottom = useCallback(() => { listRef.current?.scrollToOffset({ offset: -100 }); - }; + }, [listRef]); const onViewableItemsChanged: IListProps['onViewableItemsChanged'] = ({ viewableItems: vi }) => { viewableItems.current = vi;