From a0bb61642d3dbd28cb9192e2eaf98a56b58fef07 Mon Sep 17 00:00:00 2001
From: Diego Mello <diegolmello@gmail.com>
Date: Fri, 18 May 2018 13:41:47 -0300
Subject: [PATCH] Avatar initials and room type icon (#298)

---
 app/containers/Avatar.js            | 38 ++++++++++++-----------------
 app/containers/RoomTypeIcon.js      | 32 ++++++++++++++++++++++++
 app/presentation/RoomItem.js        | 23 +++++++++++++----
 app/utils/avatarInitialsAndColor.js |  7 +-----
 app/views/RoomActionsView/index.js  |  3 ++-
 app/views/RoomInfoView/index.js     |  9 ++++---
 app/views/RoomView/Header/index.js  |  6 ++++-
 7 files changed, 78 insertions(+), 40 deletions(-)
 create mode 100644 app/containers/RoomTypeIcon.js

diff --git a/app/containers/Avatar.js b/app/containers/Avatar.js
index 7d1b40053..3e49a100e 100644
--- a/app/containers/Avatar.js
+++ b/app/containers/Avatar.js
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import { StyleSheet, Text, View, ViewPropTypes } from 'react-native';
 import FastImage from 'react-native-fast-image';
-import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
 import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
 
 const styles = StyleSheet.create({
@@ -49,7 +48,8 @@ export default class Avatar extends React.PureComponent {
 		};
 
 		const avatarInitialsStyle = {
-			fontSize: size / 2
+			fontSize: size / 1.6,
+			fontWeight: '800'
 		};
 
 		const avatarStyle = {
@@ -58,9 +58,11 @@ export default class Avatar extends React.PureComponent {
 			borderRadius
 		};
 
+		let image;
+
 		if (type === 'd') {
 			const uri = avatar || `${ baseUrl }/avatar/${ text }`;
-			const image = uri && (
+			image = uri && (
 				<FastImage
 					style={[styles.avatar, avatarStyle]}
 					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 (
 			<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>
 		);
 	}
diff --git a/app/containers/RoomTypeIcon.js b/app/containers/RoomTypeIcon.js
new file mode 100644
index 000000000..4450594cc
--- /dev/null
+++ b/app/containers/RoomTypeIcon.js
@@ -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;
diff --git a/app/presentation/RoomItem.js b/app/presentation/RoomItem.js
index 5529dd15b..7674d95de 100644
--- a/app/presentation/RoomItem.js
+++ b/app/presentation/RoomItem.js
@@ -2,16 +2,15 @@ import React from 'react';
 import moment from 'moment';
 import PropTypes from 'prop-types';
 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 SimpleMarkdown from 'simple-markdown';
 
-import messagesStatus from '../constants/messagesStatus';
-
 import Avatar from '../containers/Avatar';
 import Status from '../containers/status';
 import Touch from '../utils/touch/index'; //eslint-disable-line
 import Markdown from '../containers/message/Markdown';
+import RoomTypeIcon from '../containers/RoomTypeIcon';
 
 const styles = StyleSheet.create({
 	container: {
@@ -93,6 +92,10 @@ const styles = StyleSheet.create({
 		right: -3,
 		borderWidth: 3,
 		borderColor: '#fff'
+	},
+	type: {
+		marginRight: 5,
+		marginTop: 3
 	}
 });
 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 ? '...' : '' }`;
 	}
 
+	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, {
 		lastDay: '[Yesterday]',
 		sameDay: 'h:mm A',
@@ -225,7 +238,7 @@ export default class RoomItem extends React.Component {
 
 	render() {
 		const {
-			favorite, unread, userMentions, name, _updatedAt, alert, status
+			favorite, unread, userMentions, name, _updatedAt, alert, type
 		} = this.props;
 
 		const date = this.formatDate(_updatedAt);
@@ -258,11 +271,11 @@ export default class RoomItem extends React.Component {
 					{this.icon}
 					<View style={styles.roomNameView}>
 						<View style={styles.firstRow}>
+							<RoomTypeIcon type={type} />
 							<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}
 						</View>
 						<View style={styles.row}>
-							{status === messagesStatus.ERROR ? <Icon name='error-outline' color='red' size={12} style={{ marginRight: 5, alignSelf: 'center' }} /> : null }
 							<Markdown
 								msg={this.lastMessage}
 								style={styles.lastMessage}
diff --git a/app/utils/avatarInitialsAndColor.js b/app/utils/avatarInitialsAndColor.js
index 13029c66c..0724d9a8a 100644
--- a/app/utils/avatarInitialsAndColor.js
+++ b/app/utils/avatarInitialsAndColor.js
@@ -10,12 +10,7 @@ export default function(username = '') {
 	const position = username.length % AVATAR_COLORS.length;
 
 	const color = AVATAR_COLORS[position];
-	username = username.replace(/[^A-Za-z0-9]/g, '.').replace(/\.+/g, '.').replace(/(^\.)|(\.$)/g, '');
-
-	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();
+	const initials = username.replace(/[^A-Za-z0-9]/g, '').substr(0, 1).toUpperCase();
 
 	return { initials, color };
 }
diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js
index 399da0b16..ab73b6e32 100644
--- a/app/views/RoomActionsView/index.js
+++ b/app/views/RoomActionsView/index.js
@@ -15,9 +15,10 @@ import database from '../../lib/realm';
 import RocketChat from '../../lib/rocketchat';
 import { leaveRoom } from '../../actions/room';
 import { setLoading } from '../../actions/selectedUsers';
+import RoomTypeIcon from '../../containers/RoomTypeIcon';
 
 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 => ({
 	user_id: state.login.user.id,
diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js
index fc25414f2..0cebb9f43 100644
--- a/app/views/RoomInfoView/index.js
+++ b/app/views/RoomInfoView/index.js
@@ -13,11 +13,12 @@ import sharedStyles from '../Styles';
 import database from '../../lib/realm';
 import RocketChat from '../../lib/rocketchat';
 import Touch from '../../utils/touch';
+import RoomTypeIcon from '../../containers/RoomTypeIcon';
 
 const PERMISSION_EDIT_ROOM = 'edit-room';
 
 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 => ({
 	baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
 	user: state.login.user,
@@ -116,8 +117,6 @@ export default class RoomInfoView extends LoggedView {
 		this.sub = result;
 	}
 
-	getRoomTitle = room => (room.t === 'd' ? room.fname : room.name);
-
 	isDirect = () => this.state.room.t === 'd';
 
 	updateRoom = async() => {
@@ -178,7 +177,9 @@ export default class RoomInfoView extends LoggedView {
 					>
 						{t === 'd' ? <Status style={[sharedStyles.status, styles.status]} id={roomUser._id} /> : null}
 					</Avatar>
-					<Text style={styles.roomTitle}>{ this.getRoomTitle(room) }</Text>
+					<Text style={styles.roomTitle}>
+						{ getRoomTitle(room) }
+					</Text>
 				</View>
 
 				{!this.isDirect() && this.renderItem('description', room)}
diff --git a/app/views/RoomView/Header/index.js b/app/views/RoomView/Header/index.js
index d7cb05cba..89f4c2a4b 100644
--- a/app/views/RoomView/Header/index.js
+++ b/app/views/RoomView/Header/index.js
@@ -11,6 +11,7 @@ import Avatar from '../../../containers/Avatar';
 import { STATUS_COLORS } from '../../../constants/colors';
 import styles from './styles';
 import { closeRoom } from '../../../actions/room';
+import RoomTypeIcon from '../../../containers/RoomTypeIcon';
 
 const title = (offline, connecting, authenticating, logged) => {
 	if (offline) {
@@ -148,7 +149,10 @@ export default class RoomHeaderView extends React.PureComponent {
 					}
 				</Avatar>
 				<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>}
 
-- 
GitLab