Compare commits
5 Commits
develop
...
fix.add-hi
Author | SHA1 | Date |
---|---|---|
Reinaldo Neto | 85118e1129 | |
Reinaldo Neto | 8cde82a3b4 | |
Reinaldo Neto | cad724f36a | |
Reinaldo Neto | 9cb719658c | |
Reinaldo Neto | 92bbf4726a |
File diff suppressed because one or more lines are too long
|
@ -4,7 +4,7 @@ import React, { forwardRef, isValidElement, useEffect, useImperativeHandle, useR
|
||||||
import { Keyboard } from 'react-native';
|
import { Keyboard } from 'react-native';
|
||||||
import { Easing } from 'react-native-reanimated';
|
import { Easing } from 'react-native-reanimated';
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import BottomSheet, { BottomSheetBackdrop } from '@gorhom/bottom-sheet';
|
import BottomSheet, { BottomSheetBackdrop, BottomSheetProps } from '@gorhom/bottom-sheet';
|
||||||
|
|
||||||
import { useDimensions, useOrientation } from '../../dimensions';
|
import { useDimensions, useOrientation } from '../../dimensions';
|
||||||
import { useTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
|
@ -27,7 +27,7 @@ const ANIMATION_CONFIG = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ActionSheet = React.memo(
|
const ActionSheet = React.memo(
|
||||||
forwardRef(({ children }: { children: React.ReactElement }, ref) => {
|
forwardRef(({ children, onChange }: { children: React.ReactElement; onChange(index: number): void }, ref) => {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const bottomSheetRef = useRef<BottomSheet>(null);
|
const bottomSheetRef = useRef<BottomSheet>(null);
|
||||||
const [data, setData] = useState<TActionSheetOptions>({} as TActionSheetOptions);
|
const [data, setData] = useState<TActionSheetOptions>({} as TActionSheetOptions);
|
||||||
|
@ -125,6 +125,13 @@ const ActionSheet = React.memo(
|
||||||
// when is android tablet and the input text is focused
|
// when is android tablet and the input text is focused
|
||||||
const androidTablet: any = isTablet && isLandscape && !isIOS ? { android_keyboardInputMode: 'adjustResize' } : {};
|
const androidTablet: any = isTablet && isLandscape && !isIOS ? { android_keyboardInputMode: 'adjustResize' } : {};
|
||||||
|
|
||||||
|
const handleOnChange: BottomSheetProps['onChange'] = index => {
|
||||||
|
onChange(index);
|
||||||
|
if (index === -1) {
|
||||||
|
return onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{children}
|
{children}
|
||||||
|
@ -139,7 +146,7 @@ const ActionSheet = React.memo(
|
||||||
enablePanDownToClose
|
enablePanDownToClose
|
||||||
style={{ ...styles.container, ...bottomSheet }}
|
style={{ ...styles.container, ...bottomSheet }}
|
||||||
backgroundStyle={{ backgroundColor: colors.focusedBackground }}
|
backgroundStyle={{ backgroundColor: colors.focusedBackground }}
|
||||||
onChange={index => index === -1 && onClose()}
|
onChange={handleOnChange}
|
||||||
// We need this to allow horizontal swipe gesture inside the bottom sheet like in reaction picker
|
// We need this to allow horizontal swipe gesture inside the bottom sheet like in reaction picker
|
||||||
enableContentPanningGesture={data?.enableContentPanningGesture ?? true}
|
enableContentPanningGesture={data?.enableContentPanningGesture ?? true}
|
||||||
{...androidTablet}
|
{...androidTablet}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import hoistNonReactStatics from 'hoist-non-react-statics';
|
import hoistNonReactStatics from 'hoist-non-react-statics';
|
||||||
import React, { ForwardedRef, forwardRef, useContext, useRef } from 'react';
|
import React, { ForwardedRef, forwardRef, useContext, useRef, useState } from 'react';
|
||||||
|
import { BottomSheetProps } from '@gorhom/bottom-sheet';
|
||||||
|
|
||||||
import { TIconsName } from '../CustomIcon';
|
import { TIconsName } from '../CustomIcon';
|
||||||
import ActionSheet from './ActionSheet';
|
import ActionSheet from './ActionSheet';
|
||||||
|
@ -27,11 +28,13 @@ export type TActionSheetOptions = {
|
||||||
export interface IActionSheetProvider {
|
export interface IActionSheetProvider {
|
||||||
showActionSheet: (item: TActionSheetOptions) => void;
|
showActionSheet: (item: TActionSheetOptions) => void;
|
||||||
hideActionSheet: () => void;
|
hideActionSheet: () => void;
|
||||||
|
actionSheetSnapIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const context = React.createContext<IActionSheetProvider>({
|
const context = React.createContext<IActionSheetProvider>({
|
||||||
showActionSheet: () => {},
|
showActionSheet: () => {},
|
||||||
hideActionSheet: () => {}
|
hideActionSheet: () => {},
|
||||||
|
actionSheetSnapIndex: -1
|
||||||
});
|
});
|
||||||
|
|
||||||
export const useActionSheet = () => useContext(context);
|
export const useActionSheet = () => useContext(context);
|
||||||
|
@ -48,20 +51,24 @@ export const withActionSheet = (Component: React.ComponentType<any>): typeof Com
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ActionSheetProvider = React.memo(({ children }: { children: React.ReactElement | React.ReactElement[] }) => {
|
export const ActionSheetProvider = React.memo(({ children }: { children: React.ReactElement | React.ReactElement[] }) => {
|
||||||
|
const [actionSheetSnapIndex, setActionSheetSnapIndex] = useState(-1);
|
||||||
const ref: ForwardedRef<IActionSheetProvider> = useRef(null);
|
const ref: ForwardedRef<IActionSheetProvider> = useRef(null);
|
||||||
|
|
||||||
|
const onChange: BottomSheetProps['onChange'] = index => setActionSheetSnapIndex(index);
|
||||||
|
|
||||||
const getContext = () => ({
|
const getContext = () => ({
|
||||||
showActionSheet: (options: TActionSheetOptions) => {
|
showActionSheet: (options: TActionSheetOptions) => {
|
||||||
ref.current?.showActionSheet(options);
|
ref.current?.showActionSheet(options);
|
||||||
},
|
},
|
||||||
hideActionSheet: () => {
|
hideActionSheet: () => {
|
||||||
ref.current?.hideActionSheet();
|
ref.current?.hideActionSheet();
|
||||||
}
|
},
|
||||||
|
actionSheetSnapIndex
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Provider value={getContext()}>
|
<Provider value={getContext()}>
|
||||||
<ActionSheet ref={ref}>
|
<ActionSheet ref={ref} onChange={onChange}>
|
||||||
<>{children}</>
|
<>{children}</>
|
||||||
</ActionSheet>
|
</ActionSheet>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text, View, FlatList } from 'react-native';
|
import { Text, View, FlatList, useWindowDimensions } from 'react-native';
|
||||||
|
|
||||||
|
import { useActionSheet } from '../ActionSheet';
|
||||||
import Emoji from '../message/Emoji';
|
import Emoji from '../message/Emoji';
|
||||||
import { useTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import { IReaction } from '../../definitions';
|
import { IReaction } from '../../definitions';
|
||||||
|
@ -8,6 +9,7 @@ import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { useAppSelector } from '../../lib/hooks';
|
import { useAppSelector } from '../../lib/hooks';
|
||||||
|
import { calculatePadding } from './calculatePadding';
|
||||||
|
|
||||||
interface IAllReactionsListItemProps {
|
interface IAllReactionsListItemProps {
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
|
@ -61,15 +63,21 @@ const AllReactionsListItem = ({ item, getCustomEmoji }: IAllReactionsListItemPro
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AllTab = ({ reactions, getCustomEmoji }: IAllTabProps): React.ReactElement => (
|
const AllTab = ({ reactions, getCustomEmoji }: IAllTabProps): React.ReactElement => {
|
||||||
<View style={styles.allTabContainer} testID='reactionsListAllTab'>
|
const { height } = useWindowDimensions();
|
||||||
<FlatList
|
const paddingBottom = calculatePadding(height);
|
||||||
data={reactions}
|
const { actionSheetSnapIndex } = useActionSheet();
|
||||||
contentContainerStyle={styles.listContainer}
|
|
||||||
renderItem={({ item }) => <AllReactionsListItem item={item} getCustomEmoji={getCustomEmoji} />}
|
return (
|
||||||
keyExtractor={item => item.emoji}
|
<View style={styles.allTabContainer} testID='reactionsListAllTab'>
|
||||||
/>
|
<FlatList
|
||||||
</View>
|
data={reactions}
|
||||||
);
|
contentContainerStyle={[styles.listContainer, actionSheetSnapIndex === 0 && { paddingBottom }]}
|
||||||
|
renderItem={({ item }) => <AllReactionsListItem item={item} getCustomEmoji={getCustomEmoji} />}
|
||||||
|
keyExtractor={item => item.emoji}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default AllTab;
|
export default AllTab;
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text, View, FlatList } from 'react-native';
|
import { Text, View, FlatList, useWindowDimensions } from 'react-native';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { useTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import { IReaction, IApplicationState } from '../../definitions';
|
import { IReaction, IApplicationState } from '../../definitions';
|
||||||
import Avatar from '../Avatar';
|
import Avatar from '../Avatar';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { useActionSheet } from '../ActionSheet';
|
||||||
|
import { calculatePadding } from './calculatePadding';
|
||||||
|
|
||||||
const UsersList = ({ tabLabel }: { tabLabel: IReaction }): React.ReactElement => {
|
const UsersList = ({ tabLabel }: { tabLabel: IReaction }): React.ReactElement => {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const useRealName = useSelector((state: IApplicationState) => state.settings.UI_Use_Real_Name);
|
const useRealName = useSelector((state: IApplicationState) => state.settings.UI_Use_Real_Name);
|
||||||
|
const { actionSheetSnapIndex } = useActionSheet();
|
||||||
|
const { height } = useWindowDimensions();
|
||||||
|
const paddingBottom = calculatePadding(height);
|
||||||
|
|
||||||
const { emoji, usernames, names } = tabLabel;
|
const { emoji, usernames, names } = tabLabel;
|
||||||
const users =
|
const users =
|
||||||
|
@ -20,7 +25,7 @@ const UsersList = ({ tabLabel }: { tabLabel: IReaction }): React.ReactElement =>
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
data={users}
|
data={users}
|
||||||
contentContainerStyle={styles.listContainer}
|
contentContainerStyle={[styles.listContainer, actionSheetSnapIndex === 0 && { paddingBottom }]}
|
||||||
ListHeaderComponent={
|
ListHeaderComponent={
|
||||||
<View style={styles.emojiNameContainer}>
|
<View style={styles.emojiNameContainer}>
|
||||||
<Text style={[styles.emojiName, { color: colors.auxiliaryText }]} testID='usersListEmojiName'>
|
<Text style={[styles.emojiName, { color: colors.auxiliaryText }]} testID='usersListEmojiName'>
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
const HEADER_HEIGHT = 48;
|
||||||
|
/**
|
||||||
|
* This SNAP_PERCENTAGE is calculate between the snaps: ['50%', '80%']
|
||||||
|
* so considering the content size is set to 80% and the first snap is 50%
|
||||||
|
* we need to 50% * 80% = 40%
|
||||||
|
*/
|
||||||
|
const SNAP_PERCENTAGE = 0.4;
|
||||||
|
/**
|
||||||
|
* This function is required for the ReactionsList to see the full list and the scroll enables,
|
||||||
|
* because there are two snaps 50% and 80%, and the content size of the flatlist is measured by the 80%,
|
||||||
|
* for either snaps and the header height is the height of the first line of the list.
|
||||||
|
* @param height
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const calculatePadding = (height: number) => height * SNAP_PERCENTAGE - HEADER_HEIGHT;
|
Loading…
Reference in New Issue