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:
parent
d21975b613
commit
7aa4fbd4a5
9 changed files with 99 additions and 23 deletions
|
|
@ -331,3 +331,10 @@ export function setChannelLoading(loading = true) {
|
|||
loading
|
||||
};
|
||||
}
|
||||
|
||||
export function setChannelRefreshing(refreshing = true) {
|
||||
return {
|
||||
type: ViewTypes.SET_CHANNEL_REFRESHING,
|
||||
refreshing
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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'}]
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
11
yarn.lock
11
yarn.lock
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue