Chore: Evaluate MessageBox - TypeScript (#3936)

* chore: migrate buttons

* chore: migrate CommandsPreview

* chore: migrate Mention

* chore: migrate Some files

* chore: migrate RecordAudio

* fix lint

* fix context value

* fix MessageBox types
This commit is contained in:
Gleidson Daniel Silva 2022-03-31 19:39:24 -03:00 committed by GitHub
parent 64b594f9ae
commit e0459aed89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 213 additions and 256 deletions

View File

@ -1,12 +1,13 @@
import FastImage from '@rocket.chat/react-native-fast-image';
import React, { useContext, useState } from 'react';
import { TouchableOpacity } from 'react-native';
import FastImage from '@rocket.chat/react-native-fast-image';
import styles from '../styles';
import { CustomIcon } from '../../../lib/Icons';
import { themes } from '../../../constants/colors';
import MessageboxContext from '../Context';
import { CustomIcon } from '../../../lib/Icons';
import { useTheme } from '../../../theme';
import ActivityIndicator from '../../ActivityIndicator';
import MessageboxContext from '../Context';
import styles from '../styles';
interface IMessageBoxCommandsPreviewItem {
item: {
@ -14,13 +15,13 @@ interface IMessageBoxCommandsPreviewItem {
id: string;
value: string;
};
theme?: string;
}
const Item = ({ item, theme }: IMessageBoxCommandsPreviewItem) => {
const Item = ({ item }: IMessageBoxCommandsPreviewItem) => {
const context = useContext(MessageboxContext);
const { onPressCommandPreview } = context;
const [loading, setLoading] = useState(true);
const { theme } = useTheme();
return (
<TouchableOpacity
@ -37,7 +38,7 @@ const Item = ({ item, theme }: IMessageBoxCommandsPreviewItem) => {
{loading ? <ActivityIndicator /> : null}
</FastImage>
) : (
<CustomIcon name='attach' size={36} color={themes[theme!].actionTintColor} />
<CustomIcon name='attach' size={36} color={themes[theme].actionTintColor} />
)}
</TouchableOpacity>
);

View File

@ -1,30 +1,30 @@
import { dequal } from 'dequal';
import React from 'react';
import { FlatList } from 'react-native';
import { dequal } from 'dequal';
import Item from './Item';
import styles from '../styles';
import { themes } from '../../../constants/colors';
import { withTheme } from '../../../theme';
import { IPreviewItem } from '../../../definitions';
import { useTheme } from '../../../theme';
import styles from '../styles';
import Item from './Item';
interface IMessageBoxCommandsPreview {
commandPreview: IPreviewItem[];
showCommandPreview: boolean;
theme?: string;
}
const CommandsPreview = React.memo(
({ theme, commandPreview, showCommandPreview }: IMessageBoxCommandsPreview) => {
({ commandPreview, showCommandPreview }: IMessageBoxCommandsPreview) => {
if (!showCommandPreview) {
return null;
}
const { theme } = useTheme();
return (
<FlatList
testID='commandbox-container'
style={[styles.mentionList, { backgroundColor: themes[theme!].messageboxBackground }]}
style={[styles.mentionList, { backgroundColor: themes[theme].messageboxBackground }]}
data={commandPreview}
renderItem={({ item }) => <Item item={item} theme={theme} />}
renderItem={({ item }) => <Item item={item} />}
keyExtractor={(item: any) => item.id}
keyboardShouldPersistTaps='always'
horizontal
@ -33,9 +33,6 @@ const CommandsPreview = React.memo(
);
},
(prevProps, nextProps) => {
if (prevProps.theme !== nextProps.theme) {
return false;
}
if (prevProps.showCommandPreview !== nextProps.showCommandPreview) {
return false;
}
@ -46,4 +43,4 @@ const CommandsPreview = React.memo(
}
);
export default withTheme(CommandsPreview);
export default CommandsPreview;

View File

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

View File

@ -7,6 +7,7 @@ import EmojiPicker from '../EmojiPicker';
import styles from './styles';
import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
import { IEmoji } from '../../definitions/IEmoji';
interface IMessageBoxEmojiKeyboard {
theme: string;
@ -21,7 +22,7 @@ export default class EmojiKeyboard extends React.PureComponent<IMessageBoxEmojiK
this.baseUrl = state.share.server.server || state.server.server;
}
onEmojiSelected = (emoji: any) => {
onEmojiSelected = (emoji: IEmoji) => {
KeyboardRegistry.onItemSelected('EmojiKeyboard', { emoji });
};

View File

@ -3,7 +3,6 @@ import React from 'react';
import { CancelEditingButton, ToggleEmojiButton } from './buttons';
interface IMessageBoxLeftButtons {
theme: string;
showEmojiKeyboard: boolean;
openEmoji(): void;
closeEmoji(): void;
@ -11,13 +10,11 @@ interface IMessageBoxLeftButtons {
editCancel(): void;
}
const LeftButtons = React.memo(
({ theme, showEmojiKeyboard, editing, editCancel, openEmoji, closeEmoji }: IMessageBoxLeftButtons) => {
const LeftButtons = React.memo(({ showEmojiKeyboard, editing, editCancel, openEmoji, closeEmoji }: IMessageBoxLeftButtons) => {
if (editing) {
return <CancelEditingButton onPress={editCancel} theme={theme} />;
return <CancelEditingButton onPress={editCancel} />;
}
return <ToggleEmojiButton show={showEmojiKeyboard} open={openEmoji} close={closeEmoji} theme={theme} />;
}
);
return <ToggleEmojiButton show={showEmojiKeyboard} open={openEmoji} close={closeEmoji} />;
});
export default LeftButtons;

View File

@ -5,23 +5,20 @@ import { ActionsButton, CancelEditingButton } from './buttons';
import styles from './styles';
interface IMessageBoxLeftButtons {
theme: string;
showMessageBoxActions(): void;
editing: boolean;
editCancel(): void;
isActionsEnabled: boolean;
}
const LeftButtons = React.memo(
({ theme, showMessageBoxActions, editing, editCancel, isActionsEnabled }: IMessageBoxLeftButtons) => {
const LeftButtons = React.memo(({ showMessageBoxActions, editing, editCancel, isActionsEnabled }: IMessageBoxLeftButtons) => {
if (editing) {
return <CancelEditingButton onPress={editCancel} theme={theme} />;
return <CancelEditingButton onPress={editCancel} />;
}
if (isActionsEnabled) {
return <ActionsButton onPress={showMessageBoxActions} theme={theme} />;
return <ActionsButton onPress={showMessageBoxActions} />;
}
return <View style={styles.buttonsWhitespace} />;
}
);
});
export default LeftButtons;

View File

@ -4,16 +4,18 @@ import { Text, TouchableOpacity } from 'react-native';
import styles from '../styles';
import I18n from '../../../i18n';
import { themes } from '../../../constants/colors';
import { useTheme } from '../../../theme';
interface IMessageBoxFixedMentionItem {
item: {
username: string;
};
onPress: Function;
theme: string;
}
const FixedMentionItem = ({ item, onPress, theme }: IMessageBoxFixedMentionItem) => (
const FixedMentionItem = ({ item, onPress }: IMessageBoxFixedMentionItem) => {
const { theme } = useTheme();
return (
<TouchableOpacity
style={[
styles.mentionItem,
@ -29,5 +31,6 @@ const FixedMentionItem = ({ item, onPress, theme }: IMessageBoxFixedMentionItem)
</Text>
</TouchableOpacity>
);
};
export default FixedMentionItem;

View File

@ -1,12 +1,11 @@
import React, { useContext } from 'react';
import { Text } from 'react-native';
import PropTypes from 'prop-types';
import shortnameToUnicode from '../../../utils/shortnameToUnicode';
import styles from '../styles';
import MessageboxContext from '../Context';
import CustomEmoji from '../../EmojiPicker/CustomEmoji';
import { IEmoji } from '../../../definitions/IEmoji';
import shortnameToUnicode from '../../../utils/shortnameToUnicode';
import CustomEmoji from '../../EmojiPicker/CustomEmoji';
import MessageboxContext from '../Context';
import styles from '../styles';
interface IMessageBoxMentionEmoji {
item: IEmoji;
@ -22,8 +21,4 @@ const MentionEmoji = ({ item }: IMessageBoxMentionEmoji) => {
return <Text style={styles.mentionItemEmoji}>{shortnameToUnicode(`:${item}:`)}</Text>;
};
MentionEmoji.propTypes = {
item: PropTypes.object
};
export default MentionEmoji;

View File

@ -1,16 +1,23 @@
import React, { useContext } from 'react';
import { View, Text, ActivityIndicator, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types';
import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
import { MENTIONS_TRACKING_TYPE_CANNED } from '../constants';
import styles from '../styles';
import sharedStyles from '../../../views/Styles';
import I18n from '../../../i18n';
import { themes } from '../../../constants/colors';
import I18n from '../../../i18n';
import { CustomIcon } from '../../../lib/Icons';
import { useTheme } from '../../../theme';
import sharedStyles from '../../../views/Styles';
import { MENTIONS_TRACKING_TYPE_CANNED } from '../constants';
import MessageboxContext from '../Context';
import styles from '../styles';
const MentionHeaderList = ({ trackingType, hasMentions, theme, loading }) => {
interface IMentionHeaderList {
trackingType: string;
hasMentions: boolean;
loading: boolean;
}
const MentionHeaderList = ({ trackingType, hasMentions, loading }: IMentionHeaderList) => {
const { theme } = useTheme();
const context = useContext(MessageboxContext);
const { onPressNoMatchCanned } = context;
@ -39,11 +46,4 @@ const MentionHeaderList = ({ trackingType, hasMentions, theme, loading }) => {
return null;
};
MentionHeaderList.propTypes = {
trackingType: PropTypes.string,
hasMentions: PropTypes.bool,
theme: PropTypes.string,
loading: PropTypes.bool
};
export default MentionHeaderList;

View File

@ -1,14 +1,15 @@
import React, { useContext } from 'react';
import { Text, TouchableOpacity } from 'react-native';
import styles from '../styles';
import Avatar from '../../Avatar';
import MessageboxContext from '../Context';
import FixedMentionItem from './FixedMentionItem';
import MentionEmoji from './MentionEmoji';
import { MENTIONS_TRACKING_TYPE_EMOJIS, MENTIONS_TRACKING_TYPE_COMMANDS, MENTIONS_TRACKING_TYPE_CANNED } from '../constants';
import { themes } from '../../../constants/colors';
import { IEmoji } from '../../../definitions/IEmoji';
import { useTheme } from '../../../theme';
import Avatar from '../../Avatar';
import { MENTIONS_TRACKING_TYPE_CANNED, MENTIONS_TRACKING_TYPE_COMMANDS, MENTIONS_TRACKING_TYPE_EMOJIS } from '../constants';
import MessageboxContext from '../Context';
import styles from '../styles';
import FixedMentionItem from './FixedMentionItem';
import MentionEmoji from './MentionEmoji';
interface IMessageBoxMentionItem {
item: {
@ -21,11 +22,48 @@ interface IMessageBoxMentionItem {
text: string;
} & IEmoji;
trackingType: string;
theme: string;
}
const MentionItem = ({ item, trackingType, theme }: IMessageBoxMentionItem) => {
const MentionItemContent = React.memo(({ trackingType, item }: IMessageBoxMentionItem) => {
const { theme } = useTheme();
switch (trackingType) {
case MENTIONS_TRACKING_TYPE_EMOJIS:
return (
<>
<MentionEmoji item={item} />
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>:{item.name || item}:</Text>
</>
);
case MENTIONS_TRACKING_TYPE_COMMANDS:
return (
<>
<Text style={[styles.slash, { backgroundColor: themes[theme].borderColor, color: themes[theme].tintColor }]}>/</Text>
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>{item.id}</Text>
</>
);
case MENTIONS_TRACKING_TYPE_CANNED:
return (
<>
<Text style={[styles.cannedItem, { color: themes[theme].titleText }]}>!{item.shortcut}</Text>
<Text numberOfLines={1} style={[styles.cannedMentionText, { color: themes[theme].auxiliaryTintColor }]}>
{item.text}
</Text>
</>
);
default:
return (
<>
<Avatar style={styles.avatar} text={item.username || item.name} size={30} type={item.t} />
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>{item.username || item.name || item}</Text>
</>
);
}
});
const MentionItem = ({ item, trackingType }: IMessageBoxMentionItem) => {
const context = useContext(MessageboxContext);
const { theme } = useTheme();
const { onPressMention } = context;
const defineTestID = (type: string) => {
@ -44,43 +82,7 @@ const MentionItem = ({ item, trackingType, theme }: IMessageBoxMentionItem) => {
const testID = defineTestID(trackingType);
if (item.username === 'all' || item.username === 'here') {
return <FixedMentionItem item={item} onPress={onPressMention} theme={theme} />;
}
let content = (
<>
<Avatar style={styles.avatar} text={item.username || item.name} size={30} type={item.t} />
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>{item.username || item.name || item}</Text>
</>
);
if (trackingType === MENTIONS_TRACKING_TYPE_EMOJIS) {
content = (
<>
<MentionEmoji item={item} />
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>:{item.name || item}:</Text>
</>
);
}
if (trackingType === MENTIONS_TRACKING_TYPE_COMMANDS) {
content = (
<>
<Text style={[styles.slash, { backgroundColor: themes[theme].borderColor, color: themes[theme].tintColor }]}>/</Text>
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>{item.id}</Text>
</>
);
}
if (trackingType === MENTIONS_TRACKING_TYPE_CANNED) {
content = (
<>
<Text style={[styles.cannedItem, { color: themes[theme].titleText }]}>!{item.shortcut}</Text>
<Text numberOfLines={1} style={[styles.cannedMentionText, { color: themes[theme].auxiliaryTintColor }]}>
{item.text}
</Text>
</>
);
return <FixedMentionItem item={item} onPress={onPressMention} />;
}
return (
@ -94,7 +96,7 @@ const MentionItem = ({ item, trackingType, theme }: IMessageBoxMentionItem) => {
]}
onPress={() => onPressMention(item)}
testID={testID}>
{content}
<MentionItemContent item={item} trackingType={trackingType} />
</TouchableOpacity>
);
};

View File

@ -6,29 +6,30 @@ import MentionHeaderList from './MentionHeaderList';
import styles from '../styles';
import MentionItem from './MentionItem';
import { themes } from '../../../constants/colors';
import { useTheme } from '../../../theme';
interface IMessageBoxMentions {
mentions: any[];
trackingType: string;
theme: string;
loading: boolean;
}
const Mentions = React.memo(
({ mentions, trackingType, theme, loading }: IMessageBoxMentions) => {
({ mentions, trackingType, loading }: IMessageBoxMentions) => {
if (!trackingType) {
return null;
}
const { theme } = useTheme();
return (
<View testID='messagebox-container'>
<FlatList
style={[styles.mentionList, { backgroundColor: themes[theme].auxiliaryBackground }]}
ListHeaderComponent={() => (
<MentionHeaderList trackingType={trackingType} hasMentions={mentions.length > 0} theme={theme} loading={loading} />
<MentionHeaderList trackingType={trackingType} hasMentions={mentions.length > 0} loading={loading} />
)}
data={mentions}
extraData={mentions}
renderItem={({ item }) => <MentionItem item={item} trackingType={trackingType} theme={theme} />}
renderItem={({ item }) => <MentionItem item={item} trackingType={trackingType} />}
keyExtractor={item => item.rid || item.name || item.command || item.shortcut || item}
keyboardShouldPersistTaps='always'
/>
@ -39,9 +40,6 @@ const Mentions = React.memo(
if (prevProps.loading !== nextProps.loading) {
return false;
}
if (prevProps.theme !== nextProps.theme) {
return false;
}
if (prevProps.trackingType !== nextProps.trackingType) {
return false;
}

View File

@ -47,23 +47,17 @@ const RECORDING_MODE = {
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX
};
const formatTime = function (seconds: any) {
let minutes: any = Math.floor(seconds / 60);
seconds %= 60;
if (minutes < 10) {
minutes = `0${minutes}`;
}
if (seconds < 10) {
seconds = `0${seconds}`;
}
return `${minutes}:${seconds}`;
const formatTime = function (time: number) {
const minutes = Math.floor(time / 60);
const seconds = time % 60;
const min = minutes < 10 ? `0${minutes}` : minutes;
const sec = seconds < 10 ? `0${seconds}` : seconds;
return `${min}:${sec}`;
};
export default class RecordAudio extends React.PureComponent<IMessageBoxRecordAudioProps, any> {
private isRecorderBusy: boolean;
private recording: any;
private recording!: Audio.Recording;
private LastDuration: number;
constructor(props: IMessageBoxRecordAudioProps) {
@ -112,7 +106,7 @@ export default class RecordAudio extends React.PureComponent<IMessageBoxRecordAu
return false;
};
onRecordingStatusUpdate = (status: any) => {
onRecordingStatusUpdate = (status: Audio.RecordingStatus) => {
this.setState({
isRecording: status.isRecording,
recordingDurationMillis: status.durationMillis
@ -157,7 +151,7 @@ export default class RecordAudio extends React.PureComponent<IMessageBoxRecordAu
await this.recording.stopAndUnloadAsync();
const fileURI = this.recording.getURI();
const fileData = await getInfoAsync(fileURI);
const fileData = await getInfoAsync(fileURI as string);
const fileInfo = {
name: `${Date.now()}.m4a`,
mime: 'audio/aac',

View File

@ -8,6 +8,8 @@ import { CustomIcon } from '../../lib/Icons';
import sharedStyles from '../../views/Styles';
import { themes } from '../../constants/colors';
import { IMessage } from '../../definitions/IMessage';
import { useTheme } from '../../theme';
import { IApplicationState } from '../../definitions';
const styles = StyleSheet.create({
container: {
@ -49,16 +51,15 @@ interface IMessageBoxReplyPreview {
baseUrl: string;
username: string;
getCustomEmoji: Function;
theme: string;
useRealName: boolean;
}
const ReplyPreview = React.memo(
({ message, Message_TimeFormat, replying, close, theme, useRealName }: IMessageBoxReplyPreview) => {
({ message, Message_TimeFormat, replying, close, useRealName }: IMessageBoxReplyPreview) => {
if (!replying) {
return null;
}
const { theme } = useTheme();
const time = moment(message.ts).format(Message_TimeFormat);
return (
<View style={[styles.container, { backgroundColor: themes[theme].messageboxBackground }]}>
@ -75,16 +76,14 @@ const ReplyPreview = React.memo(
</View>
);
},
(prevProps: any, nextProps: any) =>
prevProps.replying === nextProps.replying &&
prevProps.theme === nextProps.theme &&
prevProps.message.id === nextProps.message.id
(prevProps: IMessageBoxReplyPreview, nextProps: IMessageBoxReplyPreview) =>
prevProps.replying === nextProps.replying && prevProps.message.id === nextProps.message.id
);
const mapStateToProps = (state: any) => ({
Message_TimeFormat: state.settings.Message_TimeFormat,
const mapStateToProps = (state: IApplicationState) => ({
Message_TimeFormat: state.settings.Message_TimeFormat as string,
baseUrl: state.server.server,
useRealName: state.settings.UI_Use_Real_Name
useRealName: state.settings.UI_Use_Real_Name as boolean
});
export default connect(mapStateToProps)(ReplyPreview);

View File

@ -5,24 +5,20 @@ import { ActionsButton, SendButton } from './buttons';
import styles from './styles';
interface IMessageBoxRightButtons {
theme: string;
showSend: boolean;
submit(): void;
showMessageBoxActions(): void;
isActionsEnabled: boolean;
}
const RightButtons = React.memo(
({ theme, showSend, submit, showMessageBoxActions, isActionsEnabled }: IMessageBoxRightButtons) => {
const RightButtons = React.memo(({ showSend, submit, showMessageBoxActions, isActionsEnabled }: IMessageBoxRightButtons) => {
if (showSend) {
return <SendButton onPress={submit} theme={theme} />;
return <SendButton onPress={submit} />;
}
if (isActionsEnabled) {
return <ActionsButton onPress={showMessageBoxActions} theme={theme} />;
return <ActionsButton onPress={showMessageBoxActions} />;
}
return <View style={styles.buttonsWhitespace} />;
}
);
});
export default RightButtons;

View File

@ -3,16 +3,15 @@ import React from 'react';
import { SendButton } from './buttons';
interface IMessageBoxRightButtons {
theme: string;
showSend: boolean;
submit(): void;
}
const RightButtons = React.memo(({ theme, showSend, submit }: IMessageBoxRightButtons) => {
const RightButtons = ({ showSend, submit }: IMessageBoxRightButtons) => {
if (showSend) {
return <SendButton theme={theme} onPress={submit} />;
return <SendButton onPress={submit} />;
}
return null;
});
};
export default RightButtons;

View File

@ -3,12 +3,11 @@ import React from 'react';
import BaseButton from './BaseButton';
interface IActionsButton {
theme: string;
onPress(): void;
}
const ActionsButton = React.memo(({ theme, onPress }: IActionsButton) => (
<BaseButton onPress={onPress} testID='messagebox-actions' accessibilityLabel='Message_actions' icon='add' theme={theme} />
));
const ActionsButton = ({ onPress }: IActionsButton) => (
<BaseButton onPress={onPress} testID='messagebox-actions' accessibilityLabel='Message_actions' icon='add' />
);
export default ActionsButton;

View File

@ -1,13 +1,13 @@
import React from 'react';
import { BorderlessButton } from 'react-native-gesture-handler';
import React from 'react';
import { themes } from '../../../constants/colors';
import { CustomIcon } from '../../../lib/Icons';
import styles from '../styles';
import I18n from '../../../i18n';
import i18n from '../../../i18n';
import { CustomIcon } from '../../../lib/Icons';
import { useTheme } from '../../../theme';
import { themes } from '../../../constants/colors';
interface IBaseButton {
theme: string;
onPress(): void;
testID: string;
accessibilityLabel: string;
@ -15,16 +15,18 @@ interface IBaseButton {
color: string;
}
const BaseButton = React.memo(({ onPress, testID, accessibilityLabel, icon, theme, color }: Partial<IBaseButton>) => (
const BaseButton = ({ accessibilityLabel, icon, color, ...props }: Partial<IBaseButton>) => {
const { theme } = useTheme();
return (
<BorderlessButton
onPress={onPress}
{...props}
style={styles.actionButton}
testID={testID}
// @ts-ignore
accessibilityLabel={I18n.t(accessibilityLabel)}
accessibilityLabel={i18n.t(accessibilityLabel)}
accessibilityTraits='button'>
<CustomIcon name={icon} size={24} color={color ?? themes[theme!].auxiliaryTintColor} />
<CustomIcon name={icon} size={24} color={color || themes[theme].auxiliaryTintColor} />
</BorderlessButton>
));
);
};
export default BaseButton;

View File

@ -3,18 +3,11 @@ import React from 'react';
import BaseButton from './BaseButton';
interface ICancelEditingButton {
theme: string;
onPress(): void;
}
const CancelEditingButton = React.memo(({ theme, onPress }: ICancelEditingButton) => (
<BaseButton
onPress={onPress}
testID='messagebox-cancel-editing'
accessibilityLabel='Cancel_editing'
icon='close'
theme={theme}
/>
));
const CancelEditingButton = ({ onPress }: ICancelEditingButton) => (
<BaseButton onPress={onPress} testID='messagebox-cancel-editing' accessibilityLabel='Cancel_editing' icon='close' />
);
export default CancelEditingButton;

View File

@ -1,22 +1,24 @@
import React from 'react';
import BaseButton from './BaseButton';
import { themes } from '../../../constants/colors';
import { useTheme } from '../../../theme';
import BaseButton from './BaseButton';
interface ISendButton {
theme: string;
onPress(): void;
}
const SendButton = React.memo(({ theme, onPress }: ISendButton) => (
const SendButton = ({ onPress }: ISendButton) => {
const { theme } = useTheme();
return (
<BaseButton
onPress={onPress}
testID='messagebox-send-message'
accessibilityLabel='Send_message'
icon='send-filled'
theme={theme}
color={themes[theme].tintColor}
/>
));
);
};
export default SendButton;

View File

@ -3,33 +3,18 @@ import React from 'react';
import BaseButton from './BaseButton';
interface IToggleEmojiButton {
theme: string;
show: boolean;
open(): void;
close(): void;
}
const ToggleEmojiButton = React.memo(({ theme, show, open, close }: IToggleEmojiButton) => {
const ToggleEmojiButton = ({ show, open, close }: IToggleEmojiButton) => {
if (show) {
return (
<BaseButton
onPress={close}
testID='messagebox-close-emoji'
accessibilityLabel='Close_emoji_selector'
icon='keyboard'
theme={theme}
/>
<BaseButton onPress={close} testID='messagebox-close-emoji' accessibilityLabel='Close_emoji_selector' icon='keyboard' />
);
}
return (
<BaseButton
onPress={open}
testID='messagebox-open-emoji'
accessibilityLabel='Open_emoji_selector'
icon='emoji'
theme={theme}
/>
);
});
return <BaseButton onPress={open} testID='messagebox-open-emoji' accessibilityLabel='Open_emoji_selector' icon='emoji' />;
};
export default ToggleEmojiButton;

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Alert, Keyboard, NativeModules, Text, View } from 'react-native';
import { connect } from 'react-redux';
import { KeyboardAccessoryView } from 'react-native-ui-lib/keyboard';
import ImagePicker, { Image, ImageOrVideo } from 'react-native-image-crop-picker';
import ImagePicker, { Image, ImageOrVideo, Options } from 'react-native-image-crop-picker';
import { dequal } from 'dequal';
import DocumentPicker from 'react-native-document-picker';
import { Q } from '@nozbe/watermelondb';
@ -50,7 +50,8 @@ import { sanitizeLikeString } from '../../lib/database/utils';
import { CustomIcon } from '../../lib/Icons';
import { IMessage } from '../../definitions/IMessage';
import { forceJpgExtension } from './forceJpgExtension';
import { IPreviewItem, IUser } from '../../definitions';
import { IBaseScreen, IPreviewItem, IUser, TSubscriptionModel, TThreadModel } from '../../definitions';
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
if (isAndroid) {
require('./EmojiKeyboard');
@ -63,18 +64,18 @@ const imagePickerConfig = {
forceJpg: true
};
const libraryPickerConfig = {
const libraryPickerConfig: Options = {
multiple: true,
compressVideoPreset: 'Passthrough',
mediaType: 'any',
forceJpg: true
};
const videoPickerConfig = {
const videoPickerConfig: Options = {
mediaType: 'video'
};
export interface IMessageBoxProps {
export interface IMessageBoxProps extends IBaseScreen<MasterDetailInsideStackParamList, any> {
rid: string;
baseUrl: string;
message: IMessage;
@ -97,7 +98,6 @@ export interface IMessageBoxProps {
theme: string;
replyCancel(): void;
showSend: boolean;
navigation: any;
children: JSX.Element;
isMasterDetail: boolean;
showActionSheet: Function;
@ -118,7 +118,7 @@ interface IMessageBoxState {
commandPreview: IPreviewItem[];
showCommandPreview: boolean;
command: {
appId?: any;
appId?: string;
};
tshow: boolean;
mentionLoading: boolean;
@ -132,17 +132,15 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
private focused: boolean;
private options: any;
private imagePickerConfig: Options;
private imagePickerConfig: any;
private libraryPickerConfig: Options;
private libraryPickerConfig: any;
private videoPickerConfig: Options;
private videoPickerConfig: any;
private room!: TSubscriptionModel;
private room: any;
private thread: any;
private thread!: TThreadModel;
private unsubscribeFocus: any;
@ -713,7 +711,8 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
chooseFromLibrary = async () => {
logEvent(events.ROOM_BOX_ACTION_LIBRARY);
try {
let attachments = (await ImagePicker.openPicker(this.libraryPickerConfig)) as ImageOrVideo[];
// The type can be video or photo, however the lib understands that it is just one of them.
let attachments = (await ImagePicker.openPicker(this.libraryPickerConfig)) as unknown as ImageOrVideo[];
attachments = attachments.map(att => forceJpgExtension(att));
this.openShareView(attachments);
} catch (e) {
@ -757,12 +756,12 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
openShareView = (attachments: any) => {
const { message, replyCancel, replyWithMention } = this.props;
// Start a thread with an attachment
let { thread } = this;
let value: TThreadModel | IMessage = this.thread;
if (replyWithMention) {
thread = message;
value = message;
replyCancel();
}
Navigation.navigate('ShareView', { room: this.room, thread, attachments });
Navigation.navigate('ShareView', { room: this.room, value, attachments });
};
createDiscussion = () => {
@ -1060,7 +1059,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
const commandsPreviewAndMentions = !recording ? (
<>
<CommandsPreview commandPreview={commandPreview} showCommandPreview={showCommandPreview} />
<Mentions mentions={mentions} trackingType={trackingType} theme={theme} loading={mentionLoading} />
<Mentions mentions={mentions} trackingType={trackingType} loading={mentionLoading} />
</>
) : null;
@ -1071,7 +1070,6 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
username={user.username}
replying={replying}
getCustomEmoji={getCustomEmoji}
theme={theme}
/>
) : null;