128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
import React from 'react';
|
|
import { FlatList, StyleSheet, Text, View } from 'react-native';
|
|
|
|
import { TSupportedThemes, useTheme } from '../../theme';
|
|
import { themes } from '../../lib/constants';
|
|
import { CustomIcon } from '../CustomIcon';
|
|
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
|
|
import { addFrequentlyUsed } from '../../lib/methods';
|
|
import { useFrequentlyUsedEmoji } from '../../lib/hooks';
|
|
import CustomEmoji from '../EmojiPicker/CustomEmoji';
|
|
import { useDimensions } from '../../dimensions';
|
|
import sharedStyles from '../../views/Styles';
|
|
import { IEmoji, TAnyMessage } from '../../definitions';
|
|
import Touch from '../Touch';
|
|
|
|
export interface IHeader {
|
|
handleReaction: (emoji: IEmoji | null, message: TAnyMessage) => void;
|
|
message: TAnyMessage;
|
|
isMasterDetail: boolean;
|
|
}
|
|
|
|
type TOnReaction = ({ emoji }: { emoji?: IEmoji }) => void;
|
|
|
|
interface THeaderItem {
|
|
item: IEmoji;
|
|
onReaction: TOnReaction;
|
|
theme: TSupportedThemes;
|
|
}
|
|
|
|
interface THeaderFooter {
|
|
onReaction: TOnReaction;
|
|
theme: TSupportedThemes;
|
|
}
|
|
|
|
export const HEADER_HEIGHT = 36;
|
|
const ITEM_SIZE = 36;
|
|
const CONTAINER_MARGIN = 8;
|
|
const ITEM_MARGIN = 8;
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
alignItems: 'center',
|
|
marginHorizontal: CONTAINER_MARGIN
|
|
},
|
|
headerItem: {
|
|
height: ITEM_SIZE,
|
|
width: ITEM_SIZE,
|
|
borderRadius: ITEM_SIZE / 2,
|
|
marginHorizontal: ITEM_MARGIN,
|
|
justifyContent: 'center',
|
|
alignItems: 'center'
|
|
},
|
|
headerIcon: {
|
|
...sharedStyles.textAlignCenter,
|
|
fontSize: 20,
|
|
color: '#fff'
|
|
},
|
|
customEmoji: {
|
|
height: 20,
|
|
width: 20
|
|
}
|
|
});
|
|
|
|
const HeaderItem = ({ item, onReaction, theme }: THeaderItem) => (
|
|
<Touch
|
|
testID={`message-actions-emoji-${item}`}
|
|
onPress={() => onReaction({ emoji: item })}
|
|
style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]}
|
|
>
|
|
{typeof item === 'string' ? (
|
|
<Text style={styles.headerIcon}>{shortnameToUnicode(`:${item}:`)}</Text>
|
|
) : (
|
|
<CustomEmoji style={styles.customEmoji} emoji={item} />
|
|
)}
|
|
</Touch>
|
|
);
|
|
|
|
const HeaderFooter = ({ onReaction, theme }: THeaderFooter) => (
|
|
<Touch
|
|
testID='add-reaction'
|
|
onPress={(param: any) => onReaction(param)}
|
|
style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]}
|
|
>
|
|
<CustomIcon name='reaction-add' size={24} color={themes[theme].bodyText} />
|
|
</Touch>
|
|
);
|
|
|
|
const Header = React.memo(({ handleReaction, message, isMasterDetail }: IHeader) => {
|
|
const { width, height } = useDimensions();
|
|
const { theme } = useTheme();
|
|
const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji(true);
|
|
const isLandscape = width > height;
|
|
const size = (isLandscape || isMasterDetail ? width / 2 : width) - CONTAINER_MARGIN * 2;
|
|
const quantity = Math.trunc(size / (ITEM_SIZE + ITEM_MARGIN * 2) - 1);
|
|
|
|
const onReaction: TOnReaction = ({ emoji }) => {
|
|
handleReaction(emoji || null, message);
|
|
if (emoji) {
|
|
addFrequentlyUsed(emoji);
|
|
}
|
|
};
|
|
|
|
const renderItem = ({ item }: { item: IEmoji }) => <HeaderItem item={item} onReaction={onReaction} theme={theme} />;
|
|
|
|
const renderFooter = () => <HeaderFooter onReaction={onReaction} theme={theme} />;
|
|
|
|
if (!loaded) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<View style={[styles.container, { backgroundColor: themes[theme].focusedBackground }]}>
|
|
<FlatList
|
|
data={frequentlyUsed.slice(0, quantity)}
|
|
renderItem={renderItem}
|
|
ListFooterComponent={renderFooter}
|
|
style={{ backgroundColor: themes[theme].focusedBackground }}
|
|
keyExtractor={item => (typeof item === 'string' ? item : item.name)}
|
|
showsHorizontalScrollIndicator={false}
|
|
scrollEnabled={false}
|
|
horizontal
|
|
/>
|
|
</View>
|
|
);
|
|
});
|
|
|
|
export default Header;
|