Migrate to react-native-tab-view

This commit is contained in:
Danish 2022-08-26 19:03:09 +05:30
parent 0f51a3c5df
commit 359171ed03
7 changed files with 109 additions and 74 deletions

View File

@ -7,28 +7,30 @@ import { ITabBarProps } from './interfaces';
import { isIOS } from '../../lib/methods/helpers'; import { isIOS } from '../../lib/methods/helpers';
import { CustomIcon } from '../CustomIcon'; import { CustomIcon } from '../CustomIcon';
const TabBar = ({ activeTab, tabs, goToPage }: ITabBarProps): React.ReactElement => { const TabBar = ({ tabs, activeTab, onPress, showFrequentlyUsed }: ITabBarProps): React.ReactElement => {
const { colors } = useTheme(); const { colors } = useTheme();
return ( return (
<View style={styles.tabsContainer}> <View style={styles.tabsContainer}>
{tabs?.map((tab, i) => ( {tabs?.map((tab, i) => {
<Pressable if (i === 0 && !showFrequentlyUsed) return null;
key={tab} return (
onPress={() => goToPage?.(i)} <Pressable
testID={`emoji-picker-tab-${tab}`} key={tab.key}
android_ripple={{ color: colors.bannerBackground }} onPress={() => onPress(tab.key)}
style={({ pressed }: { pressed: boolean }) => [ testID={`emoji-picker-tab-${tab.key}`}
styles.tab, android_ripple={{ color: colors.bannerBackground }}
{ style={({ pressed }: { pressed: boolean }) => [
backgroundColor: isIOS && pressed ? colors.bannerBackground : 'transparent' styles.tab,
} {
]} backgroundColor: isIOS && pressed ? colors.bannerBackground : 'transparent'
> }
<CustomIcon name={tab} size={24} color={activeTab === i ? colors.tintColor : colors.auxiliaryTintColor} /> ]}
<View style={activeTab === i ? [styles.activeTabLine, { backgroundColor: colors.tintColor }] : styles.tabLine} /> >
</Pressable> <CustomIcon name={tab.key} size={24} color={activeTab === i ? colors.tintColor : colors.auxiliaryTintColor} />
))} <View style={activeTab === i ? [styles.activeTabLine, { backgroundColor: colors.tintColor }] : styles.tabLine} />
</Pressable>
);
})}
</View> </View>
); );
}; };

View File

@ -1,44 +1,59 @@
const list = ['frequentlyUsed', 'custom', 'people', 'nature', 'food', 'activity', 'travel', 'objects', 'symbols', 'flags']; import { TIconsName } from '../CustomIcon';
const tabs = [
export type IEmojiCategory =
| 'frequentlyUsed'
| 'custom'
| 'people'
| 'nature'
| 'food'
| 'activity'
| 'travel'
| 'objects'
| 'symbols'
| 'flags';
const tabs: {
key: TIconsName;
title: IEmojiCategory;
}[] = [
{ {
tabLabel: 'clock', key: 'clock',
category: list[0] title: 'frequentlyUsed'
}, },
{ {
tabLabel: 'rocket', key: 'rocket',
category: list[1] title: 'custom'
}, },
{ {
tabLabel: 'emoji', key: 'emoji',
category: list[2] title: 'people'
}, },
{ {
tabLabel: 'leaf', key: 'leaf',
category: list[3] title: 'nature'
}, },
{ {
tabLabel: 'burger', key: 'burger',
category: list[4] title: 'food'
}, },
{ {
tabLabel: 'basketball', key: 'basketball',
category: list[5] title: 'activity'
}, },
{ {
tabLabel: 'airplane', key: 'airplane',
category: list[6] title: 'travel'
}, },
{ {
tabLabel: 'lamp-bulb', key: 'lamp-bulb',
category: list[7] title: 'objects'
}, },
{ {
tabLabel: 'percentage', key: 'percentage',
category: list[8] title: 'symbols'
}, },
{ {
tabLabel: 'flag', key: 'flag',
category: list[9] title: 'flags'
} }
]; ];
export default { list, tabs }; export default tabs;

View File

@ -1,13 +1,13 @@
import React, { useMemo } from 'react'; import React, { useMemo, useState } from 'react';
import { View } from 'react-native'; import { View } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view'; import { TabView, SceneRendererProps, NavigationState } from 'react-native-tab-view';
import { shallowEqual } from 'react-redux'; import { shallowEqual } from 'react-redux';
import TabBar from './TabBar'; import TabBar from './TabBar';
import EmojiCategory from './EmojiCategory'; import EmojiCategory from './EmojiCategory';
import Footer from './Footer'; import Footer from './Footer';
import styles from './styles'; import styles from './styles';
import categories from './categories'; import categories, { IEmojiCategory } from './categories';
import { emojisByCategory } from './emojis'; import { emojisByCategory } from './emojis';
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode'; import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
import log from '../../lib/methods/helpers/log'; import log from '../../lib/methods/helpers/log';
@ -16,16 +16,18 @@ import { IEmoji, ICustomEmojis } from '../../definitions';
import { useAppSelector } from '../../lib/hooks'; import { useAppSelector } from '../../lib/hooks';
import { IEmojiPickerProps, EventTypes } from './interfaces'; import { IEmojiPickerProps, EventTypes } from './interfaces';
import { useFrequentlyUsedEmoji, addFrequentlyUsed } from './frequentlyUsedEmojis'; import { useFrequentlyUsedEmoji, addFrequentlyUsed } from './frequentlyUsedEmojis';
import { TIconsName } from '../CustomIcon';
const EmojiPicker = ({ const EmojiPicker = ({
onItemClicked, onItemClicked,
tabEmojiStyle,
isEmojiKeyboard = false, isEmojiKeyboard = false,
searching = false, searching = false,
searchedEmojis = [] searchedEmojis = []
}: IEmojiPickerProps): React.ReactElement | null => { }: IEmojiPickerProps): React.ReactElement | null => {
const { colors } = useTheme(); const { colors } = useTheme();
const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji(); const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji();
const [index, setIndex] = useState(0);
const [routes] = useState(categories);
const baseUrl = useAppSelector(state => state.server?.server); const baseUrl = useAppSelector(state => state.server?.server);
const allCustomEmojis: ICustomEmojis = useAppSelector(state => state.customEmojis, shallowEqual); const allCustomEmojis: ICustomEmojis = useAppSelector(state => state.customEmojis, shallowEqual);
@ -62,14 +64,16 @@ const EmojiPicker = ({
} }
}; };
const renderCategory = (category: keyof typeof emojisByCategory, i: number, label: string, tabsCount: number) => { const tabsCount = frequentlyUsed.length === 0 ? categories.length - 1 : categories.length;
const Category = React.memo(({ title }: { title: IEmojiCategory }) => {
let emojis = []; let emojis = [];
if (i === 0) { if (title === 'frequentlyUsed') {
emojis = frequentlyUsed; emojis = frequentlyUsed;
} else if (i === 1) { } else if (title === 'custom') {
emojis = customEmojis; emojis = customEmojis;
} else { } else {
emojis = emojisByCategory[category]; emojis = emojisByCategory[title];
} }
return ( return (
<EmojiCategory <EmojiCategory
@ -77,18 +81,24 @@ const EmojiPicker = ({
onEmojiSelected={(emoji: IEmoji | string) => handleEmojiSelect(emoji)} onEmojiSelected={(emoji: IEmoji | string) => handleEmojiSelect(emoji)}
style={styles.categoryContainer} style={styles.categoryContainer}
baseUrl={baseUrl} baseUrl={baseUrl}
tabLabel={label}
tabsCount={tabsCount} tabsCount={tabsCount}
/> />
); );
});
type Route = {
key: string;
title: string;
}; };
type State = NavigationState<Route>;
const renderTabBar = (props: SceneRendererProps & { navigationState: State }) => (
<TabBar tabs={categories} onPress={props.jumpTo} activeTab={index} showFrequentlyUsed={frequentlyUsed.length > 0} />
);
if (!loaded) { if (!loaded) {
return null; return null;
} }
const tabsCount = frequentlyUsed.length === 0 ? categories.tabs.length - 1 : categories.tabs.length;
return ( return (
<View style={styles.emojiPickerContainer}> <View style={styles.emojiPickerContainer}>
{searching ? ( {searching ? (
@ -97,24 +107,24 @@ const EmojiPicker = ({
onEmojiSelected={(emoji: IEmoji | string) => handleEmojiSelect(emoji)} onEmojiSelected={(emoji: IEmoji | string) => handleEmojiSelect(emoji)}
style={styles.categoryContainer} style={styles.categoryContainer}
baseUrl={baseUrl} baseUrl={baseUrl}
tabLabel={'searching'}
tabsCount={tabsCount} tabsCount={tabsCount}
/> />
) : ( ) : (
<ScrollableTabView <TabView
renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} />} lazy
contentProps={{ navigationState={{ index, routes }}
keyboardShouldPersistTaps: 'always', renderScene={({
keyboardDismissMode: 'none' route
}} }: {
route: {
key: TIconsName;
title: IEmojiCategory;
};
}) => <Category key={route.key} title={route.title} />}
onIndexChange={setIndex}
style={{ backgroundColor: colors.focusedBackground }} style={{ backgroundColor: colors.focusedBackground }}
> renderTabBar={renderTabBar}
{categories.tabs.map((tab: any, i) => />
i === 0 && frequentlyUsed.length === 0
? null // when no frequentlyUsed don't show the tab
: renderCategory(tab.category, i, tab.tabLabel, tabsCount)
)}
</ScrollableTabView>
)} )}
{isEmojiKeyboard && ( {isEmojiKeyboard && (
<Footer <Footer

View File

@ -1,5 +1,3 @@
import { StyleProp, TextStyle } from 'react-native';
import { TIconsName } from '../CustomIcon'; import { TIconsName } from '../CustomIcon';
import { IEmoji } from '../../definitions'; import { IEmoji } from '../../definitions';
@ -11,7 +9,6 @@ export enum EventTypes {
export interface IEmojiPickerProps { export interface IEmojiPickerProps {
onItemClicked: (event: EventTypes, emoji?: string, shortname?: string) => void; onItemClicked: (event: EventTypes, emoji?: string, shortname?: string) => void;
tabEmojiStyle?: StyleProp<TextStyle>;
isEmojiKeyboard?: boolean; isEmojiKeyboard?: boolean;
searching?: boolean; searching?: boolean;
searchedEmojis?: (string | IEmoji)[]; searchedEmojis?: (string | IEmoji)[];
@ -23,8 +20,8 @@ export interface IFooterProps {
} }
export interface ITabBarProps { export interface ITabBarProps {
goToPage?: (page: number) => void;
activeTab?: number; activeTab?: number;
tabs?: TIconsName[]; tabs?: { key: TIconsName; title: string }[];
tabEmojiStyle: StyleProp<TextStyle>; onPress: (ket: string) => void;
showFrequentlyUsed?: boolean;
} }

View File

@ -33,7 +33,6 @@ export interface IEmojiCategory {
emojis: (IEmoji | string)[]; emojis: (IEmoji | string)[];
onEmojiSelected: (emoji: IEmoji | string) => void; onEmojiSelected: (emoji: IEmoji | string) => void;
style: StyleProp<ImageStyle>; style: StyleProp<ImageStyle>;
tabLabel: string;
tabsCount: number; tabsCount: number;
} }

View File

@ -105,6 +105,7 @@
"react-native-notifications": "^4.2.4", "react-native-notifications": "^4.2.4",
"react-native-notifier": "1.6.1", "react-native-notifier": "1.6.1",
"react-native-orientation-locker": "1.1.8", "react-native-orientation-locker": "1.1.8",
"react-native-pager-view": "^5.4.25",
"react-native-picker-select": "^8.0.4", "react-native-picker-select": "^8.0.4",
"react-native-platform-touchable": "1.1.1", "react-native-platform-touchable": "1.1.1",
"react-native-popover-view": "4.0.1", "react-native-popover-view": "4.0.1",
@ -118,6 +119,7 @@
"react-native-simple-crypto": "RocketChat/react-native-simple-crypto#0.5.1", "react-native-simple-crypto": "RocketChat/react-native-simple-crypto#0.5.1",
"react-native-slowlog": "^1.0.2", "react-native-slowlog": "^1.0.2",
"react-native-svg": "^12.3.0", "react-native-svg": "^12.3.0",
"react-native-tab-view": "^3.1.1",
"react-native-ui-lib": "RocketChat/react-native-ui-lib", "react-native-ui-lib": "RocketChat/react-native-ui-lib",
"react-native-vector-icons": "9.1.0", "react-native-vector-icons": "9.1.0",
"react-native-webview": "10.3.2", "react-native-webview": "10.3.2",

View File

@ -17096,6 +17096,11 @@ react-native-orientation-locker@1.1.8:
resolved "https://registry.yarnpkg.com/react-native-orientation-locker/-/react-native-orientation-locker-1.1.8.tgz#45d1c9e002496b8d286ec8932d6e3e7d341f9c85" resolved "https://registry.yarnpkg.com/react-native-orientation-locker/-/react-native-orientation-locker-1.1.8.tgz#45d1c9e002496b8d286ec8932d6e3e7d341f9c85"
integrity sha512-+Vd7x6O/3zGqYIMXpeDlaw3ma074Dtnocm8ryT9v5SvaiEcWSzII4frPgXaUcc/MiCq4OWZ1JtVoyw75mdomQw== integrity sha512-+Vd7x6O/3zGqYIMXpeDlaw3ma074Dtnocm8ryT9v5SvaiEcWSzII4frPgXaUcc/MiCq4OWZ1JtVoyw75mdomQw==
react-native-pager-view@^5.4.25:
version "5.4.25"
resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-5.4.25.tgz#cd639d5387a7f3d5581b55a33c5faa1cbc200f97"
integrity sha512-3drrYwaLat2fYszymZe3nHMPASJ4aJMaxiejfA1V5SK3OygYmdtmV2u5prX7TnjueJzGSyyaCYEr2JlrRt4YPg==
react-native-picker-select@^8.0.4: react-native-picker-select@^8.0.4:
version "8.0.4" version "8.0.4"
resolved "https://registry.yarnpkg.com/react-native-picker-select/-/react-native-picker-select-8.0.4.tgz#3f7f1f42df69b06e7d2c10338288332a6c40fd10" resolved "https://registry.yarnpkg.com/react-native-picker-select/-/react-native-picker-select-8.0.4.tgz#3f7f1f42df69b06e7d2c10338288332a6c40fd10"
@ -17217,6 +17222,11 @@ react-native-swipe-gestures@^1.0.5:
resolved "https://registry.yarnpkg.com/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz#a172cb0f3e7478ccd681fd36b8bfbcdd098bde7c" resolved "https://registry.yarnpkg.com/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz#a172cb0f3e7478ccd681fd36b8bfbcdd098bde7c"
integrity sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw== integrity sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw==
react-native-tab-view@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.1.1.tgz#1f8d7a835ab4f5b1b1407ec8dddc1053b53fa3c6"
integrity sha512-M5pRN6utQfytKWoKlKVzg5NbkYu308qNoW1khGTtEOTs1k14p2dHJ/BWOJoJYHKbPVUyZldbG9MFT7gUl4YHnw==
react-native-text-size@4.0.0-rc.1: react-native-text-size@4.0.0-rc.1:
version "4.0.0-rc.1" version "4.0.0-rc.1"
resolved "https://registry.yarnpkg.com/react-native-text-size/-/react-native-text-size-4.0.0-rc.1.tgz#1e048d345dd6a5a8e1269e0585c1a5948c478da5" resolved "https://registry.yarnpkg.com/react-native-text-size/-/react-native-text-size-4.0.0-rc.1.tgz#1e048d345dd6a5a8e1269e0585c1a5948c478da5"