diff --git a/app/containers/ActivityIndicator.tsx b/app/containers/ActivityIndicator.tsx index 50a60f0c3..e2eb33926 100644 --- a/app/containers/ActivityIndicator.tsx +++ b/app/containers/ActivityIndicator.tsx @@ -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 } diff --git a/app/containers/message/Attachments.tsx b/app/containers/message/Attachments.tsx index 74be12552..07d0c0547 100644 --- a/app/containers/message/Attachments.tsx +++ b/app/containers/message/Attachments.tsx @@ -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; diff --git a/app/containers/message/Audio.js b/app/containers/message/Audio.tsx similarity index 84% rename from app/containers/message/Audio.js rename to app/containers/message/Audio.tsx index e22dff408..9bf783ff8 100644 --- a/app/containers/message/Audio.js +++ b/app/containers/message/Audio.tsx @@ -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) => ( )); -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 { 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 }} /> {this.duration} + {/*@ts-ignore*/} ); diff --git a/app/containers/message/Blocks.ts b/app/containers/message/Blocks.ts index 62b1f2d22..5f22d9ca9 100644 --- a/app/containers/message/Blocks.ts +++ b/app/containers/message/Blocks.ts @@ -1,7 +1,7 @@ import React from 'react'; import { messageBlockWithContext } from '../UIKit/MessageBlock'; -interface IMessageBlocks { +export interface IMessageBlocks { blocks: any; id: string; rid: string; diff --git a/app/containers/message/Broadcast.js b/app/containers/message/Broadcast.tsx similarity index 84% rename from app/containers/message/Broadcast.js rename to app/containers/message/Broadcast.tsx index 58de1d0dc..106ed8058 100644 --- a/app/containers/message/Broadcast.js +++ b/app/containers/message/Broadcast.tsx @@ -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; diff --git a/app/containers/message/CallButton.tsx b/app/containers/message/CallButton.tsx index a0ba95d32..19ee3ad95 100644 --- a/app/containers/message/CallButton.tsx +++ b/app/containers/message/CallButton.tsx @@ -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; } diff --git a/app/containers/message/Content.js b/app/containers/message/Content.tsx similarity index 82% rename from app/containers/message/Content.js rename to app/containers/message/Content.tsx index 90af48acd..2f1f542f0 100644 --- a/app/containers/message/Content.js +++ b/app/containers/message/Content.tsx @@ -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 { 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; diff --git a/app/containers/message/Context.js b/app/containers/message/Context.js deleted file mode 100644 index 407904b4e..000000000 --- a/app/containers/message/Context.js +++ /dev/null @@ -1,4 +0,0 @@ -import React from 'react'; - -const MessageContext = React.createContext(); -export default MessageContext; diff --git a/app/containers/message/Context.ts b/app/containers/message/Context.ts new file mode 100644 index 000000000..eee35a6c7 --- /dev/null +++ b/app/containers/message/Context.ts @@ -0,0 +1,5 @@ +import React from 'react'; + +// @ts-ignore +const MessageContext = React.createContext(); +export default MessageContext; diff --git a/app/containers/message/Discussion.tsx b/app/containers/message/Discussion.tsx index 7d7d207a9..34a88263d 100644 --- a/app/containers/message/Discussion.tsx +++ b/app/containers/message/Discussion.tsx @@ -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; diff --git a/app/containers/message/Message.js b/app/containers/message/Message.tsx similarity index 64% rename from app/containers/message/Message.js rename to app/containers/message/Message.tsx index 4bc03c000..2870ff4a5 100644 --- a/app/containers/message/Message.js +++ b/app/containers/message/Message.tsx @@ -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 ? : 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 ( @@ -129,36 +166,7 @@ const MessageTouchable = React.memo((props) => { ); }); + 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; diff --git a/app/containers/message/MessageAvatar.tsx b/app/containers/message/MessageAvatar.tsx index 26a296993..cb7f71800 100644 --- a/app/containers/message/MessageAvatar.tsx +++ b/app/containers/message/MessageAvatar.tsx @@ -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; diff --git a/app/containers/message/RepliedThread.tsx b/app/containers/message/RepliedThread.tsx index d91c3f008..4e832a961 100644 --- a/app/containers/message/RepliedThread.tsx +++ b/app/containers/message/RepliedThread.tsx @@ -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; diff --git a/app/containers/message/Thread.tsx b/app/containers/message/Thread.tsx index adbcd89e5..361a51805 100644 --- a/app/containers/message/Thread.tsx +++ b/app/containers/message/Thread.tsx @@ -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; diff --git a/app/containers/message/index.js b/app/containers/message/index.tsx similarity index 76% rename from app/containers/message/index.js rename to app/containers/message/index.tsx index 467c634a6..9e92ccb63 100644 --- a/app/containers/message/index.js +++ b/app/containers/message/index.tsx @@ -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 { 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*/}