// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import React, {Component, PropTypes} from 'react'; import { Image, Platform, StyleSheet, Text, TouchableHighlight, TouchableOpacity, View } from 'react-native'; import FormattedText from 'app/components/formatted_text'; import FormattedTime from 'app/components/formatted_time'; import MattermostIcon from 'app/components/mattermost_icon'; import Markdown from 'app/components/markdown/markdown'; import ProfilePicture from 'app/components/profile_picture'; import FileAttachmentList from 'app/components/file_attachment_list/file_attachment_list_container'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; import {isSystemMessage} from 'mattermost-redux/utils/post_utils.js'; export default class Post extends Component { static propTypes = { style: View.propTypes.style, post: PropTypes.object.isRequired, user: PropTypes.object, displayName: PropTypes.string, renderReplies: PropTypes.bool, isFirstReply: PropTypes.bool, isLastReply: PropTypes.bool, commentedOnPost: PropTypes.object, commentedOnDisplayName: PropTypes.string, theme: PropTypes.object.isRequired, onPress: PropTypes.func, actions: PropTypes.shape({ goToUserProfile: PropTypes.func.isRequired }).isRequired }; handlePress = () => { if (this.props.onPress) { this.props.onPress(this.props.post); } }; renderCommentedOnMessage = (style) => { if (!this.props.renderReplies || !this.props.commentedOnPost) { return null; } const displayName = this.props.commentedOnDisplayName; let name; if (displayName) { name = displayName; } else { name = ( ); } let apostrophe; if (displayName && displayName.slice(-1) === 's') { apostrophe = '\''; } else { apostrophe = '\'s'; } return ( ); } renderReplyBar = (style) => { if (!this.props.renderReplies || !this.props.post.root_id) { return null; } const replyBarStyle = [style.replyBar]; if (this.props.isFirstReply && !this.props.commentedOnPost) { replyBarStyle.push(style.replyBarFirst); } if (this.props.isLastReply) { replyBarStyle.push(style.replyBarLast); } return ; }; renderFileAttachments() { const {post} = this.props; const fileIds = post.file_ids || []; let attachments; if (fileIds.length > 0) { attachments = (); } return attachments; } viewUserProfile = () => { this.props.actions.goToUserProfile(this.props.user.id); }; renderMessage = (style, messageStyle, replyBar = false) => { let contents; if (this.props.post.message.length > 0) { const theme = this.props.theme; contents = ( ); } return ( {replyBar && this.renderReplyBar(style)} {contents} {this.renderFileAttachments()} ); }; render() { const theme = this.props.theme; const style = getStyleSheet(theme); const PROFILE_PICTURE_SIZE = 32; let profilePicture; let displayName; let messageStyle; if (isSystemMessage(this.props.post)) { profilePicture = ( ); displayName = ( ); messageStyle = [style.message, style.systemMessage]; } else if (this.props.post.props && this.props.post.props.from_webhook) { profilePicture = ( ); displayName = ( {this.props.post.props.override_username} ); messageStyle = style.message; } else { profilePicture = ( ); if (this.props.displayName) { displayName = ( {this.props.displayName} ); } else { displayName = ( ); } messageStyle = style.message; } let contents; if (this.props.commentedOnPost) { contents = ( {profilePicture} {displayName} {this.renderCommentedOnMessage(style)} {this.renderMessage(style, messageStyle, true)} ); } else { contents = ( {profilePicture} {this.renderReplyBar(style)} {displayName} {this.renderMessage(style, messageStyle)} ); } return contents; } } const getStyleSheet = makeStyleSheetFromTheme((theme) => { return StyleSheet.create({ container: { backgroundColor: theme.centerChannelBg, flexDirection: 'row' }, rightColumn: { flex: 1, flexDirection: 'column', marginRight: 12 }, postInfoContainer: { alignItems: 'center', flexDirection: 'row', marginTop: 10 }, messageContainerWithReplyBar: { flexDirection: 'row', flex: 1 }, profilePictureContainer: { marginBottom: 10, marginRight: 10, marginLeft: 12, marginTop: 10 }, replyBar: { backgroundColor: theme.centerChannelColor, opacity: 0.1, marginRight: 10, ...Platform.select({ ios: { width: 3, flexBasis: 3 }, android: { width: 6, flexBasis: 6 } }) }, replyBarFirst: { marginTop: 10 }, replyBarLast: { marginBottom: 10 }, displayName: { fontSize: 14, fontWeight: '600', marginRight: 10, color: theme.centerChannelColor }, time: { color: theme.centerChannelColor, fontSize: 12, opacity: 0.5 }, commentedOn: { color: theme.centerChannelColor, lineHeight: 21 }, message: { color: theme.centerChannelColor, fontSize: 14, lineHeight: 21 }, systemMessage: { opacity: 0.5 } }); }); const getMarkdownTextStyles = makeStyleSheetFromTheme((theme) => { const codeFont = Platform.OS === 'ios' ? 'Courier New' : 'monospace'; return StyleSheet.create({ emph: { fontStyle: 'italic' }, strong: { fontWeight: 'bold' }, link: { color: theme.linkColor }, heading1: { fontSize: 30, lineHeight: 45 }, heading2: { fontSize: 24, lineHeight: 36 }, heading3: { fontSize: 20, lineHeight: 30 }, heading4: { fontSize: 16, lineHeight: 24 }, heading5: { fontSize: 14, lineHeight: 21 }, heading6: { fontSize: 14, lineHeight: 21, opacity: 0.8 }, code: { alignSelf: 'center', backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), fontFamily: codeFont, paddingHorizontal: 4, paddingVertical: 2 }, codeBlock: { fontFamily: codeFont }, horizontalRule: { backgroundColor: theme.centerChannelColor, height: StyleSheet.hairlineWidth, flex: 1, marginVertical: 10 } }); }); const getMarkdownBlockStyles = makeStyleSheetFromTheme((theme) => { return StyleSheet.create({ codeBlock: { backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), borderRadius: 4, paddingHorizontal: 4, paddingVertical: 2 }, horizontalRule: { backgroundColor: theme.centerChannelColor } }); });