[IMPROVE] Create edited component for edited messages (#4048)

This commit is contained in:
Alex Junior 2022-05-10 14:40:08 -03:00 committed by GitHub
parent f60de94cba
commit e0bfdee70c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 105 additions and 97 deletions

View File

@ -1,10 +1,9 @@
import React, { PureComponent } from 'react';
import { Image, StyleProp, Text, TextStyle } from 'react-native';
import { Node, Parser } from 'commonmark';
import { Parser } from 'commonmark';
import Renderer from 'commonmark-react-renderer';
import { MarkdownAST } from '@rocket.chat/message-parser';
import I18n from '../../i18n';
import MarkdownLink from './Link';
import MarkdownList from './List';
import MarkdownListItem from './ListItem';
@ -37,7 +36,6 @@ interface IMarkdownProps {
baseUrl?: string;
username?: string;
tmid?: string;
isEdited?: boolean;
numberOfLines?: number;
customEmojis?: boolean;
useRealName?: boolean;
@ -133,9 +131,7 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
table: this.renderTable,
table_row: this.renderTableRow,
table_cell: this.renderTableCell,
editedIndicator: this.renderEditedIndicator
table_cell: this.renderTableCell
},
renderParagraphsInLists: true
});
@ -145,21 +141,6 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
return !!enableMessageParser && !!md;
}
editedMessage = (ast: any) => {
const { isEdited } = this.props;
if (isEdited) {
const editIndicatorNode = new Node('edited_indicator');
if (ast.lastChild && ['heading', 'paragraph'].includes(ast.lastChild.type)) {
ast.lastChild.appendChild(editIndicatorNode);
} else {
const node = new Node('paragraph');
node.appendChild(editIndicatorNode);
ast.appendChild(node);
}
}
};
renderText = ({ context, literal }: { context: []; literal: string }) => {
const { numberOfLines, style = [] } = this.props;
const defaultStyle = [this.isMessageContainsOnlyEmoji ? styles.textBig : {}, ...context.map(type => styles[type])];
@ -274,11 +255,6 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
return <Image style={styles.inlineImage} source={{ uri: encodeURI(src) }} />;
};
renderEditedIndicator = () => {
const { theme } = this.props;
return <Text style={[styles.edited, { color: themes[theme].auxiliaryText }]}> ({I18n.t('edited')})</Text>;
};
renderHeading = ({ children, level }: any) => {
const { numberOfLines, theme } = this.props;
// @ts-ignore
@ -373,7 +349,6 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
let ast = parser.parse(m);
ast = mergeTextNodes(ast);
this.isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
this.editedMessage(ast);
return this.renderer.render(ast);
}
}

View File

@ -94,10 +94,6 @@ export default StyleSheet.create({
fontSize: 16,
...sharedStyles.textRegular
},
edited: {
fontSize: 14,
...sharedStyles.textRegular
},
heading1: {
...sharedStyles.textBold,
fontSize: 24

View File

@ -59,7 +59,6 @@ const Content = React.memo(
getCustomEmoji={props.getCustomEmoji}
enableMessageParser={user.enableMessageParserEarlyAdoption}
username={user.username}
isEdited={props.isEdited}
channels={props.channels}
mentions={props.mentions}
navToRoomInfo={props.navToRoomInfo}
@ -72,7 +71,7 @@ const Content = React.memo(
}
// If this is a encrypted message and is not a preview
if (props.type === E2E_MESSAGE_TYPE && !isPreview) {
if (props.type === E2E_MESSAGE_TYPE && !isPreview && !props.isHeader) {
content = (
<View style={styles.flex}>
<View style={styles.contentContainer}>{content}</View>

View File

@ -0,0 +1,23 @@
import React, { memo } from 'react';
import { View } from 'react-native';
import { CustomIcon } from '../CustomIcon';
import { useTheme } from '../../theme';
import { themes } from '../../lib/constants';
import styles from './styles';
const Edited = memo(({ isEdited }: { isEdited: boolean }) => {
const { theme } = useTheme();
if (!isEdited) {
return null;
}
return (
<View style={styles.leftIcons}>
<CustomIcon name='edit' size={16} color={themes[theme].auxiliaryText} />
</View>
);
});
export default Edited;

View File

@ -17,7 +17,7 @@ const Encrypted = React.memo(({ type }: { type: string }) => {
}
return (
<Touchable onPress={onEncryptedPress} style={styles.encrypted} hitSlop={BUTTON_HIT_SLOP}>
<Touchable onPress={onEncryptedPress} style={styles.leftIcons} hitSlop={BUTTON_HIT_SLOP}>
<CustomIcon name='encrypted' size={16} color={themes[theme].auxiliaryText} />
</Touchable>
);

View File

@ -20,6 +20,8 @@ import CallButton from './CallButton';
import { themes } from '../../lib/constants';
import { IMessage, IMessageInner, IMessageTouchable } from './interfaces';
import { useTheme } from '../../theme';
import Edited from './Edited';
import MessageError from './MessageError';
const MessageInner = React.memo((props: IMessageInner) => {
const { attachments } = props;
@ -102,6 +104,12 @@ const Message = React.memo((props: IMessage) => {
<View style={[styles.messageContent, props.isHeader && styles.messageContentWithHeader]}>
<MessageInner {...props} />
</View>
{!props.isHeader ? (
<>
<Edited isEdited={props.isEdited} />
<MessageError hasError={props.hasError} />
</>
) : null}
<ReadReceipt isReadReceiptEnabled={props.isReadReceiptEnabled} unread={props.unread || false} />
</View>
</View>

View File

@ -18,8 +18,8 @@ const MessageError = React.memo(
}
return (
<Touchable onPress={onErrorPress} style={styles.errorButton} hitSlop={BUTTON_HIT_SLOP}>
<CustomIcon name='warning' color={themes[theme].dangerColor} size={18} />
<Touchable onPress={onErrorPress} style={styles.leftIcons} hitSlop={BUTTON_HIT_SLOP}>
<CustomIcon name='warning' color={themes[theme].dangerColor} size={16} />
</Touchable>
);
},

View File

@ -8,7 +8,7 @@ import { useTheme } from '../../theme';
const ReadReceipt = React.memo(({ isReadReceiptEnabled, unread }: { isReadReceiptEnabled?: boolean; unread: boolean }) => {
const { theme } = useTheme();
if (isReadReceiptEnabled && !unread && unread !== null) {
return <CustomIcon name='check' color={themes[theme].tintColor} size={15} style={styles.readReceipt} />;
return <CustomIcon name='check' color={themes[theme].tintColor} size={16} style={[styles.leftIcons, styles.readReceipt]} />;
}
return null;
});

View File

@ -11,6 +11,8 @@ import MessageContext from './Context';
import { SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME } from './utils';
import { SubscriptionType } from '../../definitions';
import { IRoomInfoParam } from '../../views/SearchMessagesView';
import Edited from './Edited';
import Encrypted from './Encrypted';
const styles = StyleSheet.create({
container: {
@ -19,6 +21,10 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
alignItems: 'center'
},
actionIcons: {
flexDirection: 'row',
alignItems: 'center'
},
username: {
fontSize: 16,
lineHeight: 22,
@ -41,7 +47,7 @@ const styles = StyleSheet.create({
interface IMessageUser {
isHeader?: boolean;
hasError?: boolean;
hasError: boolean;
useRealName?: boolean;
author?: {
_id: string;
@ -53,10 +59,11 @@ interface IMessageUser {
timeFormat?: string;
navToRoomInfo?: (navParam: IRoomInfoParam) => void;
type: string;
isEdited: boolean;
}
const User = React.memo(
({ isHeader, useRealName, author, alias, ts, timeFormat, hasError, navToRoomInfo, type, ...props }: IMessageUser) => {
({ isHeader, useRealName, author, alias, ts, timeFormat, hasError, navToRoomInfo, type, isEdited, ...props }: IMessageUser) => {
const { user } = useContext(MessageContext);
const { theme } = useTheme();
@ -100,8 +107,12 @@ const User = React.memo(
{textContent}
</Text>
</TouchableOpacity>
<Text style={[messageStyles.time, { color: themes[theme].auxiliaryTintColor }]}>{time}</Text>
{hasError ? <MessageError hasError={hasError} {...props} /> : null}
<View style={styles.actionIcons}>
<Text style={[messageStyles.time, { color: themes[theme].auxiliaryTintColor }]}>{time}</Text>
<Encrypted type={type} />
<Edited isEdited={isEdited} />
<MessageError hasError={hasError} {...props} />
</View>
</View>
);
}

View File

@ -60,6 +60,8 @@ export interface IMessageContent {
isIgnored: boolean;
type: string;
comment?: string;
hasError: boolean;
isHeader: boolean;
}
export interface IMessageEmoji {

View File

@ -74,10 +74,6 @@ export default StyleSheet.create({
avatarSmall: {
marginLeft: 16
},
errorButton: {
paddingLeft: 10,
paddingVertical: 5
},
buttonContainer: {
marginTop: 8,
flexDirection: 'row',
@ -167,12 +163,13 @@ export default StyleSheet.create({
threadBell: {
marginLeft: 8
},
leftIcons: {
paddingLeft: 5,
paddingVertical: 5
},
readReceipt: {
lineHeight: 20
},
encrypted: {
justifyContent: 'center'
},
threadDetails: {
flex: 1,
marginLeft: 12

File diff suppressed because one or more lines are too long

View File

@ -54,12 +54,6 @@ stories.add('Text', () => (
</View>
));
stories.add('Edited', () => (
<View style={styles.container}>
<Markdown msg='This is edited' theme={theme} isEdited />
</View>
));
stories.add('Preview', () => (
<View style={styles.container}>
<MarkdownPreview msg={longText} />

View File

@ -118,7 +118,12 @@ stories.add('With alias', () => (
</>
));
stories.add('Edited', () => <Message msg='Message' edited />);
stories.add('Edited', () => (
<>
<Message msg='Message header' isEdited />
<Message msg='Message without header' isEdited isHeader={false} />
</>
));
stories.add('Encrypted', () => (
<>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7245,8 +7245,8 @@ commondir@^1.0.1:
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
"commonmark-react-renderer@git+https://github.com/RocketChat/commonmark-react-renderer.git":
version "4.3.4"
resolved "git+https://github.com/RocketChat/commonmark-react-renderer.git#1264ac7b1c13d9be3e2f67eec6702a3132f4fac2"
version "4.3.6"
resolved "git+https://github.com/RocketChat/commonmark-react-renderer.git#593b64e4829e1def9cceb3ffc7098b15e5df3064"
dependencies:
lodash.assign "^4.2.0"
lodash.isplainobject "^4.0.6"