Avatar initials and room type icon (#298)
This commit is contained in:
parent
69513a8327
commit
a0bb61642d
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
@ -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}
|
||||||
|
|
|
@ -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 };
|
||||||
}
|
}
|
||||||
|
|
|
@ -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} /> {room.name}</Text>);
|
||||||
|
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
user_id: state.login.user.id,
|
user_id: state.login.user.id,
|
||||||
|
|
|
@ -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} /> {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)}
|
||||||
|
|
|
@ -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} />
|
||||||
|
{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>}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue