Chore: Evaluate Message - TypeScript (#3944)
Co-authored-by: GleidsonDaniel <gleidson10daniel@hotmail.com>
This commit is contained in:
parent
6ad4ccd4bd
commit
488074b4ae
|
@ -1,8 +1,7 @@
|
||||||
import { Action } from 'redux';
|
import { Action } from 'redux';
|
||||||
|
|
||||||
import { MESSAGES } from './actionsTypes';
|
import { MESSAGES } from './actionsTypes';
|
||||||
|
import { IMessage } from '../definitions';
|
||||||
type IMessage = Record<string, string>;
|
|
||||||
|
|
||||||
interface IReplyBroadcast extends Action {
|
interface IReplyBroadcast extends Action {
|
||||||
message: IMessage;
|
message: IMessage;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export interface IUserMention {
|
export interface IUserMention {
|
||||||
_id: string;
|
_id: string;
|
||||||
username: string;
|
username?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useContext } from 'react';
|
||||||
import { dequal } from 'dequal';
|
import { dequal } from 'dequal';
|
||||||
import { Text } from 'react-native';
|
import { Text } from 'react-native';
|
||||||
|
|
||||||
import { IMessageAttachments, IMessageAttachedActions } from './interfaces';
|
import { IMessageAttachments } from './interfaces';
|
||||||
import Image from './Image';
|
import Image from './Image';
|
||||||
import Audio from './Audio';
|
import Audio from './Audio';
|
||||||
import Video from './Video';
|
import Video from './Video';
|
||||||
|
@ -23,7 +23,7 @@ export type TElement = {
|
||||||
text: string;
|
text: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AttachedActions = ({ attachment }: IMessageAttachedActions) => {
|
const AttachedActions = ({ attachment }: { attachment: IAttachment }) => {
|
||||||
if (!attachment.actions) {
|
if (!attachment.actions) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,7 @@ const AttachedActions = ({ attachment }: IMessageAttachedActions) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Attachments = React.memo(
|
const Attachments: React.FC<IMessageAttachments> = React.memo(
|
||||||
// @ts-ignore
|
|
||||||
({ attachments, timeFormat, showAttachment, style, getCustomEmoji, isReply }: IMessageAttachments) => {
|
({ attachments, timeFormat, showAttachment, style, getCustomEmoji, isReply }: IMessageAttachments) => {
|
||||||
if (!attachments || attachments.length === 0) {
|
if (!attachments || attachments.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -64,7 +63,7 @@ const Attachments = React.memo(
|
||||||
|
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
return attachments.map((file: IAttachment, index: number) => {
|
const attachmentsElements = attachments.map((file: IAttachment, index: number) => {
|
||||||
if (file && file.image_url) {
|
if (file && file.image_url) {
|
||||||
return (
|
return (
|
||||||
<Image
|
<Image
|
||||||
|
@ -93,7 +92,6 @@ const Attachments = React.memo(
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
style={style}
|
style={style}
|
||||||
isReply={isReply}
|
isReply={isReply}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -109,6 +107,7 @@ const Attachments = React.memo(
|
||||||
|
|
||||||
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} />;
|
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} />;
|
||||||
});
|
});
|
||||||
|
return <>{attachmentsElements}</>;
|
||||||
},
|
},
|
||||||
(prevProps, nextProps) => dequal(prevProps.attachments, nextProps.attachments)
|
(prevProps, nextProps) => dequal(prevProps.attachments, nextProps.attachments)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native';
|
import { StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native';
|
||||||
import { Audio } from 'expo-av';
|
import { Audio, AVPlaybackStatus } from 'expo-av';
|
||||||
import Slider from '@react-native-community/slider';
|
import Slider from '@react-native-community/slider';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { dequal } from 'dequal';
|
import { dequal } from 'dequal';
|
||||||
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
||||||
|
import { Sound } from 'expo-av/build/Audio/Sound';
|
||||||
|
|
||||||
import Touchable from './Touchable';
|
import Touchable from './Touchable';
|
||||||
import Markdown from '../markdown';
|
import Markdown from '../markdown';
|
||||||
|
@ -23,7 +24,7 @@ interface IButton {
|
||||||
paused: boolean;
|
paused: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onPress: Function;
|
onPress: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMessageAudioProps {
|
interface IMessageAudioProps {
|
||||||
|
@ -108,7 +109,7 @@ Button.displayName = 'MessageAudioButton';
|
||||||
class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioState> {
|
class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioState> {
|
||||||
static contextType = MessageContext;
|
static contextType = MessageContext;
|
||||||
|
|
||||||
private sound: any;
|
private sound: Sound;
|
||||||
|
|
||||||
constructor(props: IMessageAudioProps) {
|
constructor(props: IMessageAudioProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -141,7 +142,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
|
||||||
this.setState({ loading: false });
|
this.setState({ loading: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: any, nextState: any) {
|
shouldComponentUpdate(nextProps: IMessageAudioProps, nextState: IMessageAudioState) {
|
||||||
const { currentTime, duration, paused, loading } = this.state;
|
const { currentTime, duration, paused, loading } = this.state;
|
||||||
const { file, theme } = this.props;
|
const { file, theme } = this.props;
|
||||||
if (nextProps.theme !== theme) {
|
if (nextProps.theme !== theme) {
|
||||||
|
@ -182,7 +183,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPlaybackStatusUpdate = (status: any) => {
|
onPlaybackStatusUpdate = (status: AVPlaybackStatus) => {
|
||||||
if (status) {
|
if (status) {
|
||||||
this.onLoad(status);
|
this.onLoad(status);
|
||||||
this.onProgress(status);
|
this.onProgress(status);
|
||||||
|
@ -190,26 +191,32 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onLoad = (data: any) => {
|
onLoad = (data: AVPlaybackStatus) => {
|
||||||
const duration = data.durationMillis / 1000;
|
if (data.isLoaded && data.durationMillis) {
|
||||||
this.setState({ duration: duration > 0 ? duration : 0 });
|
const duration = data.durationMillis / 1000;
|
||||||
};
|
this.setState({ duration: duration > 0 ? duration : 0 });
|
||||||
|
|
||||||
onProgress = (data: any) => {
|
|
||||||
const { duration } = this.state;
|
|
||||||
const currentTime = data.positionMillis / 1000;
|
|
||||||
if (currentTime <= duration) {
|
|
||||||
this.setState({ currentTime });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onEnd = async (data: any) => {
|
onProgress = (data: AVPlaybackStatus) => {
|
||||||
if (data.didJustFinish) {
|
if (data.isLoaded) {
|
||||||
try {
|
const { duration } = this.state;
|
||||||
await this.sound.stopAsync();
|
const currentTime = data.positionMillis / 1000;
|
||||||
this.setState({ paused: true, currentTime: 0 });
|
if (currentTime <= duration) {
|
||||||
} catch {
|
this.setState({ currentTime });
|
||||||
// do nothing
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onEnd = async (data: AVPlaybackStatus) => {
|
||||||
|
if (data.isLoaded) {
|
||||||
|
if (data.didJustFinish) {
|
||||||
|
try {
|
||||||
|
await this.sound.stopAsync();
|
||||||
|
this.setState({ paused: true, currentTime: 0 });
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -238,7 +245,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onValueChange = async (value: any) => {
|
onValueChange = async (value: number) => {
|
||||||
try {
|
try {
|
||||||
this.setState({ currentTime: value });
|
this.setState({ currentTime: value });
|
||||||
await this.sound.setPositionAsync(value * 1000);
|
await this.sound.setPositionAsync(value * 1000);
|
||||||
|
|
|
@ -8,15 +8,17 @@ const Blocks = React.memo(({ blocks, id: mid, rid, blockAction }: IMessageBlocks
|
||||||
const appId = blocks[0]?.appId || '';
|
const appId = blocks[0]?.appId || '';
|
||||||
return React.createElement(
|
return React.createElement(
|
||||||
messageBlockWithContext({
|
messageBlockWithContext({
|
||||||
action: async ({ actionId, value, blockId }: any) => {
|
action: async ({ actionId, value, blockId }: { actionId: string; value: string; blockId: string }) => {
|
||||||
await blockAction({
|
if (blockAction) {
|
||||||
actionId,
|
await blockAction({
|
||||||
appId,
|
actionId,
|
||||||
value,
|
appId,
|
||||||
blockId,
|
value,
|
||||||
rid,
|
blockId,
|
||||||
mid
|
rid,
|
||||||
});
|
mid
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
appId,
|
appId,
|
||||||
rid
|
rid
|
||||||
|
|
|
@ -9,10 +9,13 @@ import I18n from '../../i18n';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import { IMessageBroadcast } from './interfaces';
|
import { IMessageBroadcast } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const Broadcast = React.memo(({ author, broadcast, theme }: IMessageBroadcast) => {
|
const Broadcast = React.memo(({ author, broadcast }: IMessageBroadcast) => {
|
||||||
const { user, replyBroadcast } = useContext(MessageContext);
|
const { user, replyBroadcast } = useContext(MessageContext);
|
||||||
const isOwn = author._id === user.id;
|
const { theme } = useTheme();
|
||||||
|
const isOwn = author?._id === user.id;
|
||||||
|
|
||||||
if (broadcast && !isOwn) {
|
if (broadcast && !isOwn) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.buttonContainer}>
|
<View style={styles.buttonContainer}>
|
||||||
|
|
|
@ -8,21 +8,25 @@ import I18n from '../../i18n';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { IMessageCallButton } from './interfaces';
|
import { IMessageCallButton } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const CallButton = React.memo(({ theme, callJitsi }: IMessageCallButton) => (
|
const CallButton = React.memo(({ callJitsi }: IMessageCallButton) => {
|
||||||
<View style={styles.buttonContainer}>
|
const { theme } = useTheme();
|
||||||
<Touchable
|
return (
|
||||||
onPress={callJitsi}
|
<View style={styles.buttonContainer}>
|
||||||
background={Touchable.Ripple(themes[theme].bannerBackground)}
|
<Touchable
|
||||||
style={[styles.button, { backgroundColor: themes[theme].tintColor }]}
|
onPress={callJitsi}
|
||||||
hitSlop={BUTTON_HIT_SLOP}>
|
background={Touchable.Ripple(themes[theme].bannerBackground)}
|
||||||
<>
|
style={[styles.button, { backgroundColor: themes[theme].tintColor }]}
|
||||||
<CustomIcon name='camera' size={16} style={styles.buttonIcon} color={themes[theme].buttonText} />
|
hitSlop={BUTTON_HIT_SLOP}>
|
||||||
<Text style={[styles.buttonText, { color: themes[theme].buttonText }]}>{I18n.t('Click_to_join')}</Text>
|
<>
|
||||||
</>
|
<CustomIcon name='camera' size={16} style={styles.buttonIcon} color={themes[theme].buttonText} />
|
||||||
</Touchable>
|
<Text style={[styles.buttonText, { color: themes[theme].buttonText }]}>{I18n.t('Click_to_join')}</Text>
|
||||||
</View>
|
</>
|
||||||
));
|
</Touchable>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
CallButton.displayName = 'CallButton';
|
CallButton.displayName = 'CallButton';
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,17 @@ import MessageContext from './Context';
|
||||||
import Encrypted from './Encrypted';
|
import Encrypted from './Encrypted';
|
||||||
import { E2E_MESSAGE_TYPE } from '../../lib/encryption/constants';
|
import { E2E_MESSAGE_TYPE } from '../../lib/encryption/constants';
|
||||||
import { IMessageContent } from './interfaces';
|
import { IMessageContent } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const Content = React.memo(
|
const Content = React.memo(
|
||||||
(props: IMessageContent) => {
|
(props: IMessageContent) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
if (props.isInfo) {
|
if (props.isInfo) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const infoMessage = getInfoMessage({ ...props });
|
const infoMessage = getInfoMessage({ ...props });
|
||||||
|
|
||||||
const renderMessageContent = (
|
const renderMessageContent = (
|
||||||
<Text style={[styles.textInfo, { color: themes[props.theme].auxiliaryText }]} accessibilityLabel={infoMessage}>
|
<Text style={[styles.textInfo, { color: themes[theme].auxiliaryText }]} accessibilityLabel={infoMessage}>
|
||||||
{infoMessage}
|
{infoMessage}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
@ -36,14 +38,12 @@ const Content = React.memo(
|
||||||
return renderMessageContent;
|
return renderMessageContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPreview: any = props.tmid && !props.isThreadRoom;
|
const isPreview = props.tmid && !props.isThreadRoom;
|
||||||
let content = null;
|
let content = null;
|
||||||
|
|
||||||
if (props.isEncrypted) {
|
if (props.isEncrypted) {
|
||||||
content = (
|
content = (
|
||||||
<Text
|
<Text style={[styles.textInfo, { color: themes[theme].auxiliaryText }]} accessibilityLabel={I18n.t('Encrypted_message')}>
|
||||||
style={[styles.textInfo, { color: themes[props.theme].auxiliaryText }]}
|
|
||||||
accessibilityLabel={I18n.t('Encrypted_message')}>
|
|
||||||
{I18n.t('Encrypted_message')}
|
{I18n.t('Encrypted_message')}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
@ -65,7 +65,7 @@ const Content = React.memo(
|
||||||
navToRoomInfo={props.navToRoomInfo}
|
navToRoomInfo={props.navToRoomInfo}
|
||||||
tmid={props.tmid}
|
tmid={props.tmid}
|
||||||
useRealName={props.useRealName}
|
useRealName={props.useRealName}
|
||||||
theme={props.theme}
|
theme={theme}
|
||||||
onLinkPress={onLinkPress}
|
onLinkPress={onLinkPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -76,13 +76,13 @@ const Content = React.memo(
|
||||||
content = (
|
content = (
|
||||||
<View style={styles.flex}>
|
<View style={styles.flex}>
|
||||||
<View style={styles.contentContainer}>{content}</View>
|
<View style={styles.contentContainer}>{content}</View>
|
||||||
<Encrypted type={props.type} theme={props.theme} />
|
<Encrypted type={props.type} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.isIgnored) {
|
if (props.isIgnored) {
|
||||||
content = <Text style={[styles.textInfo, { color: themes[props.theme].auxiliaryText }]}>{I18n.t('Message_Ignored')}</Text>;
|
content = <Text style={[styles.textInfo, { color: themes[theme].auxiliaryText }]}>{I18n.t('Message_Ignored')}</Text>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <View style={props.isTemp && styles.temp}>{content}</View>;
|
return <View style={props.isTemp && styles.temp}>{content}</View>;
|
||||||
|
@ -97,9 +97,6 @@ const Content = React.memo(
|
||||||
if (prevProps.type !== nextProps.type) {
|
if (prevProps.type !== nextProps.type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (prevProps.theme !== nextProps.theme) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (prevProps.isEncrypted !== nextProps.isEncrypted) {
|
if (prevProps.isEncrypted !== nextProps.isEncrypted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,12 @@ import { DISCUSSION } from './constants';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import { formatDateThreads } from '../../utils/room';
|
import { formatDateThreads } from '../../utils/room';
|
||||||
import { IMessageDiscussion } from './interfaces';
|
import { IMessage } from '../../definitions';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const Discussion = React.memo(
|
const Discussion = React.memo(
|
||||||
({ msg, dcount, dlm, theme }: IMessageDiscussion) => {
|
({ msg, dcount, dlm }: Pick<IMessage, 'msg' | 'dcount' | 'dlm'>) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
let time;
|
let time;
|
||||||
if (dlm) {
|
if (dlm) {
|
||||||
time = formatDateThreads(dlm);
|
time = formatDateThreads(dlm);
|
||||||
|
@ -50,9 +52,6 @@ const Discussion = React.memo(
|
||||||
if (prevProps.dlm !== nextProps.dlm) {
|
if (prevProps.dlm !== nextProps.dlm) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (prevProps.theme !== nextProps.theme) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,13 +7,10 @@ import { themes } from '../../constants/colors';
|
||||||
import { BUTTON_HIT_SLOP } from './utils';
|
import { BUTTON_HIT_SLOP } from './utils';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
interface IMessageEncrypted {
|
const Encrypted = React.memo(({ type }: { type: string }) => {
|
||||||
type: string;
|
const { theme } = useTheme();
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Encrypted = React.memo(({ type, theme }: IMessageEncrypted) => {
|
|
||||||
if (type !== E2E_MESSAGE_TYPE) {
|
if (type !== E2E_MESSAGE_TYPE) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,25 +12,20 @@ import { formatAttachmentUrl } from '../../lib/utils';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
||||||
import { useTheme } from '../../theme';
|
|
||||||
import { IAttachment } from '../../definitions';
|
import { IAttachment } from '../../definitions';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
type TMessageButton = {
|
interface IMessageButton {
|
||||||
children: JSX.Element;
|
children: React.ReactElement;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onPress: Function;
|
onPress: () => void;
|
||||||
theme: string;
|
theme: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
type TMessageImage = {
|
|
||||||
img: string;
|
|
||||||
theme: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IMessageImage {
|
interface IMessageImage {
|
||||||
file: IAttachment;
|
file: IAttachment;
|
||||||
imageUrl?: string;
|
imageUrl?: string;
|
||||||
showAttachment?: Function;
|
showAttachment?: (file: IAttachment) => void;
|
||||||
style?: StyleProp<TextStyle>[];
|
style?: StyleProp<TextStyle>[];
|
||||||
isReply?: boolean;
|
isReply?: boolean;
|
||||||
getCustomEmoji?: TGetCustomEmoji;
|
getCustomEmoji?: TGetCustomEmoji;
|
||||||
|
@ -38,7 +33,7 @@ interface IMessageImage {
|
||||||
|
|
||||||
const ImageProgress = createImageProgress(FastImage);
|
const ImageProgress = createImageProgress(FastImage);
|
||||||
|
|
||||||
const Button = React.memo(({ children, onPress, disabled, theme }: TMessageButton) => (
|
const Button = React.memo(({ children, onPress, disabled, theme }: IMessageButton) => (
|
||||||
<Touchable
|
<Touchable
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
@ -48,10 +43,10 @@ const Button = React.memo(({ children, onPress, disabled, theme }: TMessageButto
|
||||||
</Touchable>
|
</Touchable>
|
||||||
));
|
));
|
||||||
|
|
||||||
export const MessageImage = React.memo(({ img, theme }: TMessageImage) => (
|
export const MessageImage = React.memo(({ imgUri, theme }: { imgUri: string; theme: string }) => (
|
||||||
<ImageProgress
|
<ImageProgress
|
||||||
style={[styles.image, { borderColor: themes[theme].borderColor }]}
|
style={[styles.image, { borderColor: themes[theme].borderColor }]}
|
||||||
source={{ uri: encodeURI(img) }}
|
source={{ uri: encodeURI(imgUri) }}
|
||||||
resizeMode={FastImage.resizeMode.cover}
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
indicator={Progress.Pie}
|
indicator={Progress.Pie}
|
||||||
indicatorProps={{
|
indicatorProps={{
|
||||||
|
@ -65,6 +60,7 @@ const ImageContainer = React.memo(
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const { baseUrl, user } = useContext(MessageContext);
|
const { baseUrl, user } = useContext(MessageContext);
|
||||||
const img = imageUrl || formatAttachmentUrl(file.image_url, user.id, user.token, baseUrl);
|
const img = imageUrl || formatAttachmentUrl(file.image_url, user.id, user.token, baseUrl);
|
||||||
|
|
||||||
if (!img) {
|
if (!img) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +85,7 @@ const ImageContainer = React.memo(
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
<MessageImage img={img} theme={theme} />
|
<MessageImage imgUri={img} theme={theme} />
|
||||||
</View>
|
</View>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -97,7 +93,7 @@ const ImageContainer = React.memo(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button disabled={isReply} theme={theme} onPress={onPress}>
|
<Button disabled={isReply} theme={theme} onPress={onPress}>
|
||||||
<MessageImage img={img} theme={theme} />
|
<MessageImage imgUri={img} theme={theme} />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,7 @@ import ReadReceipt from './ReadReceipt';
|
||||||
import CallButton from './CallButton';
|
import CallButton from './CallButton';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { IMessage, IMessageInner, IMessageTouchable } from './interfaces';
|
import { IMessage, IMessageInner, IMessageTouchable } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const MessageInner = React.memo((props: IMessageInner) => {
|
const MessageInner = React.memo((props: IMessageInner) => {
|
||||||
const { attachments } = props;
|
const { attachments } = props;
|
||||||
|
@ -85,7 +86,6 @@ const Message = React.memo((props: IMessage) => {
|
||||||
<View style={[styles.container, props.style]}>
|
<View style={[styles.container, props.style]}>
|
||||||
{thread}
|
{thread}
|
||||||
<View style={styles.flex}>
|
<View style={styles.flex}>
|
||||||
{/* @ts-ignore */}
|
|
||||||
<MessageAvatar small {...props} />
|
<MessageAvatar small {...props} />
|
||||||
<View style={[styles.messageContent, props.isHeader && styles.messageContentWithHeader]}>
|
<View style={[styles.messageContent, props.isHeader && styles.messageContentWithHeader]}>
|
||||||
<Content {...props} />
|
<Content {...props} />
|
||||||
|
@ -98,12 +98,11 @@ const Message = React.memo((props: IMessage) => {
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, props.style]}>
|
<View style={[styles.container, props.style]}>
|
||||||
<View style={styles.flex}>
|
<View style={styles.flex}>
|
||||||
{/* @ts-ignore */}
|
|
||||||
<MessageAvatar {...props} />
|
<MessageAvatar {...props} />
|
||||||
<View style={[styles.messageContent, props.isHeader && styles.messageContentWithHeader]}>
|
<View style={[styles.messageContent, props.isHeader && styles.messageContentWithHeader]}>
|
||||||
<MessageInner {...props} />
|
<MessageInner {...props} />
|
||||||
</View>
|
</View>
|
||||||
<ReadReceipt isReadReceiptEnabled={props.isReadReceiptEnabled} unread={props.unread || false} theme={props.theme} />
|
<ReadReceipt isReadReceiptEnabled={props.isReadReceiptEnabled} unread={props.unread || false} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -119,12 +118,14 @@ const MessageTouchable = React.memo((props: IMessageTouchable & IMessage) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const { onPress, onLongPress } = useContext(MessageContext);
|
const { onPress, onLongPress } = useContext(MessageContext);
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Touchable
|
<Touchable
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
disabled={(props.isInfo && !props.isThreadReply) || props.archived || props.isTemp || props.type === 'jitsi_call_started'}
|
disabled={(props.isInfo && !props.isThreadReply) || props.archived || props.isTemp || props.type === 'jitsi_call_started'}
|
||||||
style={{ backgroundColor: props.highlighted ? themes[props.theme].headerBackground : null }}>
|
style={{ backgroundColor: props.highlighted ? themes[theme].headerBackground : null }}>
|
||||||
<View>
|
<View>
|
||||||
<Message {...props} />
|
<Message {...props} />
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -6,14 +6,12 @@ import styles from './styles';
|
||||||
import { BUTTON_HIT_SLOP } from './utils';
|
import { BUTTON_HIT_SLOP } from './utils';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
interface IMessageError {
|
|
||||||
hasError: boolean;
|
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MessageError = React.memo(
|
const MessageError = React.memo(
|
||||||
({ hasError, theme }: IMessageError) => {
|
({ hasError }: { hasError: boolean }) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
if (!hasError) {
|
if (!hasError) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +22,7 @@ const MessageError = React.memo(
|
||||||
</Touchable>
|
</Touchable>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
(prevProps, nextProps) => prevProps.hasError === nextProps.hasError && prevProps.theme === nextProps.theme
|
(prevProps, nextProps) => prevProps.hasError === nextProps.hasError
|
||||||
);
|
);
|
||||||
|
|
||||||
MessageError.displayName = 'MessageError';
|
MessageError.displayName = 'MessageError';
|
||||||
|
|
|
@ -7,30 +7,28 @@ import styles from './styles';
|
||||||
import Emoji from './Emoji';
|
import Emoji from './Emoji';
|
||||||
import { BUTTON_HIT_SLOP } from './utils';
|
import { BUTTON_HIT_SLOP } from './utils';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { withTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
||||||
|
|
||||||
interface IMessageAddReaction {
|
interface IReaction {
|
||||||
theme: string;
|
_id: string;
|
||||||
|
emoji: string;
|
||||||
|
usernames: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMessageReaction {
|
interface IMessageReaction {
|
||||||
reaction: {
|
reaction: IReaction;
|
||||||
usernames: [];
|
|
||||||
emoji: object;
|
|
||||||
};
|
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMessageReactions {
|
interface IMessageReactions {
|
||||||
reactions?: object[];
|
reactions?: IReaction[];
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddReaction = React.memo(({ theme }: IMessageAddReaction) => {
|
const AddReaction = React.memo(({ theme }: { theme: string }) => {
|
||||||
const { reactionInit } = useContext(MessageContext);
|
const { reactionInit } = useContext(MessageContext);
|
||||||
return (
|
return (
|
||||||
<Touchable
|
<Touchable
|
||||||
|
@ -49,7 +47,7 @@ const AddReaction = React.memo(({ theme }: IMessageAddReaction) => {
|
||||||
|
|
||||||
const Reaction = React.memo(({ reaction, getCustomEmoji, theme }: IMessageReaction) => {
|
const Reaction = React.memo(({ reaction, getCustomEmoji, theme }: IMessageReaction) => {
|
||||||
const { onReactionPress, onReactionLongPress, baseUrl, user } = useContext(MessageContext);
|
const { onReactionPress, onReactionLongPress, baseUrl, user } = useContext(MessageContext);
|
||||||
const reacted = reaction.usernames.findIndex((item: IMessageReaction) => item === user.username) !== -1;
|
const reacted = reaction.usernames.findIndex((item: string) => item === user.username) !== -1;
|
||||||
return (
|
return (
|
||||||
<Touchable
|
<Touchable
|
||||||
onPress={() => onReactionPress(reaction.emoji)}
|
onPress={() => onReactionPress(reaction.emoji)}
|
||||||
|
@ -76,13 +74,15 @@ const Reaction = React.memo(({ reaction, getCustomEmoji, theme }: IMessageReacti
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const Reactions = React.memo(({ reactions, getCustomEmoji, theme }: IMessageReactions) => {
|
const Reactions = React.memo(({ reactions, getCustomEmoji }: IMessageReactions) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
if (!Array.isArray(reactions) || reactions.length === 0) {
|
if (!Array.isArray(reactions) || reactions.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View style={styles.reactionsContainer}>
|
<View style={styles.reactionsContainer}>
|
||||||
{reactions.map((reaction: any) => (
|
{reactions.map(reaction => (
|
||||||
<Reaction key={reaction.emoji} reaction={reaction} getCustomEmoji={getCustomEmoji} theme={theme} />
|
<Reaction key={reaction.emoji} reaction={reaction} getCustomEmoji={getCustomEmoji} theme={theme} />
|
||||||
))}
|
))}
|
||||||
<AddReaction theme={theme} />
|
<AddReaction theme={theme} />
|
||||||
|
@ -94,4 +94,4 @@ Reaction.displayName = 'MessageReaction';
|
||||||
Reactions.displayName = 'MessageReactions';
|
Reactions.displayName = 'MessageReactions';
|
||||||
AddReaction.displayName = 'MessageAddReaction';
|
AddReaction.displayName = 'MessageAddReaction';
|
||||||
|
|
||||||
export default withTheme(Reactions);
|
export default Reactions;
|
||||||
|
|
|
@ -3,14 +3,10 @@ import React from 'react';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
interface IMessageReadReceipt {
|
const ReadReceipt = React.memo(({ isReadReceiptEnabled, unread }: { isReadReceiptEnabled?: boolean; unread: boolean }) => {
|
||||||
isReadReceiptEnabled: boolean;
|
const { theme } = useTheme();
|
||||||
unread: boolean;
|
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReadReceipt = React.memo(({ isReadReceiptEnabled, unread, theme }: IMessageReadReceipt) => {
|
|
||||||
if (isReadReceiptEnabled && !unread && unread !== null) {
|
if (isReadReceiptEnabled && !unread && unread !== null) {
|
||||||
return <CustomIcon name='check' color={themes[theme].tintColor} size={15} style={styles.readReceipt} />;
|
return <CustomIcon name='check' color={themes[theme].tintColor} size={15} style={styles.readReceipt} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,18 @@ import { themes } from '../../constants/colors';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import { MarkdownPreview } from '../markdown';
|
import { MarkdownPreview } from '../markdown';
|
||||||
import { IMessageRepliedThread } from './interfaces';
|
import { IMessageRepliedThread } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
|
const RepliedThread = memo(({ tmid, tmsg, isHeader, fetchThreadName, id, isEncrypted }: IMessageRepliedThread) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
const RepliedThread = memo(({ tmid, tmsg, isHeader, fetchThreadName, id, isEncrypted, theme }: IMessageRepliedThread) => {
|
|
||||||
if (!tmid || !isHeader) {
|
if (!tmid || !isHeader) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [msg, setMsg] = useState(isEncrypted ? I18n.t('Encrypted_message') : tmsg);
|
const [msg, setMsg] = useState(isEncrypted ? I18n.t('Encrypted_message') : tmsg);
|
||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
const threadName = await fetchThreadName(tmid, id);
|
const threadName = fetchThreadName ? await fetchThreadName(tmid, id) : '';
|
||||||
setMsg(threadName);
|
setMsg(threadName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ const styles = StyleSheet.create({
|
||||||
marginBottom: 4
|
marginBottom: 4
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
// @ts-ignore
|
// @ts-ignore TODO - check with the team, change this to undefined
|
||||||
width: null,
|
width: null,
|
||||||
height: 200,
|
height: 200,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -93,24 +93,6 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IMessageTitle {
|
|
||||||
attachment: IAttachment;
|
|
||||||
timeFormat?: string;
|
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMessageDescription {
|
|
||||||
attachment: IAttachment;
|
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMessageFields {
|
|
||||||
attachment: IAttachment;
|
|
||||||
theme: string;
|
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMessageReply {
|
interface IMessageReply {
|
||||||
attachment: IAttachment;
|
attachment: IAttachment;
|
||||||
timeFormat?: string;
|
timeFormat?: string;
|
||||||
|
@ -118,7 +100,7 @@ interface IMessageReply {
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Title = React.memo(({ attachment, timeFormat, theme }: IMessageTitle) => {
|
const Title = React.memo(({ attachment, timeFormat, theme }: { attachment: IAttachment; timeFormat?: string; theme: string }) => {
|
||||||
const time = attachment.message_link && attachment.ts ? moment(attachment.ts).format(timeFormat) : null;
|
const time = attachment.message_link && attachment.ts ? moment(attachment.ts).format(timeFormat) : null;
|
||||||
return (
|
return (
|
||||||
<View style={styles.authorContainer}>
|
<View style={styles.authorContainer}>
|
||||||
|
@ -132,7 +114,7 @@ const Title = React.memo(({ attachment, timeFormat, theme }: IMessageTitle) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const Description = React.memo(
|
const Description = React.memo(
|
||||||
({ attachment, getCustomEmoji, theme }: IMessageDescription) => {
|
({ attachment, getCustomEmoji, theme }: { attachment: IAttachment; getCustomEmoji: TGetCustomEmoji; theme: string }) => {
|
||||||
const text = attachment.text || attachment.title;
|
const text = attachment.text || attachment.title;
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -164,7 +146,7 @@ const Description = React.memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
const UrlImage = React.memo(
|
const UrlImage = React.memo(
|
||||||
({ image }: any) => {
|
({ image }: { image?: string }) => {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -176,7 +158,7 @@ const UrlImage = React.memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
const Fields = React.memo(
|
const Fields = React.memo(
|
||||||
({ attachment, theme, getCustomEmoji }: IMessageFields) => {
|
({ attachment, theme, getCustomEmoji }: { attachment: IAttachment; theme: string; getCustomEmoji: TGetCustomEmoji }) => {
|
||||||
if (!attachment.fields) {
|
if (!attachment.fields) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -206,12 +188,12 @@ const Fields = React.memo(
|
||||||
const Reply = React.memo(
|
const Reply = React.memo(
|
||||||
({ attachment, timeFormat, index, getCustomEmoji }: IMessageReply) => {
|
({ attachment, timeFormat, index, getCustomEmoji }: IMessageReply) => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
if (!attachment) {
|
if (!attachment) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { theme } = useTheme();
|
|
||||||
const { baseUrl, user, jumpToMessage } = useContext(MessageContext);
|
const { baseUrl, user, jumpToMessage } = useContext(MessageContext);
|
||||||
|
|
||||||
const onPress = async () => {
|
const onPress = async () => {
|
||||||
|
|
|
@ -7,9 +7,12 @@ import MessageContext from './Context';
|
||||||
import ThreadDetails from '../ThreadDetails';
|
import ThreadDetails from '../ThreadDetails';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import { IMessageThread } from './interfaces';
|
import { IMessageThread } from './interfaces';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const Thread = React.memo(
|
const Thread = React.memo(
|
||||||
({ msg, tcount, tlm, isThreadRoom, theme, id }: IMessageThread) => {
|
({ msg, tcount, tlm, isThreadRoom, id }: IMessageThread) => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
if (!tlm || isThreadRoom || tcount === 0) {
|
if (!tlm || isThreadRoom || tcount === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -38,9 +41,6 @@ const Thread = React.memo(
|
||||||
if (prevProps.tcount !== nextProps.tcount) {
|
if (prevProps.tcount !== nextProps.tcount) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (prevProps.theme !== nextProps.theme) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,11 +8,12 @@ import Touchable from './Touchable';
|
||||||
import openLink from '../../utils/openLink';
|
import openLink from '../../utils/openLink';
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { withTheme } from '../../theme';
|
import { useTheme, withTheme } from '../../theme';
|
||||||
import { LISTENER } from '../Toast';
|
import { LISTENER } from '../Toast';
|
||||||
import EventEmitter from '../../utils/events';
|
import EventEmitter from '../../utils/events';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
|
import { IUrl } from '../../definitions';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
|
@ -50,29 +51,6 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IMessageUrlContent {
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMessageUrl {
|
|
||||||
url: {
|
|
||||||
ignoreParse: boolean;
|
|
||||||
url: string;
|
|
||||||
image: string;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
};
|
|
||||||
index: number;
|
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMessageUrls {
|
|
||||||
urls?: any;
|
|
||||||
theme?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const UrlImage = React.memo(
|
const UrlImage = React.memo(
|
||||||
({ image }: { image: string }) => {
|
({ image }: { image: string }) => {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
|
@ -86,7 +64,7 @@ const UrlImage = React.memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
const UrlContent = React.memo(
|
const UrlContent = React.memo(
|
||||||
({ title, description, theme }: IMessageUrlContent) => (
|
({ title, description, theme }: { title: string; description: string; theme: string }) => (
|
||||||
<View style={styles.textContainer}>
|
<View style={styles.textContainer}>
|
||||||
{title ? (
|
{title ? (
|
||||||
<Text style={[styles.title, { color: themes[theme].tintColor }]} numberOfLines={2}>
|
<Text style={[styles.title, { color: themes[theme].tintColor }]} numberOfLines={2}>
|
||||||
|
@ -115,7 +93,7 @@ const UrlContent = React.memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
const Url = React.memo(
|
const Url = React.memo(
|
||||||
({ url, index, theme }: IMessageUrl) => {
|
({ url, index, theme }: { url: IUrl; index: number; theme: string }) => {
|
||||||
if (!url || url?.ignoreParse) {
|
if (!url || url?.ignoreParse) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -152,14 +130,17 @@ const Url = React.memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
const Urls = React.memo(
|
const Urls = React.memo(
|
||||||
({ urls, theme }: IMessageUrls) => {
|
// TODO - didn't work - (React.ReactElement | null)[] | React.ReactElement | null
|
||||||
|
({ urls }: { urls?: IUrl[] }): any => {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
if (!urls || urls.length === 0) {
|
if (!urls || urls.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return urls.map((url: any, index: number) => <Url url={url} key={url.url} index={index} theme={theme!} />);
|
return urls.map((url: IUrl, index: number) => <Url url={url} key={url.url} index={index} theme={theme} />);
|
||||||
},
|
},
|
||||||
(oldProps, newProps) => dequal(oldProps.urls, newProps.urls) && oldProps.theme === newProps.theme
|
(oldProps, newProps) => dequal(oldProps.urls, newProps.urls)
|
||||||
);
|
);
|
||||||
|
|
||||||
UrlImage.displayName = 'MessageUrlImage';
|
UrlImage.displayName = 'MessageUrlImage';
|
||||||
|
|
|
@ -3,12 +3,14 @@ import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { withTheme } from '../../theme';
|
import { useTheme } from '../../theme';
|
||||||
import MessageError from './MessageError';
|
import MessageError from './MessageError';
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
import messageStyles from './styles';
|
import messageStyles from './styles';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
import { SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME } from './utils';
|
import { SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME } from './utils';
|
||||||
|
import { SubscriptionType } from '../../definitions';
|
||||||
|
import { IRoomInfoParam } from '../../views/SearchMessagesView';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -49,15 +51,15 @@ interface IMessageUser {
|
||||||
alias?: string;
|
alias?: string;
|
||||||
ts?: Date;
|
ts?: Date;
|
||||||
timeFormat?: string;
|
timeFormat?: string;
|
||||||
theme: string;
|
navToRoomInfo?: (navParam: IRoomInfoParam) => void;
|
||||||
navToRoomInfo?: Function;
|
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const User = React.memo(
|
const User = React.memo(
|
||||||
({ isHeader, useRealName, author, alias, ts, timeFormat, hasError, theme, navToRoomInfo, type, ...props }: IMessageUser) => {
|
({ isHeader, useRealName, author, alias, ts, timeFormat, hasError, navToRoomInfo, type, ...props }: IMessageUser) => {
|
||||||
if (isHeader || hasError) {
|
if (isHeader || hasError) {
|
||||||
const { user } = useContext(MessageContext);
|
const { user } = useContext(MessageContext);
|
||||||
|
const { theme } = useTheme();
|
||||||
const username = (useRealName && author?.name) || author?.username;
|
const username = (useRealName && author?.name) || author?.username;
|
||||||
const aliasUsername = alias ? (
|
const aliasUsername = alias ? (
|
||||||
<Text style={[styles.alias, { color: themes[theme].auxiliaryText }]}> @{username}</Text>
|
<Text style={[styles.alias, { color: themes[theme].auxiliaryText }]}> @{username}</Text>
|
||||||
|
@ -65,8 +67,8 @@ const User = React.memo(
|
||||||
const time = moment(ts).format(timeFormat);
|
const time = moment(ts).format(timeFormat);
|
||||||
const onUserPress = () => {
|
const onUserPress = () => {
|
||||||
navToRoomInfo?.({
|
navToRoomInfo?.({
|
||||||
t: 'd',
|
t: SubscriptionType.DIRECT,
|
||||||
rid: author?._id
|
rid: author?._id || ''
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const isDisabled = author?._id === user.id;
|
const isDisabled = author?._id === user.id;
|
||||||
|
@ -83,7 +85,7 @@ const User = React.memo(
|
||||||
<Text
|
<Text
|
||||||
style={[styles.usernameInfoMessage, { color: themes[theme].titleText }]}
|
style={[styles.usernameInfoMessage, { color: themes[theme].titleText }]}
|
||||||
onPress={onUserPress}
|
onPress={onUserPress}
|
||||||
// @ts-ignore
|
// @ts-ignore // TODO - check this prop
|
||||||
disabled={isDisabled}>
|
disabled={isDisabled}>
|
||||||
{textContent}
|
{textContent}
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -98,7 +100,7 @@ const User = React.memo(
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<Text style={[messageStyles.time, { color: themes[theme].auxiliaryTintColor }]}>{time}</Text>
|
<Text style={[messageStyles.time, { color: themes[theme].auxiliaryTintColor }]}>{time}</Text>
|
||||||
{hasError && <MessageError hasError={hasError} theme={theme} {...props} />}
|
{hasError ? <MessageError hasError={hasError} {...props} /> : null}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -108,4 +110,4 @@ const User = React.memo(
|
||||||
|
|
||||||
User.displayName = 'MessageUser';
|
User.displayName = 'MessageUser';
|
||||||
|
|
||||||
export default withTheme(User);
|
export default User;
|
||||||
|
|
|
@ -16,9 +16,10 @@ import I18n from '../../i18n';
|
||||||
import { IAttachment } from '../../definitions/IAttachment';
|
import { IAttachment } from '../../definitions/IAttachment';
|
||||||
import RCActivityIndicator from '../ActivityIndicator';
|
import RCActivityIndicator from '../ActivityIndicator';
|
||||||
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
||||||
|
import { useTheme } from '../../theme';
|
||||||
|
|
||||||
const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])];
|
const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])];
|
||||||
const isTypeSupported = (type: any) => SUPPORTED_TYPES.indexOf(type) !== -1;
|
const isTypeSupported = (type: string) => SUPPORTED_TYPES.indexOf(type) !== -1;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
|
@ -33,23 +34,24 @@ const styles = StyleSheet.create({
|
||||||
|
|
||||||
interface IMessageVideo {
|
interface IMessageVideo {
|
||||||
file: IAttachment;
|
file: IAttachment;
|
||||||
showAttachment?: Function;
|
showAttachment?: (file: IAttachment) => void;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
style?: StyleProp<TextStyle>[];
|
style?: StyleProp<TextStyle>[];
|
||||||
isReply?: boolean;
|
isReply?: boolean;
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Video = React.memo(
|
const Video = React.memo(
|
||||||
({ file, showAttachment, getCustomEmoji, style, isReply, theme }: IMessageVideo) => {
|
({ file, showAttachment, getCustomEmoji, style, isReply }: IMessageVideo) => {
|
||||||
const { baseUrl, user } = useContext(MessageContext);
|
const { baseUrl, user } = useContext(MessageContext);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
if (!baseUrl) {
|
if (!baseUrl) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPress = async () => {
|
const onPress = async () => {
|
||||||
if (isTypeSupported(file.video_type) && showAttachment) {
|
if (file.video_type && isTypeSupported(file.video_type) && showAttachment) {
|
||||||
return showAttachment(file);
|
return showAttachment(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ const Video = React.memo(
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
(prevProps, nextProps) => dequal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme
|
(prevProps, nextProps) => dequal(prevProps.file, nextProps.file)
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Video;
|
export default Video;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Keyboard, ViewStyle } from 'react-native';
|
import { Keyboard, ViewStyle } from 'react-native';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
import Message from './Message';
|
import Message from './Message';
|
||||||
import MessageContext from './Context';
|
import MessageContext from './Context';
|
||||||
|
@ -7,10 +8,11 @@ import debounce from '../../utils/debounce';
|
||||||
import { SYSTEM_MESSAGES, getMessageTranslation } from './utils';
|
import { SYSTEM_MESSAGES, getMessageTranslation } from './utils';
|
||||||
import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants';
|
import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants';
|
||||||
import messagesStatus from '../../constants/messagesStatus';
|
import messagesStatus from '../../constants/messagesStatus';
|
||||||
import { withTheme } from '../../theme';
|
import { useTheme, withTheme } from '../../theme';
|
||||||
import openLink from '../../utils/openLink';
|
import openLink from '../../utils/openLink';
|
||||||
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
||||||
import { TAnyMessageModel } from '../../definitions';
|
import { IAttachment, TAnyMessageModel } from '../../definitions';
|
||||||
|
import { IRoomInfoParam } from '../../views/SearchMessagesView';
|
||||||
|
|
||||||
interface IMessageContainerProps {
|
interface IMessageContainerProps {
|
||||||
item: TAnyMessageModel;
|
item: TAnyMessageModel;
|
||||||
|
@ -20,7 +22,7 @@ interface IMessageContainerProps {
|
||||||
token: string;
|
token: string;
|
||||||
};
|
};
|
||||||
msg?: string;
|
msg?: string;
|
||||||
rid?: string;
|
rid: string;
|
||||||
timeFormat?: string;
|
timeFormat?: string;
|
||||||
style?: ViewStyle;
|
style?: ViewStyle;
|
||||||
archived?: boolean;
|
archived?: boolean;
|
||||||
|
@ -37,44 +39,35 @@ interface IMessageContainerProps {
|
||||||
isIgnored?: boolean;
|
isIgnored?: boolean;
|
||||||
highlighted?: boolean;
|
highlighted?: boolean;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
onLongPress?: Function;
|
onLongPress?: (item: TAnyMessageModel) => void;
|
||||||
onReactionPress?: Function;
|
onReactionPress?: (emoji: string, id: string) => void;
|
||||||
onEncryptedPress?: Function;
|
onEncryptedPress?: () => void;
|
||||||
onDiscussionPress?: Function;
|
onDiscussionPress?: (item: TAnyMessageModel) => void;
|
||||||
onThreadPress?: Function;
|
onThreadPress?: (item: TAnyMessageModel) => void;
|
||||||
errorActionsShow?: Function;
|
errorActionsShow?: (item: TAnyMessageModel) => void;
|
||||||
replyBroadcast?: Function;
|
replyBroadcast?: (item: TAnyMessageModel) => void;
|
||||||
reactionInit?: Function;
|
reactionInit?: (item: TAnyMessageModel) => void;
|
||||||
fetchThreadName?: Function;
|
fetchThreadName?: (tmid: string, id: string) => Promise<string | undefined>;
|
||||||
showAttachment?: Function;
|
showAttachment: (file: IAttachment) => void;
|
||||||
onReactionLongPress?: Function;
|
onReactionLongPress?: (item: TAnyMessageModel) => void;
|
||||||
navToRoomInfo?: Function;
|
navToRoomInfo: (navParam: IRoomInfoParam) => void;
|
||||||
callJitsi?: Function;
|
callJitsi?: () => void;
|
||||||
blockAction?: Function;
|
blockAction?: (params: { actionId: string; appId: string; value: string; blockId: string; rid: string; mid: string }) => void;
|
||||||
onAnswerButtonPress?: Function;
|
onAnswerButtonPress?: (message: string, tmid?: string, tshow?: boolean) => void;
|
||||||
theme?: string;
|
|
||||||
threadBadgeColor?: string;
|
threadBadgeColor?: string;
|
||||||
toggleFollowThread?: Function;
|
toggleFollowThread?: (isFollowingThread: boolean, tmid?: string) => Promise<void>;
|
||||||
jumpToMessage?: Function;
|
jumpToMessage?: (link: string) => void;
|
||||||
onPress?: Function;
|
onPress?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageContainer extends React.Component<IMessageContainerProps> {
|
interface IMessageContainerState {
|
||||||
|
isManualUnignored: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageContainer extends React.Component<IMessageContainerProps, IMessageContainerState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
getCustomEmoji: () => null,
|
getCustomEmoji: () => null,
|
||||||
onLongPress: () => {},
|
onLongPress: () => {},
|
||||||
onReactionPress: () => {},
|
|
||||||
onEncryptedPress: () => {},
|
|
||||||
onDiscussionPress: () => {},
|
|
||||||
onThreadPress: () => {},
|
|
||||||
onAnswerButtonPress: () => {},
|
|
||||||
errorActionsShow: () => {},
|
|
||||||
replyBroadcast: () => {},
|
|
||||||
reactionInit: () => {},
|
|
||||||
fetchThreadName: () => {},
|
|
||||||
showAttachment: () => {},
|
|
||||||
onReactionLongPress: () => {},
|
|
||||||
navToRoomInfo: () => {},
|
|
||||||
callJitsi: () => {},
|
callJitsi: () => {},
|
||||||
blockAction: () => {},
|
blockAction: () => {},
|
||||||
archived: false,
|
archived: false,
|
||||||
|
@ -85,7 +78,7 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
|
|
||||||
state = { isManualUnignored: false };
|
state = { isManualUnignored: false };
|
||||||
|
|
||||||
private subscription: any;
|
private subscription?: Subscription;
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { item } = this.props;
|
const { item } = this.props;
|
||||||
|
@ -97,12 +90,9 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: any, nextState: any) {
|
shouldComponentUpdate(nextProps: IMessageContainerProps, nextState: IMessageContainerState) {
|
||||||
const { isManualUnignored } = this.state;
|
const { isManualUnignored } = this.state;
|
||||||
const { theme, threadBadgeColor, isIgnored, highlighted } = this.props;
|
const { threadBadgeColor, isIgnored, highlighted } = this.props;
|
||||||
if (nextProps.theme !== theme) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextProps.highlighted !== highlighted) {
|
if (nextProps.highlighted !== highlighted) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +159,7 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onReactionPress = (emoji: any) => {
|
onReactionPress = (emoji: string) => {
|
||||||
const { onReactionPress, item } = this.props;
|
const { onReactionPress, item } = this.props;
|
||||||
if (onReactionPress) {
|
if (onReactionPress) {
|
||||||
onReactionPress(emoji, item.id);
|
onReactionPress(emoji, item.id);
|
||||||
|
@ -228,7 +218,7 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
previousItem.u.username === item.u.username &&
|
previousItem.u.username === item.u.username &&
|
||||||
!(previousItem.groupable === false || item.groupable === false || broadcast === true) &&
|
!(previousItem.groupable === false || item.groupable === false || broadcast === true) &&
|
||||||
// @ts-ignore TODO: IMessage vs IMessageFromServer non-sense
|
// @ts-ignore TODO: IMessage vs IMessageFromServer non-sense
|
||||||
item.ts - previousItem.ts < Message_GroupingPeriod! * 1000 &&
|
item.ts - previousItem.ts < Message_GroupingPeriod * 1000 &&
|
||||||
previousItem.tmid === item.tmid
|
previousItem.tmid === item.tmid
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -303,10 +293,11 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
onLinkPress = (link: string): void => {
|
onLinkPress = (link: string): void => {
|
||||||
const { item, theme, jumpToMessage } = this.props;
|
const { theme } = useTheme();
|
||||||
const isMessageLink = item?.attachments?.findIndex((att: any) => att?.message_link === link) !== -1;
|
const { item, jumpToMessage } = this.props;
|
||||||
if (isMessageLink) {
|
const isMessageLink = item?.attachments?.findIndex((att: IAttachment) => att?.message_link === link) !== -1;
|
||||||
return jumpToMessage!(link);
|
if (isMessageLink && jumpToMessage) {
|
||||||
|
return jumpToMessage(link);
|
||||||
}
|
}
|
||||||
openLink(link, theme);
|
openLink(link, theme);
|
||||||
};
|
};
|
||||||
|
@ -332,7 +323,6 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
callJitsi,
|
callJitsi,
|
||||||
blockAction,
|
blockAction,
|
||||||
rid,
|
rid,
|
||||||
theme,
|
|
||||||
threadBadgeColor,
|
threadBadgeColor,
|
||||||
toggleFollowThread,
|
toggleFollowThread,
|
||||||
jumpToMessage,
|
jumpToMessage,
|
||||||
|
@ -371,8 +361,8 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
let message = msg;
|
let message = msg;
|
||||||
// "autoTranslateRoom" and "autoTranslateLanguage" are properties from the subscription
|
// "autoTranslateRoom" and "autoTranslateLanguage" are properties from the subscription
|
||||||
// "autoTranslateMessage" is a toggle between "View Original" and "Translate" state
|
// "autoTranslateMessage" is a toggle between "View Original" and "Translate" state
|
||||||
if (autoTranslateRoom && autoTranslateMessage) {
|
if (autoTranslateRoom && autoTranslateMessage && autoTranslateLanguage) {
|
||||||
message = getMessageTranslation(item, autoTranslateLanguage!) || message;
|
message = getMessageTranslation(item, autoTranslateLanguage) || message;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -396,14 +386,15 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
toggleFollowThread,
|
toggleFollowThread,
|
||||||
replies
|
replies
|
||||||
}}>
|
}}>
|
||||||
|
{/* @ts-ignore*/}
|
||||||
<Message
|
<Message
|
||||||
id={id}
|
id={id}
|
||||||
msg={message}
|
msg={message}
|
||||||
md={md}
|
md={md}
|
||||||
rid={rid!}
|
rid={rid}
|
||||||
author={u}
|
author={u}
|
||||||
ts={ts}
|
ts={ts}
|
||||||
type={t as any}
|
type={t}
|
||||||
attachments={attachments}
|
attachments={attachments}
|
||||||
blocks={blocks}
|
blocks={blocks}
|
||||||
urls={urls}
|
urls={urls}
|
||||||
|
@ -413,23 +404,20 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
emoji={emoji}
|
emoji={emoji}
|
||||||
timeFormat={timeFormat}
|
timeFormat={timeFormat}
|
||||||
style={style}
|
style={style}
|
||||||
archived={archived!}
|
archived={archived}
|
||||||
broadcast={broadcast!}
|
broadcast={broadcast}
|
||||||
useRealName={useRealName}
|
useRealName={useRealName}
|
||||||
isReadReceiptEnabled={isReadReceiptEnabled!}
|
isReadReceiptEnabled={isReadReceiptEnabled}
|
||||||
unread={unread}
|
unread={unread}
|
||||||
role={role}
|
role={role}
|
||||||
drid={drid}
|
drid={drid}
|
||||||
dcount={dcount}
|
dcount={dcount}
|
||||||
// @ts-ignore
|
|
||||||
dlm={dlm}
|
dlm={dlm}
|
||||||
tmid={tmid}
|
tmid={tmid}
|
||||||
tcount={tcount}
|
tcount={tcount}
|
||||||
// @ts-ignore
|
|
||||||
tlm={tlm}
|
tlm={tlm}
|
||||||
tmsg={tmsg}
|
tmsg={tmsg}
|
||||||
fetchThreadName={fetchThreadName!}
|
fetchThreadName={fetchThreadName}
|
||||||
// @ts-ignore
|
|
||||||
mentions={mentions}
|
mentions={mentions}
|
||||||
channels={channels}
|
channels={channels}
|
||||||
isIgnored={this.isIgnored}
|
isIgnored={this.isIgnored}
|
||||||
|
@ -442,13 +430,12 @@ class MessageContainer extends React.Component<IMessageContainerProps> {
|
||||||
isTemp={this.isTemp}
|
isTemp={this.isTemp}
|
||||||
isEncrypted={this.isEncrypted}
|
isEncrypted={this.isEncrypted}
|
||||||
hasError={this.hasError}
|
hasError={this.hasError}
|
||||||
showAttachment={showAttachment!}
|
showAttachment={showAttachment}
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
navToRoomInfo={navToRoomInfo!}
|
navToRoomInfo={navToRoomInfo}
|
||||||
callJitsi={callJitsi!}
|
callJitsi={callJitsi}
|
||||||
blockAction={blockAction!}
|
blockAction={blockAction}
|
||||||
theme={theme as string}
|
highlighted={highlighted}
|
||||||
highlighted={highlighted!}
|
|
||||||
/>
|
/>
|
||||||
</MessageContext.Provider>
|
</MessageContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,63 +1,45 @@
|
||||||
import { MarkdownAST } from '@rocket.chat/message-parser';
|
import { MarkdownAST } from '@rocket.chat/message-parser';
|
||||||
import { StyleProp, TextStyle } from 'react-native';
|
import { StyleProp, TextStyle } from 'react-native';
|
||||||
|
import { ImageStyle } from '@rocket.chat/react-native-fast-image';
|
||||||
|
|
||||||
import { IUserChannel, IUserMention } from '../markdown/interfaces';
|
import { IUserChannel } from '../markdown/interfaces';
|
||||||
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
import { TGetCustomEmoji } from '../../definitions/IEmoji';
|
||||||
import { IAttachment } from '../../definitions';
|
import { IAttachment, IThread, IUrl, IUserMention, IUserMessage, MessageType, TAnyMessageModel } from '../../definitions';
|
||||||
|
import { IRoomInfoParam } from '../../views/SearchMessagesView';
|
||||||
export type TMessageType = 'discussion-created' | 'jitsi_call_started';
|
|
||||||
|
|
||||||
export interface IMessageAttachments {
|
export interface IMessageAttachments {
|
||||||
attachments?: IAttachment[];
|
attachments?: IAttachment[];
|
||||||
timeFormat?: string;
|
timeFormat?: string;
|
||||||
style?: StyleProp<TextStyle>[];
|
style?: StyleProp<TextStyle>[];
|
||||||
isReply?: boolean;
|
isReply?: boolean;
|
||||||
showAttachment?: Function;
|
showAttachment?: (file: IAttachment) => void;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageAttachedActions {
|
|
||||||
attachment: IAttachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMessageAvatar {
|
export interface IMessageAvatar {
|
||||||
isHeader: boolean;
|
isHeader: boolean;
|
||||||
avatar: string;
|
avatar?: string;
|
||||||
emoji: string;
|
emoji?: string;
|
||||||
author: {
|
author?: IUserMessage;
|
||||||
username: string;
|
|
||||||
_id: string;
|
|
||||||
};
|
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
navToRoomInfo: Function;
|
navToRoomInfo: (navParam: IRoomInfoParam) => void;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageBlocks {
|
export interface IMessageBlocks {
|
||||||
blocks: any;
|
blocks: { appId?: string }[];
|
||||||
id: string;
|
id: string;
|
||||||
rid: string;
|
rid: string;
|
||||||
blockAction: Function;
|
blockAction?: (params: { actionId: string; appId: string; value: string; blockId: string; rid: string; mid: string }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageBroadcast {
|
export interface IMessageBroadcast {
|
||||||
author: {
|
author?: IUserMessage;
|
||||||
_id: string;
|
broadcast?: boolean;
|
||||||
};
|
|
||||||
broadcast: boolean;
|
|
||||||
theme: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageCallButton {
|
export interface IMessageCallButton {
|
||||||
theme: string;
|
callJitsi?: () => void;
|
||||||
callJitsi: Function;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUser {
|
|
||||||
id: string;
|
|
||||||
username: string;
|
|
||||||
token: string;
|
|
||||||
name: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageContent {
|
export interface IMessageContent {
|
||||||
|
@ -68,40 +50,27 @@ export interface IMessageContent {
|
||||||
isThreadRoom: boolean;
|
isThreadRoom: boolean;
|
||||||
msg?: string;
|
msg?: string;
|
||||||
md?: MarkdownAST;
|
md?: MarkdownAST;
|
||||||
theme: string;
|
|
||||||
isEdited: boolean;
|
isEdited: boolean;
|
||||||
isEncrypted: boolean;
|
isEncrypted: boolean;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
channels?: IUserChannel[];
|
channels?: IUserChannel[];
|
||||||
mentions?: IUserMention[];
|
mentions?: IUserMention[];
|
||||||
navToRoomInfo?: Function;
|
navToRoomInfo: (navParam: IRoomInfoParam) => void;
|
||||||
useRealName?: boolean;
|
useRealName?: boolean;
|
||||||
isIgnored: boolean;
|
isIgnored: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageDiscussion {
|
|
||||||
msg?: string;
|
|
||||||
dcount?: number;
|
|
||||||
dlm?: Date;
|
|
||||||
theme: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMessageEmoji {
|
export interface IMessageEmoji {
|
||||||
content: any;
|
content: string;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
standardEmojiStyle: object;
|
standardEmojiStyle: { fontSize: number };
|
||||||
customEmojiStyle: object;
|
customEmojiStyle: StyleProp<ImageStyle>;
|
||||||
getCustomEmoji: TGetCustomEmoji;
|
getCustomEmoji: TGetCustomEmoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageThread {
|
export interface IMessageThread extends Pick<IThread, 'msg' | 'tcount' | 'tlm' | 'id'> {
|
||||||
msg?: string;
|
|
||||||
tcount?: number | null;
|
|
||||||
theme: string;
|
|
||||||
tlm?: Date;
|
|
||||||
isThreadRoom: boolean;
|
isThreadRoom: boolean;
|
||||||
id: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageTouchable {
|
export interface IMessageTouchable {
|
||||||
|
@ -109,40 +78,35 @@ export interface IMessageTouchable {
|
||||||
isInfo: boolean;
|
isInfo: boolean;
|
||||||
isThreadReply: boolean;
|
isThreadReply: boolean;
|
||||||
isTemp: boolean;
|
isTemp: boolean;
|
||||||
archived: boolean;
|
archived?: boolean;
|
||||||
highlighted: boolean;
|
highlighted?: boolean;
|
||||||
theme: string;
|
ts?: string | Date;
|
||||||
ts?: any;
|
urls?: IUrl[];
|
||||||
urls?: any;
|
|
||||||
reactions?: any;
|
reactions?: any;
|
||||||
alias?: any;
|
alias?: string;
|
||||||
role?: any;
|
role?: string;
|
||||||
drid?: any;
|
drid?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageRepliedThread {
|
export interface IMessageRepliedThread extends Pick<IThread, 'tmid' | 'tmsg' | 'id'> {
|
||||||
tmid?: string;
|
|
||||||
tmsg?: string;
|
|
||||||
id: string;
|
|
||||||
isHeader: boolean;
|
isHeader: boolean;
|
||||||
theme: string;
|
fetchThreadName?: (tmid: string, id: string) => Promise<string | undefined>;
|
||||||
fetchThreadName: Function;
|
|
||||||
isEncrypted: boolean;
|
isEncrypted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageInner
|
export interface IMessageInner
|
||||||
extends IMessageDiscussion,
|
extends IMessageContent,
|
||||||
IMessageContent,
|
|
||||||
IMessageCallButton,
|
IMessageCallButton,
|
||||||
IMessageBlocks,
|
IMessageBlocks,
|
||||||
IMessageThread,
|
IMessageThread,
|
||||||
IMessageAttachments,
|
IMessageAttachments,
|
||||||
IMessageBroadcast {
|
IMessageBroadcast {
|
||||||
type: TMessageType;
|
type: MessageType;
|
||||||
blocks: [];
|
blocks: [];
|
||||||
|
urls?: IUrl[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessage extends IMessageRepliedThread, IMessageInner {
|
export interface IMessage extends IMessageRepliedThread, IMessageInner, IMessageAvatar {
|
||||||
isThreadReply: boolean;
|
isThreadReply: boolean;
|
||||||
isThreadSequential: boolean;
|
isThreadSequential: boolean;
|
||||||
isInfo: boolean;
|
isInfo: boolean;
|
||||||
|
@ -150,9 +114,11 @@ export interface IMessage extends IMessageRepliedThread, IMessageInner {
|
||||||
isHeader: boolean;
|
isHeader: boolean;
|
||||||
hasError: boolean;
|
hasError: boolean;
|
||||||
style: any;
|
style: any;
|
||||||
onLongPress: Function;
|
// style: ViewStyle;
|
||||||
isReadReceiptEnabled: boolean;
|
onLongPress?: (item: TAnyMessageModel) => void;
|
||||||
|
isReadReceiptEnabled?: boolean;
|
||||||
unread?: boolean;
|
unread?: boolean;
|
||||||
theme: string;
|
|
||||||
isIgnored: boolean;
|
isIgnored: boolean;
|
||||||
|
dcount: number | undefined;
|
||||||
|
dlm: string | Date | undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export interface IAttachment {
|
||||||
image_size?: number;
|
image_size?: number;
|
||||||
author_name?: string;
|
author_name?: string;
|
||||||
author_icon?: string;
|
author_icon?: string;
|
||||||
actions?: [];
|
actions?: { type: string; msg: string; text: string }[];
|
||||||
message_link?: string;
|
message_link?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
short?: boolean;
|
short?: boolean;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { IAttachment } from './IAttachment';
|
||||||
import { IReaction } from './IReaction';
|
import { IReaction } from './IReaction';
|
||||||
import { TThreadMessageModel } from './IThreadMessage';
|
import { TThreadMessageModel } from './IThreadMessage';
|
||||||
import { TThreadModel } from './IThread';
|
import { TThreadModel } from './IThread';
|
||||||
import { IUrlFromServer } from './IUrl';
|
import { IUrl, IUrlFromServer } from './IUrl';
|
||||||
|
|
||||||
export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj' | MessageTypeLoad;
|
export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj' | MessageTypeLoad;
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ export interface IMessageFromServer {
|
||||||
ts: string | Date; // wm date issue
|
ts: string | Date; // wm date issue
|
||||||
u: IUserMessage;
|
u: IUserMessage;
|
||||||
_updatedAt: string | Date;
|
_updatedAt: string | Date;
|
||||||
urls?: IUrlFromServer[];
|
urls?: IUrl[];
|
||||||
mentions?: IUserMention[];
|
mentions?: IUserMention[];
|
||||||
channels?: IUserChannel[];
|
channels?: IUserChannel[];
|
||||||
md?: MarkdownAST;
|
md?: MarkdownAST;
|
||||||
|
@ -111,7 +111,7 @@ export interface ILoadMoreMessage {
|
||||||
|
|
||||||
export interface IMessage extends IMessageFromServer {
|
export interface IMessage extends IMessageFromServer {
|
||||||
id: string;
|
id: string;
|
||||||
t?: MessageType;
|
t: MessageType;
|
||||||
alias?: string;
|
alias?: string;
|
||||||
parseUrls?: boolean;
|
parseUrls?: boolean;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
|
|
|
@ -45,5 +45,4 @@ export interface IUrl extends IUrlFromServer {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
image: string;
|
image: string;
|
||||||
url: string;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ export type ChatsStackParamList = {
|
||||||
};
|
};
|
||||||
RoomInfoView: {
|
RoomInfoView: {
|
||||||
room?: ISubscription;
|
room?: ISubscription;
|
||||||
member: any;
|
member?: any;
|
||||||
rid: string;
|
rid: string;
|
||||||
t: SubscriptionType;
|
t: SubscriptionType;
|
||||||
showCloseModal?: boolean;
|
showCloseModal?: boolean;
|
||||||
|
|
|
@ -22,6 +22,7 @@ import styles from './styles';
|
||||||
import { ChatsStackParamList } from '../../stacks/types';
|
import { ChatsStackParamList } from '../../stacks/types';
|
||||||
import { ISubscription, SubscriptionType } from '../../definitions/ISubscription';
|
import { ISubscription, SubscriptionType } from '../../definitions/ISubscription';
|
||||||
import { IEmoji } from '../../definitions/IEmoji';
|
import { IEmoji } from '../../definitions/IEmoji';
|
||||||
|
import { IRoomInfoParam } from '../SearchMessagesView';
|
||||||
import { TMessageModel } from '../../definitions';
|
import { TMessageModel } from '../../definitions';
|
||||||
|
|
||||||
interface IMessagesViewProps {
|
interface IMessagesViewProps {
|
||||||
|
@ -43,14 +44,6 @@ interface IMessagesViewProps {
|
||||||
isMasterDetail: boolean;
|
isMasterDetail: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IRoomInfoParam {
|
|
||||||
room: ISubscription;
|
|
||||||
member: any;
|
|
||||||
rid: string;
|
|
||||||
t: SubscriptionType;
|
|
||||||
joined: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMessagesViewState {
|
interface IMessagesViewState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
messages: [];
|
messages: [];
|
||||||
|
@ -188,7 +181,8 @@ class MessagesView extends React.Component<IMessagesViewProps, any> {
|
||||||
showAttachment: this.showAttachment,
|
showAttachment: this.showAttachment,
|
||||||
getCustomEmoji: this.getCustomEmoji,
|
getCustomEmoji: this.getCustomEmoji,
|
||||||
navToRoomInfo: this.navToRoomInfo,
|
navToRoomInfo: this.navToRoomInfo,
|
||||||
onPress: () => this.jumpToMessage({ item })
|
onPress: () => this.jumpToMessage({ item }),
|
||||||
|
rid: this.rid
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -219,7 +213,6 @@ class MessagesView extends React.Component<IMessagesViewProps, any> {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -867,7 +867,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
replyBroadcast = (message: Record<string, string>) => {
|
replyBroadcast = (message: IMessage) => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
dispatch(replyBroadcast(message));
|
dispatch(replyBroadcast(message));
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,12 +42,12 @@ interface ISearchMessagesViewState {
|
||||||
searchText: string;
|
searchText: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IRoomInfoParam {
|
export interface IRoomInfoParam {
|
||||||
room: ISubscription;
|
room?: ISubscription;
|
||||||
member: any;
|
member?: any;
|
||||||
rid: string;
|
rid: string;
|
||||||
t: SubscriptionType;
|
t: SubscriptionType;
|
||||||
joined: boolean;
|
joined?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface INavigationOption {
|
interface INavigationOption {
|
||||||
|
|
Loading…
Reference in New Issue