parent
3cd281b66f
commit
7a1d359a4f
|
@ -30,7 +30,7 @@ const onlyUnique = function onlyUnique(value, index, self) {
|
||||||
typing: status => dispatch(userTyping(status)),
|
typing: status => dispatch(userTyping(status)),
|
||||||
clearInput: () => dispatch(clearInput())
|
clearInput: () => dispatch(clearInput())
|
||||||
}))
|
}))
|
||||||
export default class MessageBox extends React.Component {
|
export default class MessageBox extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onSubmit: PropTypes.func.isRequired,
|
onSubmit: PropTypes.func.isRequired,
|
||||||
rid: PropTypes.string.isRequired,
|
rid: PropTypes.string.isRequired,
|
||||||
|
|
|
@ -19,7 +19,10 @@ const styles = StyleSheet.create({
|
||||||
usersTyping: state.room.usersTyping
|
usersTyping: state.room.usersTyping
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export default class Typing extends React.PureComponent {
|
export default class Typing extends React.Component {
|
||||||
|
shouldComponentUpdate(nextProps) {
|
||||||
|
return this.props.usersTyping.join() !== nextProps.usersTyping.join();
|
||||||
|
}
|
||||||
get usersTyping() {
|
get usersTyping() {
|
||||||
const users = this.props.usersTyping.filter(_username => this.props.username !== _username);
|
const users = this.props.usersTyping.filter(_username => this.props.username !== _username);
|
||||||
return users.length ? `${ users.join(' ,') } ${ users.length > 1 ? 'are' : 'is' } typing` : '';
|
return users.length ? `${ users.join(' ,') } ${ users.length > 1 ? 'are' : 'is' } typing` : '';
|
||||||
|
|
|
@ -25,7 +25,7 @@ const BlockCode = ({ node, state }) => (
|
||||||
{node.content}
|
{node.content}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
const mentionStyle = { color: '#13679a' };
|
||||||
const rules = {
|
const rules = {
|
||||||
username: {
|
username: {
|
||||||
order: -1,
|
order: -1,
|
||||||
|
@ -38,7 +38,7 @@ const rules = {
|
||||||
children: (
|
children: (
|
||||||
<Text
|
<Text
|
||||||
key={state.key}
|
key={state.key}
|
||||||
style={{ color: '#13679a' }}
|
style={mentionStyle}
|
||||||
onPress={() => alert('Username')}
|
onPress={() => alert('Username')}
|
||||||
>
|
>
|
||||||
{node.content}
|
{node.content}
|
||||||
|
@ -58,7 +58,7 @@ const rules = {
|
||||||
children: (
|
children: (
|
||||||
<Text
|
<Text
|
||||||
key={state.key}
|
key={state.key}
|
||||||
style={{ color: '#13679a' }}
|
style={mentionStyle}
|
||||||
onPress={() => alert('Room')}
|
onPress={() => alert('Room')}
|
||||||
>
|
>
|
||||||
{node.content}
|
{node.content}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { View, StyleSheet, TouchableHighlight, Text, TouchableOpacity } from 'react-native';
|
import { View, TouchableHighlight, Text, TouchableOpacity, Animated } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
@ -15,27 +15,11 @@ import Markdown from './Markdown';
|
||||||
import Url from './Url';
|
import Url from './Url';
|
||||||
import Reply from './Reply';
|
import Reply from './Reply';
|
||||||
import messageStatus from '../../constants/messagesStatus';
|
import messageStatus from '../../constants/messagesStatus';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const avatar = { marginRight: 10 };
|
||||||
|
const flex = { flexDirection: 'row', flex: 1 };
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
content: {
|
|
||||||
flexGrow: 1,
|
|
||||||
flexShrink: 1
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
padding: 12,
|
|
||||||
paddingTop: 6,
|
|
||||||
paddingBottom: 6,
|
|
||||||
flexDirection: 'row',
|
|
||||||
transform: [{ scaleY: -1 }]
|
|
||||||
},
|
|
||||||
textInfo: {
|
|
||||||
fontStyle: 'italic',
|
|
||||||
color: '#a0a0a0'
|
|
||||||
},
|
|
||||||
editing: {
|
|
||||||
backgroundColor: '#fff5df'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
message: state.messages.message,
|
message: state.messages.message,
|
||||||
|
@ -53,7 +37,30 @@ export default class Message extends React.Component {
|
||||||
user: PropTypes.object.isRequired,
|
user: PropTypes.object.isRequired,
|
||||||
editing: PropTypes.bool,
|
editing: PropTypes.bool,
|
||||||
actionsShow: PropTypes.func,
|
actionsShow: PropTypes.func,
|
||||||
errorActionsShow: PropTypes.func
|
errorActionsShow: PropTypes.func,
|
||||||
|
animate: PropTypes.bool
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this._visibility = new Animated.Value(this.props.animate ? 0 : 1);
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.animate) {
|
||||||
|
Animated.timing(this._visibility, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 300
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentWillReceiveProps() {
|
||||||
|
this.extraStyle = this.extraStyle || {};
|
||||||
|
if (this.props.item.status === messageStatus.TEMP || this.props.item.status === messageStatus.ERROR) {
|
||||||
|
this.extraStyle.opacity = 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps) {
|
||||||
|
return this.props.item._updatedAt.toGMTString() !== nextProps.item._updatedAt.toGMTString() || this.props.item.status !== nextProps.item.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
onLongPress() {
|
onLongPress() {
|
||||||
|
@ -157,11 +164,14 @@ export default class Message extends React.Component {
|
||||||
item, message, editing, baseUrl
|
item, message, editing, baseUrl
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const extraStyle = {};
|
const marginLeft = this._visibility.interpolate({
|
||||||
if (item.status === messageStatus.TEMP || item.status === messageStatus.ERROR) {
|
inputRange: [0, 1],
|
||||||
extraStyle.opacity = 0.3;
|
outputRange: [-30, 0]
|
||||||
}
|
});
|
||||||
|
const opacity = this._visibility.interpolate({
|
||||||
|
inputRange: [0, 1],
|
||||||
|
outputRange: [0, 1]
|
||||||
|
});
|
||||||
const username = item.alias || item.u.username;
|
const username = item.alias || item.u.username;
|
||||||
const isEditing = message._id === item._id && editing;
|
const isEditing = message._id === item._id && editing;
|
||||||
|
|
||||||
|
@ -176,11 +186,11 @@ export default class Message extends React.Component {
|
||||||
style={[styles.message, isEditing ? styles.editing : null]}
|
style={[styles.message, isEditing ? styles.editing : null]}
|
||||||
accessibilityLabel={accessibilityLabel}
|
accessibilityLabel={accessibilityLabel}
|
||||||
>
|
>
|
||||||
<View style={{ flexDirection: 'row', flex: 1 }}>
|
<Animated.View style={[flex, { opacity, marginLeft }]}>
|
||||||
{this.renderError()}
|
{this.renderError()}
|
||||||
<View style={[extraStyle, { flexDirection: 'row', flex: 1 }]}>
|
<View style={[this.extraStyle, flex]}>
|
||||||
<Avatar
|
<Avatar
|
||||||
style={{ marginRight: 10 }}
|
style={avatar}
|
||||||
text={item.avatar ? '' : username}
|
text={item.avatar ? '' : username}
|
||||||
size={40}
|
size={40}
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
|
@ -198,7 +208,7 @@ export default class Message extends React.Component {
|
||||||
{this.renderUrl()}
|
{this.renderUrl()}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</Animated.View>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
export default StyleSheet.create({
|
||||||
|
content: {
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 1
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
padding: 12,
|
||||||
|
paddingTop: 6,
|
||||||
|
paddingBottom: 6,
|
||||||
|
flexDirection: 'row',
|
||||||
|
transform: [{ scaleY: -1 }]
|
||||||
|
},
|
||||||
|
textInfo: {
|
||||||
|
fontStyle: 'italic',
|
||||||
|
color: '#a0a0a0'
|
||||||
|
},
|
||||||
|
editing: {
|
||||||
|
backgroundColor: '#fff5df'
|
||||||
|
}
|
||||||
|
});
|
|
@ -5,7 +5,7 @@ const initialState = {
|
||||||
connected: false,
|
connected: false,
|
||||||
errorMessage: '',
|
errorMessage: '',
|
||||||
failure: false,
|
failure: false,
|
||||||
server: {}
|
server: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import styles from './styles';
|
||||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||||
activeUsers: state.activeUsers
|
activeUsers: state.activeUsers
|
||||||
}))
|
}))
|
||||||
export default class extends React.Component {
|
export default class extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigation: PropTypes.object.isRequired,
|
navigation: PropTypes.object.isRequired,
|
||||||
user: PropTypes.object.isRequired,
|
user: PropTypes.object.isRequired,
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
import { ListView as OldList } from 'realm/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import cloneReferencedElement from 'react-clone-referenced-element';
|
||||||
|
import { ScrollView, ListView as OldList2 } from 'react-native';
|
||||||
|
|
||||||
|
const DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
||||||
|
|
||||||
|
export class DataSource extends OldList.DataSource {
|
||||||
|
getRowData(sectionIndex: number, rowIndex: number): any {
|
||||||
|
const sectionID = this.sectionIdentities[sectionIndex];
|
||||||
|
const rowID = this.rowIdentities[sectionIndex][rowIndex];
|
||||||
|
return this._getRowData(this._dataBlob, sectionID, rowID);
|
||||||
|
}
|
||||||
|
_calculateDirtyArrays() { // eslint-disable-line
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class ListView extends OldList2 {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
curRenderedRowsCount: this.props.initialListSize,
|
||||||
|
highlightedRow: ({}: Object)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.renderRow = this.renderRow.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRow(_, sectionId, rowId, ...args) {
|
||||||
|
const { props } = this;
|
||||||
|
const item = props.dataSource.getRow(sectionId, rowId);
|
||||||
|
|
||||||
|
// The item could be null because our data is a snapshot and it was deleted.
|
||||||
|
return item ? props.renderRow(item, sectionId, rowId, ...args) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerViewNode() {
|
||||||
|
return this.refs.listView.getInnerViewNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollTo(...args) {
|
||||||
|
this.refs.listView.scrollTo(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
setNativeProps(props) {
|
||||||
|
this.refs.listView.setNativeProps(props);
|
||||||
|
}
|
||||||
|
static DataSource = DataSource;
|
||||||
|
render() {
|
||||||
|
const bodyComponents = [];
|
||||||
|
|
||||||
|
const { dataSource } = this.props;
|
||||||
|
const allRowIDs = dataSource.rowIdentities;
|
||||||
|
let rowCount = 0;
|
||||||
|
// const stickySectionHeaderIndices = [];
|
||||||
|
|
||||||
|
// const { renderSectionHeader } = this.props;
|
||||||
|
|
||||||
|
const header = this.props.renderHeader && this.props.renderHeader();
|
||||||
|
const footer = this.props.renderFooter && this.props.renderFooter();
|
||||||
|
// let totalIndex = header ? 1 : 0;
|
||||||
|
|
||||||
|
for (let sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx += 1) {
|
||||||
|
const sectionID = dataSource.sectionIdentities[sectionIdx];
|
||||||
|
const rowIDs = allRowIDs[sectionIdx];
|
||||||
|
if (rowIDs.length === 0) {
|
||||||
|
continue; // eslint-disable-line
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (renderSectionHeader) {
|
||||||
|
// const element = renderSectionHeader(
|
||||||
|
// dataSource.getSectionHeaderData(sectionIdx),
|
||||||
|
// sectionID,
|
||||||
|
// );
|
||||||
|
// if (element) {
|
||||||
|
// bodyComponents.push(React.cloneElement(element, { key: `s_${ sectionID }` }), );
|
||||||
|
// if (this.props.stickySectionHeadersEnabled) {
|
||||||
|
// stickySectionHeaderIndices.push(totalIndex);
|
||||||
|
// }
|
||||||
|
// totalIndex++;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (let rowIdx = 0; rowIdx < rowIDs.length; rowIdx += 1) {
|
||||||
|
const rowID = rowIDs[rowIdx];
|
||||||
|
const data = dataSource._dataBlob[sectionID][rowID];
|
||||||
|
bodyComponents.push(this.props.renderRow.bind(
|
||||||
|
null,
|
||||||
|
data,
|
||||||
|
sectionID,
|
||||||
|
rowID,
|
||||||
|
this._onRowHighlighted,
|
||||||
|
)());
|
||||||
|
// totalIndex += 1;
|
||||||
|
rowCount += 1;
|
||||||
|
if (rowCount === this.state.curRenderedRowsCount) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rowCount >= this.state.curRenderedRowsCount) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { ...props } = this.props;
|
||||||
|
if (!props.scrollEventThrottle) {
|
||||||
|
props.scrollEventThrottle = DEFAULT_SCROLL_CALLBACK_THROTTLE;
|
||||||
|
}
|
||||||
|
if (props.removeClippedSubviews === undefined) {
|
||||||
|
props.removeClippedSubviews = true;
|
||||||
|
}
|
||||||
|
/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This comment
|
||||||
|
* suppresses an error found when Flow v0.54 was deployed. To see the error
|
||||||
|
* delete this comment and run Flow. */
|
||||||
|
Object.assign(props, {
|
||||||
|
onScroll: this._onScroll,
|
||||||
|
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
|
||||||
|
* comment suppresses an error when upgrading Flow's support for React.
|
||||||
|
* To see the error delete this comment and run Flow. */
|
||||||
|
// stickyHeaderIndices: this.props.stickyHeaderIndices.concat(stickySectionHeaderIndices,),
|
||||||
|
|
||||||
|
// Do not pass these events downstream to ScrollView since they will be
|
||||||
|
// registered in ListView's own ScrollResponder.Mixin
|
||||||
|
onKeyboardWillShow: undefined,
|
||||||
|
onKeyboardWillHide: undefined,
|
||||||
|
onKeyboardDidShow: undefined,
|
||||||
|
onKeyboardDidHide: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
return cloneReferencedElement(
|
||||||
|
<ScrollView {...props} />,
|
||||||
|
{
|
||||||
|
ref: this._setScrollComponentRef,
|
||||||
|
onContentSizeChange: this._onContentSizeChange,
|
||||||
|
onLayout: this._onLayout
|
||||||
|
},
|
||||||
|
header,
|
||||||
|
bodyComponents,
|
||||||
|
footer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ListView.DataSource = DataSource;
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Text, View } from 'react-native';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
@connect(state => ({
|
||||||
|
loading: state.messages.isFetching
|
||||||
|
}), null)
|
||||||
|
export default class Banner extends React.PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
loading: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (this.props.loading ? (
|
||||||
|
<View style={styles.bannerContainer}>
|
||||||
|
<Text style={styles.bannerText}>Loading new messages...</Text>
|
||||||
|
</View>
|
||||||
|
) : null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Text, View, Button, SafeAreaView } from 'react-native';
|
import { Text, View, Button, SafeAreaView } from 'react-native';
|
||||||
import { ListView } from 'realm/react-native';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
|
import equal from 'deep-equal';
|
||||||
|
|
||||||
|
import { ListView } from './ListView';
|
||||||
import * as actions from '../../actions';
|
import * as actions from '../../actions';
|
||||||
import { openRoom } from '../../actions/room';
|
import { openRoom } from '../../actions/room';
|
||||||
import { editCancel } from '../../actions/messages';
|
import { editCancel } from '../../actions/messages';
|
||||||
|
@ -18,8 +19,11 @@ import Typing from '../../containers/Typing';
|
||||||
import KeyboardView from '../../presentation/KeyboardView';
|
import KeyboardView from '../../presentation/KeyboardView';
|
||||||
import Header from '../../containers/Header';
|
import Header from '../../containers/Header';
|
||||||
import RoomsHeader from './Header';
|
import RoomsHeader from './Header';
|
||||||
|
import Banner from './banner';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
|
import debounce from '../../utils/debounce';
|
||||||
|
|
||||||
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1._id !== r2._id });
|
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1._id !== r2._id });
|
||||||
|
|
||||||
const typing = () => <Typing />;
|
const typing = () => <Typing />;
|
||||||
|
@ -45,8 +49,7 @@ export default class RoomView extends React.Component {
|
||||||
rid: PropTypes.string,
|
rid: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
Site_Url: PropTypes.string,
|
Site_Url: PropTypes.string,
|
||||||
Message_TimeFormat: PropTypes.string,
|
Message_TimeFormat: PropTypes.string
|
||||||
loading: PropTypes.bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static navigationOptions = ({ navigation }) => ({
|
static navigationOptions = ({ navigation }) => ({
|
||||||
|
@ -61,13 +64,15 @@ export default class RoomView extends React.Component {
|
||||||
this.name = this.props.name ||
|
this.name = this.props.name ||
|
||||||
this.props.navigation.state.params.name ||
|
this.props.navigation.state.params.name ||
|
||||||
this.props.navigation.state.params.room.name;
|
this.props.navigation.state.params.room.name;
|
||||||
|
this.opened = new Date();
|
||||||
this.data = database.objects('messages')
|
this.data = database
|
||||||
|
.objects('messages')
|
||||||
.filtered('rid = $0', this.rid)
|
.filtered('rid = $0', this.rid)
|
||||||
.sorted('ts', true);
|
.sorted('ts', true);
|
||||||
|
const rowIds = this.data.map((row, index) => index);
|
||||||
this.room = database.objects('subscriptions').filtered('rid = $0', this.rid);
|
this.room = database.objects('subscriptions').filtered('rid = $0', this.rid);
|
||||||
this.state = {
|
this.state = {
|
||||||
dataSource: ds.cloneWithRows([]),
|
dataSource: ds.cloneWithRows(this.data, rowIds),
|
||||||
loaded: true,
|
loaded: true,
|
||||||
joined: typeof props.rid === 'undefined'
|
joined: typeof props.rid === 'undefined'
|
||||||
};
|
};
|
||||||
|
@ -80,8 +85,8 @@ export default class RoomView extends React.Component {
|
||||||
this.props.openRoom({ rid: this.rid, name: this.name });
|
this.props.openRoom({ rid: this.rid, name: this.name });
|
||||||
this.data.addListener(this.updateState);
|
this.data.addListener(this.updateState);
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
this.updateState();
|
return !(equal(this.props, nextProps) && equal(this.state, nextState));
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
clearTimeout(this.timer);
|
clearTimeout(this.timer);
|
||||||
|
@ -90,9 +95,8 @@ export default class RoomView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onEndReached = () => {
|
onEndReached = () => {
|
||||||
const rowCount = this.state.dataSource.getRowCount();
|
|
||||||
if (
|
if (
|
||||||
rowCount &&
|
// rowCount &&
|
||||||
this.state.loaded &&
|
this.state.loaded &&
|
||||||
this.state.loadingMore !== true &&
|
this.state.loadingMore !== true &&
|
||||||
this.state.end !== true
|
this.state.end !== true
|
||||||
|
@ -100,22 +104,27 @@ export default class RoomView extends React.Component {
|
||||||
this.setState({
|
this.setState({
|
||||||
loadingMore: true
|
loadingMore: true
|
||||||
});
|
});
|
||||||
|
requestAnimationFrame(() => {
|
||||||
const lastRowData = this.data[rowCount - 1];
|
const lastRowData = this.data[this.data.length - 1];
|
||||||
RocketChat.loadMessagesForRoom(this.rid, lastRowData.ts, ({ end }) => {
|
if (!lastRowData) {
|
||||||
this.setState({
|
return;
|
||||||
loadingMore: false,
|
}
|
||||||
end
|
RocketChat.loadMessagesForRoom(this.rid, lastRowData.ts, ({ end }) => {
|
||||||
|
this.setState({
|
||||||
|
loadingMore: false,
|
||||||
|
end
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateState = () => {
|
updateState = debounce(() => {
|
||||||
|
const rowIds = this.data.map((row, index) => index);
|
||||||
this.setState({
|
this.setState({
|
||||||
dataSource: ds.cloneWithRows(this.data)
|
dataSource: this.state.dataSource.cloneWithRows(this.data, rowIds)
|
||||||
});
|
});
|
||||||
};
|
}, 50);
|
||||||
|
|
||||||
sendMessage = message => RocketChat.sendMessage(this.rid, message);
|
sendMessage = message => RocketChat.sendMessage(this.rid, message);
|
||||||
|
|
||||||
|
@ -126,17 +135,11 @@ export default class RoomView extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
renderBanner = () =>
|
renderItem = item => (
|
||||||
(this.props.loading ? (
|
|
||||||
<View style={styles.bannerContainer}>
|
|
||||||
<Text style={styles.bannerText}>Loading new messages...</Text>
|
|
||||||
</View>
|
|
||||||
) : null);
|
|
||||||
|
|
||||||
renderItem = ({ item }) => (
|
|
||||||
<Message
|
<Message
|
||||||
key={item._id}
|
key={item._id}
|
||||||
item={item}
|
item={item}
|
||||||
|
animate={this.opened.toISOString() < item.ts.toISOString()}
|
||||||
baseUrl={this.props.Site_Url}
|
baseUrl={this.props.Site_Url}
|
||||||
Message_TimeFormat={this.props.Message_TimeFormat}
|
Message_TimeFormat={this.props.Message_TimeFormat}
|
||||||
user={this.props.user}
|
user={this.props.user}
|
||||||
|
@ -169,17 +172,18 @@ export default class RoomView extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<KeyboardView contentContainerStyle={styles.container} keyboardVerticalOffset={64}>
|
<KeyboardView contentContainerStyle={styles.container} keyboardVerticalOffset={64}>
|
||||||
{this.renderBanner()}
|
|
||||||
|
<Banner />
|
||||||
<SafeAreaView style={styles.safeAreaView}>
|
<SafeAreaView style={styles.safeAreaView}>
|
||||||
<ListView
|
<ListView
|
||||||
enableEmptySections
|
enableEmptySections
|
||||||
style={styles.list}
|
style={styles.list}
|
||||||
onEndReachedThreshold={0.5}
|
onEndReachedThreshold={500}
|
||||||
renderFooter={this.renderHeader}
|
renderFooter={this.renderHeader}
|
||||||
renderHeader={typing}
|
renderHeader={typing}
|
||||||
onEndReached={this.onEndReached}
|
onEndReached={this.onEndReached}
|
||||||
dataSource={this.state.dataSource}
|
dataSource={this.state.dataSource}
|
||||||
renderRow={item => this.renderItem({ item })}
|
renderRow={item => this.renderItem(item)}
|
||||||
initialListSize={10}
|
initialListSize={10}
|
||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
keyboardDismissMode='interactive'
|
keyboardDismissMode='interactive'
|
||||||
|
|
|
@ -26,10 +26,12 @@
|
||||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||||
"babel-plugin-transform-remove-console": "^6.8.5",
|
"babel-plugin-transform-remove-console": "^6.8.5",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
"ejson": "^2.1.2",
|
"ejson": "^2.1.2",
|
||||||
"moment": "^2.20.1",
|
"moment": "^2.20.1",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react": "^16.2.0",
|
"react": "^16.2.0",
|
||||||
|
"react-clone-referenced-element": "^1.0.1",
|
||||||
"react-emojione": "^5.0.0",
|
"react-emojione": "^5.0.0",
|
||||||
"react-native": "^0.51.0",
|
"react-native": "^0.51.0",
|
||||||
"react-native-action-button": "^2.8.3",
|
"react-native-action-button": "^2.8.3",
|
||||||
|
|
Loading…
Reference in New Issue