fixed conf now up to date

This commit is contained in:
ue 2019-11-11 23:09:58 +03:00
commit d7afdc32da
31 changed files with 670 additions and 738 deletions

View File

@ -26,13 +26,15 @@ class BasicHeaderContainer extends Component {
if (isNewPost) {
navigation.navigate({
routeName: ROUTES.SCREENS.HOME,
routeName: ROUTES.SCREENS.FEED,
});
} else {
navigation.goBack();
}
if (handleOnBackPress) handleOnBackPress();
if (handleOnBackPress) {
handleOnBackPress();
}
};
render() {

View File

@ -21,7 +21,7 @@ import styles from './bottomTabBarStyles';
const _jumpTo = (route, index, routes, jumpTo) => {
const _routeName = routes[index].routeName;
if (!!get(route, 'params.scrollToTop') && _routeName === ROUTES.TABBAR.HOME) {
if (!!get(route, 'params.scrollToTop') && _routeName === ROUTES.TABBAR.FEED) {
route.params.scrollToTop();
}

View File

@ -12,8 +12,14 @@ export default EStyleSheet.create({
},
zIndex: 99,
},
dropdownWrapper: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
filterBarWrapper: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
rightIconWrapper: {
@ -24,4 +30,8 @@ export default EStyleSheet.create({
color: '$darkIconColor',
textAlign: 'center',
},
customOptionWrapper: {
left: 120,
position: 'absolute',
},
});

View File

@ -1,12 +1,12 @@
import React from 'react';
import { View, TouchableOpacity } from 'react-native';
import { View, Text, TouchableOpacity } from 'react-native';
import { Icon } from '../../icon';
// External Components
import { DropdownButton } from '../../dropdownButton';
// Components
import { LineBreak } from '../../basicUIElements';
import { LineBreak, Tag } from '../../basicUIElements';
// Styles
import styles from './filterBarStyles';
@ -27,18 +27,27 @@ const FilterBarView = ({
rightIconName,
rightIconType,
selectedOptionIndex,
customOption,
}) => (
<View style={styles.container}>
{!isHide && (
<LineBreak height={38}>
<View style={styles.filterBarWrapper}>
<DropdownButton
iconName={dropdownIconName}
options={options}
defaultText={defaultText}
onSelect={onDropdownSelect}
selectedOptionIndex={selectedOptionIndex}
/>
<View style={styles.dropdownWrapper}>
<DropdownButton
iconName={dropdownIconName}
options={options}
defaultText={defaultText}
onSelect={onDropdownSelect}
selectedOptionIndex={selectedOptionIndex}
/>
<View style={styles.customOptionWrapper}>
{customOption && (
<Tag value={customOption} isPin onPress={() => onDropdownSelect(3)} />
)}
</View>
</View>
{rightIconName && (
<TouchableOpacity
onPress={() => onRightIconPress && onRightIconPress()}

View File

@ -6,9 +6,9 @@ export default EStyleSheet.create({
borderTopRightRadius: 8,
marginTop: 16,
flexDirection: 'row',
backgroundColor: '$primaryLightBackground',
height: 60,
borderBottomWidth: 2,
backgroundColor: '$primaryWhiteLightBackground',
},
firstImage: {
width: 24,

View File

@ -1,80 +1,53 @@
import React, { PureComponent } from 'react';
import React from 'react';
import { withNavigation } from 'react-navigation';
import { connect } from 'react-redux';
import { get, has } from 'lodash';
import get from 'lodash/get';
import has from 'lodash/has';
// Component
import HeaderView from '../view/headerView';
/*
* Props Name Description Value
*@props --> props name here description here Value Type Here
*
*/
class HeaderContainer extends PureComponent {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycle Functions
// Component Functions
_handleOpenDrawer = () => {
const { navigation } = this.props;
import { AccountContainer, ThemeContainer } from '../../../containers';
const HeaderContainer = ({ selectedUser, isReverse, navigation, handleOnBackPress }) => {
const _handleOpenDrawer = () => {
if (has(navigation, 'openDrawer') && typeof get(navigation, 'openDrawer') === 'function') {
navigation.openDrawer();
}
};
_handleOnPressBackButton = () => {
const { navigation, handleOnBackPress } = this.props;
if (handleOnBackPress) handleOnBackPress();
const _handleOnPressBackButton = () => {
if (handleOnBackPress) {
handleOnBackPress();
}
navigation.goBack();
};
render() {
const {
isLoggedIn,
currentAccount,
selectedUser,
isReverse,
isLoginDone,
isDarkTheme,
} = this.props;
const _user = isReverse && selectedUser ? selectedUser : currentAccount;
return (
<ThemeContainer>
{({ isDarkTheme }) => (
<AccountContainer>
{({ currentAccount, isLoggedIn, isLoginDone }) => {
const _user = isReverse && selectedUser ? selectedUser : currentAccount;
const displayName = get(_user, 'display_name');
const username = get(_user, 'name');
const reputation = get(_user, 'reputation');
return (
<HeaderView
displayName={get(_user, 'display_name')}
handleOnPressBackButton={_handleOnPressBackButton}
handleOpenDrawer={_handleOpenDrawer}
isDarkTheme={isDarkTheme}
isLoggedIn={isLoggedIn}
isLoginDone={isLoginDone}
isReverse={isReverse}
reputation={get(_user, 'reputation')}
username={get(_user, 'name')}
/>
);
}}
</AccountContainer>
)}
</ThemeContainer>
);
};
return (
<HeaderView
handleOnPressBackButton={this._handleOnPressBackButton}
handleOpenDrawer={this._handleOpenDrawer}
isLoggedIn={isLoggedIn}
isReverse={isReverse}
isLoginDone={isLoginDone}
displayName={displayName}
username={username}
reputation={reputation}
isDarkTheme={isDarkTheme}
/>
);
}
}
const mapStateToProps = state => ({
isLoggedIn: state.application.isLoggedIn,
isLoginDone: state.application.isLoginDone,
isDarkTheme: state.application.isDarkTheme,
currentAccount: state.account.currentAccount,
});
export default connect(mapStateToProps)(withNavigation(HeaderContainer));
export default withNavigation(HeaderContainer);

View File

@ -7,7 +7,7 @@ export default EStyleSheet.create({
width: '$deviceWidth',
backgroundColor: '$primaryBackgroundColor',
flex: 1,
maxHeight: Platform.OS === 'ios' ? 95 : 80,
maxHeight: Platform.OS === 'ios' ? 105 : 80,
},
containerReverse: {
justifyContent: 'space-between',
@ -33,8 +33,7 @@ export default EStyleSheet.create({
titleWrapper: {
flexDirection: 'column',
justifyContent: 'center',
marginLeft: 8,
marginRight: 8,
marginHorizontal: 8,
},
title: {
fontSize: 14,

View File

@ -1,131 +1,107 @@
import React, { Component } from 'react';
import React, { useState } from 'react';
import { View, Text, SafeAreaView, TouchableOpacity } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import { injectIntl } from 'react-intl';
import { useIntl } from 'react-intl';
// Components
import { SearchModal } from '../../searchModal';
import { IconButton } from '../../iconButton';
import { UserAvatar } from '../../userAvatar';
// Styles
import styles from './headerStyles';
class HeaderView extends Component {
/* Props
* ------------------------------------------------
* @prop { boolean } hideStatusBar - Can declare status bar is hide or not.
*
*/
const HeaderView = ({
displayName,
handleOnPressBackButton,
handleOpenDrawer,
isDarkTheme,
isLoggedIn,
isLoginDone,
isReverse,
reputation,
username,
}) => {
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false);
const intl = useIntl();
let gradientColor;
constructor(props) {
super(props);
this.state = {
isSearchModalOpen: false,
};
if (isReverse) {
gradientColor = isDarkTheme ? ['#43638e', '#081c36'] : ['#357ce6', '#2d5aa0'];
} else {
gradientColor = isDarkTheme ? ['#081c36', '#43638e'] : ['#2d5aa0', '#357ce6'];
}
// Component Life Cycles
// Component Functions
_handleOnCloseSearch = () => {
this.setState({ isSearchModalOpen: false });
};
render() {
const {
displayName,
handleOnPressBackButton,
handleOpenDrawer,
intl,
isDarkTheme,
isLoggedIn,
isLoginDone,
isReverse,
reputation,
username,
} = this.props;
const { isSearchModalOpen } = this.state;
let gredientColor;
if (isReverse) {
gredientColor = isDarkTheme ? ['#43638e', '#081c36'] : ['#357ce6', '#2d5aa0'];
} else {
gredientColor = isDarkTheme ? ['#081c36', '#43638e'] : ['#2d5aa0', '#357ce6'];
}
return (
<SafeAreaView style={[styles.container, isReverse && styles.containerReverse]}>
<SearchModal
placeholder={intl.formatMessage({
id: 'header.search',
})}
isOpen={isSearchModalOpen}
handleOnClose={this._handleOnCloseSearch}
/>
<TouchableOpacity
style={styles.avatarWrapper}
onPress={() => handleOpenDrawer()}
disabled={isReverse}
return (
<SafeAreaView style={[styles.container, isReverse && styles.containerReverse]}>
<SearchModal
placeholder={intl.formatMessage({
id: 'header.search',
})}
isOpen={isSearchModalOpen}
handleOnClose={() => setIsSearchModalOpen(false)}
/>
<TouchableOpacity
style={styles.avatarWrapper}
onPress={handleOpenDrawer}
disabled={isReverse}
>
<LinearGradient
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
colors={gradientColor}
style={[
styles.avatarButtonWrapper,
isReverse ? styles.avatarButtonWrapperReverse : styles.avatarDefault,
]}
>
<LinearGradient
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
colors={gredientColor}
style={[
styles.avatarButtonWrapper,
isReverse ? styles.avatarButtonWrapperReverse : styles.avatarDefault,
]}
>
<UserAvatar
noAction
style={isReverse ? styles.reverseAvatar : styles.avatar}
username={username}
/>
</LinearGradient>
</TouchableOpacity>
{displayName || username ? (
<View style={styles.titleWrapper}>
{displayName && <Text style={styles.title}>{displayName}</Text>}
<Text style={styles.subTitle}>
{`@${username}`}
{reputation && ` (${reputation})`}
<UserAvatar
noAction
style={isReverse ? styles.reverseAvatar : styles.avatar}
username={username}
/>
</LinearGradient>
</TouchableOpacity>
{displayName || username ? (
<View style={styles.titleWrapper}>
{displayName && <Text style={styles.title}>{displayName}</Text>}
<Text style={styles.subTitle}>
{`@${username}`}
{reputation && ` (${reputation})`}
</Text>
</View>
) : (
<View style={styles.titleWrapper}>
{isLoginDone && !isLoggedIn && (
<Text style={styles.noAuthTitle}>
{intl.formatMessage({
id: 'header.title',
})}
</Text>
</View>
) : (
<View style={styles.titleWrapper}>
{isLoginDone && !isLoggedIn && (
<Text style={styles.noAuthTitle}>
{intl.formatMessage({
id: 'header.title',
})}
</Text>
)}
</View>
)}
{isReverse && (
<View style={styles.reverseBackButtonWrapper}>
<IconButton
style={styles.backButton}
iconStyle={styles.backIcon}
name="md-arrow-back"
onPress={() => handleOnPressBackButton()}
/>
</View>
)}
)}
</View>
)}
{!isReverse && (
<View style={styles.backButtonWrapper}>
<IconButton
iconStyle={styles.backIcon}
name="md-search"
onPress={() => this.setState({ isSearchModalOpen: true })}
/>
</View>
)}
</SafeAreaView>
);
}
}
{isReverse ? (
<View style={styles.reverseBackButtonWrapper}>
<IconButton
style={styles.backButton}
iconStyle={styles.backIcon}
name="md-arrow-back"
onPress={handleOnPressBackButton}
/>
</View>
) : (
<View style={styles.backButtonWrapper}>
<IconButton
iconStyle={styles.backIcon}
name="md-search"
onPress={() => setIsSearchModalOpen(true)}
/>
</View>
)}
</SafeAreaView>
);
};
export default injectIntl(HeaderView);
export default HeaderView;

View File

@ -120,6 +120,7 @@ export default EStyleSheet.create({
scrollContainer: {
flex: 1,
backgroundColor: '$primaryBackgroundColor',
marginBottom: 60,
},
popoverDetails: {
flexDirection: 'row',

View File

@ -1,94 +1,73 @@
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import get from 'lodash/get';
import React from 'react';
import { connect, useDispatch } from 'react-redux';
// Component
import PostsView from '../view/postsView';
// Container
import { AccountContainer } from '../../../containers';
// Actions
import { setFeedPosts } from '../../../redux/actions/postsAction';
import { hidePostsThumbnails } from '../../../redux/actions/uiAction';
/*
* Props Name Description Value
*@props --> props name here description here Value Type Here
*
*/
class PostsContainer extends PureComponent {
constructor(props) {
super(props);
this.state = {
promotedPosts: [],
};
}
// Component Life Cycle Functions
// Component Functions
_setFeedPosts = posts => {
const { dispatch } = this.props;
const PostsContainer = ({
changeForceLoadPostState,
feedPosts,
filterOptions,
forceLoadPost,
getFor,
handleOnScroll,
isConnected,
isHideImages,
pageType,
selectedOptionIndex,
tag,
nsfw,
filterOptionsValue,
customOption,
}) => {
const dispatch = useDispatch();
const _setFeedPosts = posts => {
dispatch(setFeedPosts(posts));
};
_handleImagesHide = () => {
const { dispatch, isHideImages } = this.props;
const _handleImagesHide = () => {
dispatch(hidePostsThumbnails(!isHideImages));
};
render() {
const {
changeForceLoadPostState,
currentAccount,
feedPosts,
filterOptions,
forceLoadPost,
getFor,
handleOnScroll,
isConnected,
isHideImages,
pageType,
selectedOptionIndex,
tag,
isLoginDone,
isLoggedIn,
nsfw,
} = this.props;
const { promotedPosts } = this.state;
return (
<PostsView
changeForceLoadPostState={changeForceLoadPostState}
currentAccountUsername={get(currentAccount, 'name', '')}
feedPosts={feedPosts}
filterOptions={filterOptions}
forceLoadPost={forceLoadPost}
getFor={getFor}
handleOnScroll={handleOnScroll}
handleImagesHide={this._handleImagesHide}
hidePostsThumbnails={hidePostsThumbnails}
isConnected={isConnected}
isHideImage={isHideImages}
pageType={pageType}
promotedPosts={promotedPosts}
selectedOptionIndex={selectedOptionIndex}
setFeedPosts={this._setFeedPosts}
tag={tag}
isLoginDone={isLoginDone}
isLoggedIn={isLoggedIn}
nsfw={nsfw}
/>
);
}
}
return (
<AccountContainer>
{({ username, isLoggedIn, isLoginDone }) => (
<PostsView
changeForceLoadPostState={changeForceLoadPostState}
currentAccountUsername={username}
feedPosts={feedPosts}
filterOptions={filterOptions}
forceLoadPost={forceLoadPost}
getFor={getFor}
handleImagesHide={_handleImagesHide}
handleOnScroll={handleOnScroll}
hidePostsThumbnails={hidePostsThumbnails}
isConnected={isConnected}
isHideImage={isHideImages}
isLoggedIn={isLoggedIn}
isLoginDone={isLoginDone}
nsfw={nsfw}
pageType={pageType}
selectedOptionIndex={selectedOptionIndex}
setFeedPosts={_setFeedPosts}
tag={tag}
filterOptionsValue={filterOptionsValue}
customOption={customOption}
/>
)}
</AccountContainer>
);
};
const mapStateToProps = state => ({
currentAccount: state.account.currentAccount,
isLoggedIn: state.application.isLoggedIn,
isLoginDone: state.application.isLoginDone,
nsfw: state.application.nsfw,
feedPosts: state.posts.feedPosts,
isConnected: state.application.isConnected,

View File

@ -1,7 +1,7 @@
/* eslint-disable react/jsx-wrap-multilines */
import React, { Component, Fragment } from 'react';
import React, { useState, Fragment, useEffect, useCallback } from 'react';
import { FlatList, View, ActivityIndicator, RefreshControl } from 'react-native';
import { injectIntl } from 'react-intl';
import { useIntl } from 'react-intl';
import { withNavigation } from 'react-navigation';
import { get, isEqual, unionWith } from 'lodash';
@ -13,272 +13,272 @@ import { getPromotePosts } from '../../../providers/esteem/esteem';
import { PostCard } from '../../postCard';
import { FilterBar } from '../../filterBar';
import { PostCardPlaceHolder, NoPost } from '../../basicUIElements';
import { POPULAR_FILTERS, PROFILE_FILTERS } from '../../../constants/options/filters';
import { ThemeContainer } from '../../../containers';
// Styles
import styles from './postsStyles';
import { default as ROUTES } from '../../../constants/routeNames';
class PostsView extends Component {
constructor(props) {
super(props);
this.state = {
posts: props.isConnected ? [] : props.feedPosts,
startAuthor: '',
startPermlink: '',
refreshing: false,
isLoading: false,
isShowFilterBar: true,
selectedFilterIndex: get(props, 'selectedOptionIndex', 0),
isNoPost: false,
promotedPosts: [],
scrollOffsetY: 0,
lockFilterBar: false,
};
}
// Component Functions
componentWillMount() {
const { navigation } = this.props;
navigation.setParams({
scrollToTop: this._scrollToTop,
});
}
async componentDidMount() {
const { isConnected, pageType } = this.props;
const PostsView = ({
filterOptions,
selectedOptionIndex,
isHideImage,
handleImagesHide,
feedPosts,
isConnected,
currentAccountUsername,
getFor,
tag,
nsfw,
setFeedPosts,
pageType,
isLoginDone,
isLoggedIn,
handleOnScroll,
navigation,
changeForceLoadPostState,
forceLoadPost,
filterOptionsValue,
customOption,
}) => {
const [posts, setPosts] = useState(isConnected ? [] : feedPosts);
const [startAuthor, setStartAuthor] = useState('');
const [startPermlink, setStartPermlink] = useState('');
const [refreshing, setRefreshing] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isShowFilterBar, setIsShowFilterBar] = useState(true);
const [selectedFilterIndex, setSelectedFilterIndex] = useState(selectedOptionIndex || 0);
const [isNoPost, setIsNoPost] = useState(false);
const [promotedPosts, setPromotedPosts] = useState([]);
const [scrollOffsetY, setScrollOffsetY] = useState(0);
const intl = useIntl();
useEffect(() => {
if (isConnected) {
if (pageType !== 'profiles') {
await this._getPromotePosts();
}
this._loadPosts();
} else {
this.setState({
refreshing: false,
isLoading: false,
});
const fetchPromotePost = async () => {
if (pageType !== 'profiles') {
await _getPromotePosts();
}
};
fetchPromotePost();
_loadPosts();
setRefreshing(false);
setIsLoading(false);
}
}
}, [
_getPromotePosts,
_loadPosts,
changeForceLoadPostState,
currentAccountUsername,
forceLoadPost,
isConnected,
pageType,
selectedOptionIndex,
]);
UNSAFE_componentWillReceiveProps(nextProps) {
const { currentAccountUsername, changeForceLoadPostState } = this.props;
useEffect(() => {
if (forceLoadPost) {
setPosts([]);
setStartAuthor('');
setStartPermlink('');
setRefreshing(false);
setIsLoading(false);
setSelectedFilterIndex(selectedOptionIndex || 0);
setIsNoPost(false);
if (
(currentAccountUsername &&
currentAccountUsername !== nextProps.currentAccountUsername &&
nextProps.currentAccountUsername) ||
nextProps.forceLoadPost
) {
// Set all initial data (New user new rules)
this.setState(
{
posts: [],
startAuthor: '',
startPermlink: '',
refreshing: false,
isLoading: false,
selectedFilterIndex: get(nextProps, 'selectedOptionIndex', 0),
isNoPost: false,
},
() => {
this._loadPosts();
if (changeForceLoadPostState) {
changeForceLoadPostState(false);
}
},
_loadPosts();
if (changeForceLoadPostState) {
changeForceLoadPostState(false);
}
}
}, [
_loadPosts,
changeForceLoadPostState,
currentAccountUsername,
forceLoadPost,
selectedOptionIndex,
]);
useEffect(() => {
if (!startAuthor && !startPermlink) {
_loadPosts(
filterOptions && filterOptions.length > 0 && filterOptionsValue[selectedFilterIndex],
);
}
}
}, [
_loadPosts,
filterOptions,
filterOptionsValue,
selectedFilterIndex,
startAuthor,
startPermlink,
]);
_getPromotePosts = async () => {
const { currentAccountUsername } = this.props;
const _handleOnDropdownSelect = async index => {
setSelectedFilterIndex(index);
setPosts([]);
setStartPermlink('');
setStartAuthor('');
setIsNoPost(false);
};
await getPromotePosts().then(async res => {
if (res && res.length) {
const promotedPosts = await Promise.all(
res.map(item =>
getPost(get(item, 'author'), get(item, 'permlink'), currentAccountUsername, true).then(
post => post,
const _getPromotePosts = useCallback(async () => {
await getPromotePosts()
.then(async res => {
if (res && res.length) {
const _promotedPosts = await Promise.all(
res.map(item =>
getPost(
get(item, 'author'),
get(item, 'permlink'),
currentAccountUsername,
true,
).then(post => post),
),
),
);
);
this.setState({ promotedPosts });
}
});
};
_scrollToTop = () => {
if (this.flatList) {
this.flatList.scrollToOffset({ x: 0, y: 0, animated: true });
}
};
_loadPosts = async () => {
const {
getFor,
tag,
currentAccountUsername,
pageType,
nsfw,
setFeedPosts,
isConnected,
} = this.props;
const {
posts,
startAuthor,
startPermlink,
refreshing,
selectedFilterIndex,
isLoading,
promotedPosts,
} = this.state;
const filter =
pageType === 'posts'
? POPULAR_FILTERS[selectedFilterIndex].toLowerCase()
: PROFILE_FILTERS[selectedFilterIndex].toLowerCase();
let options;
const limit = 3;
if (!isConnected) {
this.setState({
refreshing: false,
isLoading: false,
});
return null;
}
if (isLoading) {
return null;
}
this.setState({ isLoading: true });
if (tag || filter === 'feed' || filter === 'blog' || getFor === 'blog') {
options = {
tag,
limit,
};
} else if (filter === 'reblogs') {
options = {
tag,
limit,
};
} else {
options = {
limit,
};
}
if (startAuthor && startPermlink && !refreshing) {
options.start_author = startAuthor;
options.start_permlink = startPermlink;
}
getPostsSummary(filter, options, currentAccountUsername, nsfw)
.then(result => {
if (result.length > 0) {
let _posts = result;
if (filter === 'reblogs') {
for (let i = _posts.length - 1; i >= 0; i--) {
if (_posts[i].author === currentAccountUsername) {
_posts.splice(i, 1);
}
}
}
if (_posts.length > 0) {
if (posts.length > 0) {
if (refreshing) {
_posts = unionWith(_posts, posts, isEqual);
} else {
_posts.shift();
_posts = [...posts, ..._posts];
}
}
if (posts.length < 5) {
setFeedPosts(_posts);
}
// Promoted post start
if (promotedPosts && promotedPosts.length > 0) {
const insert = (arr, index, newItem) => [
...arr.slice(0, index),
newItem,
...arr.slice(index),
];
if (refreshing) {
_posts = _posts.filter(item => !item.is_promoted);
}
_posts.map((d, i) => {
if ([3, 6, 9].includes(i)) {
const ix = i / 3 - 1;
if (promotedPosts[ix] !== undefined) {
if (get(_posts, [i], {}).permlink !== promotedPosts[ix].permlink) {
_posts = insert(_posts, i, promotedPosts[ix]);
}
}
}
});
}
// Promoted post end
if (refreshing) {
this.setState({
posts: _posts,
});
} else if (!refreshing) {
this.setState({
posts: _posts,
startAuthor: result[result.length - 1] && result[result.length - 1].author,
startPermlink: result[result.length - 1] && result[result.length - 1].permlink,
});
}
this.setState({
refreshing: false,
isLoading: false,
});
}
} else if (result.length === 0) {
this.setState({ isNoPost: true });
setPromotedPosts(_promotedPosts);
}
})
.catch(() => {
this.setState({
refreshing: false,
.catch(() => {});
}, [currentAccountUsername]);
const _loadPosts = useCallback(
async type => {
if (isLoading) {
return;
} else {
setIsLoading(true);
}
const filter =
type ||
(filterOptions && filterOptions.length > 0 && filterOptionsValue[selectedFilterIndex]);
let options;
const limit = 3;
if (!isConnected) {
setRefreshing(false);
setIsLoading(false);
return null;
}
if (filter === 'feed' || filter === 'blog' || getFor === 'blog' || filter === 'reblogs') {
options = {
tag,
limit,
};
} else {
options = {
limit,
};
}
if (startAuthor && startPermlink && !refreshing) {
options.start_author = startAuthor;
options.start_permlink = startPermlink;
}
getPostsSummary(filter, options, currentAccountUsername, nsfw)
.then(result => {
if (result.length > 0) {
let _posts = result;
if (filter === 'reblogs') {
for (let i = _posts.length - 1; i >= 0; i--) {
if (_posts[i].author === currentAccountUsername) {
_posts.splice(i, 1);
}
}
}
if (_posts.length > 0) {
if (posts.length > 0) {
if (refreshing) {
_posts = unionWith(_posts, posts, isEqual);
} else {
_posts.shift();
_posts = [...posts, ..._posts];
}
}
if (posts.length < 5) {
setFeedPosts(_posts);
}
// Promoted post start
if (promotedPosts && promotedPosts.length > 0) {
const insert = (arr, index, newItem) => [
...arr.slice(0, index),
newItem,
...arr.slice(index),
];
if (refreshing) {
_posts = _posts.filter(item => !item.is_promoted);
}
_posts.map((d, i) => {
if ([3, 6, 9].includes(i)) {
const ix = i / 3 - 1;
if (promotedPosts[ix] !== undefined) {
if (get(_posts, [i], {}).permlink !== promotedPosts[ix].permlink) {
_posts = insert(_posts, i, promotedPosts[ix]);
}
}
}
});
}
// Promoted post end
if (refreshing) {
} else if (!refreshing) {
setStartAuthor(result[result.length - 1] && result[result.length - 1].author);
setStartPermlink(result[result.length - 1] && result[result.length - 1].permlink);
}
setPosts(_posts);
setRefreshing(false);
setIsLoading(false);
}
} else if (result.length === 0) {
setIsNoPost(true);
}
})
.catch(() => {
setRefreshing(false);
});
});
},
[
currentAccountUsername,
filterOptions,
filterOptionsValue,
getFor,
isConnected,
isLoading,
nsfw,
posts,
promotedPosts,
refreshing,
selectedFilterIndex,
setFeedPosts,
startAuthor,
startPermlink,
tag,
],
);
const _handleOnRefreshPosts = async () => {
setRefreshing(true);
if (pageType !== 'profiles') {
await _getPromotePosts();
}
_loadPosts();
};
_handleOnRefreshPosts = () => {
const { pageType } = this.props;
this.setState(
{
refreshing: true,
},
async () => {
if (pageType !== 'profiles') {
await this._getPromotePosts();
}
this._loadPosts();
},
);
};
_renderFooter = () => {
const { isLoading } = this.state;
const _renderFooter = () => {
if (isLoading) {
return (
<View style={styles.flatlistFooter}>
@ -286,29 +286,15 @@ class PostsView extends Component {
</View>
);
}
return null;
};
_handleOnDropdownSelect = async index => {
await this.setState({
selectedFilterIndex: index,
posts: [],
startAuthor: '',
startPermlink: '',
isNoPost: false,
});
this._loadPosts();
};
_handleOnPressLogin = () => {
const { navigation } = this.props;
const _handleOnPressLogin = () => {
navigation.navigate(ROUTES.SCREENS.LOGIN);
};
_renderEmptyContent = () => {
const { intl, getFor, isLoginDone, isLoggedIn, tag } = this.props;
const { isNoPost } = this.state;
const _renderEmptyContent = () => {
if (getFor === 'feed' && isLoginDone && !isLoggedIn) {
return (
<NoPost
@ -317,7 +303,7 @@ class PostsView extends Component {
defaultText={intl.formatMessage({
id: 'profile.login_to_see',
})}
handleOnButtonPress={this._handleOnPressLogin}
handleOnButtonPress={_handleOnPressLogin}
/>
);
}
@ -345,76 +331,68 @@ class PostsView extends Component {
);
};
_handleOnScroll = event => {
const { scrollOffsetY } = this.state;
const { handleOnScroll } = this.props;
const _handleOnScroll = event => {
const currentOffset = event.nativeEvent.contentOffset.y;
if (handleOnScroll) {
handleOnScroll();
}
this.setState({ scrollOffsetY: currentOffset });
this.setState({ isShowFilterBar: scrollOffsetY > currentOffset || scrollOffsetY <= 0 });
setScrollOffsetY(currentOffset);
setIsShowFilterBar(scrollOffsetY > currentOffset || scrollOffsetY <= 0);
};
render() {
const { refreshing, posts, isShowFilterBar } = this.state;
const { filterOptions, selectedOptionIndex, isHideImage, handleImagesHide } = this.props;
return (
<View style={styles.container}>
{filterOptions && isShowFilterBar && (
<FilterBar
dropdownIconName="arrow-drop-down"
options={filterOptions}
selectedOptionIndex={selectedOptionIndex}
defaultText={filterOptions[selectedOptionIndex]}
rightIconName="view-module"
rightIconType="MaterialIcons"
onDropdownSelect={this._handleOnDropdownSelect}
onRightIconPress={handleImagesHide}
/>
)}
<ThemeContainer>
{({ isDarkTheme }) => (
<FlatList
data={posts}
showsVerticalScrollIndicator={false}
renderItem={({ item }) =>
get(item, 'author', null) && (
<PostCard isRefresh={refreshing} content={item} isHideImage={isHideImage} />
)
}
keyExtractor={(content, i) => `${get(content, 'permlink', '')}${i.toString()}`}
onEndReached={() => this._loadPosts()}
removeClippedSubviews
refreshing={refreshing}
onRefresh={() => this._handleOnRefreshPosts()}
onEndThreshold={0}
initialNumToRender={10}
ListFooterComponent={this._renderFooter}
onScrollEndDrag={this._handleOnScroll}
ListEmptyComponent={this._renderEmptyContent}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={this._handleOnRefreshPosts}
progressBackgroundColor="#357CE6"
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
titleColor="#fff"
colors={['#fff']}
/>
}
ref={ref => {
this.flatList = ref;
}}
return (
<ThemeContainer>
{({ isDarkTheme }) => (
<View style={styles.container}>
{filterOptions && isShowFilterBar && (
<FilterBar
dropdownIconName="arrow-drop-down"
options={filterOptions}
selectedOptionIndex={selectedOptionIndex}
defaultText={filterOptions[selectedOptionIndex]}
rightIconName="view-module"
rightIconType="MaterialIcons"
onDropdownSelect={_handleOnDropdownSelect}
onRightIconPress={handleImagesHide}
customOption={customOption}
/>
)}
</ThemeContainer>
</View>
);
}
}
export default withNavigation(injectIntl(PostsView));
<FlatList
data={posts}
showsVerticalScrollIndicator={false}
renderItem={({ item }) =>
get(item, 'author', null) && (
<PostCard isRefresh={refreshing} content={item} isHideImage={isHideImage} />
)
}
keyExtractor={(content, i) => `${get(content, 'permlink', '')}${i.toString()}`}
onEndReached={_loadPosts}
removeClippedSubviews
refreshing={refreshing}
onRefresh={_handleOnRefreshPosts}
onEndThreshold={0}
initialNumToRender={10}
ListFooterComponent={_renderFooter}
onScrollEndDrag={_handleOnScroll}
ListEmptyComponent={_renderEmptyContent}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={_handleOnRefreshPosts}
progressBackgroundColor="#357CE6"
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
titleColor="#fff"
colors={['#fff']}
/>
}
/>
</View>
)}
</ThemeContainer>
);
};
export default withNavigation(PostsView);

View File

@ -15,7 +15,7 @@ import { TabBar } from '../tabBar';
import { Wallet } from '../wallet';
// Constants
import { PROFILE_FILTERS } from '../../constants/options/filters';
import { PROFILE_FILTERS, PROFILE_FILTERS_VALUE } from '../../constants/options/filters';
// Utils
import { getFormatedCreatedDate } from '../../utils/time';
@ -38,13 +38,17 @@ class ProfileView extends PureComponent {
_handleOnScroll = () => {
const { isSummaryOpen } = this.state;
if (isSummaryOpen) this.setState({ isSummaryOpen: false });
if (isSummaryOpen) {
this.setState({ isSummaryOpen: false });
}
};
_handleOnSummaryExpanded = () => {
const { isSummaryOpen } = this.state;
if (!isSummaryOpen) this.setState({ isSummaryOpen: true });
if (!isSummaryOpen) {
this.setState({ isSummaryOpen: true });
}
};
_handleUIChange = height => {
@ -156,7 +160,9 @@ class ProfileView extends PureComponent {
estimatedWalletValue: 0,
oldEstimatedWalletValue: estimatedWalletValue,
});
} else this.setState({ estimatedWalletValue: oldEstimatedWalletValue });
} else {
this.setState({ estimatedWalletValue: oldEstimatedWalletValue });
}
}}
>
<View
@ -167,6 +173,7 @@ class ProfileView extends PureComponent {
>
<Posts
filterOptions={PROFILE_FILTERS}
filterOptionsValue={PROFILE_FILTERS_VALUE}
selectedOptionIndex={0}
pageType="profiles"
getFor="blog"

View File

@ -15,5 +15,6 @@ export default EStyleSheet.create({
input: {
flex: 1,
minHeight: 50,
backgroundColor: '$primaryWhiteLightBackground',
},
});

View File

@ -1,10 +1,13 @@
export const POPULAR_FILTERS = [
'TRENDING',
'HOT',
'CREATED',
'ACTIVE',
'PROMOTED',
'VOTES',
'CHILDREN',
];
export const POPULAR_FILTERS = ['TRENDING', 'NEW', 'PROMOTED'];
export const POPULAR_FILTERS_VALUE = ['trending', 'created', 'promoted'];
export const PROFILE_FILTERS = ['BLOG', 'FEED'];
export const PROFILE_FILTERS_VALUE = ['blog', 'feed'];
// 'TRENDING',
// 'HOT',
// 'CREATED',
// 'ACTIVE',
// 'PROMOTED',
// 'VOTES',
// 'CHILDREN',

View File

@ -11,7 +11,7 @@ export default {
EDITOR: `Editor${SCREEN_SUFFIX}`,
FOLLOWS: `Follows${SCREEN_SUFFIX}`,
SPIN_GAME: `SpinGame${SCREEN_SUFFIX}`,
HOME: `Home${SCREEN_SUFFIX}`,
FEED: `Feed${SCREEN_SUFFIX}`,
LOGIN: `Login${SCREEN_SUFFIX}`,
PINCODE: `PinCode${SCREEN_SUFFIX}`,
POST: `Post${SCREEN_SUFFIX}`,
@ -29,7 +29,7 @@ export default {
MAIN: `Main${DRAWER_SUFFIX}`,
},
TABBAR: {
HOME: `Home${TABBAR_SUFFIX}`,
FEED: `Feed${TABBAR_SUFFIX}`,
NOTIFICATION: `Notification${TABBAR_SUFFIX}`,
POINTS: `Points${TABBAR_SUFFIX}`,
POST_BUTTON: `PostButton${TABBAR_SUFFIX}`,

View File

@ -0,0 +1,33 @@
/* eslint-disable no-unused-vars */
import React from 'react';
import { connect } from 'react-redux';
const AccountContainer = ({
accounts,
children,
currentAccount,
isLoggedIn,
isLoginDone,
username,
}) => {
return (
children &&
children({
accounts,
currentAccount,
isLoggedIn,
isLoginDone,
username,
})
);
};
const mapStateToProps = state => ({
accounts: state.account.otherAccounts,
currentAccount: state.account.currentAccount,
isLoggedIn: state.application.isLoggedIn,
isLoginDone: state.application.isLoginDone,
username: state.account.currentAccount.name,
});
export default connect(mapStateToProps)(AccountContainer);

View File

@ -1,3 +1,4 @@
import AccountContainer from './accountContainer';
import InAppPurchaseContainer from './inAppPurchaseContainer';
import PointsContainer from './pointsContainer';
import ProfileContainer from './profileContainer';
@ -8,6 +9,7 @@ import TransferContainer from './transferContainer';
import ThemeContainer from './themeContainer';
export {
AccountContainer,
InAppPurchaseContainer,
PointsContainer,
ProfileContainer,

View File

@ -6,13 +6,13 @@ import ROUTES from '../constants/routeNames';
// Components
import { Icon, IconContainer } from '../components/icon';
import { Home, Notification, Profile, Points } from '../screens';
import { Feed, Notification, Profile, Points } from '../screens';
import { PostButton, BottomTabBar } from '../components';
const BaseNavigator = createBottomTabNavigator(
{
[ROUTES.TABBAR.HOME]: {
screen: Home,
[ROUTES.TABBAR.FEED]: {
screen: Feed,
navigationOptions: () => ({
tabBarIcon: ({ tintColor }) => (
<Icon iconType="MaterialIcons" name="view-day" color={tintColor} size={26} />

View File

@ -31,7 +31,7 @@ import { SideMenu } from '../components';
const mainNavigation = createDrawerNavigator(
{
[ROUTES.SCREENS.HOME]: {
[ROUTES.SCREENS.FEED]: {
screen: BaseNavigator,
},
},

View File

@ -357,7 +357,13 @@ export const getSCAccessToken = code =>
api.post('/sc-token-refresh', { code }).then(resp => resolve(resp.data));
});
export const getPromotePosts = () => api.get('/promoted-posts').then(resp => resp.data);
export const getPromotePosts = () => {
try {
return api.get('/promoted-posts').then(resp => resp.data);
} catch (error) {
return error;
}
};
export const purchaseOrder = data => api.post('/purchase-order', data).then(resp => resp.data);

View File

@ -0,0 +1,4 @@
import Feed from './screen/feedScreen';
export { Feed };
export default Feed;

View File

@ -0,0 +1,43 @@
import React, { Fragment } from 'react';
import { SafeAreaView } from 'react-native';
import get from 'lodash/get';
// Components
import { Posts, Header } from '../../../components';
// Container
import { AccountContainer } from '../../../containers';
// Styles
import styles from './feedStyles';
import {
POPULAR_FILTERS,
PROFILE_FILTERS,
PROFILE_FILTERS_VALUE,
POPULAR_FILTERS_VALUE,
} from '../../../constants/options/filters';
const FeedScreen = () => {
return (
<AccountContainer>
{({ currentAccount, isLoggedIn }) => (
<Fragment>
<Header />
<SafeAreaView style={styles.container}>
<Posts
filterOptions={[...PROFILE_FILTERS, ...POPULAR_FILTERS]}
filterOptionsValue={[...PROFILE_FILTERS_VALUE, ...POPULAR_FILTERS_VALUE]}
getFor={isLoggedIn ? 'feed' : 'trending'}
selectedOptionIndex={isLoggedIn ? 1 : 2}
tag={get(currentAccount, 'name')}
customOption="HOT"
/>
</SafeAreaView>
</Fragment>
)}
</AccountContainer>
);
};
export default FeedScreen;

View File

@ -1,38 +0,0 @@
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
// Component
import HomeScreen from '../screen/homeScreen';
/*
* Props Name Description Value
*@props --> props name here description here Value Type Here
*
*/
class HomeContainer extends PureComponent {
constructor(props) {
super(props);
this.state = {};
}
render() {
const { isLoggedIn, isLoginDone, currentAccount } = this.props;
return (
<HomeScreen
isLoggedIn={isLoggedIn}
isLoginDone={isLoginDone}
currentAccount={currentAccount}
/>
);
}
}
const mapStateToProps = state => ({
isLoggedIn: state.application.isLoggedIn,
isLoginDone: state.application.isLoginDone,
currentAccount: state.account.currentAccount,
});
export default connect(mapStateToProps)(HomeContainer);

View File

@ -1,5 +0,0 @@
import HomeScreen from './screen/homeScreen';
import Home from './container/homeContainer';
export { HomeScreen, Home };
export default Home;

View File

@ -1,73 +0,0 @@
import React, { PureComponent, Fragment } from 'react';
import { View, SafeAreaView } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import { injectIntl } from 'react-intl';
// Components
import { TabBar, Posts, Header } from '../../../components';
// Styles
import styles from './homeStyles';
import globalStyles from '../../../globalStyles';
import { POPULAR_FILTERS, PROFILE_FILTERS } from '../../../constants/options/filters';
class HomeScreen extends PureComponent {
constructor(props) {
super(props);
this.state = {};
}
render() {
const { currentAccount, intl, isLoggedIn } = this.props;
return (
<Fragment>
<Header />
<SafeAreaView style={styles.container}>
<ScrollableTabView
style={globalStyles.tabView}
activeTab={!isLoggedIn ? 1 : 0}
renderTabBar={() => (
<TabBar
style={styles.tabbar}
tabUnderlineDefaultWidth={80}
tabUnderlineScaleX={2}
tabBarPosition="overlayTop"
/>
)}
>
<View
tabLabel={intl.formatMessage({
id: 'home.feed',
})}
style={styles.tabbarItem}
>
<Posts
filterOptions={PROFILE_FILTERS}
getFor={PROFILE_FILTERS[1].toLowerCase()}
tag={currentAccount.name}
selectedOptionIndex={1}
/>
</View>
<View
tabLabel={intl.formatMessage({
id: 'home.popular',
})}
style={styles.tabbarItem}
>
<Posts
filterOptions={POPULAR_FILTERS}
getFor={POPULAR_FILTERS[0].toLowerCase()}
selectedOptionIndex={0}
pageType="posts"
/>
</View>
</ScrollableTabView>
</SafeAreaView>
</Fragment>
);
}
}
export default injectIntl(HomeScreen);

View File

@ -2,7 +2,7 @@ import { Bookmarks } from './bookmarks';
import { Drafts } from './drafts';
import { Editor } from './editor';
import { Follows } from './follows';
import { Home } from './home';
import { Feed } from './feed';
import { Launch } from './launch';
import { Login } from './login';
import { Notification } from './notification';
@ -27,7 +27,7 @@ export {
Drafts,
Editor,
Follows,
Home,
Feed,
Launch,
Login,
Notification,

View File

@ -1,11 +1,11 @@
import React from 'react';
import { View } from 'react-native';
import LottieView from 'lottie-react-native';
import { initialMode as nativeThemeInitialMode } from 'react-native-dark-mode';
import styles from './launchStyles';
const LaunchScreen = () => (
<View style={styles.container}>
<View style={nativeThemeInitialMode !== 'dark' ? styles.container : styles.darkContainer}>
<LottieView source={require('./animation.json')} autoPlay loop={false} />
</View>
);

View File

@ -7,4 +7,10 @@ export default EStyleSheet.create({
alignItems: 'center',
backgroundColor: '$pureWhite',
},
darkContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1e2835',
},
});

View File

@ -108,7 +108,9 @@ class PinCodeContainer extends Component {
dispatch(updateCurrentAccount({ ..._currentAccount }));
this._savePinCode(pin);
if (callback) callback(pin, oldPinCode);
if (callback) {
callback(pin, oldPinCode);
}
dispatch(closePinCodeModal());
if (navigateTo) {
NavigationService.navigate({
@ -169,7 +171,9 @@ class PinCodeContainer extends Component {
setExistUser(true).then(() => {
this._savePinCode(pin);
if (callback) callback(pin, oldPinCode);
if (callback) {
callback(pin, oldPinCode);
}
dispatch(closePinCodeModal());
if (navigateTo) {
NavigationService.navigate({
@ -193,7 +197,7 @@ class PinCodeContainer extends Component {
} = this.props;
const { oldPinCode } = this.state;
// If the user is exist, we are just checking to pin and navigating to home screen
// If the user is exist, we are just checking to pin and navigating to feed screen
const pinData = {
pinCode: pin,
password: currentAccount ? currentAccount.password : '',

View File

@ -10,6 +10,13 @@ import { SearchInput, Posts, TabBar } from '../../../components';
import styles from './searchResultStyles';
import globalStyles from '../../../globalStyles';
import {
POPULAR_FILTERS,
PROFILE_FILTERS,
PROFILE_FILTERS_VALUE,
POPULAR_FILTERS_VALUE,
} from '../../../constants/options/filters';
class SearchResultScreen extends PureComponent {
constructor(props) {
super(props);
@ -46,7 +53,12 @@ class SearchResultScreen extends PureComponent {
})}
style={styles.tabbarItem}
>
<Posts pageType="posts" tag={tag} />
<Posts
key={tag}
filterOptions={POPULAR_FILTERS}
filterOptionsValue={POPULAR_FILTERS_VALUE}
tag={tag}
/>
</View>
</ScrollableTabView>
</View>