Skip to content

Instantly share code, notes, and snippets.

@alien3d
Created April 27, 2017 14:55
Show Gist options
  • Save alien3d/1d3100ca43e643a8e8ab83a636415370 to your computer and use it in GitHub Desktop.
Save alien3d/1d3100ca43e643a8e8ab83a636415370 to your computer and use it in GitHub Desktop.
react native element list item
import React, {PropTypes, Component} from 'react';
import {
ScrollView,
View,
StyleSheet,
TouchableHighlight,
Image,
Platform,
Switch,
TextInput,
DatePickerAndroid,
DatePickerIOS,
TimePickerAndroid,
TouchableWithoutFeedback,
TouchableOpacity
} from 'react-native';
import Badge from '../badge/badge';
import Icon from '../icons/Icon';
import Text from '../text/Text';
import colors from '../config/colors';
import fonts from '../config/fonts';
import normalize from '../helpers/normalizeText';
import Moment from 'moment';
let styles;
const FORMATS = {
'date': 'YYYY-MM-DD',
'datetime': 'YYYY-MM-DD HH:mm',
'time': 'HH:mm'
};
class ListItem extends Component {
constructor(props) {
super(props);
var date = new Date();
this.state = {
currentDate: date,
currentDateTime: date.getFullYear() + (date.getMonth() + 1) + date.getDay() + " " + date.getHours + ":" + date.getMinutes(),
currentTime: this._formatTime(date.getHours(), + date.getMinutes()),
currentHour: date.getHours(),
currentMinute: date.getMinutes(),
is24Hour: false
}
}
showPickerAndroid = async(options) => {
try {
var newState = {};
const {action, year, month, day} = await DatePickerAndroid.open(options);
if (action === DatePickerAndroid.dismissedAction) {
newState['currentText'] = 'dismissed';
} else {
var date = new Date(year, month, day);
newState['currentText'] = date.toLocaleDateString();
newState['currentDate'] = date;
this
.props
.textInputDateOnChange(date);
}
this.setState(newState);
} catch ({code, message}) {
console.warn(`Error `, message);
}
};
showTimePickerAndroid = async(options) => {
console.log(options)
try {
const {action, minute, hour} = await TimePickerAndroid.open(options);
var newState = {};
if (action === TimePickerAndroid.timeSetAction) {
newState['currentTime'] = this._formatTime(hour, minute);
newState['currentHour'] = hour;
newState['currentMinute'] = minute;
this
.props
.textInputTimeOnChange(this._formatTime(hour, minute));
} else if (action === TimePickerAndroid.dismissedAction) {
newState['currentText'] = 'dismissed';
}
this.setState(newState);
} catch ({code, message}) {
console.warn(`Error `, message);
}
};
_formatTime(hour, minute) {
return hour + ':' + (minute < 10
? '0' + minute
: minute);
}
/**
* Format Date. Either using default or pre-defined
* @param {object} date
* @param {type} dateType
* @param {object} format
* @returns {string} date
*/
_formatDate(date, type, format) {
dateParse = null;
// if js can do like this.. could be shorter FORMATS.{type} ?
var dateParse = null;
// use pre defined format
if (typeof format !== 'object') {
switch (type) {
case "date":
dateParse = Moment(date, FORMATS.date).format(FORMATS.date);
break;
case "datetime":
dateParse = Moment(date, FORMATS.datetime).format(FORMATS.datetime);
break;
case "time":
dateParse = Moment(date, FORMATS.time).format(FORMATS.time);
break;
case "hour":
if (date.length == 1) {
dateParse = "0".date;
} else {
dataParse = date;
}
break;
case "minute":
if (date.length == 1) {
dateParse = "0".date;
} else {
dataParse = date;
}
break;
default:
dateParse = "1.4 : unknown custom date";
}
} else {
switch (type) {
case "date":
dateParse = Moment(date, format.date);
break;
case "datetime":
dateParse = Moment(date, format.datetime);
break;
case "time":
dateParse = Moment(date, format.time);
break;
case "hour":
if (date.length == 1) {
dateParse = "0".date;
} else {
dataParse = date;
}
break;
case "minute":
if (date.length == 1) {
dateParse = "0".date;
} else {
dataParse = date;
}
break;
default:
dateParse = "2.4 unknown custom date";
}
}
return dateParse;
}
/**
* TextInput Focus
* @returns {void}
*/
focus() {
const ref = this.props.textInputRef;
this
.refs[ref]
.focus();
}
/**
* TextInput Blur
* @returns {void}
*/
blur() {
const ref = this.props.textInputRef;
this
.refs[ref]
.blur();
}
/**
* Switch Value
* @param {bool} value
*/
_onSwitchChange(value) {
this
.props
.switchOnChange(value);
}
render() {
const {
onPress,
title,
leftIcon,
rightIcon,
leftIconContainerStyle,
avatarStyle,
underlayColor,
subtitle,
subtitleStyle,
containerStyle,
wrapperStyle,
titleStyle,
titleContainerStyle,
hideChevron,
chevronColor,
chevronOnPress,
roundAvatar,
component,
fontFamily,
rightTitle,
rightTitleContainerStyle,
rightTitleStyle,
subtitleContainerStyle,
badge,
badgeContainerStyle,
badgeTextStyle,
label,
onLongPress,
switchButton,
onSwitch,
switchDisabled,
switchOnTintColor,
switchThumbTintColor,
switchTintColor,
switched,
textInput,
textInputRef,
textInputSecureTextEntry,
textInputAutoCapitalize,
textInputAutoCorrect,
textInputFocus,
textInputAutoFocus,
textInputEditable,
textInputKeyboardType,
textInputMaxLength,
textInputMultiline,
textInputOnChangeText,
textInputOnFocus,
textInputOnBlur,
textInputOnSubmitEditing,
textInputSelectTextOnFocus,
textInputReturnKeyType,
textInputValue,
textInputStyle,
textInputContainerStyle,
textInputPlaceHolder,
textInputHour,
textInputHourFormat,
textInputMinute,
textInputMinuteFormat,
textInputTime,
textInputTimeFormat,
textInputTimeIs24Hour,
textInputDate,
textInputDateFormat,
textInputDateMode,
textInputDateMinDate,
textInputDateMaxDate,
textInputDateTime,
textInputDateTimeFormat,
...attributes
} = this.props;
let {avatar} = this.props;
if (typeof avatar === 'string') {
avatar = {
uri: avatar
}
}
if (typeof textInputDate === "string") {
// just double recheck from props..
if (textInputDate.length > 0) {
// check valid date and is format
if (Moment(textInputDate, textInputDateFormat, true).isValid()) {
this.setState({currentDate: textInputDate});
} else {
console.log("Date give is not in right format. Date : " + textInputDate + " Format " + textInputDateFormat);
}
}
}
if (typeof textInputDateTime === "string") {
// just double recheck from props..
if (textInputDateTime.length > 0) {
// check valid date and is format
if (Moment(textInputDateTime, textInputDateTimeFormat, true).isValid()) {
this.setState({currentDateTime: textInputDateTime});
} else {
console.log("Date give is not in right format. Date : " + textInputDateTime + " Format " + textInputDateTimeFormat);
}
}
}
if (typeof textInputHour === "string") {
if (textInputHour.length > 0) {
if (Moment(textInputHour, textInputHourFormat, true).isValid()) {
this.setState({currentHour: textInputHour});
}
}
}
// unknown yet output should be
if (typeof textInputMinute === "string") {
if (textInputMinute.length > 0) {
if (Moment(textInputHour, textInputTimeFormat, true).isValid()) {
this.setState({currentMinute: textInputMinute});
}
}
}
if (typeof textInputTimeIs24Hour === "string") {
// just double recheck from props..
if (textInputTimeIs24Hour.length > 0) {
if (textInputTimeIs24Hour == "true" || textInputTimeIs24Hour == "false" || textInputTimeIs24Hour == true || textInputTimeIs24Hour == false) {
this.setState({is24Hour: textInputTimeIs24Hour});
}
}
}
return (
<TouchableHighlight
onLongPress={onLongPress}
onPress={onPress}
underlayColor={underlayColor}
style={[
styles.container, containerStyle && containerStyle
]}
{...attributes}>
<View
style={[
styles.wrapper, wrapperStyle && wrapperStyle
]}>
{leftIcon && leftIcon.name && (
<View
style={[
styles.iconStyle, leftIconContainerStyle && leftIconContainerStyle
]}><Icon
type={leftIcon.type}
iconStyle={[
styles.icon, leftIcon.style && leftIcon.style
]}
name={leftIcon.name}
color={leftIcon.color || colors.grey4}
size={leftIcon.size || 24}/>
</View>
)
}
{avatar && (<Image
style={[
styles.avatar, roundAvatar && {
borderRadius: 17
},
avatarStyle && avatarStyle
]}
source={avatar}/>)
}
<View style={styles.titleSubtitleContainer}>
<View style={titleContainerStyle}>
{(title && (typeof title === 'string' || typeof title === 'number'))
? (
<Text
style={[
styles.title, !leftIcon && {
marginLeft: 10
},
titleStyle && titleStyle,
fontFamily && {
fontFamily
}
]}>{title}</Text>
)
: (
<View>
{title}
</View>
)}
</View>
<View style={subtitleContainerStyle}>
{(subtitle && (typeof subtitle === 'string' || typeof subtitle === 'number'))
? (
<Text
style={[
styles.subtitle, !leftIcon && {
marginLeft: 10
},
subtitleStyle && subtitleStyle,
fontFamily && {
fontFamily
}
]}>{subtitle}</Text>
)
: (
<View>
{subtitle}
</View>
)}
</View>
</View>
{rightTitle && (rightTitle !== '') && !textInput && (
<View style={[styles.rightTitleContainer, rightTitleContainerStyle]}>
<Text style={[styles.rightTitleStyle, rightTitleStyle]}>{rightTitle}</Text>
</View>
)
}
{textInput && (
<View style={textInputContainerStyle}>
<TextInput
ref={textInputRef}
secureTextEntry={textInputSecureTextEntry}
underlineColorAndroid='transparent'
style={textInputStyle}
defaultValue={rightTitle}
value={textInputValue}
autoCapitalize={textInputAutoCapitalize}
autoCorrect={textInputAutoCorrect}
autoFocus={textInputAutoFocus}
focus={textInputFocus}
editable={textInputEditable}
keyboardType={textInputKeyboardType}
maxLength={textInputMaxLength}
multiline={textInputMultiline}
onChangeText={textInputOnChangeText}
onFocus={textInputOnFocus}
onBlur={textInputOnBlur}
onSubmitEditing={textInputOnSubmitEditing}
selectTextOnFocus={textInputSelectTextOnFocus}
returnKeyType={textInputReturnKeyType}
placeholder={textInputPlaceHolder}/>
</View>
)
}
{Platform.OS === 'android' && textInputDate && (
<View style={textInputContainerStyle}>
<TouchableWithoutFeedback
onPress={this
.showPickerAndroid
.bind(this, {
date: this.state.currentDate,
mode: textInputDateMode,
minDate: textInputDateMinDate,
maxDate: textInputDateMaxDate
})}>
<View style={styles.datePickerStyle}>
<Text>{this._formatDate(this.state.currentDate, "date", textInputDateFormat)}</Text>
</View>
</TouchableWithoutFeedback>
</View>
)
}
{Platform.OS === 'android' && textInputDateTime && (
<View style={textInputContainerStyle}>
<Text>Sorry not supported yet by react native
</Text>
</View>
)
}
{Platform.OS === 'android' && textInputTime && (
<View style={textInputContainerStyle}>
<TouchableWithoutFeedback
onPress={this
.showTimePickerAndroid
.bind(this, {
hour: this.state.currentHour,
minute: this.state.currentMinute,
is24Hour: this.state.is24Hour
})}>
<View style={styles.datePickerStyle}>
<Text>{this.state.currentTime}</Text>
</View>
</TouchableWithoutFeedback>
</View>
)
}
{Platform.OS === 'ios' && TextInputDate(
<View>
<Text>Wait on going
</Text>
</View>
)
}
{Platform.OS === 'ios' && TextInputDateTime(
<View>
<Text>Wait on going
</Text>
</View>
)
}
{Platform.OS === 'ios' && TextInputTime(
<View>
<Text>Wait on going
</Text>
</View>
)
}
{!hideChevron && (
<View style={styles.chevronContainer} onPress={chevronOnPress}>
<Icon
type={rightIcon.type}
iconStyle={rightIcon.style}
size={28}
name={rightIcon.name || 'chevron-right'}
color={rightIcon.color || chevronColor}/>
</View>
)
}
{switchButton && hideChevron && (
<View style={styles.switchContainer}>
<Switch
onValueChange={this
._onSwitchChange
.bind(this)}
style={{
marginBottom: 10
}}
disabled={switchDisabled}
onTintColor={switchOnTintColor}
thumbTintColor={switchThumbTintColor}
tintColor={switchTintColor}
value={switched}/>
</View>
)
}
{badge && !rightTitle && (<Badge badge={badge}/>)
}
{label && label
}
</View>
</TouchableHighlight>
)
}
};
ListItem.defaultProps = {
underlayColor: 'white',
chevronColor: colors.grey4,
rightIcon: {
name: 'chevron-right'
},
hideChevron: false,
roundAvatar: false,
textInputEditable: true
}
ListItem.propTypes = {
title: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
avatar: PropTypes.object,
icon: PropTypes.any,
onPress: PropTypes.func,
rightIcon: PropTypes.object,
underlayColor: PropTypes.string,
subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
subtitleStyle: PropTypes.any,
containerStyle: PropTypes.any,
wrapperStyle: PropTypes.any,
titleStyle: PropTypes.any,
titleContainerStyle: PropTypes.any,
hideChevron: PropTypes.bool,
chevronColor: PropTypes.string,
roundAvatar: PropTypes.bool,
badge: PropTypes.any,
switchButton: PropTypes.bool,
onSwitch: PropTypes.func,
switchDisabled: PropTypes.bool,
switchOnTintColor: PropTypes.string,
switchThumbTintColor: PropTypes.string,
switchTintColor: PropTypes.string,
switched: PropTypes.bool,
textInput: PropTypes.bool,
textInputAutoCapitalize: PropTypes.bool,
textInputAutoCorrect: PropTypes.bool,
textInputAutoFocus: PropTypes.bool,
textInputEditable: PropTypes.bool,
textInputKeyboardType: PropTypes.oneOf([
'default',
'email-address',
'numeric',
'phone-pad',
'ascii-capable',
'numbers-and-punctuation',
'url',
'number-pad',
'name-phone-pad',
'decimal-pad',
'twitter',
'web-search'
]),
textInputMaxLength: PropTypes.number,
textInputMultiline: PropTypes.bool,
textInputOnChangeText: PropTypes.func,
textInputOnFocus: PropTypes.func,
textInputOnBlur: PropTypes.func,
textInputSelectTextOnFocus: PropTypes.bool,
textInputReturnKeyType: PropTypes.string,
textInputValue: PropTypes.string,
textInputStyle: PropTypes.any,
textInputContainerStyle: PropTypes.any,
textInputDate: PropTypes.any,
textInputDateMinDate: PropTypes.any,
textInputDateMaxDate: PropTypes.any,
textInputDateTime: PropTypes.any,
textInputTime: PropTypes.any,
textInputHour: PropTypes.number,
textInputMinute: PropTypes.number,
textInputHourFormat: PropTypes.string,
textInputMinuteFormat: PropTypes.string,
textInputTimeIs24Hour: PropTypes.bool,
textInputDateOnChange: PropTypes.func,
textInputDateMode: PropTypes.oneOf(['default', 'calendar', 'spinner', 'default']),
textInputDateIosMode: PropTypes.oneOf(['date', 'time', 'datetime']),
switchOnChange: PropTypes.func,
chevronOnPress: PropTypes.func
};
styles = StyleSheet.create({
avatar: {
width: 34,
height: 34
},
container: {
paddingTop: 10,
paddingRight: 10,
paddingBottom: 10,
borderBottomColor: '#ededed',
borderBottomWidth: 1,
backgroundColor: 'transparent'
},
wrapper: {
flexDirection: 'row',
marginLeft: 10
},
iconStyle: {
flex: 0.15,
justifyContent: 'center',
alignItems: 'center'
},
icon: {
marginRight: 8
},
title: {
fontSize: normalize(14),
color: colors.grey1
},
subtitle: {
color: colors.grey3,
fontSize: normalize(12),
marginTop: 1,
...Platform.select({
ios: {
fontWeight: '600'
},
android: {
...fonts.android.bold
}
})
},
titleSubtitleContainer: {
justifyContent: 'center',
flex: 1
},
chevronContainer: {
flex: 0.3,
alignItems: 'flex-end',
justifyContent: 'center'
},
switchContainer: {
flex: 0.15,
alignItems: 'flex-end',
justifyContent: 'center',
marginRight: 5
},
rightTitleContainer: {
flex: 1,
alignItems: 'flex-end',
justifyContent: 'center'
},
rightTitleStyle: {
marginRight: 5,
color: colors.grey4
},
datePickerStyle: {
alignItems: 'flex-start',
flex: 1
}
});
export default ListItem;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment