Avatar initials and room type icon (#298)

This commit is contained in:
Diego Mello 2018-05-18 13:41:47 -03:00 committed by Guilherme Gazzo
parent 69513a8327
commit a0bb61642d
7 changed files with 78 additions and 40 deletions

View File

@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { StyleSheet, Text, View, ViewPropTypes } from 'react-native'; import { StyleSheet, Text, View, ViewPropTypes } from 'react-native';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import avatarInitialsAndColor from '../utils/avatarInitialsAndColor'; import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -49,7 +48,8 @@ export default class Avatar extends React.PureComponent {
}; };
const avatarInitialsStyle = { const avatarInitialsStyle = {
fontSize: size / 2 fontSize: size / 1.6,
fontWeight: '800'
}; };
const avatarStyle = { const avatarStyle = {
@ -58,9 +58,11 @@ export default class Avatar extends React.PureComponent {
borderRadius borderRadius
}; };
let image;
if (type === 'd') { if (type === 'd') {
const uri = avatar || `${ baseUrl }/avatar/${ text }`; const uri = avatar || `${ baseUrl }/avatar/${ text }`;
const image = uri && ( image = uri && (
<FastImage <FastImage
style={[styles.avatar, avatarStyle]} style={[styles.avatar, avatarStyle]}
source={{ source={{
@ -69,30 +71,20 @@ export default class Avatar extends React.PureComponent {
}} }}
/> />
); );
return (
<View style={[styles.iconContainer, iconContainerStyle, style]}>
{this.state.showInitials &&
<Text
style={[styles.avatarInitials, avatarInitialsStyle]}
allowFontScaling={false}
>
{initials}
</Text>
}
{image}
{this.props.children}
</View>);
} }
const icon = {
c: 'pound',
p: 'lock',
l: 'account'
}[type];
return ( return (
<View style={[styles.iconContainer, iconContainerStyle, style]}> <View style={[styles.iconContainer, iconContainerStyle, style]}>
<MaterialCommunityIcons name={icon} style={[styles.avatarInitials, avatarInitialsStyle]} /> {this.state.showInitials &&
<Text
style={[styles.avatarInitials, avatarInitialsStyle]}
allowFontScaling={false}
>
{initials}
</Text>
}
{image}
{this.props.children}
</View> </View>
); );
} }

View File

@ -0,0 +1,32 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
const styles = StyleSheet.create({
type: {
marginRight: 5,
marginTop: 3
}
});
const RoomTypeIcon = ({ type, size }) => {
const icon = {
c: 'pound',
p: 'lock',
l: 'account',
d: 'at'
}[type];
return <Icon name={icon} size={size} style={styles.type} />;
};
RoomTypeIcon.propTypes = {
type: PropTypes.string.isRequired,
size: PropTypes.number
};
RoomTypeIcon.defaultProps = {
size: 15
};
export default RoomTypeIcon;

View File

@ -2,16 +2,15 @@ import React from 'react';
import moment from 'moment'; import moment from 'moment';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, Text, StyleSheet, ViewPropTypes } from 'react-native'; import { View, Text, StyleSheet, ViewPropTypes } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import SimpleMarkdown from 'simple-markdown'; import SimpleMarkdown from 'simple-markdown';
import messagesStatus from '../constants/messagesStatus';
import Avatar from '../containers/Avatar'; import Avatar from '../containers/Avatar';
import Status from '../containers/status'; import Status from '../containers/status';
import Touch from '../utils/touch/index'; //eslint-disable-line import Touch from '../utils/touch/index'; //eslint-disable-line
import Markdown from '../containers/message/Markdown'; import Markdown from '../containers/message/Markdown';
import RoomTypeIcon from '../containers/RoomTypeIcon';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -93,6 +92,10 @@ const styles = StyleSheet.create({
right: -3, right: -3,
borderWidth: 3, borderWidth: 3,
borderColor: '#fff' borderColor: '#fff'
},
type: {
marginRight: 5,
marginTop: 3
} }
}); });
const markdownStyle = { block: { marginBottom: 0, flexWrap: 'wrap', flexDirection: 'row' } }; const markdownStyle = { block: { marginBottom: 0, flexWrap: 'wrap', flexDirection: 'row' } };
@ -216,6 +219,16 @@ export default class RoomItem extends React.Component {
return `${ msg.slice(0, maxChars) }${ msg.replace(/:[a-z0-9]+:/gi, ':::').length > maxChars ? '...' : '' }`; return `${ msg.slice(0, maxChars) }${ msg.replace(/:[a-z0-9]+:/gi, ':::').length > maxChars ? '...' : '' }`;
} }
get type() {
const icon = {
c: 'pound',
p: 'lock',
l: 'account',
d: 'at'
}[this.props.type];
return <Icon name={icon} size={15} style={styles.type} />;
}
formatDate = date => moment(date).calendar(null, { formatDate = date => moment(date).calendar(null, {
lastDay: '[Yesterday]', lastDay: '[Yesterday]',
sameDay: 'h:mm A', sameDay: 'h:mm A',
@ -225,7 +238,7 @@ export default class RoomItem extends React.Component {
render() { render() {
const { const {
favorite, unread, userMentions, name, _updatedAt, alert, status favorite, unread, userMentions, name, _updatedAt, alert, type
} = this.props; } = this.props;
const date = this.formatDate(_updatedAt); const date = this.formatDate(_updatedAt);
@ -258,11 +271,11 @@ export default class RoomItem extends React.Component {
{this.icon} {this.icon}
<View style={styles.roomNameView}> <View style={styles.roomNameView}>
<View style={styles.firstRow}> <View style={styles.firstRow}>
<RoomTypeIcon type={type} />
<Text style={[styles.roomName, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text> <Text style={[styles.roomName, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
{_updatedAt ? <Text style={[styles.update, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null} {_updatedAt ? <Text style={[styles.update, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null}
</View> </View>
<View style={styles.row}> <View style={styles.row}>
{status === messagesStatus.ERROR ? <Icon name='error-outline' color='red' size={12} style={{ marginRight: 5, alignSelf: 'center' }} /> : null }
<Markdown <Markdown
msg={this.lastMessage} msg={this.lastMessage}
style={styles.lastMessage} style={styles.lastMessage}

View File

@ -10,12 +10,7 @@ export default function(username = '') {
const position = username.length % AVATAR_COLORS.length; const position = username.length % AVATAR_COLORS.length;
const color = AVATAR_COLORS[position]; const color = AVATAR_COLORS[position];
username = username.replace(/[^A-Za-z0-9]/g, '.').replace(/\.+/g, '.').replace(/(^\.)|(\.$)/g, ''); const initials = username.replace(/[^A-Za-z0-9]/g, '').substr(0, 1).toUpperCase();
const usernameParts = username.split('.');
let initials = usernameParts.length > 1 ? usernameParts[0][0] + usernameParts[usernameParts.length - 1][0] : username.replace(/[^A-Za-z0-9]/g, '').substr(0, 2);
initials = initials.toUpperCase();
return { initials, color }; return { initials, color };
} }

View File

@ -15,9 +15,10 @@ import database from '../../lib/realm';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import { leaveRoom } from '../../actions/room'; import { leaveRoom } from '../../actions/room';
import { setLoading } from '../../actions/selectedUsers'; import { setLoading } from '../../actions/selectedUsers';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
const renderSeparator = () => <View style={styles.separator} />; const renderSeparator = () => <View style={styles.separator} />;
const getRoomTitle = room => (room.t === 'd' ? room.fname : room.name); const getRoomTitle = room => (room.t === 'd' ? <Text>{room.fname}</Text> : <Text><RoomTypeIcon type={room.t} />&nbsp;{room.name}</Text>);
@connect(state => ({ @connect(state => ({
user_id: state.login.user.id, user_id: state.login.user.id,

View File

@ -13,11 +13,12 @@ import sharedStyles from '../Styles';
import database from '../../lib/realm'; import database from '../../lib/realm';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import Touch from '../../utils/touch'; import Touch from '../../utils/touch';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
const PERMISSION_EDIT_ROOM = 'edit-room'; const PERMISSION_EDIT_ROOM = 'edit-room';
const camelize = str => str.replace(/^(.)/, (match, chr) => chr.toUpperCase()); const camelize = str => str.replace(/^(.)/, (match, chr) => chr.toUpperCase());
const getRoomTitle = room => (room.t === 'd' ? <Text>{room.fname}</Text> : <Text><RoomTypeIcon type={room.t} />&nbsp;{room.name}</Text>);
@connect(state => ({ @connect(state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: state.login.user, user: state.login.user,
@ -116,8 +117,6 @@ export default class RoomInfoView extends LoggedView {
this.sub = result; this.sub = result;
} }
getRoomTitle = room => (room.t === 'd' ? room.fname : room.name);
isDirect = () => this.state.room.t === 'd'; isDirect = () => this.state.room.t === 'd';
updateRoom = async() => { updateRoom = async() => {
@ -178,7 +177,9 @@ export default class RoomInfoView extends LoggedView {
> >
{t === 'd' ? <Status style={[sharedStyles.status, styles.status]} id={roomUser._id} /> : null} {t === 'd' ? <Status style={[sharedStyles.status, styles.status]} id={roomUser._id} /> : null}
</Avatar> </Avatar>
<Text style={styles.roomTitle}>{ this.getRoomTitle(room) }</Text> <Text style={styles.roomTitle}>
{ getRoomTitle(room) }
</Text>
</View> </View>
{!this.isDirect() && this.renderItem('description', room)} {!this.isDirect() && this.renderItem('description', room)}

View File

@ -11,6 +11,7 @@ import Avatar from '../../../containers/Avatar';
import { STATUS_COLORS } from '../../../constants/colors'; import { STATUS_COLORS } from '../../../constants/colors';
import styles from './styles'; import styles from './styles';
import { closeRoom } from '../../../actions/room'; import { closeRoom } from '../../../actions/room';
import RoomTypeIcon from '../../../containers/RoomTypeIcon';
const title = (offline, connecting, authenticating, logged) => { const title = (offline, connecting, authenticating, logged) => {
if (offline) { if (offline) {
@ -148,7 +149,10 @@ export default class RoomHeaderView extends React.PureComponent {
} }
</Avatar> </Avatar>
<View style={styles.titleTextContainer}> <View style={styles.titleTextContainer}>
<Text style={styles.title} allowFontScaling={false}>{this.state.room.name}</Text> <Text style={styles.title} allowFontScaling={false}>
<RoomTypeIcon type={this.state.room.t} size={13} />&nbsp;
{this.state.room.name}
</Text>
{ t && <Text style={styles.userStatus} allowFontScaling={false} numberOfLines={1}>{t}</Text>} { t && <Text style={styles.userStatus} allowFontScaling={false} numberOfLines={1}>{t}</Text>}