Skip to content
Permalink
Browse files

[expo][example] Updated example functionality (#1154)

* Updated CustomView

* Added touchable to map element
* Added map linking

* Added CustomActions

* Added AccessoryBar
* Added Footer

* removed comments

* Fixed up utils

* Added permission handling
  • Loading branch information...
EvanBacon authored and xcarpentier committed Mar 2, 2019
1 parent dd54219 commit 9f305124e31f0c86e67d8abcb74a4c65291da9f0
@@ -0,0 +1,39 @@
import { MaterialIcons } from '@expo/vector-icons';
import React from 'react';
import { StyleSheet, TouchableOpacity, View } from 'react-native';

import { getLocationAsync, pickImageAsync, takePictureAsync } from './mediaUtils';

export default class AccessoryBar extends React.Component {

render() {
const { onSend } = this.props;
return (
<View style={styles.container}>
<Button onPress={() => pickImageAsync(onSend)} name="photo" />
<Button onPress={() => takePictureAsync(onSend)} name="camera" />
<Button onPress={() => getLocationAsync(onSend)} name="my-location" />
</View>
);
}

}

const Button = ({ onPress, size = 30, color = 'rgba(0,0,0,0.5)', ...props }) => (
<TouchableOpacity onPress={onPress}>
<MaterialIcons size={size} color={color} {...props} />
</TouchableOpacity>
);

const styles = StyleSheet.create({
container: {
height: 44,
width: '100%',
backgroundColor: 'white',
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: 'rgba(0,0,0,0.3)',
},
});
@@ -1,13 +1,15 @@
import { AppLoading, Asset, Linking } from 'expo';
import React, { Component } from 'react';
import { Asset, AppLoading } from 'expo';
import { View, StyleSheet, Linking } from 'react-native';

import { GiftedChat } from 'react-native-gifted-chat';
import { StyleSheet, View } from 'react-native';
import { Bubble, GiftedChat, SystemMessage } from 'react-native-gifted-chat';
import Sentry from 'sentry-expo';

import messagesData from './data';
import NavBar from './NavBar';
import AccessoryBar from './AccessoryBar';
import CustomActions from './CustomActions';
import CustomView from './CustomView';
import NavBar from './NavBar';
import messagesData from './data/messages';
import earlierMessages from './data/earlierMessages';

Sentry.config('https://2a164b1e89424a5aafc186da811308cb@sentry.io/276804').install();

@@ -18,37 +20,73 @@ const styles = StyleSheet.create({
const filterBotMessages = (message) => !message.system && message.user && message.user._id && message.user._id === 2;
const findStep = (step) => (_, index) => index === step - 1;

export default class App extends Component {
const user = {
_id: 1,
name: 'Developer',
};

constructor(props) {
super(props);
const otherUser = {
_id: 2,
name: 'React Native',
avatar: 'https://facebook.github.io/react/img/logo_og.png',
};

this.state = {
messages: [],
step: 0,
appIsReady: false,
};
export default class App extends Component {

this.onSend = this.onSend.bind(this);
this.parsePatterns = this.parsePatterns.bind(this);
}
state = {
step: 0,
messages: [],
loadEarlier: true,
typingText: null,
isLoadingEarlier: false,
};

_isMounted = false;

async componentWillMount() {
this._isMounted = true;
// init with only system messages
await Asset.fromModule(require('./assets/avatar.png')).downloadAsync();
this.setState({ messages: messagesData.filter((message) => message.system), appIsReady: true });
}

onSend(messages = []) {
const step = this.state.step + 1;
this.setState((previousState) => ({
messages: GiftedChat.append(previousState.messages, [{ ...messages[0], sent: true, received: true }]),
step,
}));
setTimeout(() => this.botSend(step), 1200 + Math.round(Math.random() * 1000));
componentWillUnmount() {
this._isMounted = false;
}

botSend(step = 0) {
onLoadEarlier = () => {
this.setState((previousState) => {
return {
isLoadingEarlier: true,
};
});

setTimeout(() => {
if (this._isMounted === true) {
this.setState((previousState) => {
return {
messages: GiftedChat.prepend(previousState.messages, earlierMessages),
loadEarlier: false,
isLoadingEarlier: false,
};
});
}
}, 1000); // simulating network
};

onSend = (messages = []) => {
const step = this.state.step + 1;
this.setState((previousState) => {
const sentMessages = [{ ...messages[0], sent: true, received: true }];
return {
messages: GiftedChat.append(previousState.messages, sentMessages),
step,
};
});
// for demo purpose
setTimeout(() => this.botSend(step), Math.round(Math.random() * 1000));
};

botSend = (step = 0) => {
const newMessage = messagesData
.reverse()
.filter(filterBotMessages)
@@ -58,17 +96,90 @@ export default class App extends Component {
messages: GiftedChat.append(previousState.messages, newMessage),
}));
}
}
};

parsePatterns(linkStyle) {
parsePatterns = (linkStyle) => {
return [
{
pattern: /#(\w+)/,
style: { ...linkStyle, color: 'darkorange' },
onPress: () => Linking.openURL('http://gifted.chat'),
},
];
};

renderCustomView(props) {
return <CustomView {...props} />;
}

onReceive = (text) => {
this.setState((previousState) => {
return {
messages: GiftedChat.append(previousState.messages, {
_id: Math.round(Math.random() * 1000000),
text,
createdAt: new Date(),
user: otherUser,
}),
};
});
};

onSendFromUser = (messages = []) => {
const createdAt = new Date();
const messagesToUpload = messages.map((message) => ({
...message,
user,
createdAt,
_id: Math.round(Math.random() * 1000000),
}));
this.onSend(messagesToUpload);
};

renderAccessory = () => <AccessoryBar onSend={this.onSendFromUser} />;

renderCustomActions = (props) => {
return <CustomActions {...props} onSend={this.onSendFromUser} />;
};

renderBubble = (props) => {
return (
<Bubble
{...props}
wrapperStyle={{
left: {
backgroundColor: '#f0f0f0',
},
}}
/>
);
};

renderSystemMessage = (props) => {
return (
<SystemMessage
{...props}
containerStyle={{
marginBottom: 15,
}}
textStyle={{
fontSize: 14,
}}
/>
);
};

renderFooter = (props) => {
if (this.state.typingText) {
return (
<View style={styles.footerContainer}>
<Text style={styles.footerText}>{this.state.typingText}</Text>
</View>
);
}
return null;
};

render() {
if (!this.state.appIsReady) {
return <AppLoading />;
@@ -79,12 +190,18 @@ export default class App extends Component {
<GiftedChat
messages={this.state.messages}
onSend={this.onSend}
renderCustomView={CustomView}
keyboardShouldPersistTaps="never"
user={{
_id: 1,
}}
loadEarlier={this.state.loadEarlier}
onLoadEarlier={this.onLoadEarlier}
isLoadingEarlier={this.state.isLoadingEarlier}
parsePatterns={this.parsePatterns}
user={user}
renderAccessory={this.renderAccessory}
renderActions={this.renderCustomActions}
renderBubble={this.renderBubble}
renderSystemMessage={this.renderSystemMessage}
renderCustomView={this.renderCustomView}
renderFooter={this.renderFooter}
/>
</View>
);
@@ -0,0 +1,97 @@
import PropTypes from 'prop-types';
import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View, ViewPropTypes } from 'react-native';

import { getLocationAsync, pickImageAsync, takePictureAsync } from './mediaUtils';

export default class CustomActions extends React.Component {

onActionsPress = () => {
const options = ['Choose From Library', 'Take Picture', 'Send Location', 'Cancel'];
const cancelButtonIndex = options.length - 1;
this.context.actionSheet().showActionSheetWithOptions(
{
options,
cancelButtonIndex,
},
async (buttonIndex) => {
const { onSend } = this.props;
switch (buttonIndex) {
case 0:
pickImageAsync(onSend);
return;
case 1:
takePictureAsync(onSend);
return;
case 2:
getLocationAsync(onSend);
default:
}
},
);
};

renderIcon = () => {
if (this.props.renderIcon) {
return this.props.renderIcon();
}
return (
<View style={[styles.wrapper, this.props.wrapperStyle]}>
<Text style={[styles.iconText, this.props.iconTextStyle]}>+</Text>
</View>
);
};

render() {
return (
<TouchableOpacity style={[styles.container, this.props.containerStyle]} onPress={this.onActionsPress}>
{this.renderIcon()}
</TouchableOpacity>
);
}

}

const styles = StyleSheet.create({
container: {
width: 26,
height: 26,
marginLeft: 10,
marginBottom: 10,
},
wrapper: {
borderRadius: 13,
borderColor: '#b2b2b2',
borderWidth: 2,
flex: 1,
},
iconText: {
color: '#b2b2b2',
fontWeight: 'bold',
fontSize: 16,
backgroundColor: 'transparent',
textAlign: 'center',
},
});

CustomActions.contextTypes = {
actionSheet: PropTypes.func,
};

CustomActions.defaultProps = {
onSend: () => {},
options: {},
renderIcon: null,
containerStyle: {},
wrapperStyle: {},
iconTextStyle: {},
};

CustomActions.propTypes = {
onSend: PropTypes.func,
options: PropTypes.object,
renderIcon: PropTypes.func,
containerStyle: ViewPropTypes.style,
wrapperStyle: ViewPropTypes.style,
iconTextStyle: Text.propTypes.style,
};
Oops, something went wrong.

0 comments on commit 9f30512

Please sign in to comment.
You can’t perform that action at this time.