[RN] Extract AvatarListItem
This commit is contained in:
parent
555f8b3a99
commit
38b1be1291
|
@ -1 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export * from './native';
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// @flow
|
||||
|
||||
export * from './_';
|
||||
export { default as AbstractPage } from './AbstractPage';
|
||||
export { default as NavigateSectionList } from './NavigateSectionList';
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import { Icon } from '../../../font-icons';
|
||||
import { Avatar } from '../../../participants';
|
||||
import { StyleType } from '../../../styles';
|
||||
|
||||
import { type Item } from '../../Types';
|
||||
|
||||
import Container from './Container';
|
||||
import styles, { AVATAR_SIZE, UNDERLAY_COLOR } from './styles';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Preferred size of the avatar.
|
||||
*/
|
||||
avatarSize?: number,
|
||||
|
||||
/**
|
||||
* External style to be applied to the avatar (icon).
|
||||
*/
|
||||
avatarStyle?: StyleType,
|
||||
|
||||
/**
|
||||
* External style to be applied to the avatar (text).
|
||||
*/
|
||||
avatarTextStyle?: StyleType,
|
||||
|
||||
/**
|
||||
* Children of the component.
|
||||
*/
|
||||
children?: ?React$Element<*>,
|
||||
|
||||
/**
|
||||
* item containing data to be rendered
|
||||
*/
|
||||
item: Item,
|
||||
|
||||
/**
|
||||
* External style prop to be applied to the extra lines.
|
||||
*/
|
||||
linesStyle?: StyleType,
|
||||
|
||||
/**
|
||||
* Function to invoke on press.
|
||||
*/
|
||||
onPress: ?Function,
|
||||
|
||||
/**
|
||||
* External style prop to be applied to the title.
|
||||
*/
|
||||
titleStyle?: StyleType
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a list item with an avatar rendered for it.
|
||||
*/
|
||||
export default class AvatarListItem extends Component<Props> {
|
||||
/**
|
||||
* Constructor of the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._renderItemLine = this._renderItemLine.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
avatarSize = AVATAR_SIZE,
|
||||
avatarStyle,
|
||||
avatarTextStyle
|
||||
} = this.props;
|
||||
const { avatar, colorBase, lines, title } = this.props.item;
|
||||
const avatarStyles = {
|
||||
...styles.avatar,
|
||||
...this._getAvatarColor(colorBase),
|
||||
...avatarStyle,
|
||||
borderRadius: avatarSize / 2,
|
||||
height: avatarSize,
|
||||
width: avatarSize
|
||||
};
|
||||
|
||||
const isAvatarURL = Boolean(avatar && avatar.match(/^http[s]*:\/\//i));
|
||||
|
||||
return (
|
||||
<Container
|
||||
onClick = { this.props.onPress }
|
||||
style = { styles.listItem }
|
||||
underlayColor = { UNDERLAY_COLOR }>
|
||||
<Container style = { styles.avatarContainer }>
|
||||
<Container style = { avatarStyles }>
|
||||
{
|
||||
isAvatarURL && <Avatar
|
||||
size = { avatarSize }
|
||||
uri = { avatar } />
|
||||
}
|
||||
|
||||
{
|
||||
Boolean(avatar && !isAvatarURL) && <Icon
|
||||
name = { avatar } />
|
||||
}
|
||||
|
||||
{
|
||||
!avatar && <Text
|
||||
style = { [
|
||||
styles.avatarContent,
|
||||
avatarTextStyle
|
||||
] }>
|
||||
{ title.substr(0, 1).toUpperCase() }
|
||||
</Text>
|
||||
}
|
||||
</Container>
|
||||
</Container>
|
||||
<Container style = { styles.listItemDetails }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
style = { [
|
||||
styles.listItemText,
|
||||
styles.listItemTitle,
|
||||
this.props.titleStyle
|
||||
] }>
|
||||
{ title }
|
||||
</Text>
|
||||
{this._renderItemLines(lines)}
|
||||
</Container>
|
||||
{ this.props.children }
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a style (color) based on the string that determines the color of
|
||||
* the avatar.
|
||||
*
|
||||
* @param {string} colorBase - The string that is the base of the color.
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
_getAvatarColor(colorBase) {
|
||||
if (!colorBase) {
|
||||
return null;
|
||||
}
|
||||
let nameHash = 0;
|
||||
|
||||
for (let i = 0; i < colorBase.length; i++) {
|
||||
nameHash += colorBase.codePointAt(i);
|
||||
}
|
||||
|
||||
return styles[`avatarColor${(nameHash % 5) + 1}`];
|
||||
}
|
||||
|
||||
_renderItemLine: (string, number) => React$Node;
|
||||
|
||||
/**
|
||||
* Renders a single line from the additional lines.
|
||||
*
|
||||
* @param {string} line - The line text.
|
||||
* @param {number} index - The index of the line.
|
||||
* @private
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
_renderItemLine(line, index) {
|
||||
if (!line) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text
|
||||
key = { index }
|
||||
numberOfLines = { 1 }
|
||||
style = { [
|
||||
styles.listItemText,
|
||||
this.props.linesStyle
|
||||
] }>
|
||||
{line}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
_renderItemLines: Array<string> => Array<React$Node>;
|
||||
|
||||
/**
|
||||
* Renders the additional item lines, if any.
|
||||
*
|
||||
* @param {Array<string>} lines - The lines to render.
|
||||
* @private
|
||||
* @returns {Array<React$Node>}
|
||||
*/
|
||||
_renderItemLines(lines) {
|
||||
return lines && lines.length ? lines.map(this._renderItemLine) : null;
|
||||
}
|
||||
}
|
|
@ -7,9 +7,11 @@ import { ColorPalette } from '../../../styles';
|
|||
|
||||
import Container from './Container';
|
||||
import Text from './Text';
|
||||
import styles, { UNDERLAY_COLOR } from './styles';
|
||||
import styles from './styles';
|
||||
import type { Item } from '../../Types';
|
||||
|
||||
import AvatarListItem from './AvatarListItem';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
|
@ -48,34 +50,11 @@ export default class NavigateSectionListItem extends Component<Props> {
|
|||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this._getAvatarColor = this._getAvatarColor.bind(this);
|
||||
|
||||
this._renderItemLine = this._renderItemLine.bind(this);
|
||||
this._renderItemLines = this._renderItemLines.bind(this);
|
||||
}
|
||||
|
||||
_getAvatarColor: string => Object;
|
||||
|
||||
/**
|
||||
* Returns a style (color) based on the string that determines the color of
|
||||
* the avatar.
|
||||
*
|
||||
* @param {string} colorBase - The string that is the base of the color.
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
_getAvatarColor(colorBase) {
|
||||
if (!colorBase) {
|
||||
return null;
|
||||
}
|
||||
let nameHash = 0;
|
||||
|
||||
for (let i = 0; i < colorBase.length; i++) {
|
||||
nameHash += colorBase.codePointAt(i);
|
||||
}
|
||||
|
||||
return styles[`avatarColor${(nameHash % 5) + 1}`];
|
||||
}
|
||||
|
||||
_renderItemLine: (string, number) => React$Node;
|
||||
|
||||
/**
|
||||
|
@ -138,12 +117,8 @@ export default class NavigateSectionListItem extends Component<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { slideActions } = this.props;
|
||||
const { id, colorBase, lines, title } = this.props.item;
|
||||
const avatarStyles = {
|
||||
...styles.avatar,
|
||||
...this._getAvatarColor(colorBase)
|
||||
};
|
||||
const { item, slideActions } = this.props;
|
||||
const { id } = item;
|
||||
let right;
|
||||
|
||||
// NOTE: The {@code Swipeout} component has an onPress prop encapsulated
|
||||
|
@ -165,31 +140,12 @@ export default class NavigateSectionListItem extends Component<Props> {
|
|||
<Swipeout
|
||||
backgroundColor = { ColorPalette.transparent }
|
||||
right = { right }>
|
||||
<Container
|
||||
onClick = { this.props.onPress }
|
||||
style = { styles.listItem }
|
||||
underlayColor = { UNDERLAY_COLOR }>
|
||||
<Container style = { styles.avatarContainer }>
|
||||
<Container style = { avatarStyles }>
|
||||
<Text style = { styles.avatarContent }>
|
||||
{title.substr(0, 1).toUpperCase()}
|
||||
</Text>
|
||||
</Container>
|
||||
</Container>
|
||||
<Container style = { styles.listItemDetails }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
style = { [
|
||||
styles.listItemText,
|
||||
styles.listItemTitle
|
||||
] }>
|
||||
{title}
|
||||
</Text>
|
||||
{this._renderItemLines(lines)}
|
||||
</Container>
|
||||
<AvatarListItem
|
||||
item = { item }
|
||||
onPress = { this.props.onPress }>
|
||||
{ this.props.secondaryAction
|
||||
&& this._renderSecondaryAction() }
|
||||
</Container>
|
||||
</AvatarListItem>
|
||||
</Swipeout>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// @flow
|
||||
|
||||
export { default as AvatarListItem } from './AvatarListItem';
|
||||
export { default as BackButton } from './BackButton';
|
||||
export { default as Container } from './Container';
|
||||
export { default as Header } from './Header';
|
||||
|
|
|
@ -5,7 +5,6 @@ import { StyleSheet } from 'react-native';
|
|||
import { BoxModel, ColorPalette, createStyleSheet } from '../../../styles';
|
||||
|
||||
const AVATAR_OPACITY = 0.4;
|
||||
const AVATAR_SIZE = 65;
|
||||
const HEADER_COLOR = ColorPalette.blue;
|
||||
|
||||
// Header height is from Android guidelines. Also, this looks good.
|
||||
|
@ -13,6 +12,7 @@ const HEADER_HEIGHT = 56;
|
|||
const OVERLAY_FONT_COLOR = 'rgba(255, 255, 255, 0.6)';
|
||||
const SECONDARY_ACTION_BUTTON_SIZE = 30;
|
||||
|
||||
export const AVATAR_SIZE = 65;
|
||||
export const HEADER_PADDING = BoxModel.padding;
|
||||
export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
|
||||
export const SIDEBAR_WIDTH = 250;
|
||||
|
@ -153,10 +153,7 @@ const SECTION_LIST_STYLES = {
|
|||
avatar: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: `rgba(23, 160, 219, ${AVATAR_OPACITY})`,
|
||||
borderRadius: AVATAR_SIZE,
|
||||
height: AVATAR_SIZE,
|
||||
justifyContent: 'center',
|
||||
width: AVATAR_SIZE
|
||||
justifyContent: 'center'
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -200,7 +197,7 @@ const SECTION_LIST_STYLES = {
|
|||
avatarContent: {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0)',
|
||||
color: OVERLAY_FONT_COLOR,
|
||||
fontSize: 32,
|
||||
fontSize: Math.floor(AVATAR_SIZE / 2),
|
||||
fontWeight: '100',
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue