176 lines
4.1 KiB
JavaScript
176 lines
4.1 KiB
JavaScript
'use strict';
|
|
|
|
import React, { Component } from 'react';
|
|
import {
|
|
ActivityIndicator,
|
|
Button,
|
|
ListView,
|
|
StyleSheet,
|
|
Text,
|
|
TextInput,
|
|
View,
|
|
} from 'react-native';
|
|
import KeyboardSpacer from '../../components/KeyboardSpacer';
|
|
import Backend from '../../lib/Backend';
|
|
|
|
export default class ChatScreen extends Component {
|
|
|
|
static navigationOptions = {
|
|
title: (navigation) => `Chat with ${navigation.state.params.name}`,
|
|
}
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
|
|
this.state = {
|
|
messages: [],
|
|
dataSource: ds,
|
|
myMessage: '',
|
|
isLoading: true,
|
|
};
|
|
}
|
|
|
|
async componentDidMount() {
|
|
let chat;
|
|
try {
|
|
chat = await Backend.fetchChat(this.props.navigation.state.params.name);
|
|
} catch (err) {
|
|
// Here we would handle the fact the request failed, e.g.
|
|
// set state to display "Messages could not be loaded".
|
|
// We should also check network connection first before making any
|
|
// network requests - maybe we're offline? See React Native's NetInfo
|
|
// module.
|
|
this.setState({
|
|
isLoading: false,
|
|
});
|
|
return;
|
|
}
|
|
this.setState((prevState) => ({
|
|
messages: chat.messages,
|
|
dataSource: prevState.dataSource.cloneWithRows(chat.messages),
|
|
isLoading: false,
|
|
}));
|
|
}
|
|
|
|
onAddMessage = async () => {
|
|
// Optimistically update the UI
|
|
this.addMessageLocal();
|
|
// Send the request
|
|
try {
|
|
await Backend.sendMessage({
|
|
name: this.props.navigation.state.params.name,
|
|
// TODO Is reading state like this outside of setState OK?
|
|
// Can it contain a stale value?
|
|
message: this.state.myMessage,
|
|
});
|
|
} catch (err) {
|
|
// Here we would handle the request failure, e.g. call setState
|
|
// to display a visual hint showing the message could not be sent.
|
|
}
|
|
}
|
|
|
|
addMessageLocal = () => {
|
|
this.setState((prevState) => {
|
|
if (!prevState.myMessage) {
|
|
return prevState;
|
|
}
|
|
const messages = [
|
|
...prevState.messages, {
|
|
name: 'Me',
|
|
text: prevState.myMessage,
|
|
}
|
|
];
|
|
return {
|
|
messages: messages,
|
|
dataSource: prevState.dataSource.cloneWithRows(messages),
|
|
myMessage: '',
|
|
}
|
|
});
|
|
this.textInput.clear();
|
|
}
|
|
|
|
onMyMessageChange = (event) => {
|
|
this.setState({myMessage: event.nativeEvent.text});
|
|
}
|
|
|
|
renderRow = (message) => (
|
|
<View style={styles.bubble}>
|
|
<Text style={styles.name}>{message.name}</Text>
|
|
<Text>{message.text}</Text>
|
|
</View>
|
|
)
|
|
|
|
render() {
|
|
if (this.state.isLoading) {
|
|
return (
|
|
<View style={styles.container}>
|
|
<ActivityIndicator />
|
|
</View>
|
|
);
|
|
}
|
|
return (
|
|
<View style={styles.container}>
|
|
<ListView
|
|
dataSource={this.state.dataSource}
|
|
renderRow={this.renderRow}
|
|
style={styles.listView}
|
|
onLayout={this.scrollToBottom}
|
|
/>
|
|
<View style={styles.composer}>
|
|
<TextInput
|
|
ref={(textInput) => { this.textInput = textInput; }}
|
|
style={styles.textInput}
|
|
placeholder="Type a message..."
|
|
text={this.state.myMessage}
|
|
onSubmitEditing={this.onAddMessage}
|
|
onChange={this.onMyMessageChange}
|
|
/>
|
|
{this.state.myMessage !== '' && (
|
|
<Button
|
|
title="Send"
|
|
onPress={this.onAddMessage}
|
|
/>
|
|
)}
|
|
</View>
|
|
<KeyboardSpacer />
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
padding: 8,
|
|
backgroundColor: 'white',
|
|
},
|
|
listView: {
|
|
flex: 1,
|
|
alignSelf: 'stretch',
|
|
},
|
|
bubble: {
|
|
alignSelf: 'flex-end',
|
|
backgroundColor: '#d6f3fc',
|
|
padding: 12,
|
|
borderRadius: 4,
|
|
marginBottom: 4,
|
|
},
|
|
name: {
|
|
fontWeight: 'bold',
|
|
},
|
|
composer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
height: 36,
|
|
},
|
|
textInput: {
|
|
flex: 1,
|
|
borderColor: '#ddd',
|
|
borderWidth: 1,
|
|
padding: 4,
|
|
height: 30,
|
|
fontSize: 13,
|
|
marginRight: 8,
|
|
}
|
|
});
|