diff --git a/app/components/Message.js b/app/components/Message.js index 8a7e74b23..949ad39cf 100644 --- a/app/components/Message.js +++ b/app/components/Message.js @@ -4,6 +4,7 @@ import { View, Text, StyleSheet } from 'react-native'; import { CachedImage } from 'react-native-img-cache'; import { emojify } from 'react-emojione'; import Markdown from 'react-native-easy-markdown'; +import avatarInitialsAndColor from '../utils/avatarInitialsAndColor'; const styles = StyleSheet.create({ message: { @@ -45,8 +46,6 @@ const styles = StyleSheet.create({ } }); -const colors = ['#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39', '#FFC107', '#FF9800', '#FF5722', '#795548', '#9E9E9E', '#607D8B']; - export default class Message extends React.PureComponent { static propTypes = { item: PropTypes.object.isRequired, @@ -61,16 +60,8 @@ export default class Message extends React.PureComponent { const msg = emojify(this.props.item.msg, { output: 'unicode' }); - let username = this.props.item.u.username; - const position = username.length % colors.length; + const { initials, color } = avatarInitialsAndColor(this.props.item.u.username); - const color = 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(); return ( diff --git a/app/components/RoomItem.js b/app/components/RoomItem.js index 492b37fdd..754286d7b 100644 --- a/app/components/RoomItem.js +++ b/app/components/RoomItem.js @@ -1,14 +1,17 @@ import React from 'react'; - +import { CachedImage } from 'react-native-img-cache'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import PropTypes from 'prop-types'; import { View, Text, StyleSheet } from 'react-native'; +import avatarInitialsAndColor from '../utils/avatarInitialsAndColor'; + const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'row', - padding: 24, + padding: 10, + paddingLeft: 14, alignItems: 'center' }, number: { @@ -27,17 +30,43 @@ const styles = StyleSheet.create({ fontSize: 20, color: '#444' }, - icon: { - fontSize: 18, + iconContainer: { marginTop: 5, - marginRight: 5, - color: '#aaa' + marginRight: 10, + backgroundColor: '#ccc', + height: 40, + width: 40, + borderRadius: 20, + overflow: 'hidden', + justifyContent: 'center', + alignItems: 'center' + }, + icon: { + fontSize: 20, + color: '#fff', + backgroundColor: '#ccc', + height: 36, + width: 36, + borderRadius: 18, + overflow: 'hidden', + textAlign: 'center', + lineHeight: 36 + }, + avatar: { + width: 40, + height: 40, + position: 'absolute' + }, + avatarInitials: { + fontSize: 22, + color: '#ffffff' } }); export default class RoomItem extends React.PureComponent { static propTypes = { - item: PropTypes.object.isRequired + item: PropTypes.object.isRequired, + baseUrl: PropTypes.string.isRequired } get icon() { const icon = { @@ -46,11 +75,29 @@ export default class RoomItem extends React.PureComponent { p: 'lock', l: 'account' }[this.props.item.t]; + if (!icon) { return null; } - return ; + + if (this.props.item.t === 'd') { + const { name } = this.props.item; + const { initials, color } = avatarInitialsAndColor(name); + return ( + + {initials} + + + ); + } + + return ( + + + + ); } + renderNumber = (item) => { if (item.unread) { return ( @@ -62,7 +109,7 @@ export default class RoomItem extends React.PureComponent { } render() { - const name = this.props.item.name; + const { name } = this.props.item; return ( {this.icon} diff --git a/app/constants/colors.js b/app/constants/colors.js new file mode 100644 index 000000000..145e665be --- /dev/null +++ b/app/constants/colors.js @@ -0,0 +1,2 @@ +export const AVATAR_COLORS = ['#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39', '#FFC107', '#FF9800', '#FF5722', '#795548', '#9E9E9E', '#607D8B']; +export const ESLINT_FIX = null; diff --git a/app/utils/avatarInitialsAndColor.js b/app/utils/avatarInitialsAndColor.js new file mode 100644 index 000000000..09c41fb1d --- /dev/null +++ b/app/utils/avatarInitialsAndColor.js @@ -0,0 +1,15 @@ +import { AVATAR_COLORS } from '../constants/colors'; + +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(); + + return { initials, color }; +} diff --git a/app/views/roomsList.js b/app/views/roomsList.js index a3d56fa50..8148d8d3b 100644 --- a/app/views/roomsList.js +++ b/app/views/roomsList.js @@ -78,7 +78,8 @@ const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }); class RoomsListItem extends React.PureComponent { static propTypes = { item: PropTypes.object.isRequired, - onPress: PropTypes.func.isRequired + onPress: PropTypes.func.isRequired, + baseUrl: PropTypes.string.isRequired } _onPress = (...args) => { this.props.onPress(...args); @@ -91,6 +92,7 @@ class RoomsListItem extends React.PureComponent { ); @@ -111,6 +113,10 @@ export default class RoomsListView extends React.Component { constructor(props) { super(props); this.data = realm.objects('subscriptions').filtered('_server.id = $0', this.props.server); + const siteUrl = realm.objectForPrimaryKey('settings', 'Site_Url'); + if (siteUrl) { + this.url = siteUrl.value; + } this.state = { dataSource: ds.cloneWithRows([]), searching: false, @@ -243,6 +249,7 @@ export default class RoomsListView extends React.Component { getSubscriptions = () => this.data.sorted('_updatedAt', true) updateState = debounce(() => { + this.url = realm.objectForPrimaryKey('settings', 'Site_Url').value; this.setState({ dataSource: ds.cloneWithRows(this.data.filtered('_server.id = $0', this.props.server).sorted('ls', true)) }); @@ -309,7 +316,11 @@ export default class RoomsListView extends React.Component { } renderItem = ({ item }) => ( - this._onPressItem(item._id, item)} /> + this._onPressItem(item._id, item)} + baseUrl={this.url} + /> ); renderSeparator = () => ( @@ -346,6 +357,7 @@ export default class RoomsListView extends React.Component { dataSource={this.state.dataSource} style={styles.list} renderRow={item => this.renderItem({ item })} + renderHeader={this.renderSearchBar} enableEmptySections /> ) @@ -362,7 +374,6 @@ export default class RoomsListView extends React.Component { return ( {this.renderBanner()} - {this.renderSearchBar()} {this.renderList()} {this.renderCreateButtons()}