[IMPROVE] - migrating the message container (finished)

This commit is contained in:
AlexAlexandre 2021-07-22 22:59:16 -03:00
parent 6db54e9920
commit 024c744615
16 changed files with 200 additions and 194 deletions

View File

@ -3,7 +3,7 @@ import { ActivityIndicator, ActivityIndicatorProps, StyleSheet } from 'react-nat
import { themes } from '../constants/colors';
interface IActivityIndicator extends ActivityIndicatorProps{
theme?: 'light' | 'dark' | 'black',
theme?: 'light' | 'dark' | 'black' | string,
absolute?: boolean,
props?: object
}

View File

@ -6,7 +6,7 @@ import Audio from './Audio';
import Video from './Video';
import Reply from './Reply';
interface IMessageAttachments {
export interface IMessageAttachments {
attachments: any;
timeFormat: string;
showAttachment: Function;

View File

@ -1,8 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
View, StyleSheet, Text, Easing
} from 'react-native';
import { View, StyleSheet, Text, Easing } from 'react-native';
import { Audio } from 'expo-av';
import Slider from '@react-native-community/slider';
import moment from 'moment';
@ -19,6 +16,30 @@ import MessageContext from './Context';
import ActivityIndicator from '../ActivityIndicator';
import { withDimensions } from '../../dimensions';
type TButton = {
loading: boolean;
paused: boolean;
theme: string;
onPress: Function;
};
interface IMessageAudioProps {
file: {
audio_url: string;
description: string;
};
theme: string;
getCustomEmoji: Function;
scale: number;
}
interface IMessageAudioState {
loading: boolean,
currentTime: number,
duration: number,
paused: boolean
}
const mode = {
allowsRecordingIOS: false,
playsInSilentModeIOS: true,
@ -57,19 +78,17 @@ const styles = StyleSheet.create({
}
});
const formatTime = seconds => moment.utc(seconds * 1000).format('mm:ss');
const BUTTON_HIT_SLOP = {
top: 12, right: 12, bottom: 12, left: 12
};
const formatTime = (seconds: number) => moment.utc(seconds * 1000).format('mm:ss');
const BUTTON_HIT_SLOP = { top: 12, right: 12, bottom: 12, left: 12 };
const sliderAnimationConfig = {
duration: 250,
easing: Easing.linear,
delay: 0
};
const Button = React.memo(({
loading, paused, onPress, theme
}) => (
const Button = React.memo(({ loading, paused, onPress, theme }: TButton) => (
<Touchable
style={styles.playPauseButton}
onPress={onPress}
@ -84,25 +103,13 @@ const Button = React.memo(({
</Touchable>
));
Button.propTypes = {
loading: PropTypes.bool,
paused: PropTypes.bool,
theme: PropTypes.string,
onPress: PropTypes.func
};
Button.displayName = 'MessageAudioButton';
class MessageAudio extends React.Component {
class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioState> {
static contextType = MessageContext;
private sound: any;
static propTypes = {
file: PropTypes.object.isRequired,
theme: PropTypes.string,
getCustomEmoji: PropTypes.func,
scale: PropTypes.number
}
constructor(props) {
constructor(props: IMessageAudioProps) {
super(props);
this.state = {
loading: false,
@ -133,7 +140,7 @@ class MessageAudio extends React.Component {
this.setState({ loading: false });
}
shouldComponentUpdate(nextProps, nextState) {
shouldComponentUpdate(nextProps: any, nextState: any) {
const {
currentTime, duration, paused, loading
} = this.state;
@ -176,7 +183,7 @@ class MessageAudio extends React.Component {
}
}
onPlaybackStatusUpdate = (status) => {
onPlaybackStatusUpdate = (status: any) => {
if (status) {
this.onLoad(status);
this.onProgress(status);
@ -184,12 +191,12 @@ class MessageAudio extends React.Component {
}
}
onLoad = (data) => {
onLoad = (data: any) => {
const duration = data.durationMillis / 1000;
this.setState({ duration: duration > 0 ? duration : 0 });
}
onProgress = (data) => {
onProgress = (data: any) => {
const { duration } = this.state;
const currentTime = data.positionMillis / 1000;
if (currentTime <= duration) {
@ -197,7 +204,7 @@ class MessageAudio extends React.Component {
}
}
onEnd = async(data) => {
onEnd = async(data: any) => {
if (data.didJustFinish) {
try {
await this.sound.stopAsync();
@ -232,7 +239,7 @@ class MessageAudio extends React.Component {
}
}
onValueChange = async(value) => {
onValueChange = async(value: any) => {
try {
this.setState({ currentTime: value });
await this.sound.setPositionAsync(value * 1000);
@ -275,10 +282,12 @@ class MessageAudio extends React.Component {
minimumTrackTintColor={themes[theme].tintColor}
maximumTrackTintColor={themes[theme].auxiliaryText}
onValueChange={this.onValueChange}
/*@ts-ignore*/
thumbImage={isIOS && { uri: 'audio_thumb', scale }}
/>
<Text style={[styles.duration, { color: themes[theme].auxiliaryText }]}>{this.duration}</Text>
</View>
{/*@ts-ignore*/}
<Markdown msg={description} baseUrl={baseUrl} username={user.username} getCustomEmoji={getCustomEmoji} theme={theme} />
</>
);

View File

@ -1,7 +1,7 @@
import React from 'react';
import { messageBlockWithContext } from '../UIKit/MessageBlock';
interface IMessageBlocks {
export interface IMessageBlocks {
blocks: any;
id: string;
rid: string;

View File

@ -1,6 +1,5 @@
import React, { useContext } from 'react';
import { View, Text } from 'react-native';
import PropTypes from 'prop-types';
import Touchable from './Touchable';
import { CustomIcon } from '../../lib/Icons';
@ -10,9 +9,15 @@ import I18n from '../../i18n';
import { themes } from '../../constants/colors';
import MessageContext from './Context';
const Broadcast = React.memo(({
author, broadcast, theme
}) => {
export interface IMessageBroadcast {
author: {
_id: string
};
broadcast: boolean;
theme: string
}
const Broadcast = React.memo(({ author, broadcast, theme }: IMessageBroadcast) => {
const { user, replyBroadcast } = useContext(MessageContext);
const isOwn = author._id === user.id;
if (broadcast && !isOwn) {
@ -36,11 +41,6 @@ const Broadcast = React.memo(({
return null;
});
Broadcast.propTypes = {
author: PropTypes.object,
broadcast: PropTypes.bool,
theme: PropTypes.string
};
Broadcast.displayName = 'MessageBroadcast';
export default Broadcast;

View File

@ -8,7 +8,7 @@ import I18n from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import { themes } from '../../constants/colors';
interface IMessageCallButton {
export interface IMessageCallButton {
theme: string;
callJitsi: Function;
}

View File

@ -1,6 +1,5 @@
import React, { useContext } from 'react';
import { Text, View } from 'react-native';
import PropTypes from 'prop-types';
import { dequal } from 'dequal';
import I18n from '../../i18n';
@ -12,9 +11,29 @@ import { themes } from '../../constants/colors';
import MessageContext from './Context';
import Encrypted from './Encrypted';
import { E2E_MESSAGE_TYPE } from '../../lib/encryption/constants';
import {TChannel} from "../markdown/Hashtag";
const Content = React.memo((props) => {
export interface IMessageContent {
isTemp: boolean;
isInfo: boolean;
tmid: string;
isThreadRoom: boolean;
msg: string;
theme: string;
isEdited: boolean;
isEncrypted: boolean;
getCustomEmoji: Function;
channels: TChannel[];
mentions: object[];
navToRoomInfo: Function;
useRealName: boolean;
isIgnored: boolean;
type: string;
}
const Content = React.memo((props: IMessageContent) => {
if (props.isInfo) {
// @ts-ignore
const infoMessage = getInfoMessage({ ...props });
const renderMessageContent = (
@ -37,7 +56,7 @@ const Content = React.memo((props) => {
return renderMessageContent;
}
const isPreview = props.tmid && !props.isThreadRoom;
const isPreview: any = props.tmid && !props.isThreadRoom;
let content = null;
if (props.tmid && !props.msg) {
@ -47,6 +66,7 @@ const Content = React.memo((props) => {
} else {
const { baseUrl, user, onLinkPress } = useContext(MessageContext);
content = (
// @ts-ignore
<Markdown
msg={props.msg}
baseUrl={baseUrl}
@ -118,23 +138,6 @@ const Content = React.memo((props) => {
return true;
});
Content.propTypes = {
isTemp: PropTypes.bool,
isInfo: PropTypes.bool,
tmid: PropTypes.string,
isThreadRoom: PropTypes.bool,
msg: PropTypes.string,
theme: PropTypes.string,
isEdited: PropTypes.bool,
isEncrypted: PropTypes.bool,
getCustomEmoji: PropTypes.func,
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
navToRoomInfo: PropTypes.func,
useRealName: PropTypes.bool,
isIgnored: PropTypes.bool,
type: PropTypes.string
};
Content.displayName = 'MessageContent';
export default Content;

View File

@ -1,4 +0,0 @@
import React from 'react';
const MessageContext = React.createContext();
export default MessageContext;

View File

@ -0,0 +1,5 @@
import React from 'react';
// @ts-ignore
const MessageContext = React.createContext<any>();
export default MessageContext;

View File

@ -11,7 +11,7 @@ import { themes } from '../../constants/colors';
import MessageContext from './Context';
import { formatDateThreads } from '../../utils/room';
interface IMessageDiscussion {
export interface IMessageDiscussion {
msg: string;
dcount: number;
dlm: string;

View File

@ -1,5 +1,4 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
import Touchable from 'react-native-platform-touchable';
@ -7,21 +6,59 @@ import MessageContext from './Context';
import User from './User';
import styles from './styles';
import RepliedThread from './RepliedThread';
import MessageAvatar from './MessageAvatar';
import Attachments from './Attachments';
import RepliedThread, {IMessageRepliedThread} from './RepliedThread';
import MessageAvatar, {IMessageAvatar} from './MessageAvatar';
import Attachments, {IMessageAttachments} from './Attachments';
import Urls from './Urls';
import Thread from './Thread';
import Blocks from './Blocks';
import Thread, {IMessageThread} from './Thread';
import Blocks, {IMessageBlocks} from './Blocks';
import Reactions from './Reactions';
import Broadcast from './Broadcast';
import Discussion from './Discussion';
import Content from './Content';
import Broadcast, {IMessageBroadcast} from './Broadcast';
import Discussion, {IMessageDiscussion} from './Discussion';
import Content, {IMessageContent} from './Content';
import ReadReceipt from './ReadReceipt';
import CallButton from './CallButton';
import CallButton, {IMessageCallButton} from './CallButton';
import { themes } from '../../constants/colors';
const MessageInner = React.memo((props) => {
type TMessageInner = {
type: string;
blocks: [];
} & IMessageDiscussion & IMessageContent & IMessageCallButton & IMessageBlocks
& IMessageThread & IMessageAttachments & IMessageBroadcast;
type TMessage = {
isThreadReply: boolean;
isThreadSequential: boolean;
isInfo: boolean;
isTemp: boolean;
isHeader: boolean;
hasError: boolean;
style: any;
onLongPress: Function;
isReadReceiptEnabled: boolean;
unread: boolean;
theme: string;
isIgnored: boolean;
} & IMessageRepliedThread & IMessageAvatar & IMessageContent & TMessageInner;
interface IMessageTouchable {
hasError: boolean;
isInfo: boolean;
isThreadReply: boolean;
isTemp: boolean;
archived: boolean;
highlighted: boolean;
theme: string;
ts?: any
urls?: any;
reactions?: any;
alias?: any;
role?: any;
drid?: any;
}
const MessageInner = React.memo((props: TMessageInner) => {
if (props.type === 'discussion-created') {
return (
<>
@ -63,7 +100,7 @@ const MessageInner = React.memo((props) => {
});
MessageInner.displayName = 'MessageInner';
const Message = React.memo((props) => {
const Message = React.memo((props: TMessage) => {
if (props.isThreadReply || props.isThreadSequential || props.isInfo || props.isIgnored) {
const thread = props.isThreadReply ? <RepliedThread {...props} /> : null;
return (
@ -107,7 +144,7 @@ const Message = React.memo((props) => {
});
Message.displayName = 'Message';
const MessageTouchable = React.memo((props) => {
const MessageTouchable = React.memo((props: IMessageTouchable & TMessage) => {
if (props.hasError) {
return (
<View>
@ -129,36 +166,7 @@ const MessageTouchable = React.memo((props) => {
</Touchable>
);
});
MessageTouchable.displayName = 'MessageTouchable';
MessageTouchable.propTypes = {
hasError: PropTypes.bool,
isInfo: PropTypes.bool,
isThreadReply: PropTypes.bool,
isTemp: PropTypes.bool,
archived: PropTypes.bool,
highlighted: PropTypes.bool,
theme: PropTypes.string
};
Message.propTypes = {
isThreadReply: PropTypes.bool,
isThreadSequential: PropTypes.bool,
isInfo: PropTypes.bool,
isTemp: PropTypes.bool,
isHeader: PropTypes.bool,
hasError: PropTypes.bool,
style: PropTypes.any,
onLongPress: PropTypes.func,
isReadReceiptEnabled: PropTypes.bool,
unread: PropTypes.bool,
theme: PropTypes.string,
isIgnored: PropTypes.bool
};
MessageInner.propTypes = {
type: PropTypes.string,
blocks: PropTypes.array
};
export default MessageTouchable;

View File

@ -4,7 +4,7 @@ import Avatar from '../Avatar';
import styles from './styles';
import MessageContext from './Context';
interface IMessageAvatar {
export interface IMessageAvatar {
isHeader: boolean;
avatar: string;
emoji: string;
@ -12,7 +12,7 @@ interface IMessageAvatar {
username: string
_id: string;
};
small: boolean;
small?: boolean;
navToRoomInfo: Function;
getCustomEmoji(): void;
theme: string;

View File

@ -7,7 +7,7 @@ import { themes } from '../../constants/colors';
import I18n from '../../i18n';
import Markdown from '../markdown';
interface IMessageRepliedThread {
export interface IMessageRepliedThread {
tmid: string;
tmsg: string;
id: string;

View File

@ -7,7 +7,7 @@ import MessageContext from './Context';
import ThreadDetails from '../ThreadDetails';
import I18n from '../../i18n';
interface IMessageThread {
export interface IMessageThread {
msg: string;
tcount: number;
theme: string;

View File

@ -11,75 +11,62 @@ import messagesStatus from '../../constants/messagesStatus';
import { withTheme } from '../../theme';
import openLink from '../../utils/openLink';
class MessageContainer extends React.Component {
static propTypes = {
item: PropTypes.object.isRequired,
user: PropTypes.shape({
id: PropTypes.string.isRequired,
username: PropTypes.string.isRequired,
token: PropTypes.string.isRequired
}),
rid: PropTypes.string,
timeFormat: PropTypes.string,
style: PropTypes.any,
archived: PropTypes.bool,
broadcast: PropTypes.bool,
previousItem: PropTypes.object,
baseUrl: PropTypes.string,
Message_GroupingPeriod: PropTypes.number,
isReadReceiptEnabled: PropTypes.bool,
isThreadRoom: PropTypes.bool,
useRealName: PropTypes.bool,
autoTranslateRoom: PropTypes.bool,
autoTranslateLanguage: PropTypes.string,
status: PropTypes.number,
isIgnored: PropTypes.bool,
highlighted: PropTypes.bool,
getCustomEmoji: PropTypes.func,
onLongPress: PropTypes.func,
onReactionPress: PropTypes.func,
onEncryptedPress: PropTypes.func,
onDiscussionPress: PropTypes.func,
onThreadPress: PropTypes.func,
errorActionsShow: PropTypes.func,
replyBroadcast: PropTypes.func,
reactionInit: PropTypes.func,
fetchThreadName: PropTypes.func,
showAttachment: PropTypes.func,
onReactionLongPress: PropTypes.func,
navToRoomInfo: PropTypes.func,
callJitsi: PropTypes.func,
blockAction: PropTypes.func,
theme: PropTypes.string,
threadBadgeColor: PropTypes.string,
toggleFollowThread: PropTypes.func,
jumpToMessage: PropTypes.func,
onPress: PropTypes.func
}
interface IMessageContainerProps {
item: any;
user: {
id: string;
username: string;
token: string;
};
rid: string;
timeFormat: string;
style: any;
archived: boolean;
broadcast: boolean;
previousItem: {
ts: any;
u: any;
groupable: any;
id: any;
tmid: any;
status: any
};
baseUrl: string;
Message_GroupingPeriod: number;
isReadReceiptEnabled: boolean;
isThreadRoom: boolean;
useRealName: boolean;
autoTranslateRoom: boolean;
autoTranslateLanguage: string;
status: number;
isIgnored: boolean;
highlighted: boolean;
getCustomEmoji(): void;
onLongPress: Function;
onReactionPress: Function;
onEncryptedPress: Function;
onDiscussionPress: Function;
onThreadPress: Function;
errorActionsShow: Function;
replyBroadcast: Function;
reactionInit: Function;
fetchThreadName: Function;
showAttachment: Function;
onReactionLongPress: Function;
navToRoomInfo: Function;
callJitsi: Function;
blockAction: Function;
theme: string;
threadBadgeColor: string;
toggleFollowThread: Function;
jumpToMessage: Function;
onPress: Function;
}
static defaultProps = {
getCustomEmoji: () => {},
onLongPress: () => {},
onReactionPress: () => {},
onEncryptedPress: () => {},
onDiscussionPress: () => {},
onThreadPress: () => {},
errorActionsShow: () => {},
replyBroadcast: () => {},
reactionInit: () => {},
fetchThreadName: () => {},
showAttachment: () => {},
onReactionLongPress: () => {},
navToRoomInfo: () => {},
callJitsi: () => {},
blockAction: () => {},
archived: false,
broadcast: false,
isIgnored: false,
theme: 'light'
}
class MessageContainer extends React.Component<IMessageContainerProps, any> {
state = { isManualUnignored: false };
private subscription: any;
componentDidMount() {
const { item } = this.props;
@ -91,7 +78,7 @@ class MessageContainer extends React.Component {
}
}
shouldComponentUpdate(nextProps, nextState) {
shouldComponentUpdate(nextProps: any, nextState: any) {
const { isManualUnignored } = this.state;
const {
theme, threadBadgeColor, isIgnored, highlighted
@ -155,7 +142,7 @@ class MessageContainer extends React.Component {
}
}
onReactionPress = (emoji) => {
onReactionPress = (emoji: any) => {
const { onReactionPress, item } = this.props;
if (onReactionPress) {
onReactionPress(emoji, item.id);
@ -195,9 +182,7 @@ class MessageContainer extends React.Component {
}
get isHeader() {
const {
item, previousItem, broadcast, Message_GroupingPeriod
} = this.props;
const { item, previousItem, broadcast, Message_GroupingPeriod } = this.props;
if (this.hasError || (previousItem && previousItem.status === messagesStatus.ERROR)) {
return true;
}
@ -218,9 +203,7 @@ class MessageContainer extends React.Component {
}
get isThreadReply() {
const {
item, previousItem, isThreadRoom
} = this.props;
const { item, previousItem, isThreadRoom } = this.props;
if (isThreadRoom) {
return false;
}
@ -279,9 +262,9 @@ class MessageContainer extends React.Component {
}
}
onLinkPress = (link) => {
onLinkPress = (link: any) => {
const { item, theme, jumpToMessage } = this.props;
const isMessageLink = item?.attachments?.findIndex(att => att?.message_link === link) !== -1;
const isMessageLink = item?.attachments?.findIndex((att: any) => att?.message_link === link) !== -1;
if (isMessageLink) {
return jumpToMessage(link);
}
@ -372,6 +355,7 @@ class MessageContainer extends React.Component {
replies
}}
>
{/*@ts-ignore*/}
<Message
id={id}
msg={message}

View File

@ -2,4 +2,5 @@ declare module 'rn-extensions-share';
declare module 'commonmark';
declare module 'commonmark-react-renderer';
declare module 'remove-markdown';
declare module 'react-native-image-progress'
declare module 'react-native-image-progress';
declare module 'react-native-platform-touchable';