Remove wrong use of memo and some requested changes

This commit is contained in:
Danish Ahmed Mirza 2022-07-20 17:59:18 +05:30 committed by Danish
parent 64afe08fe6
commit 10f074eb02
8 changed files with 178 additions and 168 deletions

View File

@ -1,6 +1,5 @@
import React from 'react';
import { View, Pressable } from 'react-native';
import { BorderlessButton } from 'react-native-gesture-handler';
import { useTheme } from '../../theme';
import { CustomIcon } from '../CustomIcon';
@ -9,19 +8,22 @@ import { IFooterProps } from './interfaces';
const BUTTON_HIT_SLOP = { top: 15, right: 15, bottom: 15, left: 15 };
const Footer = React.memo(({ onSearchPressed, onBackspacePressed }: IFooterProps) => {
const Footer = ({ onSearchPressed, onBackspacePressed }: IFooterProps): React.ReactElement => {
const { colors } = useTheme();
return (
<View style={[styles.footerContainer, { backgroundColor: colors.bannerBackground }]}>
<BorderlessButton activeOpacity={0.7} onPress={onSearchPressed} style={styles.footerButtonsContainer}>
<Pressable
onPress={onSearchPressed}
hitSlop={BUTTON_HIT_SLOP}
style={({ pressed }) => [[styles.footerButtonsContainer, { opacity: pressed ? 0.7 : 1 }]]}>
<CustomIcon color={colors.auxiliaryTintColor} size={24} name='search' />
</BorderlessButton>
</Pressable>
<Pressable onPress={onBackspacePressed} hitSlop={BUTTON_HIT_SLOP} style={({ pressed }) => [{ opacity: pressed ? 0.7 : 1 }]}>
<CustomIcon color={colors.auxiliaryTintColor} size={24} name='backspace' />
</Pressable>
</View>
);
});
};
export default Footer;

View File

@ -24,7 +24,7 @@ const TabBar = ({ activeTab, tabs, goToPage }: ITabBarProps): React.ReactElement
backgroundColor: isIOS && pressed ? colors.bannerBackground : 'transparent'
}
]}>
<CustomIcon name={tab} size={24} color={colors.titleText} />
<CustomIcon name={tab} size={24} color={activeTab === i ? colors.tintColor : colors.auxiliaryTintColor} />
<View style={activeTab === i ? [styles.activeTabLine, { backgroundColor: colors.tintColor }] : styles.tabLine} />
</Pressable>
))}

View File

@ -19,7 +19,7 @@ import { IEmoji, ICustomEmojis, TFrequentlyUsedEmojiModel } from '../../definiti
import { useAppSelector } from '../../lib/hooks';
import { IEmojiPickerProps, EventTypes } from './interfaces';
const useFrequentlyUsedEmoji = () => {
export const useFrequentlyUsedEmoji = () => {
const [frequentlyUsed, setFrequentlyUsed] = useState<IEmoji[]>([]);
const [loaded, setLoaded] = useState(false);
const getFrequentlyUsedEmojis = async () => {
@ -41,146 +41,150 @@ const useFrequentlyUsedEmoji = () => {
return { frequentlyUsed, loaded };
};
const EmojiPicker = React.memo(
({ onItemClicked, tabEmojiStyle, isEmojiKeyboard = false, searching = false, searchedEmojis = [] }: IEmojiPickerProps) => {
const [width, setWidth] = useState(null);
const { colors } = useTheme();
const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji();
const EmojiPicker = ({
onItemClicked,
tabEmojiStyle,
isEmojiKeyboard = false,
searching = false,
searchedEmojis = []
}: IEmojiPickerProps): React.ReactElement | null => {
const [width, setWidth] = useState(null);
const { colors } = useTheme();
const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji();
const baseUrl = useAppSelector(state => state.server?.server);
const allCustomEmojis: ICustomEmojis = useAppSelector(state => state.customEmojis);
const customEmojis = useMemo(
() =>
Object.keys(allCustomEmojis)
.filter(item => item === allCustomEmojis[item].name)
.map(item => ({
content: allCustomEmojis[item].name,
extension: allCustomEmojis[item].extension,
isCustom: true
})),
[allCustomEmojis]
);
const baseUrl = useAppSelector(state => state.server?.server);
const allCustomEmojis: ICustomEmojis = useAppSelector(state => state.customEmojis);
const customEmojis = useMemo(
() =>
Object.keys(allCustomEmojis)
.filter(item => item === allCustomEmojis[item].name)
.map(item => ({
content: allCustomEmojis[item].name,
extension: allCustomEmojis[item].extension,
isCustom: true
})),
[allCustomEmojis]
);
const handleEmojiSelect = (emoji: IEmoji) => {
try {
if (emoji.isCustom) {
_addFrequentlyUsed({
content: emoji.content,
extension: emoji.extension,
isCustom: true
});
onItemClicked(EventTypes.EMOJI_PRESSED, `:${emoji.content}:`);
} else {
const content = emoji;
_addFrequentlyUsed({ content, isCustom: false });
const shortname = `:${emoji}:`;
onItemClicked(EventTypes.EMOJI_PRESSED, shortnameToUnicode(shortname), shortname);
}
} catch (e) {
log(e);
}
};
const _addFrequentlyUsed = protectedFunction(async (emoji: IEmoji) => {
const db = database.active;
const freqEmojiCollection = db.get('frequently_used_emojis');
let freqEmojiRecord: TFrequentlyUsedEmojiModel;
try {
freqEmojiRecord = await freqEmojiCollection.find(emoji.content);
} catch (error) {
// Do nothing
}
await db.write(async () => {
if (freqEmojiRecord) {
await freqEmojiRecord.update(f => {
if (f.count) {
f.count += 1;
}
});
} else {
await freqEmojiCollection.create(f => {
f._raw = sanitizedRaw({ id: emoji.content }, freqEmojiCollection.schema);
Object.assign(f, emoji);
f.count = 1;
});
}
});
});
const onLayout = ({
nativeEvent: {
layout: { width }
}
}: any) => setWidth(width);
const renderCategory = (category: keyof typeof emojisByCategory, i: number, label: string, tabsCount: number) => {
let emojis = [];
if (i === 0) {
emojis = frequentlyUsed;
} else if (i === 1) {
emojis = customEmojis;
const handleEmojiSelect = (emoji: IEmoji) => {
try {
if (emoji.isCustom) {
_addFrequentlyUsed({
content: emoji.content,
extension: emoji.extension,
isCustom: true
});
onItemClicked(EventTypes.EMOJI_PRESSED, `:${emoji.content}:`);
} else {
emojis = emojisByCategory[category];
const content = emoji;
_addFrequentlyUsed({ content, isCustom: false });
const shortname = `:${emoji}:`;
onItemClicked(EventTypes.EMOJI_PRESSED, shortnameToUnicode(shortname), shortname);
}
return (
} catch (e) {
log(e);
}
};
const _addFrequentlyUsed = protectedFunction(async (emoji: IEmoji) => {
const db = database.active;
const freqEmojiCollection = db.get('frequently_used_emojis');
let freqEmojiRecord: TFrequentlyUsedEmojiModel;
try {
freqEmojiRecord = await freqEmojiCollection.find(emoji.content);
} catch (error) {
// Do nothing
}
await db.write(async () => {
if (freqEmojiRecord) {
await freqEmojiRecord.update(f => {
if (f.count) {
f.count += 1;
}
});
} else {
await freqEmojiCollection.create(f => {
f._raw = sanitizedRaw({ id: emoji.content }, freqEmojiCollection.schema);
Object.assign(f, emoji);
f.count = 1;
});
}
});
});
const onLayout = ({
nativeEvent: {
layout: { width }
}
}: any) => setWidth(width);
const renderCategory = (category: keyof typeof emojisByCategory, i: number, label: string, tabsCount: number) => {
let emojis = [];
if (i === 0) {
emojis = frequentlyUsed;
} else if (i === 1) {
emojis = customEmojis;
} else {
emojis = emojisByCategory[category];
}
return (
<EmojiCategory
emojis={emojis as IEmoji[]}
onEmojiSelected={(emoji: IEmoji) => handleEmojiSelect(emoji)}
style={styles.categoryContainer}
width={width}
baseUrl={baseUrl}
tabLabel={label}
tabsCount={tabsCount}
isBottomSheet={!isEmojiKeyboard}
/>
);
};
if (!loaded) {
return null;
}
const tabsCount = frequentlyUsed.length === 0 ? categories.tabs.length - 1 : categories.tabs.length;
return (
<View onLayout={onLayout} style={{ flex: 1 }}>
{searching ? (
<EmojiCategory
emojis={emojis as IEmoji[]}
emojis={searchedEmojis as IEmoji[]}
onEmojiSelected={(emoji: IEmoji) => handleEmojiSelect(emoji)}
style={styles.categoryContainer}
width={width}
baseUrl={baseUrl}
tabLabel={label}
tabLabel={'searching'}
tabsCount={tabsCount}
isBottomSheet={!isEmojiKeyboard}
/>
);
};
if (!loaded) {
return null;
}
const tabsCount = frequentlyUsed.length === 0 ? categories.tabs.length - 1 : categories.tabs.length;
return (
<View onLayout={onLayout} style={{ flex: 1 }}>
{searching ? (
<EmojiCategory
emojis={searchedEmojis as IEmoji[]}
onEmojiSelected={(emoji: IEmoji) => handleEmojiSelect(emoji)}
style={styles.categoryContainer}
width={width}
baseUrl={baseUrl}
tabLabel={'searching'}
tabsCount={tabsCount}
isBottomSheet={!isEmojiKeyboard}
/>
) : (
<ScrollableTabView
renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} />}
contentProps={{
keyboardShouldPersistTaps: 'always',
keyboardDismissMode: 'none'
}}
style={{ backgroundColor: colors.focusedBackground }}
>
{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 && (
<Footer
onSearchPressed={() => onItemClicked(EventTypes.SEARCH_PRESSED)}
onBackspacePressed={() => onItemClicked(EventTypes.BACKSPACE_PRESSED)}
/>
)}
</View>
);
}
);
) : (
<ScrollableTabView
renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} />}
contentProps={{
keyboardShouldPersistTaps: 'always',
keyboardDismissMode: 'none'
}}
style={{ backgroundColor: colors.focusedBackground }}
>
{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 && (
<Footer
onSearchPressed={() => onItemClicked(EventTypes.SEARCH_PRESSED)}
onBackspacePressed={() => onItemClicked(EventTypes.BACKSPACE_PRESSED)}
/>
)}
</View>
);
};
export default EmojiPicker;

View File

@ -13,6 +13,7 @@ import database from '../../lib/database';
import styles from './styles';
const BUTTON_HIT_SLOP = { top: 15, right: 15, bottom: 15, left: 15 };
const EMOJI_SIZE = 30;
interface IEmojiSearchbarProps {
openEmoji: () => void;
@ -22,12 +23,17 @@ interface IEmojiSearchbarProps {
baseUrl: string;
}
const renderEmoji = (emoji: IEmoji, size: number, baseUrl: string) => {
const Emoji = React.memo(({ emoji, baseUrl }: { emoji: IEmoji; baseUrl: string }) => {
const { colors } = useTheme();
if (emoji?.name) {
return <CustomEmoji style={{ height: size, width: size, margin: 4 }} emoji={emoji} baseUrl={baseUrl} />;
return <CustomEmoji style={{ height: EMOJI_SIZE, width: EMOJI_SIZE, margin: 4 }} emoji={emoji} baseUrl={baseUrl} />;
}
return <Text style={[styles.searchedEmoji, { fontSize: size }]}>{shortnameToUnicode(`:${emoji}:`)}</Text>;
};
return (
<Text style={[styles.searchedEmoji, { fontSize: EMOJI_SIZE, color: colors.backdropColor }]}>
{shortnameToUnicode(`:${emoji}:`)}
</Text>
);
});
const EmojiSearchbar = React.forwardRef<TextInput, IEmojiSearchbarProps>(
({ openEmoji, onChangeText, emojis, onEmojiSelected, baseUrl }, ref) => {
@ -59,14 +65,13 @@ const EmojiSearchbar = React.forwardRef<TextInput, IEmojiSearchbarProps>(
if (!text) getFrequentlyUsedEmojis();
};
const renderItem = (emoji: IEmoji) => {
const emojiSize = 30;
return (
<View style={[styles.emojiContainer]}>
<Pressable onPress={() => onEmojiSelected(emoji)}>{renderEmoji(emoji, emojiSize, baseUrl)}</Pressable>
</View>
);
};
const renderItem = (emoji: IEmoji) => (
<View style={[styles.emojiContainer]}>
<Pressable onPress={() => onEmojiSelected(emoji)}>
<Emoji emoji={emoji} baseUrl={baseUrl} />
</Pressable>
</View>
);
return (
<View style={{ borderTopWidth: 1, borderTopColor: colors.borderColor, backgroundColor: colors.backgroundColor }}>
<FlatList

View File

@ -166,7 +166,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
private typingTimeout: any;
private emojiSearchbarRef: any;
private emojiSearchbarRef: React.RefObject<RNTextInput>;
static defaultProps = {
message: {
@ -627,7 +627,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
case EventTypes.SEARCH_PRESSED:
this.setState({ showEmojiKeyboard: false, showEmojiSearchbar: true });
setTimeout(() => {
this.emojiSearchbarRef.current.focus();
this.emojiSearchbarRef.current?.focus();
}, 400);
break;
default:
@ -930,6 +930,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
openEmoji = () => {
logEvent(events.ROOM_OPEN_EMOJI);
this.setState({ showEmojiKeyboard: true, showEmojiSearchbar: false });
this.stopTrackingMention();
};
recordingCallback = (recording: any) => {

View File

@ -159,8 +159,7 @@ export default StyleSheet.create({
...sharedStyles.textRegular
},
searchedEmoji: {
backgroundColor: 'transparent',
color: '#ffffff'
backgroundColor: 'transparent'
},
emojiContainer: { justifyContent: 'center', marginHorizontal: 2 },
emojiListContainer: { height: 50, paddingHorizontal: 5, marginVertical: 5, flexGrow: 1 },
@ -172,7 +171,7 @@ export default StyleSheet.create({
alignItems: 'center'
},
openEmojiKeyboard: { marginHorizontal: 10, justifyContent: 'center' },
emojiSearchbar: { padding: 10, borderRadius: 5 },
emojiSearchbar: { paddingHorizontal: 20, borderRadius: 2, fontSize: 16 },
textInputContainer: { justifyContent: 'center', marginBottom: 0, marginRight: 15 },
listEmptyComponent: {
width: '100%',

View File

@ -73,7 +73,7 @@ const ReactionPicker = React.memo(({ onEmojiSelected, message, reactionClose }:
};
return (
<View style={[styles.reactionPickerContainer]} testID='reaction-picker'>
<View style={styles.reactionPickerContainer} testID='reaction-picker'>
<View style={styles.searchbarContainer}>
<FormTextInput
autoCapitalize='none'

View File

@ -831,20 +831,19 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
showReactionPicker = () => {
const { showActionSheet, width, height } = this.props;
const { reacting, selectedMessage } = this.state;
showActionSheet &&
showActionSheet({
children: (
<ReactionPicker
show={reacting}
message={selectedMessage}
onEmojiSelected={this.onReactionPress}
reactionClose={this.onReactionClose}
width={width}
height={height}
/>
),
snaps: [400, '100%']
});
showActionSheet({
children: (
<ReactionPicker
show={reacting}
message={selectedMessage}
onEmojiSelected={this.onReactionPress}
reactionClose={this.onReactionClose}
width={width}
height={height}
/>
),
snaps: [400, '100%']
});
};
onReactionInit = (message: TAnyMessageModel) => {