fix: NavBottomFAB position (#5555)
This commit is contained in:
parent
c8e1f20d1e
commit
b189f59950
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import mitt from 'mitt';
|
||||
|
||||
import { TMarkdownStyle } from './interfaces';
|
||||
|
||||
type Events = {
|
||||
toolbarMention: undefined;
|
||||
addMarkdown: {
|
||||
style: TMarkdownStyle;
|
||||
};
|
||||
};
|
||||
|
||||
export const emitter = mitt<Events>();
|
||||
|
||||
emitter.on('*', (type, e) => console.log(type, e));
|
|
@ -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<ITrackingView>) => {
|
||||
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]);
|
||||
};
|
||||
|
|
|
@ -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<TEmitterEvents>();
|
||||
|
||||
emitter.on('*', (type, e) => console.log(type, e));
|
|
@ -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) => {
|
||||
|
|
|
@ -16,4 +16,5 @@ export * from './isValidEmail';
|
|||
export * from './random';
|
||||
export * from './image';
|
||||
export * from './askAndroidMediaPermissions';
|
||||
export * from './emitter';
|
||||
export * from './parseJson';
|
||||
|
|
|
@ -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 (
|
||||
<View style={[styles.container, positionStyle]} testID='nav-jump-to-bottom'>
|
||||
<Touch onPress={() => onPress()} style={[styles.button, { backgroundColor: colors.backgroundColor }]}>
|
||||
<View style={[styles.content, { borderColor: colors.borderColor }]}>
|
||||
<CustomIcon name='chevron-down' color={colors.auxiliaryTintColor} size={36} />
|
||||
</View>
|
||||
</Touch>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
...Platform.select({
|
||||
ios: {
|
||||
bottom: 100 + (isThread ? 40 : 0)
|
||||
},
|
||||
android: {
|
||||
top: 15,
|
||||
scaleY: -1
|
||||
}
|
||||
})
|
||||
}
|
||||
]}
|
||||
testID='nav-jump-to-bottom'
|
||||
>
|
||||
<Touch onPress={() => onPress()} style={[styles.button, { backgroundColor: colors.backgroundColor }]}>
|
||||
<View style={[styles.content, { borderColor: colors.borderColor }]}>
|
||||
<CustomIcon name='chevron-down' color={colors.auxiliaryTintColor} size={36} />
|
||||
</View>
|
||||
</Touch>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
);
|
||||
|
||||
export default NavBottomFAB;
|
||||
|
|
|
@ -5,3 +5,5 @@ export const VIEWABILITY_CONFIG = {
|
|||
};
|
||||
|
||||
export const SCROLL_LIMIT = 200;
|
||||
|
||||
export const EDGE_DISTANCE = 15;
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from './useNavBottomStyle';
|
||||
export * from './useMessages';
|
||||
export * from './useScroll';
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './useNavBottomStyle';
|
|
@ -0,0 +1,8 @@
|
|||
import { ViewStyle } from 'react-native';
|
||||
|
||||
import { EDGE_DISTANCE } from '../../constants';
|
||||
|
||||
export const useNavBottomStyle = (): ViewStyle => ({
|
||||
top: EDGE_DISTANCE,
|
||||
scaleY: -1
|
||||
});
|
|
@ -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
|
||||
};
|
||||
};
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue