RN-136 Post list pull to refresh (#558)

* Fix post list inverted issue

* Add pull to refresh to post list
This commit is contained in:
enahum 2017-05-22 08:09:52 -04:00 committed by GitHub
parent d21975b613
commit 7aa4fbd4a5
9 changed files with 99 additions and 23 deletions

View file

@ -331,3 +331,10 @@ export function setChannelLoading(loading = true) {
loading
};
}
export function setChannelRefreshing(refreshing = true) {
return {
type: ViewTypes.SET_CHANNEL_REFRESHING,
refreshing
};
}

View file

@ -1,18 +1,32 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {loadPostsIfNecessary, setChannelRefreshing} from 'app/actions/views/channel';
import {getTheme} from 'app/selectors/preferences';
import PostList from './post_list';
function mapStateToProps(state, ownProps) {
const {loading, refreshing} = state.views.channel;
return {
...ownProps,
channelIsLoading: state.views.channel.loading,
channelIsLoading: loading,
refreshing,
theme: getTheme(state)
};
}
export default connect(mapStateToProps)(PostList);
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
loadPostsIfNecessary,
setChannelRefreshing
}, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(PostList);

View file

@ -5,9 +5,10 @@ import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {
ListView,
StyleSheet,
RefreshControl,
View
} from 'react-native';
import InvertibleScrollView from 'react-native-invertible-scroll-view';
import {General, Posts} from 'mattermost-redux/constants';
import {addDatesToPostList} from 'mattermost-redux/utils/post_utils';
@ -22,6 +23,10 @@ const LOAD_MORE_POSTS = 'load-more-posts';
export default class PostList extends Component {
static propTypes = {
actions: PropTypes.shape({
loadPostsIfNecessary: PropTypes.func.isRequired,
setChannelRefreshing: PropTypes.func.isRequired
}).isRequired,
channel: PropTypes.object,
channelIsLoading: PropTypes.bool.isRequired,
posts: PropTypes.array.isRequired,
@ -31,6 +36,7 @@ export default class PostList extends Component {
isLoadingMore: PropTypes.bool,
showLoadMore: PropTypes.bool,
onPostPress: PropTypes.func,
refreshing: PropTypes.bool,
renderReplies: PropTypes.bool,
indicateNewMessages: PropTypes.bool,
currentUserId: PropTypes.string,
@ -53,6 +59,7 @@ export default class PostList extends Component {
componentWillReceiveProps(nextProps) {
if (nextProps.posts !== this.props.posts) {
this.props.actions.setChannelRefreshing(false);
const posts = this.getPostsWithDates(nextProps);
this.setState({posts});
}
@ -79,6 +86,15 @@ export default class PostList extends Component {
}
};
onRefresh = () => {
const {actions, channel} = this.props;
if (Object.keys(channel).length) {
actions.setChannelRefreshing(true);
actions.loadPostsIfNecessary(channel);
}
};
renderChannelIntro = () => {
const {channel, channelIsLoading, posts} = this.props;
@ -90,7 +106,7 @@ export default class PostList extends Component {
}
return (
<View style={style.row}>
<View>
<ChannelIntro/>
</View>
);
@ -107,7 +123,6 @@ export default class PostList extends Component {
return (
<NewMessagesDivider
theme={this.props.theme}
style={style.row}
/>
);
}
@ -116,7 +131,6 @@ export default class PostList extends Component {
<LoadMorePosts
loading={this.props.isLoadingMore}
theme={this.props.theme}
style={style.row}
/>
);
}
@ -128,7 +142,6 @@ export default class PostList extends Component {
return (
<DateHeader
theme={this.props.theme}
style={style.row}
date={date}
/>
);
@ -137,7 +150,6 @@ export default class PostList extends Component {
renderPost = (post) => {
return (
<Post
style={style.row}
post={post}
renderReplies={this.props.renderReplies}
isFirstReply={post.isFirstReply}
@ -149,29 +161,45 @@ export default class PostList extends Component {
);
};
renderRefreshControl = () => {
const {theme, refreshing} = this.props;
return (
<RefreshControl
refreshing={refreshing}
onRefresh={this.onRefresh}
tintColor={theme.centerChannelColor}
colors={[theme.centerChannelColor]}
/>
);
};
renderScrollComponent = (props) => {
return (
<InvertibleScrollView
{...props}
inverted={true}
/>
);
};
render() {
const {dataSource} = this.state;
return (
<ListView
style={style.container}
dataSource={this.state.dataSource.cloneWithRows(this.getPostsWithLoadMore())}
renderScrollComponent={this.renderScrollComponent}
dataSource={dataSource.cloneWithRows(this.getPostsWithLoadMore())}
renderFooter={this.renderChannelIntro}
renderRow={this.renderRow}
onEndReached={this.loadMore}
enableEmptySections={true}
showsVerticalScrollIndicator={false}
showsVerticalScrollIndicator={true}
initialListSize={30}
onEndReachedThreshold={200}
pageSize={10}
refreshControl={this.renderRefreshControl()}
/>
);
}
}
const style = StyleSheet.create({
container: {
transform: [{rotate: '180deg'}]
},
row: {
transform: [{rotate: '180deg'}]
}
});

View file

@ -34,6 +34,7 @@ const ViewTypes = keyMirror({
ADD_FILE_TO_FETCH_CACHE: null,
SET_CHANNEL_LOADER: null,
SET_CHANNEL_REFRESHING: null,
SET_LAST_CHANNEL_FOR_TEAM: null,

View file

@ -172,7 +172,17 @@ function loading(state = false, action) {
}
}
function refreshing(state = false, action) {
switch (action.type) {
case ViewTypes.SET_CHANNEL_REFRESHING:
return action.refreshing;
default:
return state;
}
}
export default combineReducers({
drafts,
loading
loading,
refreshing
});

View file

@ -29,6 +29,7 @@ class ChannelPostList extends PureComponent {
applicationInitializing: PropTypes.bool.isRequired,
channel: PropTypes.object.isRequired,
channelIsLoading: PropTypes.bool,
channelIsRefreshing: PropTypes.bool,
intl: intlShape.isRequired,
myMember: PropTypes.object.isRequired,
navigator: PropTypes.object,
@ -147,6 +148,7 @@ class ChannelPostList extends PureComponent {
applicationInitializing,
channel,
channelIsLoading,
channelIsRefreshing,
navigator,
posts,
postsRequests,
@ -162,7 +164,7 @@ class ChannelPostList extends PureComponent {
theme={theme}
/>
);
} else if (!applicationInitializing && !channelIsLoading && posts && (postsRequests.getPosts.status !== RequestStatus.STARTED || !this.state.didInitialPostsLoad)) {
} else if (!applicationInitializing && !channelIsLoading && posts && (postsRequests.getPosts.status !== RequestStatus.STARTED || channelIsRefreshing || !this.state.didInitialPostsLoad)) {
component = (
<PostList
posts={posts}

View file

@ -64,10 +64,12 @@ const getPostsInCurrentChannelWithReplyProps = createSelector(
);
function mapStateToProps(state, ownProps) {
const {loading, refreshing} = state.views.channel;
return {
...ownProps,
applicationInitializing: state.views.root.appInitializing,
channelIsLoading: state.views.channel.loading,
channelIsLoading: loading,
channelIsRefreshing: refreshing,
myMember: getMyCurrentChannelMembership(state),
postsRequests: state.requests.posts,
posts: getPostsInCurrentChannelWithReplyProps(state),

View file

@ -23,6 +23,7 @@
"react-native-device-info": "0.10.2",
"react-native-drawer": "2.3.0",
"react-native-image-picker": "jp928/react-native-image-picker#6ee35b69f3dbd6c7c66f580fd4d9eabf398703d4",
"react-native-invertible-scroll-view": "1.0.0",
"react-native-keyboard-aware-scroll-view": "0.2.8",
"react-native-linear-gradient": "2.0.0",
"react-native-navigation": "1.1.72",

View file

@ -4307,6 +4307,13 @@ react-native-image-picker@jp928/react-native-image-picker#6ee35b69f3dbd6c7c66f58
version "0.26.2"
resolved "https://codeload.github.com/jp928/react-native-image-picker/tar.gz/6ee35b69f3dbd6c7c66f580fd4d9eabf398703d4"
react-native-invertible-scroll-view@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-native-invertible-scroll-view/-/react-native-invertible-scroll-view-1.0.0.tgz#60ceb384dc950c34eba3a5aeda39f97cdc7d4e23"
dependencies:
react-clone-referenced-element "^1.0.1"
react-native-scrollable-mixin "^1.0.1"
react-native-keyboard-aware-scroll-view@0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.2.8.tgz#e9843c0d7467a2e6a2a737883bd9c2b7c7e38e35"
@ -4365,6 +4372,10 @@ react-native-push-notification@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/react-native-push-notification/-/react-native-push-notification-3.0.0.tgz#00282ea656443e89df6057f14b10500e7b89551f"
react-native-scrollable-mixin@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/react-native-scrollable-mixin/-/react-native-scrollable-mixin-1.0.1.tgz#34a32167b64248594154fd0d6a8b03f22740548e"
react-native-search-bar@enahum/react-native-search-bar.git:
version "2.16.0"
resolved "https://codeload.github.com/enahum/react-native-search-bar/tar.gz/88e6f5ba68012440ec21bde8388ca9e3124921c0"