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:
parent
64b594f9ae
commit
e0459aed89
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
|
||||
// @ts-ignore
|
||||
const MessageboxContext = React.createContext<any>();
|
||||
const MessageboxContext = React.createContext<any>(null);
|
||||
export default MessageboxContext;
|
||||
|
|
|
@ -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 });
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue