Room item layout (#835)
This commit is contained in:
parent
03adaa3f81
commit
0266cc2e01
|
@ -20808,6 +20808,10 @@ exports[`Storyshots RoomItem list 1`] = `
|
|||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
View
|
||||
<Text
|
||||
style={
|
||||
Array [
|
||||
|
|
|
@ -1,73 +1,69 @@
|
|||
import React, { PureComponent } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { View, ViewPropTypes } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
export default class Avatar extends PureComponent {
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string.isRequired,
|
||||
style: ViewPropTypes.style,
|
||||
text: PropTypes.string,
|
||||
avatar: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
borderRadius: PropTypes.number,
|
||||
type: PropTypes.string,
|
||||
children: PropTypes.object,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
})
|
||||
const Avatar = React.memo(({
|
||||
text, size, baseUrl, borderRadius, style, avatar, type, children, userId, token
|
||||
}) => {
|
||||
const avatarStyle = {
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius
|
||||
};
|
||||
|
||||
if (!text && !avatar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
text: '',
|
||||
size: 25,
|
||||
type: 'd',
|
||||
borderRadius: 4
|
||||
const room = type === 'd' ? text : `@${ text }`;
|
||||
|
||||
// Avoid requesting several sizes by having only two sizes on cache
|
||||
const uriSize = size === 100 ? 100 : 50;
|
||||
|
||||
let avatarAuthURLFragment = '';
|
||||
if (userId && token) {
|
||||
avatarAuthURLFragment = `&rc_token=${ token }&rc_uid=${ userId }`;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
text, size, baseUrl, borderRadius, style, avatar, type, children, user
|
||||
} = this.props;
|
||||
const uri = avatar || `${ baseUrl }/avatar/${ room }?format=png&width=${ uriSize }&height=${ uriSize }${ avatarAuthURLFragment }`;
|
||||
|
||||
const avatarStyle = {
|
||||
width: size,
|
||||
height: size,
|
||||
borderRadius
|
||||
};
|
||||
const image = (
|
||||
<FastImage
|
||||
style={avatarStyle}
|
||||
source={{
|
||||
uri,
|
||||
priority: FastImage.priority.high
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
if (!text && !avatar) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View style={[avatarStyle, style]}>
|
||||
{image}
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
const room = type === 'd' ? text : `@${ text }`;
|
||||
Avatar.propTypes = {
|
||||
baseUrl: PropTypes.string.isRequired,
|
||||
style: ViewPropTypes.style,
|
||||
text: PropTypes.string,
|
||||
avatar: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
borderRadius: PropTypes.number,
|
||||
type: PropTypes.string,
|
||||
children: PropTypes.object,
|
||||
userId: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
};
|
||||
|
||||
// Avoid requesting several sizes by having only two sizes on cache
|
||||
const uriSize = size === 100 ? 100 : 50;
|
||||
Avatar.defaultProps = {
|
||||
text: '',
|
||||
size: 25,
|
||||
type: 'd',
|
||||
borderRadius: 4
|
||||
};
|
||||
|
||||
let avatarAuthURLFragment = '';
|
||||
if (user && user.id && user.token) {
|
||||
avatarAuthURLFragment = `&rc_token=${ user.token }&rc_uid=${ user.id }`;
|
||||
}
|
||||
|
||||
const uri = avatar || `${ baseUrl }/avatar/${ room }?format=png&width=${ uriSize }&height=${ uriSize }${ avatarAuthURLFragment }`;
|
||||
|
||||
const image = (
|
||||
<FastImage
|
||||
style={avatarStyle}
|
||||
source={{
|
||||
uri,
|
||||
priority: FastImage.priority.high
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={[avatarStyle, style]}>
|
||||
{image}
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Avatar;
|
||||
|
|
|
@ -706,7 +706,8 @@ class MessageBox extends Component {
|
|||
size={30}
|
||||
type={item.username ? 'd' : 'c'}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
/>,
|
||||
<Text key='mention-item-name' style={styles.mentionText}>{ item.username || item.name }</Text>
|
||||
]
|
||||
|
|
|
@ -238,7 +238,8 @@ export default class Message extends PureComponent {
|
|||
borderRadius={4}
|
||||
avatar={avatar}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,278 +0,0 @@
|
|||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
View, Text, StyleSheet, PixelRatio
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { emojify } from 'react-emojione';
|
||||
import { RectButton } from 'react-native-gesture-handler';
|
||||
|
||||
import Avatar from '../containers/Avatar';
|
||||
import Status from '../containers/Status';
|
||||
import RoomTypeIcon from '../containers/RoomTypeIcon';
|
||||
import I18n from '../i18n';
|
||||
import sharedStyles from '../views/Styles';
|
||||
import { COLOR_SEPARATOR, COLOR_PRIMARY, COLOR_WHITE } from '../constants/colors';
|
||||
|
||||
export const ROW_HEIGHT = 75 * PixelRatio.getFontScale();
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginLeft: 14,
|
||||
height: ROW_HEIGHT
|
||||
},
|
||||
centerContainer: {
|
||||
flex: 1,
|
||||
paddingVertical: 10,
|
||||
paddingRight: 14,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: COLOR_SEPARATOR
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
fontSize: 17,
|
||||
lineHeight: 20,
|
||||
...sharedStyles.textColorNormal,
|
||||
...sharedStyles.textMedium
|
||||
},
|
||||
alert: {
|
||||
...sharedStyles.textSemibold
|
||||
},
|
||||
row: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start'
|
||||
},
|
||||
titleContainer: {
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
date: {
|
||||
fontSize: 13,
|
||||
marginLeft: 4,
|
||||
...sharedStyles.textColorDescription,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
updateAlert: {
|
||||
color: COLOR_PRIMARY,
|
||||
...sharedStyles.textSemibold
|
||||
},
|
||||
unreadNumberContainer: {
|
||||
minWidth: 23,
|
||||
padding: 3,
|
||||
borderRadius: 4,
|
||||
backgroundColor: COLOR_PRIMARY,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginLeft: 10
|
||||
},
|
||||
unreadNumberText: {
|
||||
color: COLOR_WHITE,
|
||||
overflow: 'hidden',
|
||||
fontSize: 13,
|
||||
...sharedStyles.textRegular,
|
||||
letterSpacing: 0.56
|
||||
},
|
||||
status: {
|
||||
marginRight: 7,
|
||||
marginTop: 3
|
||||
},
|
||||
markdownText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
lineHeight: 17,
|
||||
...sharedStyles.textRegular,
|
||||
...sharedStyles.textColorDescription
|
||||
},
|
||||
markdownTextAlert: {
|
||||
...sharedStyles.textColorNormal
|
||||
},
|
||||
avatar: {
|
||||
marginRight: 10
|
||||
}
|
||||
});
|
||||
|
||||
const renderNumber = (unread, userMentions) => {
|
||||
if (!unread || unread <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unread >= 1000) {
|
||||
unread = '999+';
|
||||
}
|
||||
|
||||
if (userMentions > 0) {
|
||||
unread = `@ ${ unread }`;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.unreadNumberContainer}>
|
||||
<Text style={styles.unreadNumberText}>{ unread }</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type'];
|
||||
@connect(state => ({
|
||||
user: {
|
||||
id: state.login.user && state.login.user.id,
|
||||
username: state.login.user && state.login.user.username,
|
||||
token: state.login.user && state.login.user.token
|
||||
}
|
||||
}))
|
||||
export default class RoomItem extends React.Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
baseUrl: PropTypes.string.isRequired,
|
||||
showLastMessage: PropTypes.bool,
|
||||
_updatedAt: PropTypes.string,
|
||||
lastMessage: PropTypes.object,
|
||||
alert: PropTypes.bool,
|
||||
unread: PropTypes.number,
|
||||
userMentions: PropTypes.number,
|
||||
id: PropTypes.string,
|
||||
prid: PropTypes.string,
|
||||
onPress: PropTypes.func,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
username: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
}),
|
||||
avatarSize: PropTypes.number,
|
||||
testID: PropTypes.string,
|
||||
height: PropTypes.number
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
avatarSize: 48
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const { lastMessage, _updatedAt } = this.props;
|
||||
const oldlastMessage = lastMessage;
|
||||
const newLastmessage = nextProps.lastMessage;
|
||||
|
||||
if (oldlastMessage && newLastmessage && oldlastMessage.ts !== newLastmessage.ts) {
|
||||
return true;
|
||||
}
|
||||
if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt !== _updatedAt) {
|
||||
return true;
|
||||
}
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
return attrs.some(key => nextProps[key] !== this.props[key]);
|
||||
}
|
||||
|
||||
get avatar() {
|
||||
const {
|
||||
type, name, avatarSize, baseUrl, user
|
||||
} = this.props;
|
||||
return <Avatar text={name} size={avatarSize} type={type} baseUrl={baseUrl} style={styles.avatar} user={user} />;
|
||||
}
|
||||
|
||||
get lastMessage() {
|
||||
const {
|
||||
lastMessage, type, showLastMessage, user
|
||||
} = this.props;
|
||||
|
||||
if (!showLastMessage) {
|
||||
return '';
|
||||
}
|
||||
if (!lastMessage) {
|
||||
return I18n.t('No_Message');
|
||||
}
|
||||
|
||||
let prefix = '';
|
||||
const me = lastMessage.u.username === user.username;
|
||||
|
||||
if (!lastMessage.msg && Object.keys(lastMessage.attachments).length > 0) {
|
||||
if (me) {
|
||||
return I18n.t('User_sent_an_attachment', { user: I18n.t('You') });
|
||||
} else {
|
||||
return I18n.t('User_sent_an_attachment', { user: lastMessage.u.username });
|
||||
}
|
||||
}
|
||||
|
||||
if (me) {
|
||||
prefix = I18n.t('You_colon');
|
||||
} else if (type !== 'd') {
|
||||
prefix = `${ lastMessage.u.username }: `;
|
||||
}
|
||||
|
||||
let msg = `${ prefix }${ lastMessage.msg.replace(/[\n\t\r]/igm, '') }`;
|
||||
msg = emojify(msg, { output: 'unicode' });
|
||||
return msg;
|
||||
}
|
||||
|
||||
get type() {
|
||||
const { type, id, prid } = this.props;
|
||||
if (type === 'd') {
|
||||
return <Status style={styles.status} size={10} id={id} />;
|
||||
}
|
||||
return <RoomTypeIcon type={prid ? 'discussion' : type} />;
|
||||
}
|
||||
|
||||
formatDate = date => moment(date).calendar(null, {
|
||||
lastDay: `[${ I18n.t('Yesterday') }]`,
|
||||
sameDay: 'h:mm A',
|
||||
lastWeek: 'dddd',
|
||||
sameElse: 'MMM D'
|
||||
})
|
||||
|
||||
render() {
|
||||
const {
|
||||
unread, userMentions, name, _updatedAt, alert, testID, height, onPress
|
||||
} = this.props;
|
||||
|
||||
const date = this.formatDate(_updatedAt);
|
||||
|
||||
let accessibilityLabel = name;
|
||||
if (unread === 1) {
|
||||
accessibilityLabel += `, ${ unread } ${ I18n.t('alert') }`;
|
||||
} else if (unread > 1) {
|
||||
accessibilityLabel += `, ${ unread } ${ I18n.t('alerts') }`;
|
||||
}
|
||||
|
||||
if (userMentions > 0) {
|
||||
accessibilityLabel += `, ${ I18n.t('you_were_mentioned') }`;
|
||||
}
|
||||
|
||||
if (date) {
|
||||
accessibilityLabel += `, ${ I18n.t('last_message') } ${ date }`;
|
||||
}
|
||||
|
||||
return (
|
||||
<RectButton
|
||||
onPress={onPress}
|
||||
activeOpacity={0.8}
|
||||
underlayColor='#e1e5e8'
|
||||
testID={testID}
|
||||
>
|
||||
<View
|
||||
style={[styles.container, height && { height }]}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
>
|
||||
{this.avatar}
|
||||
<View style={styles.centerContainer}>
|
||||
<View style={styles.titleContainer}>
|
||||
{this.type}
|
||||
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
|
||||
{_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null}
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Text style={[styles.markdownText, alert && styles.markdownTextAlert]} numberOfLines={2}>
|
||||
{this.lastMessage}
|
||||
</Text>
|
||||
{renderNumber(unread, userMentions)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</RectButton>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import React from 'react';
|
||||
import { Text } from 'react-native';
|
||||
import { emojify } from 'react-emojione';
|
||||
import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
|
||||
import I18n from '../../i18n';
|
||||
import styles from './styles';
|
||||
|
||||
const formatMsg = ({
|
||||
lastMessage, type, showLastMessage, username
|
||||
}) => {
|
||||
if (!showLastMessage) {
|
||||
return '';
|
||||
}
|
||||
if (!lastMessage) {
|
||||
return I18n.t('No_Message');
|
||||
}
|
||||
|
||||
let prefix = '';
|
||||
const isLastMessageSentByMe = lastMessage.u.username === username;
|
||||
|
||||
if (!lastMessage.msg && Object.keys(lastMessage.attachments).length) {
|
||||
const user = isLastMessageSentByMe ? I18n.t('You') : lastMessage.u.username;
|
||||
return I18n.t('User_sent_an_attachment', { user });
|
||||
}
|
||||
|
||||
if (isLastMessageSentByMe) {
|
||||
prefix = I18n.t('You_colon');
|
||||
} else if (type !== 'd') {
|
||||
prefix = `${ lastMessage.u.username }: `;
|
||||
}
|
||||
|
||||
let msg = `${ prefix }${ lastMessage.msg.replace(/[\n\t\r]/igm, '') }`;
|
||||
if (msg) {
|
||||
msg = emojify(msg, { output: 'unicode' });
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
const arePropsEqual = (oldProps, newProps) => _.isEqual(oldProps, newProps);
|
||||
|
||||
const LastMessage = React.memo(({
|
||||
lastMessage, type, showLastMessage, username
|
||||
}) => (
|
||||
<Text style={[styles.markdownText, alert && styles.markdownTextAlert]} numberOfLines={2}>
|
||||
{formatMsg({
|
||||
lastMessage, type, showLastMessage, username
|
||||
})}
|
||||
</Text>
|
||||
), arePropsEqual);
|
||||
|
||||
LastMessage.propTypes = {
|
||||
lastMessage: PropTypes.object,
|
||||
type: PropTypes.string,
|
||||
showLastMessage: PropTypes.bool,
|
||||
username: PropTypes.string
|
||||
};
|
||||
|
||||
export default LastMessage;
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Status from '../../containers/Status';
|
||||
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||
import styles from './styles';
|
||||
|
||||
const TypeIcon = React.memo(({ type, id, prid }) => {
|
||||
if (type === 'd') {
|
||||
return <Status style={styles.status} size={10} id={id} />;
|
||||
}
|
||||
return <RoomTypeIcon type={prid ? 'discussion' : type} />;
|
||||
});
|
||||
|
||||
TypeIcon.propTypes = {
|
||||
type: PropTypes.string,
|
||||
id: PropTypes.string,
|
||||
prid: PropTypes.string
|
||||
};
|
||||
|
||||
export default TypeIcon;
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { View, Text } from 'react-native';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
const UnreadBadge = React.memo(({ unread, userMentions, type }) => {
|
||||
if (!unread || unread <= 0) {
|
||||
return;
|
||||
}
|
||||
if (unread >= 1000) {
|
||||
unread = '999+';
|
||||
}
|
||||
const mentioned = userMentions > 0 && type !== 'd';
|
||||
|
||||
return (
|
||||
<View style={[styles.unreadNumberContainer, mentioned && styles.unreadMentioned]}>
|
||||
<Text style={styles.unreadNumberText}>{ unread }</Text>
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
UnreadBadge.propTypes = {
|
||||
unread: PropTypes.number,
|
||||
userMentions: PropTypes.number,
|
||||
type: PropTypes.string
|
||||
};
|
||||
|
||||
export default UnreadBadge;
|
|
@ -0,0 +1,120 @@
|
|||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import PropTypes from 'prop-types';
|
||||
import { View, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { RectButton } from 'react-native-gesture-handler';
|
||||
|
||||
import Avatar from '../../containers/Avatar';
|
||||
import I18n from '../../i18n';
|
||||
import styles, { ROW_HEIGHT } from './styles';
|
||||
import UnreadBadge from './UnreadBadge';
|
||||
import TypeIcon from './TypeIcon';
|
||||
import LastMessage from './LastMessage';
|
||||
|
||||
export { ROW_HEIGHT };
|
||||
|
||||
const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type'];
|
||||
@connect(state => ({
|
||||
userId: state.login.user && state.login.user.id,
|
||||
username: state.login.user && state.login.user.username,
|
||||
token: state.login.user && state.login.user.token
|
||||
}))
|
||||
export default class RoomItem extends React.Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
baseUrl: PropTypes.string.isRequired,
|
||||
showLastMessage: PropTypes.bool,
|
||||
_updatedAt: PropTypes.string,
|
||||
lastMessage: PropTypes.object,
|
||||
alert: PropTypes.bool,
|
||||
unread: PropTypes.number,
|
||||
userMentions: PropTypes.number,
|
||||
id: PropTypes.string,
|
||||
prid: PropTypes.string,
|
||||
onPress: PropTypes.func,
|
||||
userId: PropTypes.string,
|
||||
username: PropTypes.string,
|
||||
token: PropTypes.string,
|
||||
avatarSize: PropTypes.number,
|
||||
testID: PropTypes.string,
|
||||
height: PropTypes.number
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
avatarSize: 48
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const { lastMessage, _updatedAt } = this.props;
|
||||
const oldlastMessage = lastMessage;
|
||||
const newLastmessage = nextProps.lastMessage;
|
||||
|
||||
if (oldlastMessage && newLastmessage && oldlastMessage.ts !== newLastmessage.ts) {
|
||||
return true;
|
||||
}
|
||||
if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt !== _updatedAt) {
|
||||
return true;
|
||||
}
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
return attrs.some(key => nextProps[key] !== this.props[key]);
|
||||
}
|
||||
|
||||
formatDate = date => moment(date).calendar(null, {
|
||||
lastDay: `[${ I18n.t('Yesterday') }]`,
|
||||
sameDay: 'h:mm A',
|
||||
lastWeek: 'dddd',
|
||||
sameElse: 'MMM D'
|
||||
})
|
||||
|
||||
render() {
|
||||
const {
|
||||
unread, userMentions, name, _updatedAt, alert, testID, height, type, avatarSize, baseUrl, userId, username, token, onPress, id, prid, showLastMessage, lastMessage
|
||||
} = this.props;
|
||||
|
||||
const date = this.formatDate(_updatedAt);
|
||||
|
||||
let accessibilityLabel = name;
|
||||
if (unread === 1) {
|
||||
accessibilityLabel += `, ${ unread } ${ I18n.t('alert') }`;
|
||||
} else if (unread > 1) {
|
||||
accessibilityLabel += `, ${ unread } ${ I18n.t('alerts') }`;
|
||||
}
|
||||
|
||||
if (userMentions > 0) {
|
||||
accessibilityLabel += `, ${ I18n.t('you_were_mentioned') }`;
|
||||
}
|
||||
|
||||
if (date) {
|
||||
accessibilityLabel += `, ${ I18n.t('last_message') } ${ date }`;
|
||||
}
|
||||
|
||||
return (
|
||||
<RectButton
|
||||
onPress={onPress}
|
||||
activeOpacity={0.8}
|
||||
underlayColor='#e1e5e8'
|
||||
testID={testID}
|
||||
>
|
||||
<View
|
||||
style={[styles.container, height && { height }]}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
>
|
||||
<Avatar text={name} size={avatarSize} type={type} baseUrl={baseUrl} style={styles.avatar} userId={userId} token={token} />
|
||||
<View style={styles.centerContainer}>
|
||||
<View style={styles.titleContainer}>
|
||||
<TypeIcon type={type} id={id} prid={prid} />
|
||||
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
|
||||
{_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null}
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} />
|
||||
<UnreadBadge unread={unread} userMentions={userMentions} type={type} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</RectButton>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
import { StyleSheet, PixelRatio } from 'react-native';
|
||||
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import {
|
||||
COLOR_SEPARATOR, COLOR_PRIMARY, COLOR_WHITE, COLOR_TEXT
|
||||
} from '../../constants/colors';
|
||||
|
||||
export const ROW_HEIGHT = 75 * PixelRatio.getFontScale();
|
||||
|
||||
export default StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginLeft: 14,
|
||||
height: ROW_HEIGHT
|
||||
},
|
||||
centerContainer: {
|
||||
flex: 1,
|
||||
paddingVertical: 10,
|
||||
paddingRight: 14,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: COLOR_SEPARATOR
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
fontSize: 17,
|
||||
lineHeight: 20,
|
||||
...sharedStyles.textColorNormal,
|
||||
...sharedStyles.textMedium
|
||||
},
|
||||
alert: {
|
||||
...sharedStyles.textSemibold
|
||||
},
|
||||
row: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start'
|
||||
},
|
||||
titleContainer: {
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
date: {
|
||||
fontSize: 13,
|
||||
marginLeft: 4,
|
||||
...sharedStyles.textColorDescription,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
updateAlert: {
|
||||
color: COLOR_PRIMARY,
|
||||
...sharedStyles.textSemibold
|
||||
},
|
||||
unreadNumberContainer: {
|
||||
minWidth: 22,
|
||||
height: 22,
|
||||
paddingVertical: 3,
|
||||
paddingHorizontal: 5,
|
||||
borderRadius: 14,
|
||||
backgroundColor: COLOR_TEXT,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginLeft: 10
|
||||
},
|
||||
unreadMentioned: {
|
||||
backgroundColor: COLOR_PRIMARY
|
||||
},
|
||||
unreadNumberText: {
|
||||
color: COLOR_WHITE,
|
||||
overflow: 'hidden',
|
||||
fontSize: 13,
|
||||
...sharedStyles.textRegular,
|
||||
letterSpacing: 0.56,
|
||||
textAlign: 'center'
|
||||
},
|
||||
status: {
|
||||
marginRight: 7,
|
||||
marginTop: 3
|
||||
},
|
||||
markdownText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
lineHeight: 17,
|
||||
...sharedStyles.textRegular,
|
||||
...sharedStyles.textColorDescription
|
||||
},
|
||||
markdownTextAlert: {
|
||||
...sharedStyles.textColorNormal
|
||||
},
|
||||
avatar: {
|
||||
marginRight: 10
|
||||
}
|
||||
});
|
|
@ -49,7 +49,7 @@ const UserItem = ({
|
|||
}) => (
|
||||
<Touch onPress={onPress} onLongPress={onLongPress} style={styles.button} testID={testID}>
|
||||
<View style={[styles.container, style]}>
|
||||
<Avatar text={username} size={30} type='d' style={styles.avatar} baseUrl={baseUrl} user={user} />
|
||||
<Avatar text={username} size={30} type='d' style={styles.avatar} baseUrl={baseUrl} userId={user.id} token={user.token} />
|
||||
<View style={styles.textContainer}>
|
||||
<Text style={styles.name}>{name}</Text>
|
||||
<Text style={styles.username}>@{username}</Text>
|
||||
|
|
|
@ -286,7 +286,7 @@ export default class ProfileView extends LoggedView {
|
|||
return (
|
||||
<View style={styles.avatarButtons}>
|
||||
{this.renderAvatarButton({
|
||||
child: <Avatar text={`@${ user.username }`} size={50} baseUrl={baseUrl} user={user} />,
|
||||
child: <Avatar text={`@${ user.username }`} size={50} baseUrl={baseUrl} userId={user.id} token={user.token} />,
|
||||
onPress: () => this.resetAvatar(),
|
||||
key: 'profile-view-reset-avatar'
|
||||
})}
|
||||
|
@ -305,7 +305,7 @@ export default class ProfileView extends LoggedView {
|
|||
const { url, blob, contentType } = avatarSuggestions[service];
|
||||
return this.renderAvatarButton({
|
||||
key: `profile-view-avatar-${ service }`,
|
||||
child: <Avatar avatar={url} size={50} baseUrl={baseUrl} user={user} />,
|
||||
child: <Avatar avatar={url} size={50} baseUrl={baseUrl} userId={user.id} token={user.token} />,
|
||||
onPress: () => this.setAvatar({
|
||||
url, data: blob, service, contentType
|
||||
})
|
||||
|
@ -399,7 +399,8 @@ export default class ProfileView extends LoggedView {
|
|||
avatar={avatar && avatar.url}
|
||||
size={100}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
/>
|
||||
</View>
|
||||
<RCTextInput
|
||||
|
|
|
@ -397,7 +397,8 @@ export default class RoomActionsView extends LoggedView {
|
|||
style={styles.avatar}
|
||||
type={t}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
>
|
||||
{t === 'd' ? <Status style={sharedStyles.status} id={member._id} /> : null }
|
||||
</Avatar>,
|
||||
|
|
|
@ -234,7 +234,8 @@ export default class RoomInfoView extends LoggedView {
|
|||
style={styles.avatar}
|
||||
type={room.t}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
>
|
||||
{room.t === 'd' ? <Status style={[sharedStyles.status, styles.status]} size={24} id={roomUser._id} /> : null}
|
||||
</Avatar>
|
||||
|
|
|
@ -230,7 +230,8 @@ export default class Sidebar extends Component {
|
|||
size={30}
|
||||
style={styles.avatar}
|
||||
baseUrl={baseUrl}
|
||||
user={user}
|
||||
userId={user.id}
|
||||
token={user.token}
|
||||
/>
|
||||
<View style={styles.headerTextContainer}>
|
||||
<View style={styles.headerUsername}>
|
||||
|
|
|
@ -57,6 +57,10 @@ export default (
|
|||
<RoomItem alert unread={1000} />
|
||||
<RoomItem alert unread={1} userMentions={1} />
|
||||
<RoomItem alert unread={1000} userMentions={1} />
|
||||
<RoomItem alert name='general' unread={1} type='c' />
|
||||
<RoomItem alert name='general' unread={1000} type='c' />
|
||||
<RoomItem alert name='general' unread={1} userMentions={1} type='c' />
|
||||
<RoomItem alert name='general' unread={1000} userMentions={1} type='c' />
|
||||
|
||||
<StoriesSeparator title='Last Message' />
|
||||
<RoomItem
|
||||
|
|
Loading…
Reference in New Issue