Improve channel’s layout

This commit is contained in:
Rodrigo Nascimento 2017-08-13 00:19:14 -03:00
parent 03b97c25b1
commit 196e91cf4b
5 changed files with 89 additions and 23 deletions

View File

@ -4,6 +4,7 @@ import { View, Text, StyleSheet } from 'react-native';
import { CachedImage } from 'react-native-img-cache'; import { CachedImage } from 'react-native-img-cache';
import { emojify } from 'react-emojione'; import { emojify } from 'react-emojione';
import Markdown from 'react-native-easy-markdown'; import Markdown from 'react-native-easy-markdown';
import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
message: { 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 { export default class Message extends React.PureComponent {
static propTypes = { static propTypes = {
item: PropTypes.object.isRequired, item: PropTypes.object.isRequired,
@ -61,16 +60,8 @@ export default class Message extends React.PureComponent {
const msg = emojify(this.props.item.msg, { output: 'unicode' }); const msg = emojify(this.props.item.msg, { output: 'unicode' });
let username = this.props.item.u.username; const { initials, color } = avatarInitialsAndColor(this.props.item.u.username);
const position = username.length % colors.length;
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 ( return (
<View style={[styles.message, extraStyle]}> <View style={[styles.message, extraStyle]}>
<View style={[styles.avatarContainer, { backgroundColor: color }]}> <View style={[styles.avatarContainer, { backgroundColor: color }]}>

View File

@ -1,14 +1,17 @@
import React from 'react'; import React from 'react';
import { CachedImage } from 'react-native-img-cache';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, Text, StyleSheet } from 'react-native'; import { View, Text, StyleSheet } from 'react-native';
import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
padding: 24, padding: 10,
paddingLeft: 14,
alignItems: 'center' alignItems: 'center'
}, },
number: { number: {
@ -27,17 +30,43 @@ const styles = StyleSheet.create({
fontSize: 20, fontSize: 20,
color: '#444' color: '#444'
}, },
icon: { iconContainer: {
fontSize: 18,
marginTop: 5, marginTop: 5,
marginRight: 5, marginRight: 10,
color: '#aaa' 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 { export default class RoomItem extends React.PureComponent {
static propTypes = { static propTypes = {
item: PropTypes.object.isRequired item: PropTypes.object.isRequired,
baseUrl: PropTypes.string.isRequired
} }
get icon() { get icon() {
const icon = { const icon = {
@ -46,11 +75,29 @@ export default class RoomItem extends React.PureComponent {
p: 'lock', p: 'lock',
l: 'account' l: 'account'
}[this.props.item.t]; }[this.props.item.t];
if (!icon) { if (!icon) {
return null; return null;
} }
return <MaterialCommunityIcons name={icon} style={styles.icon} />;
if (this.props.item.t === 'd') {
const { name } = this.props.item;
const { initials, color } = avatarInitialsAndColor(name);
return (
<View style={[styles.iconContainer, { backgroundColor: color }]}>
<Text style={styles.avatarInitials}>{initials}</Text>
<CachedImage style={styles.avatar} source={{ uri: `${ this.props.baseUrl }/avatar/${ name }` }} />
</View>
);
}
return (
<View style={styles.iconContainer}>
<MaterialCommunityIcons name={icon} style={styles.icon} />
</View>
);
} }
renderNumber = (item) => { renderNumber = (item) => {
if (item.unread) { if (item.unread) {
return ( return (
@ -62,7 +109,7 @@ export default class RoomItem extends React.PureComponent {
} }
render() { render() {
const name = this.props.item.name; const { name } = this.props.item;
return ( return (
<View style={styles.container}> <View style={styles.container}>
{this.icon} {this.icon}

2
app/constants/colors.js Normal file
View File

@ -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;

View File

@ -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 };
}

View File

@ -78,7 +78,8 @@ const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
class RoomsListItem extends React.PureComponent { class RoomsListItem extends React.PureComponent {
static propTypes = { static propTypes = {
item: PropTypes.object.isRequired, item: PropTypes.object.isRequired,
onPress: PropTypes.func.isRequired onPress: PropTypes.func.isRequired,
baseUrl: PropTypes.string.isRequired
} }
_onPress = (...args) => { _onPress = (...args) => {
this.props.onPress(...args); this.props.onPress(...args);
@ -91,6 +92,7 @@ class RoomsListItem extends React.PureComponent {
<RoomItem <RoomItem
id={item._id} id={item._id}
item={item} item={item}
baseUrl={this.props.baseUrl}
/> />
</TouchableOpacity> </TouchableOpacity>
); );
@ -111,6 +113,10 @@ export default class RoomsListView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.data = realm.objects('subscriptions').filtered('_server.id = $0', this.props.server); 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 = { this.state = {
dataSource: ds.cloneWithRows([]), dataSource: ds.cloneWithRows([]),
searching: false, searching: false,
@ -243,6 +249,7 @@ export default class RoomsListView extends React.Component {
getSubscriptions = () => this.data.sorted('_updatedAt', true) getSubscriptions = () => this.data.sorted('_updatedAt', true)
updateState = debounce(() => { updateState = debounce(() => {
this.url = realm.objectForPrimaryKey('settings', 'Site_Url').value;
this.setState({ this.setState({
dataSource: ds.cloneWithRows(this.data.filtered('_server.id = $0', this.props.server).sorted('ls', true)) 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 }) => ( renderItem = ({ item }) => (
<RoomsListItem item={item} onPress={() => this._onPressItem(item._id, item)} /> <RoomsListItem
item={item}
onPress={() => this._onPressItem(item._id, item)}
baseUrl={this.url}
/>
); );
renderSeparator = () => ( renderSeparator = () => (
@ -346,6 +357,7 @@ export default class RoomsListView extends React.Component {
dataSource={this.state.dataSource} dataSource={this.state.dataSource}
style={styles.list} style={styles.list}
renderRow={item => this.renderItem({ item })} renderRow={item => this.renderItem({ item })}
renderHeader={this.renderSearchBar}
enableEmptySections enableEmptySections
/> />
) )
@ -362,7 +374,6 @@ export default class RoomsListView extends React.Component {
return ( return (
<View style={styles.container}> <View style={styles.container}>
{this.renderBanner()} {this.renderBanner()}
{this.renderSearchBar()}
{this.renderList()} {this.renderList()}
{this.renderCreateButtons()} {this.renderCreateButtons()}
</View> </View>