Merge pull request #1030 from esteemapp/enhancment/posts

created scroll for filter bar && enhanced all flat list && other enha…
This commit is contained in:
Mustafa Buyukcelebi 2019-08-10 14:40:16 +03:00 committed by GitHub
commit 15be6906cc
14 changed files with 262 additions and 268 deletions

View File

@ -27,7 +27,6 @@ const WalletLineItem = ({
isHasdropdown,
dropdownOptions,
onDropdownSelect,
dropdownStyle,
}) => (
<GrayWrapper isGray={index && index % 2 !== 0}>
<View style={[styles.container, fitContent && styles.fitContent, style]}>

View File

@ -45,18 +45,15 @@ class LeaderboardView extends PureComponent {
id: 'notification.leaderboard_title',
})}
</Text>
{!users ? (
<ListPlaceHolder />
) : (
<FlatList
data={users}
refreshing={refreshing}
keyExtractor={item => get(item, '_id', Math.random()).toString()}
removeClippedSubviews={false}
onRefresh={() => fetchLeaderBoard()}
renderItem={({ item, index }) => this._renderItem(item, index)}
/>
)}
<FlatList
data={users}
refreshing={refreshing}
keyExtractor={item => get(item, '_id', Math.random()).toString()}
removeClippedSubviews={false}
ListEmptyComponent={<ListPlaceHolder />}
onRefresh={() => fetchLeaderBoard()}
renderItem={({ item, index }) => this._renderItem(item, index)}
/>
</View>
);
}

View File

@ -1,3 +1,4 @@
/* eslint-disable react/jsx-wrap-multilines */
import React, { PureComponent, Fragment } from 'react';
import { View, FlatList, ActivityIndicator, RefreshControl } from 'react-native';
import { injectIntl } from 'react-intl';
@ -168,38 +169,35 @@ class NotificationView extends PureComponent {
rightIconType="MaterialIcons"
onRightIconPress={readAllNotification}
/>
{_notifications.length === 0 ? (
<ListPlaceHolder />
) : (
<FlatList
data={_notifications}
refreshing={isNotificationRefreshing}
onRefresh={() => getActivities()}
keyExtractor={item => item.title}
onEndReached={() => getActivities(null, selectedFilter, true)}
ListFooterComponent={this._renderFooterLoading}
refreshControl={
<RefreshControl
refreshing={isNotificationRefreshing}
progressBackgroundColor="#357CE6"
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
titleColor="#fff"
colors={['#fff']}
<FlatList
data={_notifications}
refreshing={isNotificationRefreshing}
onRefresh={() => getActivities()}
keyExtractor={item => item.title}
onEndReached={() => getActivities(null, selectedFilter, true)}
ListFooterComponent={this._renderFooterLoading}
ListEmptyComponent={<ListPlaceHolder />}
refreshControl={
<RefreshControl
refreshing={isNotificationRefreshing}
progressBackgroundColor="#357CE6"
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
titleColor="#fff"
colors={['#fff']}
/>
}
renderItem={({ item, index }) => (
<Fragment>
<ContainerHeader
hasSeperator={index !== 0}
isBoldTitle
title={item.title}
key={item.title}
/>
}
renderItem={({ item, index }) => (
<Fragment>
<ContainerHeader
hasSeperator={index !== 0}
isBoldTitle
title={item.title}
key={item.title}
/>
{this._renderList(item.notifications)}
</Fragment>
)}
/>
)}
{this._renderList(item.notifications)}
</Fragment>
)}
/>
</View>
);
}

View File

@ -140,6 +140,7 @@ class PointsView extends Component {
<FlatList
style={styles.iconsList}
data={POINTS_KEYS}
keyExtractor={item => get(item, 'type', Math.random()).toString()}
horizontal
renderItem={({ item }) => (
<PopoverController key={get(item, 'type')}>
@ -192,27 +193,24 @@ class PointsView extends Component {
</View>
<View style={styles.listWrapper}>
{!userActivities ? (
this._renderLoading()
) : (
<FlatList
data={userActivities}
keyExtractor={item => item.id.toString()}
renderItem={({ item, index }) => (
<WalletLineItem
index={index + 1}
text={this._getTranslation(get(item, 'textKey'))}
description={getTimeFromNow(get(item, 'created'))}
isCircleIcon
isThin
isBlackText
iconName={get(item, 'icon')}
iconType={get(item, 'iconType')}
rightText={`${get(item, 'amount')} ESTM`}
/>
)}
/>
)}
<FlatList
data={userActivities}
keyExtractor={item => item.id.toString()}
ListEmptyComponent={this._renderLoading()}
renderItem={({ item, index }) => (
<WalletLineItem
index={index + 1}
text={this._getTranslation(get(item, 'textKey'))}
description={getTimeFromNow(get(item, 'created'))}
isCircleIcon
isThin
isBlackText
iconName={get(item, 'icon')}
iconType={get(item, 'iconType')}
rightText={`${get(item, 'amount')} ESTM`}
/>
)}
/>
</View>
</ScrollView>
</Fragment>

View File

@ -1,10 +1,9 @@
import React, { PureComponent, Fragment } from 'react';
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import get from 'lodash/get';
// Component
import PostsView from '../view/postsView';
import { PostCardPlaceHolder } from '../../basicUIElements';
// Actions
import { setFeedPosts } from '../../../redux/actions/postsAction';
@ -41,32 +40,40 @@ class PostsContainer extends PureComponent {
};
render() {
const { currentAccount, isLoginDone, tag, feedPosts, isConnected, isHideImages } = this.props;
const {
changeForceLoadPostState,
currentAccount,
feedPosts,
filterOptions,
forceLoadPost,
getFor,
handleOnScroll,
isConnected,
isHideImages,
pageType,
selectedOptionIndex,
tag,
} = this.props;
const { promotedPosts } = this.state;
if (!isLoginDone && !tag) {
return (
<Fragment>
<PostCardPlaceHolder />
<PostCardPlaceHolder />
</Fragment>
);
}
return (
<PostsView
promotedPosts={promotedPosts}
hidePostsThumbnails={hidePostsThumbnails}
handleOnScrollStart={this._handleOnScrollStart}
hanldeImagesHide={this._handleImagesHide}
isHideImage={isHideImages}
currentAccountUsername={
currentAccount && (get(currentAccount, 'username') || get(currentAccount, 'name'))
}
setFeedPosts={this._setFeedPosts}
changeForceLoadPostState={changeForceLoadPostState}
currentAccountUsername={get(currentAccount, 'name', '')}
feedPosts={feedPosts}
filterOptions={filterOptions}
forceLoadPost={forceLoadPost}
getFor={getFor}
handleOnScroll={handleOnScroll}
hanldeImagesHide={this._handleImagesHide}
hidePostsThumbnails={hidePostsThumbnails}
isConnected={isConnected}
{...this.props}
isHideImage={isHideImages}
pageType={pageType}
promotedPosts={promotedPosts}
selectedOptionIndex={selectedOptionIndex}
setFeedPosts={this._setFeedPosts}
tag={tag}
/>
);
}

View File

@ -28,10 +28,11 @@ class PostsView extends Component {
startPermlink: '',
refreshing: false,
isLoading: false,
isPostsLoading: true,
isShowFilterBar: true,
selectedFilterIndex: get(props, 'selectedOptionIndex', 0),
isNoPost: false,
promotedPosts: [],
scrollOffsetY: 0,
};
}
@ -45,15 +46,14 @@ class PostsView extends Component {
}
async componentDidMount() {
const { isConnected } = this.props;
const { isConnected, pageType } = this.props;
if (isConnected) {
await this._getPromotePosts();
if (pageType !== 'profiles') await this._getPromotePosts();
this._loadPosts();
} else {
this.setState({
refreshing: false,
isPostsLoading: false,
isLoading: false,
});
}
@ -76,7 +76,6 @@ class PostsView extends Component {
startPermlink: '',
refreshing: false,
isLoading: false,
isPostsLoading: false,
selectedFilterIndex: get(nextProps, 'selectedOptionIndex', 0),
isNoPost: false,
},
@ -92,14 +91,16 @@ class PostsView extends Component {
_getPromotePosts = async () => {
const { currentAccountUsername } = this.props;
await getPromotePosts().then(async res => {
const promotedPosts = [];
res &&
res.length > 0 &&
res.map(async item => {
if (res && res.length) {
res.forEach(async item => {
const post = await getPost(item.author, item.permlink, currentAccountUsername, true);
promotedPosts.push(post);
});
}
await this.setState({ promotedPosts });
});
@ -139,7 +140,6 @@ class PostsView extends Component {
if (!isConnected) {
this.setState({
refreshing: false,
isPostsLoading: false,
isLoading: false,
});
return null;
@ -220,7 +220,6 @@ class PostsView extends Component {
this.setState({
refreshing: false,
isPostsLoading: false,
isLoading: false,
});
}
@ -231,7 +230,6 @@ class PostsView extends Component {
.catch(() => {
this.setState({
refreshing: false,
isPostsLoading: false,
});
});
};
@ -262,7 +260,6 @@ class PostsView extends Component {
_handleOnDropdownSelect = async index => {
await this.setState({
isPostsLoading: true,
selectedFilterIndex: index,
posts: [],
startAuthor: '',
@ -277,16 +274,61 @@ class PostsView extends Component {
navigation.navigate(ROUTES.SCREENS.LOGIN);
};
_renderEmptyContent = () => {
const { intl, getFor, isLoginDone, isLoggedIn, tag } = this.props;
const { isNoPost } = this.state;
if (getFor === 'feed' && isLoginDone && !isLoggedIn) {
return (
<NoPost
imageStyle={styles.noImage}
isButtonText
defaultText={intl.formatMessage({
id: 'profile.login_to_see',
})}
handleOnButtonPress={this._handleOnPressLogin}
/>
);
}
if (isNoPost) {
return (
<NoPost
imageStyle={styles.noImage}
name={tag}
text={intl.formatMessage({
id: 'profile.havent_posted',
})}
defaultText={intl.formatMessage({
id: 'profile.login_to_see',
})}
/>
);
}
return (
<Fragment>
<PostCardPlaceHolder />
<PostCardPlaceHolder />
</Fragment>
);
};
_handleOnScroll = event => {
const { scrollOffsetY } = this.state;
const { handleOnScroll } = this.props;
const currentOffset = event.nativeEvent.contentOffset.y;
if (handleOnScroll) handleOnScroll();
this.setState({ scrollOffsetY: currentOffset });
this.setState({ isShowFilterBar: scrollOffsetY > currentOffset || scrollOffsetY <= 0 });
};
render() {
const { refreshing, posts, isPostsLoading, isNoPost } = this.state;
const { refreshing, posts, isShowFilterBar } = this.state;
const {
filterOptions,
selectedOptionIndex,
intl,
isLoggedIn,
getFor,
isLoginDone,
tag,
isDarkTheme,
isHideImage,
hanldeImagesHide,
@ -294,7 +336,7 @@ class PostsView extends Component {
return (
<View style={styles.container}>
{filterOptions && (
{filterOptions && isShowFilterBar && (
<FilterBar
dropdownIconName="arrow-drop-down"
options={filterOptions}
@ -306,67 +348,42 @@ class PostsView extends Component {
onRightIconPress={hanldeImagesHide}
/>
)}
<Fragment>
{getFor === 'feed' && isLoginDone && !isLoggedIn && (
<NoPost
imageStyle={styles.noImage}
isButtonText
defaultText={intl.formatMessage({
id: 'profile.login_to_see',
})}
handleOnButtonPress={this._handleOnPressLogin}
/>
<FlatList
data={posts}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<PostCard isRefresh={refreshing} content={item} isHideImage={isHideImage} />
)}
</Fragment>
{posts && posts.length > 0 && !isPostsLoading && (
<FlatList
data={posts}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<PostCard isRefresh={refreshing} content={item} isHideImage={isHideImage} />
)}
keyExtractor={(post, index) => index.toString()}
onEndReached={() => this._loadPosts()}
removeClippedSubviews
refreshing={refreshing}
onRefresh={() => this._handleOnRefreshPosts()}
onEndThreshold={0}
initialNumToRender={10}
ListFooterComponent={this._renderFooter}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={this._handleOnRefreshPosts}
progressBackgroundColor="#357CE6"
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
titleColor="#fff"
colors={['#fff']}
/>
}
ref={ref => {
this.flatList = ref;
}}
/>
)}
{isNoPost ? (
<NoPost
imageStyle={styles.noImage}
name={tag}
text={intl.formatMessage({
id: 'profile.havent_posted',
})}
defaultText={intl.formatMessage({
id: 'profile.login_to_see',
})}
/>
) : (
<Fragment>
<PostCardPlaceHolder />
<PostCardPlaceHolder />
</Fragment>
)}
keyExtractor={content => content.permlink}
onEndReached={() => this._loadPosts()}
removeClippedSubviews
refreshing={refreshing}
onRefresh={() => this._handleOnRefreshPosts()}
onEndThreshold={0}
initialNumToRender={10}
ListFooterComponent={this._renderFooter}
onScroll={this._handleOnScroll}
ListEmptyComponent={
<Fragment>
<PostCardPlaceHolder />
<PostCardPlaceHolder />
</Fragment>
}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={this._handleOnRefreshPosts}
progressBackgroundColor="#357CE6"
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
titleColor="#fff"
colors={['#fff']}
/>
}
ref={ref => {
this.flatList = ref;
}}
/>
</View>
);
}

View File

@ -137,7 +137,7 @@ class WalletContainer extends Component {
};
render() {
const { currentAccount, selectedUser, isDarkTheme } = this.props;
const { currentAccount, selectedUser, isDarkTheme, handleOnScroll } = this.props;
const { walletData, isClaiming, isRefreshing } = this.state;
return (
@ -150,6 +150,7 @@ class WalletContainer extends Component {
handleOnWalletRefresh={this._handleOnWalletRefresh}
isRefreshing={isRefreshing}
isDarkTheme={isDarkTheme}
handleOnScroll={handleOnScroll}
/>
);
}

View File

@ -1,3 +1,4 @@
/* eslint-disable react/jsx-wrap-multilines */
import React, { PureComponent, Fragment } from 'react';
import { View, Text, ScrollView, RefreshControl } from 'react-native';
import { injectIntl } from 'react-intl';
@ -53,10 +54,13 @@ class WalletView extends PureComponent {
selectedUsername,
walletData,
isDarkTheme,
handleOnScroll,
} = this.props;
return (
<ScrollView
onScroll={handleOnScroll && handleOnScroll}
style={styles.scrollView}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
@ -67,7 +71,6 @@ class WalletView extends PureComponent {
colors={['#fff']}
/>
}
style={styles.scrollView}
>
{!walletData ? (
<Fragment>

View File

@ -57,38 +57,38 @@ class BookmarksScreen extends Component {
}
};
_getTabItem = (data, type) => {
_renderEmptyContent = () => {
const { isLoading, intl } = this.props;
const isNoItem = (data && data.length === 0) || !data;
const placeHolder =
type === 'bookmarks' ? <PostCardPlaceHolder /> : <WalletDetailsPlaceHolder />;
if (isLoading) {
return <WalletDetailsPlaceHolder />;
}
return (
<Text style={globalStyles.hintText}>
{intl.formatMessage({
id: 'bookmarks.empty_list',
})}
</Text>
);
};
_getTabItem = (data, type) => {
const isFavorites = type === 'favorites';
return (
<View style={styles.container}>
{isNoItem && !isLoading && (
<Text style={globalStyles.hintText}>
{intl.formatMessage({
id: 'bookmarks.empty_list',
})}
</Text>
)}
{isLoading ? (
<View>{placeHolder}</View>
) : (
!isNoItem && (
<FlatList
data={data.map(item =>
item._id !== data[item._id] && isFavorites
? item.account !== data[item.account] && item
: item,
)}
keyExtractor={item => item._id}
removeClippedSubviews={false}
renderItem={({ item, index }) => this._renderItem(item, index, type)}
/>
)
)}
<FlatList
data={data.map(item =>
item._id !== data[item._id] && isFavorites
? item.account !== data[item.account] && item
: item,
)}
keyExtractor={item => item._id}
removeClippedSubviews={false}
renderItem={({ item, index }) => this._renderItem(item, index, type)}
ListEmptyComponent={this._renderEmptyContent()}
/>
</View>
);
};

View File

@ -1,3 +1,4 @@
/* eslint-disable react/jsx-wrap-multilines */
import React, { Component } from 'react';
import { injectIntl } from 'react-intl';
import { View, FlatList, Text } from 'react-native';
@ -66,38 +67,39 @@ class DraftsScreen extends Component {
);
};
_getTabItem = (data, type) => {
_renderEmptyContent = () => {
const { isLoading, intl } = this.props;
const isNoItem = (data && data.length === 0) || !data;
if (isLoading) {
return (
<View>
<PostCardPlaceHolder />
<PostCardPlaceHolder />
</View>
);
}
return (
<View style={globalStyles.lightContainer}>
{isNoItem && !isLoading && (
<Text style={globalStyles.hintText}>
{intl.formatMessage({
id: 'drafts.empty_list',
})}
</Text>
)}
{isLoading ? (
<View>
<PostCardPlaceHolder />
<PostCardPlaceHolder />
</View>
) : (
!isNoItem && (
<FlatList
data={data}
keyExtractor={item => item._id}
removeClippedSubviews={false}
renderItem={({ item }) => this._renderItem(item, type)}
/>
)
)}
</View>
<Text style={globalStyles.hintText}>
{intl.formatMessage({
id: 'drafts.empty_list',
})}
</Text>
);
};
_getTabItem = (data, type) => (
<View style={globalStyles.lightContainer}>
<FlatList
data={data}
keyExtractor={item => item._id}
removeClippedSubviews={false}
renderItem={({ item }) => this._renderItem(item, type)}
ListEmptyComponent={this._renderEmptyContent()}
/>
</View>
);
render() {
const { drafts, schedules, intl, moveScheduleToDraft } = this.props;
const { selectedId } = this.state;

View File

@ -1,5 +1,6 @@
/* eslint-disable react/jsx-wrap-multilines */
import React, { PureComponent } from 'react';
import { View, Text, FlatList, ActivityIndicator } from 'react-native';
import { View, Text, FlatList } from 'react-native';
import { injectIntl } from 'react-intl';
// Constants
@ -33,46 +34,30 @@ class FollowsScreen extends PureComponent {
return <UserListItem index={index} username={username} />;
};
_renderFooter = () => {
const { isLoading } = this.props;
if (isLoading) {
return (
<View style={styles.flatlistFooter}>
<ActivityIndicator animating size="large" />
</View>
);
}
return null;
};
render() {
const { loadMore, data, isFollowing, count, handleSearch, intl } = this.props;
const title = intl.formatMessage({
id: !isFollowing ? 'profile.follower' : 'profile.following',
});
const headerTitle = `${title} (${count})`;
return (
<View style={styles.container}>
<BasicHeader title={headerTitle} isHasSearch handleOnSearch={handleSearch} />
{data && data.length > 0 ? (
<FlatList
data={data}
keyExtractor={(item, index) => index.toString()}
onEndReached={() => loadMore()}
removeClippedSubviews={false}
renderItem={({ item, index }) => this._renderItem(item, index)}
// ListFooterComponent={this._renderFooter}
/>
) : (
<Text style={styles.text}>
{intl.formatMessage({
id: 'voters.no_user',
})}
</Text>
)}
<FlatList
data={data}
keyExtractor={(item, index) => index.toString()}
onEndReached={() => loadMore()}
removeClippedSubviews={false}
renderItem={({ item, index }) => this._renderItem(item, index)}
ListEmptyComponent={
<Text style={styles.text}>
{intl.formatMessage({
id: 'voters.no_user',
})}
</Text>
}
/>
</View>
);
}

View File

@ -52,7 +52,6 @@ class HomeScreen extends PureComponent {
getFor={PROFILE_FILTERS[1].toLowerCase()}
tag={tag || currentAccount.name}
selectedOptionIndex={1}
pageType="profiles"
/>
</View>
<View

View File

@ -207,7 +207,7 @@ class ProfileScreen extends PureComponent {
getFor="blog"
tag={username}
key={username}
handleOnScroll={this._handleOnScroll}
handleOnScroll={isSummaryOpen ? this._handleOnScroll : null}
forceLoadPost={forceLoadPost}
changeForceLoadPostState={changeForceLoadPostState}
/>
@ -225,7 +225,7 @@ class ProfileScreen extends PureComponent {
style={styles.commentsTabBar}
>
{comments && comments.length > 0 ? (
<ScrollView>
<ScrollView onScroll={this._handleOnScroll}>
<Comments isProfilePreview comments={comments} fetchPost={getReplies} />
</ScrollView>
) : (
@ -253,6 +253,7 @@ class ProfileScreen extends PureComponent {
<Wallet
setEstimatedWalletValue={this._setEstimatedWalletValue}
selectedUser={selectedUser}
handleOnScroll={isSummaryOpen ? this._handleOnScroll : null}
/>
) : (
<WalletDetailsPlaceHolder />

View File

@ -50,19 +50,6 @@ class SearchResultScreen extends PureComponent {
>
<Posts pageType="posts" tag={tag} />
</View>
{/* <View
tabLabel={intl.formatMessage({
id: 'search.comments',
})}
style={styles.tabbarItem}
>
<Posts
filterOptions={POPULAR_FILTERS}
getFor={POPULAR_FILTERS[0].toLowerCase()}
selectedOptionIndex={0}
pageType="posts"
/>
</Fragment> */}
</ScrollableTabView>
</View>
);