UNPKG

react-native-gifted-chat-flashlist

Version:

React Native Gifted Chat with FlashList optimization for better performance

379 lines 13.4 kB
import PropTypes from 'prop-types'; import React from 'react'; import { Text, StyleSheet, TouchableWithoutFeedback, View, } from 'react-native'; import { GiftedChatContext } from './GiftedChatContext'; import { QuickReplies } from './QuickReplies'; import { MessageText } from './MessageText'; import { MessageImage } from './MessageImage'; import { MessageVideo } from './MessageVideo'; import { MessageAudio } from './MessageAudio'; import { Time } from './Time'; import Color from './Color'; import { StylePropType, isSameUser, isSameDay } from './utils'; const styles = { left: StyleSheet.create({ container: { flex: 1, alignItems: 'flex-start', }, wrapper: { borderRadius: 15, backgroundColor: Color.leftBubbleBackground, marginRight: 60, minHeight: 20, justifyContent: 'flex-end', }, containerToNext: { borderBottomLeftRadius: 3, }, containerToPrevious: { borderTopLeftRadius: 3, }, bottom: { flexDirection: 'row', justifyContent: 'flex-start', }, }), right: StyleSheet.create({ container: { flex: 1, alignItems: 'flex-end', }, wrapper: { borderRadius: 15, backgroundColor: Color.defaultBlue, marginLeft: 60, minHeight: 20, justifyContent: 'flex-end', }, containerToNext: { borderBottomRightRadius: 3, }, containerToPrevious: { borderTopRightRadius: 3, }, bottom: { flexDirection: 'row', justifyContent: 'flex-end', }, }), content: StyleSheet.create({ tick: { fontSize: 10, backgroundColor: Color.backgroundTransparent, color: Color.white, }, tickView: { flexDirection: 'row', marginRight: 10, }, username: { top: -3, left: 0, fontSize: 12, backgroundColor: 'transparent', color: '#aaa', }, usernameView: { flexDirection: 'row', marginHorizontal: 10, }, }), }; class Bubble extends React.Component { constructor() { super(...arguments); this.onPress = () => { if (this.props.onPress) this.props.onPress(this.context, this.props.currentMessage); }; this.onLongPress = () => { const { currentMessage, onLongPress, optionTitles, } = this.props; if (onLongPress) { onLongPress(this.context, currentMessage); return; } if (!optionTitles?.length) return; const options = optionTitles; const cancelButtonIndex = options.length - 1; this.context.actionSheet().showActionSheetWithOptions({ options, cancelButtonIndex, }, (buttonIndex) => { console.log('onLongPress', { buttonIndex }); }); }; } styledBubbleToNext() { const { currentMessage, nextMessage, position, containerToNextStyle } = this.props; if (currentMessage && nextMessage && position && isSameUser(currentMessage, nextMessage) && isSameDay(currentMessage, nextMessage)) return [ styles[position].containerToNext, containerToNextStyle?.[position], ]; return null; } styledBubbleToPrevious() { const { currentMessage, previousMessage, position, containerToPreviousStyle, } = this.props; if (currentMessage && previousMessage && position && isSameUser(currentMessage, previousMessage) && isSameDay(currentMessage, previousMessage)) return [ styles[position].containerToPrevious, containerToPreviousStyle && containerToPreviousStyle[position], ]; return null; } renderQuickReplies() { const { currentMessage, onQuickReply, nextMessage, renderQuickReplySend, quickReplyStyle, quickReplyTextStyle, quickReplyContainerStyle, } = this.props; if (currentMessage && currentMessage.quickReplies) { const { /* eslint-disable @typescript-eslint/no-unused-vars */ containerStyle, wrapperStyle, /* eslint-enable @typescript-eslint/no-unused-vars */ ...quickReplyProps } = this.props; if (this.props.renderQuickReplies) return this.props.renderQuickReplies(quickReplyProps); return (<QuickReplies currentMessage={currentMessage} onQuickReply={onQuickReply} renderQuickReplySend={renderQuickReplySend} quickReplyStyle={quickReplyStyle} quickReplyTextStyle={quickReplyTextStyle} quickReplyContainerStyle={quickReplyContainerStyle} nextMessage={nextMessage}/>); } return null; } renderMessageText() { if (this.props.currentMessage && this.props.currentMessage.text) { const { /* eslint-disable @typescript-eslint/no-unused-vars */ containerStyle, wrapperStyle, optionTitles, /* eslint-enable @typescript-eslint/no-unused-vars */ ...messageTextProps } = this.props; if (this.props.renderMessageText) return this.props.renderMessageText(messageTextProps); return <MessageText {...messageTextProps}/>; } return null; } renderMessageImage() { if (this.props.currentMessage && this.props.currentMessage.image) { const { /* eslint-disable @typescript-eslint/no-unused-vars */ containerStyle, wrapperStyle, /* eslint-enable @typescript-eslint/no-unused-vars */ ...messageImageProps } = this.props; if (this.props.renderMessageImage) return this.props.renderMessageImage(messageImageProps); return <MessageImage {...messageImageProps}/>; } return null; } renderMessageVideo() { if (!this.props.currentMessage?.video) return null; const { /* eslint-disable @typescript-eslint/no-unused-vars */ containerStyle, wrapperStyle, /* eslint-enable @typescript-eslint/no-unused-vars */ ...messageVideoProps } = this.props; if (this.props.renderMessageVideo) return this.props.renderMessageVideo(messageVideoProps); return <MessageVideo />; } renderMessageAudio() { if (!this.props.currentMessage?.audio) return null; const { /* eslint-disable @typescript-eslint/no-unused-vars */ containerStyle, wrapperStyle, /* eslint-enable @typescript-eslint/no-unused-vars */ ...messageAudioProps } = this.props; if (this.props.renderMessageAudio) return this.props.renderMessageAudio(messageAudioProps); return <MessageAudio />; } renderTicks() { const { currentMessage, renderTicks, user } = this.props; if (renderTicks && currentMessage) return renderTicks(currentMessage); if (currentMessage && user && currentMessage.user && currentMessage.user._id !== user._id) return null; if (currentMessage && (currentMessage.sent || currentMessage.received || currentMessage.pending)) return (<View style={styles.content.tickView}> {!!currentMessage.sent && (<Text style={[styles.content.tick, this.props.tickStyle]}> {'✓'} </Text>)} {!!currentMessage.received && (<Text style={[styles.content.tick, this.props.tickStyle]}> {'✓'} </Text>)} {!!currentMessage.pending && (<Text style={[styles.content.tick, this.props.tickStyle]}> {'🕓'} </Text>)} </View>); return null; } renderTime() { if (this.props.currentMessage && this.props.currentMessage.createdAt) { const { /* eslint-disable @typescript-eslint/no-unused-vars */ containerStyle, wrapperStyle, textStyle, /* eslint-enable @typescript-eslint/no-unused-vars */ ...timeProps } = this.props; if (this.props.renderTime) return this.props.renderTime(timeProps); return <Time {...timeProps}/>; } return null; } renderUsername() { const { currentMessage, user, renderUsername } = this.props; if (this.props.renderUsernameOnMessage && currentMessage) { if (user && currentMessage.user._id === user._id) return null; if (renderUsername) return renderUsername(currentMessage.user); return (<View style={styles.content.usernameView}> <Text style={[styles.content.username, this.props.usernameStyle]}> {'~ '} {currentMessage.user.name} </Text> </View>); } return null; } renderCustomView() { if (this.props.renderCustomView) return this.props.renderCustomView(this.props); return null; } renderBubbleContent() { return this.props.isCustomViewBottom ? (<View> {this.renderMessageImage()} {this.renderMessageVideo()} {this.renderMessageAudio()} {this.renderMessageText()} {this.renderCustomView()} </View>) : (<View> {this.renderCustomView()} {this.renderMessageImage()} {this.renderMessageVideo()} {this.renderMessageAudio()} {this.renderMessageText()} </View>); } render() { const { position, containerStyle, wrapperStyle, bottomContainerStyle } = this.props; return (<View style={[ styles[position].container, containerStyle && containerStyle[position], ]}> <View style={[ styles[position].wrapper, this.styledBubbleToNext(), this.styledBubbleToPrevious(), wrapperStyle && wrapperStyle[position], ]}> <TouchableWithoutFeedback onPress={this.onPress} onLongPress={this.onLongPress} accessibilityRole='text' {...this.props.touchableProps}> <View> {this.renderBubbleContent()} <View style={[ styles[position].bottom, bottomContainerStyle && bottomContainerStyle[position], ]}> {this.renderUsername()} {this.renderTime()} {this.renderTicks()} </View> </View> </TouchableWithoutFeedback> </View> {this.renderQuickReplies()} </View>); } } Bubble.contextType = GiftedChatContext; Bubble.defaultProps = { touchableProps: {}, onPress: null, onLongPress: null, renderMessageImage: null, renderMessageVideo: null, renderMessageAudio: null, renderMessageText: null, renderCustomView: null, renderUsername: null, renderTicks: null, renderTime: null, renderQuickReplies: null, onQuickReply: null, position: 'left', currentMessage: { text: null, createdAt: null, image: null, }, nextMessage: {}, previousMessage: {}, containerStyle: {}, wrapperStyle: {}, bottomContainerStyle: {}, tickStyle: {}, usernameStyle: {}, containerToNextStyle: {}, containerToPreviousStyle: {}, }; Bubble.propTypes = { user: PropTypes.object.isRequired, touchableProps: PropTypes.object, onLongPress: PropTypes.func, renderMessageImage: PropTypes.func, renderMessageVideo: PropTypes.func, renderMessageAudio: PropTypes.func, renderMessageText: PropTypes.func, renderCustomView: PropTypes.func, isCustomViewBottom: PropTypes.bool, renderUsernameOnMessage: PropTypes.bool, renderUsername: PropTypes.func, renderTime: PropTypes.func, renderTicks: PropTypes.func, renderQuickReplies: PropTypes.func, onQuickReply: PropTypes.func, position: PropTypes.oneOf(['left', 'right']), optionTitles: PropTypes.arrayOf(PropTypes.string), currentMessage: PropTypes.object, nextMessage: PropTypes.object, previousMessage: PropTypes.object, containerStyle: PropTypes.shape({ left: StylePropType, right: StylePropType, }), wrapperStyle: PropTypes.shape({ left: StylePropType, right: StylePropType, }), bottomContainerStyle: PropTypes.shape({ left: StylePropType, right: StylePropType, }), tickStyle: StylePropType, usernameStyle: StylePropType, containerToNextStyle: PropTypes.shape({ left: StylePropType, right: StylePropType, }), containerToPreviousStyle: PropTypes.shape({ left: StylePropType, right: StylePropType, }), }; export default Bubble; //# sourceMappingURL=Bubble.js.map