[IMPROVEMENT] Message Touchable (#2082)
* [FIX] Avatar touchable * [IMPROVEMENT] onLongPress on all Message Touchables * [IMPROVEMENT] User & baseUrl on MessageContext * [FIX] Context Access * [FIX] BaseURL * Fix User Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
2ea6d34fd1
commit
e46ee13b38
File diff suppressed because it is too large
Load Diff
|
@ -2,12 +2,13 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||
import Touch from '../utils/touch';
|
||||
|
||||
import { avatarURL } from '../utils/avatar';
|
||||
|
||||
const Avatar = React.memo(({
|
||||
text, size, baseUrl, borderRadius, style, avatar, type, children, userId, token, onPress, theme
|
||||
text, size, baseUrl, borderRadius, style, avatar, type, children, userId, token, onPress
|
||||
}) => {
|
||||
const avatarStyle = {
|
||||
width: size,
|
||||
|
@ -36,9 +37,9 @@ const Avatar = React.memo(({
|
|||
|
||||
if (onPress) {
|
||||
image = (
|
||||
<Touch onPress={onPress} theme={theme}>
|
||||
<Touchable onPress={onPress}>
|
||||
{image}
|
||||
</Touch>
|
||||
</Touchable>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -61,7 +62,6 @@ Avatar.propTypes = {
|
|||
children: PropTypes.object,
|
||||
userId: PropTypes.string,
|
||||
token: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
onPress: PropTypes.func
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import Video from './Video';
|
|||
import Reply from './Reply';
|
||||
|
||||
const Attachments = React.memo(({
|
||||
attachments, timeFormat, user, baseUrl, showAttachment, getCustomEmoji, theme
|
||||
attachments, timeFormat, showAttachment, getCustomEmoji, theme
|
||||
}) => {
|
||||
if (!attachments || attachments.length === 0) {
|
||||
return null;
|
||||
|
@ -16,25 +16,23 @@ const Attachments = React.memo(({
|
|||
|
||||
return attachments.map((file, index) => {
|
||||
if (file.image_url) {
|
||||
return <Image key={file.image_url} file={file} user={user} baseUrl={baseUrl} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
return <Image key={file.image_url} file={file} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
}
|
||||
if (file.audio_url) {
|
||||
return <Audio key={file.audio_url} file={file} user={user} baseUrl={baseUrl} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
return <Audio key={file.audio_url} file={file} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
}
|
||||
if (file.video_url) {
|
||||
return <Video key={file.video_url} file={file} user={user} baseUrl={baseUrl} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
return <Video key={file.video_url} file={file} showAttachment={showAttachment} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} user={user} baseUrl={baseUrl} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||
});
|
||||
}, (prevProps, nextProps) => isEqual(prevProps.attachments, nextProps.attachments) && prevProps.theme === nextProps.theme);
|
||||
|
||||
Attachments.propTypes = {
|
||||
attachments: PropTypes.array,
|
||||
timeFormat: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
showAttachment: PropTypes.func,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
|
|
|
@ -7,14 +7,15 @@ import { Audio } from 'expo-av';
|
|||
import Slider from '@react-native-community/slider';
|
||||
import moment from 'moment';
|
||||
import equal from 'deep-equal';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import Markdown from '../markdown';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { isAndroid, isIOS } from '../../utils/deviceInfo';
|
||||
import { withSplit } from '../../split';
|
||||
import MessageContext from './Context';
|
||||
import ActivityIndicator from '../ActivityIndicator';
|
||||
|
||||
const mode = {
|
||||
|
@ -91,10 +92,10 @@ Button.propTypes = {
|
|||
Button.displayName = 'MessageAudioButton';
|
||||
|
||||
class MessageAudio extends React.Component {
|
||||
static contextType = MessageContext;
|
||||
|
||||
static propTypes = {
|
||||
file: PropTypes.object.isRequired,
|
||||
baseUrl: PropTypes.string.isRequired,
|
||||
user: PropTypes.object.isRequired,
|
||||
theme: PropTypes.string,
|
||||
split: PropTypes.bool,
|
||||
getCustomEmoji: PropTypes.func
|
||||
|
@ -102,13 +103,11 @@ class MessageAudio extends React.Component {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { baseUrl, file, user } = props;
|
||||
this.state = {
|
||||
loading: false,
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
paused: true,
|
||||
uri: `${ baseUrl }${ file.audio_url }?rc_uid=${ user.id }&rc_token=${ user.token }`
|
||||
paused: true
|
||||
};
|
||||
|
||||
this.sound = new Audio.Sound();
|
||||
|
@ -116,12 +115,13 @@ class MessageAudio extends React.Component {
|
|||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const { uri } = this.state;
|
||||
const { file } = this.props;
|
||||
const { baseUrl, user } = this.context;
|
||||
|
||||
this.setState({ loading: true });
|
||||
try {
|
||||
await Audio.setAudioModeAsync(mode);
|
||||
await this.sound.loadAsync({ uri });
|
||||
await this.sound.loadAsync({ uri: `${ baseUrl }${ file.audio_url }?rc_uid=${ user.id }&rc_token=${ user.token }` });
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ class MessageAudio extends React.Component {
|
|||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const {
|
||||
currentTime, duration, paused, uri, loading
|
||||
currentTime, duration, paused, loading
|
||||
} = this.state;
|
||||
const { file, split, theme } = this.props;
|
||||
if (nextProps.theme !== theme) {
|
||||
|
@ -145,9 +145,6 @@ class MessageAudio extends React.Component {
|
|||
if (nextState.paused !== paused) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.uri !== uri) {
|
||||
return true;
|
||||
}
|
||||
if (!equal(nextProps.file, file)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -237,9 +234,10 @@ class MessageAudio extends React.Component {
|
|||
loading, paused, currentTime, duration
|
||||
} = this.state;
|
||||
const {
|
||||
user, baseUrl, file, getCustomEmoji, split, theme
|
||||
file, getCustomEmoji, split, theme
|
||||
} = this.props;
|
||||
const { description } = file;
|
||||
const { baseUrl, user } = this.context;
|
||||
|
||||
if (!baseUrl) {
|
||||
return null;
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import styles from './styles';
|
||||
import { BUTTON_HIT_SLOP } from './utils';
|
||||
import I18n from '../../i18n';
|
||||
import { themes } from '../../constants/colors';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const Broadcast = React.memo(({
|
||||
author, user, broadcast, replyBroadcast, theme
|
||||
author, broadcast, theme
|
||||
}) => {
|
||||
const { user, replyBroadcast } = useContext(MessageContext);
|
||||
const isOwn = author._id === user.id;
|
||||
if (broadcast && !isOwn) {
|
||||
return (
|
||||
|
@ -36,10 +38,8 @@ const Broadcast = React.memo(({
|
|||
|
||||
Broadcast.propTypes = {
|
||||
author: PropTypes.object,
|
||||
user: PropTypes.object,
|
||||
broadcast: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
replyBroadcast: PropTypes.func
|
||||
theme: PropTypes.string
|
||||
};
|
||||
Broadcast.displayName = 'MessageBroadcast';
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import { formatLastMessage, BUTTON_HIT_SLOP } from './utils';
|
||||
import styles from './styles';
|
||||
import I18n from '../../i18n';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import equal from 'deep-equal';
|
||||
|
@ -8,6 +8,7 @@ import styles from './styles';
|
|||
import Markdown from '../markdown';
|
||||
import { getInfoMessage } from './utils';
|
||||
import { themes } from '../../constants/colors';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const Content = React.memo((props) => {
|
||||
if (props.isInfo) {
|
||||
|
@ -26,12 +27,13 @@ const Content = React.memo((props) => {
|
|||
if (props.tmid && !props.msg) {
|
||||
content = <Text style={[styles.text, { color: themes[props.theme].bodyText }]}>{I18n.t('Sent_an_attachment')}</Text>;
|
||||
} else {
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
content = (
|
||||
<Markdown
|
||||
msg={props.msg}
|
||||
baseUrl={props.baseUrl}
|
||||
baseUrl={baseUrl}
|
||||
getCustomEmoji={props.getCustomEmoji}
|
||||
username={props.user.username}
|
||||
username={user.username}
|
||||
isEdited={props.isEdited}
|
||||
numberOfLines={(props.tmid && !props.isThreadRoom) ? 1 : 0}
|
||||
preview={props.tmid && !props.isThreadRoom}
|
||||
|
@ -77,8 +79,6 @@ Content.propTypes = {
|
|||
msg: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
isEdited: PropTypes.bool,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import React from 'react';
|
||||
|
||||
const MessageContext = React.createContext();
|
||||
export default MessageContext;
|
|
@ -1,20 +1,22 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import { formatLastMessage, formatMessageCount, BUTTON_HIT_SLOP } from './utils';
|
||||
import styles from './styles';
|
||||
import I18n from '../../i18n';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import { DISCUSSION } from './constants';
|
||||
import { themes } from '../../constants/colors';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const Discussion = React.memo(({
|
||||
msg, dcount, dlm, onDiscussionPress, theme
|
||||
msg, dcount, dlm, theme
|
||||
}) => {
|
||||
const time = formatLastMessage(dlm);
|
||||
const buttonText = formatMessageCount(dcount, DISCUSSION);
|
||||
const { onDiscussionPress } = useContext(MessageContext);
|
||||
return (
|
||||
<>
|
||||
<Text style={[styles.startedDiscussion, { color: themes[theme].auxiliaryText }]}>{I18n.t('Started_discussion')}</Text>
|
||||
|
@ -55,8 +57,7 @@ Discussion.propTypes = {
|
|||
msg: PropTypes.string,
|
||||
dcount: PropTypes.number,
|
||||
dlm: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
onDiscussionPress: PropTypes.func
|
||||
theme: PropTypes.string
|
||||
};
|
||||
Discussion.displayName = 'MessageDiscussion';
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { Text } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import shortnameToUnicode from '../../utils/shortnameToUnicode';
|
||||
import CustomEmoji from '../EmojiPicker/CustomEmoji';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const Emoji = React.memo(({
|
||||
content, standardEmojiStyle, customEmojiStyle, baseUrl, getCustomEmoji
|
||||
content, standardEmojiStyle, customEmojiStyle, getCustomEmoji
|
||||
}) => {
|
||||
const { baseUrl } = useContext(MessageContext);
|
||||
const parsedContent = content.replace(/^:|:$/g, '');
|
||||
const emoji = getCustomEmoji(parsedContent);
|
||||
if (emoji) {
|
||||
|
@ -20,7 +22,6 @@ Emoji.propTypes = {
|
|||
content: PropTypes.string,
|
||||
standardEmojiStyle: PropTypes.object,
|
||||
customEmojiStyle: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
getCustomEmoji: PropTypes.func
|
||||
};
|
||||
Emoji.displayName = 'MessageEmoji';
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import equal from 'deep-equal';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import { createImageProgress } from 'react-native-image-progress';
|
||||
import * as Progress from 'react-native-progress';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import Markdown from '../markdown';
|
||||
import styles from './styles';
|
||||
import { formatAttachmentUrl } from '../../lib/utils';
|
||||
import { withSplit } from '../../split';
|
||||
import { themes } from '../../constants/colors';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const ImageProgress = createImageProgress(FastImage);
|
||||
|
||||
|
@ -41,8 +42,9 @@ export const MessageImage = React.memo(({ img, theme }) => (
|
|||
));
|
||||
|
||||
const ImageContainer = React.memo(({
|
||||
file, imageUrl, baseUrl, user, showAttachment, getCustomEmoji, split, theme
|
||||
file, imageUrl, showAttachment, getCustomEmoji, split, theme
|
||||
}) => {
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
const img = imageUrl || formatAttachmentUrl(file.image_url, user.id, user.token, baseUrl);
|
||||
if (!img) {
|
||||
return null;
|
||||
|
@ -71,8 +73,6 @@ const ImageContainer = React.memo(({
|
|||
ImageContainer.propTypes = {
|
||||
file: PropTypes.object,
|
||||
imageUrl: PropTypes.string,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
showAttachment: PropTypes.func,
|
||||
theme: PropTypes.string,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { View } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
|
||||
import MessageContext from './Context';
|
||||
|
||||
import User from './User';
|
||||
import styles from './styles';
|
||||
import RepliedThread from './RepliedThread';
|
||||
|
@ -111,10 +113,11 @@ const MessageTouchable = React.memo((props) => {
|
|||
</View>
|
||||
);
|
||||
}
|
||||
const { onPress, onLongPress } = useContext(MessageContext);
|
||||
return (
|
||||
<Touchable
|
||||
onLongPress={props.onLongPress}
|
||||
onPress={props.onPress}
|
||||
onLongPress={onLongPress}
|
||||
onPress={onPress}
|
||||
disabled={props.isInfo || props.archived || props.isTemp}
|
||||
>
|
||||
<View>
|
||||
|
@ -129,9 +132,7 @@ MessageTouchable.propTypes = {
|
|||
hasError: PropTypes.bool,
|
||||
isInfo: PropTypes.bool,
|
||||
isTemp: PropTypes.bool,
|
||||
archived: PropTypes.bool,
|
||||
onLongPress: PropTypes.func,
|
||||
onPress: PropTypes.func
|
||||
archived: PropTypes.bool
|
||||
};
|
||||
|
||||
Message.propTypes = {
|
||||
|
@ -143,7 +144,6 @@ Message.propTypes = {
|
|||
hasError: PropTypes.bool,
|
||||
style: PropTypes.any,
|
||||
onLongPress: PropTypes.func,
|
||||
onPress: PropTypes.func,
|
||||
isReadReceiptEnabled: PropTypes.bool,
|
||||
unread: PropTypes.bool,
|
||||
theme: PropTypes.string
|
||||
|
|
|
@ -1,34 +1,31 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { TouchableOpacity } from 'react-native';
|
||||
|
||||
import Avatar from '../Avatar';
|
||||
import styles from './styles';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const MessageAvatar = React.memo(({
|
||||
isHeader, avatar, author, baseUrl, user, small, navToRoomInfo
|
||||
isHeader, avatar, author, small, navToRoomInfo
|
||||
}) => {
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
if (isHeader && author) {
|
||||
const navParam = {
|
||||
t: 'd',
|
||||
rid: author._id
|
||||
};
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => navToRoomInfo(navParam)}
|
||||
disabled={author._id === user.id}
|
||||
>
|
||||
<Avatar
|
||||
style={small ? styles.avatarSmall : styles.avatar}
|
||||
text={avatar ? '' : author.username}
|
||||
size={small ? 20 : 36}
|
||||
borderRadius={small ? 2 : 4}
|
||||
onPress={author._id === user.id ? undefined : () => navToRoomInfo(navParam)}
|
||||
avatar={avatar}
|
||||
baseUrl={baseUrl}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
@ -38,8 +35,6 @@ MessageAvatar.propTypes = {
|
|||
isHeader: PropTypes.bool,
|
||||
avatar: PropTypes.string,
|
||||
author: PropTypes.obj,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.obj,
|
||||
small: PropTypes.bool,
|
||||
navToRoomInfo: PropTypes.func
|
||||
};
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import React from 'react';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import React, { useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import styles from './styles';
|
||||
import { BUTTON_HIT_SLOP } from './utils';
|
||||
import { themes } from '../../constants/colors';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const MessageError = React.memo(({ hasError, onErrorPress, theme }) => {
|
||||
const MessageError = React.memo(({ hasError, theme }) => {
|
||||
if (!hasError) {
|
||||
return null;
|
||||
}
|
||||
const { onErrorPress } = useContext(MessageContext);
|
||||
return (
|
||||
<Touchable onPress={onErrorPress} style={styles.errorButton} hitSlop={BUTTON_HIT_SLOP}>
|
||||
<CustomIcon name='warning' color={themes[theme].dangerColor} size={18} />
|
||||
|
@ -20,7 +22,6 @@ const MessageError = React.memo(({ hasError, onErrorPress, theme }) => {
|
|||
|
||||
MessageError.propTypes = {
|
||||
hasError: PropTypes.bool,
|
||||
onErrorPress: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
MessageError.displayName = 'MessageError';
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import styles from './styles';
|
||||
import Emoji from './Emoji';
|
||||
import { BUTTON_HIT_SLOP } from './utils';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { withTheme } from '../../theme';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const AddReaction = React.memo(({ reactionInit, theme }) => (
|
||||
const AddReaction = React.memo(({ theme }) => {
|
||||
const { reactionInit } = useContext(MessageContext);
|
||||
return (
|
||||
<Touchable
|
||||
onPress={reactionInit}
|
||||
key='message-add-reaction'
|
||||
|
@ -23,11 +26,15 @@ const AddReaction = React.memo(({ reactionInit, theme }) => (
|
|||
<CustomIcon name='add-reaction' size={21} color={themes[theme].tintColor} />
|
||||
</View>
|
||||
</Touchable>
|
||||
));
|
||||
);
|
||||
});
|
||||
|
||||
const Reaction = React.memo(({
|
||||
reaction, user, onReactionLongPress, onReactionPress, baseUrl, getCustomEmoji, theme
|
||||
reaction, getCustomEmoji, theme
|
||||
}) => {
|
||||
const {
|
||||
onReactionPress, onReactionLongPress, baseUrl, user
|
||||
} = useContext(MessageContext);
|
||||
const reacted = reaction.usernames.findIndex(item => item === user.username) !== -1;
|
||||
return (
|
||||
<Touchable
|
||||
|
@ -54,7 +61,7 @@ const Reaction = React.memo(({
|
|||
});
|
||||
|
||||
const Reactions = React.memo(({
|
||||
reactions, user, baseUrl, onReactionPress, reactionInit, onReactionLongPress, getCustomEmoji, theme
|
||||
reactions, getCustomEmoji, theme
|
||||
}) => {
|
||||
if (!Array.isArray(reactions) || reactions.length === 0) {
|
||||
return null;
|
||||
|
@ -65,25 +72,17 @@ const Reactions = React.memo(({
|
|||
<Reaction
|
||||
key={reaction.emoji}
|
||||
reaction={reaction}
|
||||
user={user}
|
||||
baseUrl={baseUrl}
|
||||
onReactionLongPress={onReactionLongPress}
|
||||
onReactionPress={onReactionPress}
|
||||
getCustomEmoji={getCustomEmoji}
|
||||
theme={theme}
|
||||
/>
|
||||
))}
|
||||
<AddReaction reactionInit={reactionInit} theme={theme} />
|
||||
<AddReaction theme={theme} />
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
Reaction.propTypes = {
|
||||
reaction: PropTypes.object,
|
||||
user: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
onReactionPress: PropTypes.func,
|
||||
onReactionLongPress: PropTypes.func,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
@ -91,18 +90,12 @@ Reaction.displayName = 'MessageReaction';
|
|||
|
||||
Reactions.propTypes = {
|
||||
reactions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
user: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
onReactionPress: PropTypes.func,
|
||||
reactionInit: PropTypes.func,
|
||||
onReactionLongPress: PropTypes.func,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
Reactions.displayName = 'MessageReactions';
|
||||
|
||||
AddReaction.propTypes = {
|
||||
reactionInit: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
AddReaction.displayName = 'MessageAddReaction';
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { View, Text, StyleSheet } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import moment from 'moment';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import isEqual from 'deep-equal';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import Markdown from '../markdown';
|
||||
import openLink from '../../utils/openLink';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { withSplit } from '../../split';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
|
@ -79,12 +80,13 @@ const Title = React.memo(({ attachment, timeFormat, theme }) => {
|
|||
});
|
||||
|
||||
const Description = React.memo(({
|
||||
attachment, baseUrl, user, getCustomEmoji, theme
|
||||
attachment, getCustomEmoji, theme
|
||||
}) => {
|
||||
const text = attachment.text || attachment.title;
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
return (
|
||||
<Markdown
|
||||
msg={text}
|
||||
|
@ -124,11 +126,12 @@ const Fields = React.memo(({ attachment, theme }) => {
|
|||
}, (prevProps, nextProps) => isEqual(prevProps.attachment.fields, nextProps.attachment.fields) && prevProps.theme === nextProps.theme);
|
||||
|
||||
const Reply = React.memo(({
|
||||
attachment, timeFormat, baseUrl, user, index, getCustomEmoji, split, theme
|
||||
attachment, timeFormat, index, getCustomEmoji, split, theme
|
||||
}) => {
|
||||
if (!attachment) {
|
||||
return null;
|
||||
}
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
|
||||
const onPress = () => {
|
||||
let url = attachment.title_link || attachment.author_link;
|
||||
|
@ -160,8 +163,6 @@ const Reply = React.memo(({
|
|||
<Description
|
||||
attachment={attachment}
|
||||
timeFormat={timeFormat}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
getCustomEmoji={getCustomEmoji}
|
||||
theme={theme}
|
||||
/>
|
||||
|
@ -174,8 +175,6 @@ const Reply = React.memo(({
|
|||
Reply.propTypes = {
|
||||
attachment: PropTypes.object,
|
||||
timeFormat: PropTypes.string,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
index: PropTypes.number,
|
||||
theme: PropTypes.string,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
|
@ -192,8 +191,6 @@ Title.displayName = 'MessageReplyTitle';
|
|||
|
||||
Description.propTypes = {
|
||||
attachment: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import React, { useContext } from 'react';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import MessageContext from './Context';
|
||||
|
||||
const RCTouchable = React.memo(({ children, ...props }) => {
|
||||
const { onLongPress } = useContext(MessageContext);
|
||||
|
||||
return (
|
||||
<Touchable
|
||||
onLongPress={onLongPress}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Touchable>
|
||||
);
|
||||
});
|
||||
RCTouchable.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
RCTouchable.Ripple = (...args) => Touchable.Ripple(...args);
|
||||
RCTouchable.SelectableBackgroundBorderless = () => Touchable.SelectableBackgroundBorderless();
|
||||
|
||||
export default RCTouchable;
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import {
|
||||
View, Text, StyleSheet, Clipboard
|
||||
} from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import openLink from '../../utils/openLink';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { themes } from '../../constants/colors';
|
||||
|
@ -15,6 +15,7 @@ import { withSplit } from '../../split';
|
|||
import { LISTENER } from '../Toast';
|
||||
import EventEmitter from '../../utils/events';
|
||||
import I18n from '../../i18n';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
|
@ -52,10 +53,11 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const UrlImage = React.memo(({ image, user, baseUrl }) => {
|
||||
const UrlImage = React.memo(({ image }) => {
|
||||
if (!image) {
|
||||
return null;
|
||||
}
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
image = image.includes('http') ? image : `${ baseUrl }/${ image }?rc_uid=${ user.id }&rc_token=${ user.token }`;
|
||||
return <FastImage source={{ uri: image }} style={styles.image} resizeMode={FastImage.resizeMode.cover} />;
|
||||
}, (prevProps, nextProps) => prevProps.image === nextProps.image);
|
||||
|
@ -79,7 +81,7 @@ const UrlContent = React.memo(({ title, description, theme }) => (
|
|||
});
|
||||
|
||||
const Url = React.memo(({
|
||||
url, index, user, baseUrl, split, theme
|
||||
url, index, split, theme
|
||||
}) => {
|
||||
if (!url) {
|
||||
return null;
|
||||
|
@ -109,7 +111,7 @@ const Url = React.memo(({
|
|||
background={Touchable.Ripple(themes[theme].bannerBackground)}
|
||||
>
|
||||
<>
|
||||
<UrlImage image={url.image} user={user} baseUrl={baseUrl} />
|
||||
<UrlImage image={url.image} />
|
||||
<UrlContent title={url.title} description={url.description} theme={theme} />
|
||||
</>
|
||||
</Touchable>
|
||||
|
@ -117,21 +119,19 @@ const Url = React.memo(({
|
|||
}, (oldProps, newProps) => isEqual(oldProps.url, newProps.url) && oldProps.split === newProps.split && oldProps.theme === newProps.theme);
|
||||
|
||||
const Urls = React.memo(({
|
||||
urls, user, baseUrl, split, theme
|
||||
urls, split, theme
|
||||
}) => {
|
||||
if (!urls || urls.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return urls.map((url, index) => (
|
||||
<Url url={url} key={url.url} index={index} user={user} baseUrl={baseUrl} split={split} theme={theme} />
|
||||
<Url url={url} key={url.url} index={index} split={split} theme={theme} />
|
||||
));
|
||||
}, (oldProps, newProps) => isEqual(oldProps.urls, newProps.urls) && oldProps.split === newProps.split && oldProps.theme === newProps.theme);
|
||||
|
||||
UrlImage.propTypes = {
|
||||
image: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
baseUrl: PropTypes.string
|
||||
image: PropTypes.string
|
||||
};
|
||||
UrlImage.displayName = 'MessageUrlImage';
|
||||
|
||||
|
@ -145,8 +145,6 @@ UrlContent.displayName = 'MessageUrlContent';
|
|||
Url.propTypes = {
|
||||
url: PropTypes.object.isRequired,
|
||||
index: PropTypes.number,
|
||||
user: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
split: PropTypes.bool
|
||||
};
|
||||
|
@ -154,8 +152,6 @@ Url.displayName = 'MessageUrl';
|
|||
|
||||
Urls.propTypes = {
|
||||
urls: PropTypes.array,
|
||||
user: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
split: PropTypes.bool
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
View, Text, StyleSheet, TouchableOpacity
|
||||
|
@ -11,6 +11,7 @@ import { withTheme } from '../../theme';
|
|||
import MessageError from './MessageError';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import messageStyles from './styles';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -35,13 +36,14 @@ const styles = StyleSheet.create({
|
|||
});
|
||||
|
||||
const User = React.memo(({
|
||||
isHeader, useRealName, author, alias, ts, timeFormat, hasError, theme, navToRoomInfo, user, ...props
|
||||
isHeader, useRealName, author, alias, ts, timeFormat, hasError, theme, navToRoomInfo, ...props
|
||||
}) => {
|
||||
if (isHeader || hasError) {
|
||||
const navParam = {
|
||||
t: 'd',
|
||||
rid: author._id
|
||||
};
|
||||
const { user } = useContext(MessageContext);
|
||||
const username = (useRealName && author.name) || author.username;
|
||||
const aliasUsername = alias ? (<Text style={[styles.alias, { color: themes[theme].auxiliaryText }]}> @{username}</Text>) : null;
|
||||
const time = moment(ts).format(timeFormat);
|
||||
|
@ -49,15 +51,14 @@ const User = React.memo(({
|
|||
return (
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity
|
||||
style={styles.titleContainer}
|
||||
onPress={() => navToRoomInfo(navParam)}
|
||||
disabled={author._id === user.id}
|
||||
>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={[styles.username, { color: themes[theme].titleText }]} numberOfLines={1}>
|
||||
{alias || username}
|
||||
{aliasUsername}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<Text style={[messageStyles.time, { color: themes[theme].auxiliaryText }]}>{time}</Text>
|
||||
{ hasError && <MessageError hasError={hasError} theme={theme} {...props} /> }
|
||||
|
@ -76,7 +77,6 @@ User.propTypes = {
|
|||
ts: PropTypes.instanceOf(Date),
|
||||
timeFormat: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
user: PropTypes.obj,
|
||||
navToRoomInfo: PropTypes.func
|
||||
};
|
||||
User.displayName = 'MessageUser';
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
import isEqual from 'deep-equal';
|
||||
|
||||
import Touchable from './Touchable';
|
||||
import Markdown from '../markdown';
|
||||
import openLink from '../../utils/openLink';
|
||||
import { isIOS, isTablet } from '../../utils/deviceInfo';
|
||||
|
@ -11,6 +11,7 @@ import { CustomIcon } from '../../lib/Icons';
|
|||
import { formatAttachmentUrl } from '../../lib/utils';
|
||||
import { themes } from '../../constants/colors';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import MessageContext from './Context';
|
||||
|
||||
const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])];
|
||||
const isTypeSupported = type => SUPPORTED_TYPES.indexOf(type) !== -1;
|
||||
|
@ -27,12 +28,12 @@ const styles = StyleSheet.create({
|
|||
});
|
||||
|
||||
const Video = React.memo(({
|
||||
file, baseUrl, user, showAttachment, getCustomEmoji, theme
|
||||
file, showAttachment, getCustomEmoji, theme
|
||||
}) => {
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
if (!baseUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onPress = () => {
|
||||
if (isTypeSupported(file.video_type)) {
|
||||
return showAttachment(file);
|
||||
|
@ -61,8 +62,6 @@ const Video = React.memo(({
|
|||
|
||||
Video.propTypes = {
|
||||
file: PropTypes.object,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
showAttachment: PropTypes.func,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
|
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import { KeyboardUtils } from 'react-native-keyboard-input';
|
||||
|
||||
import Message from './Message';
|
||||
import MessageContext from './Context';
|
||||
import debounce from '../../utils/debounce';
|
||||
import { SYSTEM_MESSAGES, getMessageTranslation } from './utils';
|
||||
import messagesStatus from '../../constants/messagesStatus';
|
||||
|
@ -240,6 +241,20 @@ class MessageContainer extends React.Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<MessageContext.Provider
|
||||
value={{
|
||||
user,
|
||||
baseUrl,
|
||||
onPress: this.onPress,
|
||||
onLongPress: this.onLongPress,
|
||||
reactionInit: this.reactionInit,
|
||||
onErrorPress: this.onErrorPress,
|
||||
replyBroadcast: this.replyBroadcast,
|
||||
onReactionPress: this.onReactionPress,
|
||||
onDiscussionPress: this.onDiscussionPress,
|
||||
onReactionLongPress: this.onReactionLongPress
|
||||
}}
|
||||
>
|
||||
<Message
|
||||
id={id}
|
||||
msg={message}
|
||||
|
@ -253,13 +268,11 @@ class MessageContainer extends React.Component {
|
|||
reactions={reactions}
|
||||
alias={alias}
|
||||
avatar={avatar}
|
||||
user={user}
|
||||
timeFormat={timeFormat}
|
||||
customThreadTimeFormat={customThreadTimeFormat}
|
||||
style={style}
|
||||
archived={archived}
|
||||
broadcast={broadcast}
|
||||
baseUrl={baseUrl}
|
||||
useRealName={useRealName}
|
||||
isReadReceiptEnabled={isReadReceiptEnabled}
|
||||
unread={unread}
|
||||
|
@ -282,14 +295,6 @@ class MessageContainer extends React.Component {
|
|||
isInfo={this.isInfo}
|
||||
isTemp={this.isTemp}
|
||||
hasError={this.hasError}
|
||||
onErrorPress={this.onErrorPress}
|
||||
onPress={this.onPress}
|
||||
onLongPress={this.onLongPress}
|
||||
onReactionLongPress={this.onReactionLongPress}
|
||||
onReactionPress={this.onReactionPress}
|
||||
replyBroadcast={this.replyBroadcast}
|
||||
reactionInit={this.reactionInit}
|
||||
onDiscussionPress={this.onDiscussionPress}
|
||||
showAttachment={showAttachment}
|
||||
getCustomEmoji={getCustomEmoji}
|
||||
navToRoomInfo={navToRoomInfo}
|
||||
|
@ -297,6 +302,7 @@ class MessageContainer extends React.Component {
|
|||
blockAction={blockAction}
|
||||
theme={theme}
|
||||
/>
|
||||
</MessageContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ const RoomHeaderLeft = ({
|
|||
style={styles.avatar}
|
||||
userId={userId}
|
||||
token={token}
|
||||
theme={theme}
|
||||
onPress={goRoomActionsView}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ import messagesStatus from '../../app/constants/messagesStatus';
|
|||
import MessageSeparator from '../../app/views/RoomView/Separator';
|
||||
|
||||
import { themes } from '../../app/constants/colors';
|
||||
import MessageContext from '../../app/containers/message/Context';
|
||||
|
||||
let _theme = 'light';
|
||||
|
||||
|
@ -41,6 +42,20 @@ const getCustomEmoji = (content) => {
|
|||
};
|
||||
|
||||
const Message = props => (
|
||||
<MessageContext.Provider
|
||||
value={{
|
||||
user,
|
||||
baseUrl,
|
||||
onPress: () => {},
|
||||
onLongPress: () => {},
|
||||
reactionInit: () => {},
|
||||
onErrorPress: () => {},
|
||||
replyBroadcast: () => {},
|
||||
onReactionPress: () => {},
|
||||
onDiscussionPress: () => {},
|
||||
onReactionLongPress: () => {}
|
||||
}}
|
||||
>
|
||||
<MessageComponent
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
|
@ -52,6 +67,7 @@ const Message = props => (
|
|||
theme={_theme}
|
||||
{...props}
|
||||
/>
|
||||
</MessageContext.Provider>
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react/prop-types
|
||||
|
|
Loading…
Reference in New Issue