Merge pull request #79 from esteemapp/feature/postScreen

[Feature] Post Screen
This commit is contained in:
Feruz M 2018-11-01 00:37:14 +05:30 committed by GitHub
commit f43675648c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1454 additions and 405 deletions

View File

@ -1,21 +1,27 @@
import Card from './view/cardView';
// import Card from './view/cardView';
import Chip from './view/chipView';
import GrayWrapper from './view/grayWrapperView';
import LineBreak from './view/lineBreakView';
import NoPost from './view/noPostView';
import PostCardPlaceHolder from './view/postCardPlaceHolderView';
import PostPlaceHolder from './view/postPlaceHolderView';
import ProfileSummaryPlaceHolder from './view/profileSummaryPlaceHolder';
import Tag from './view/tagView';
import TextWithIcon from './view/textWithIconView';
import WalletLineItem from './view/walletLineItemView';
import Chip from './view/chipView';
import ProfileSummaryPlaceHolder from './view/profileSummaryPlaceHolder';
import StickyBar from './view/stickyBarView';
export {
Card,
GrayWrapper,
// Card,
StickyBar,
Chip,
GrayWrapper,
LineBreak,
NoPost,
PostCardPlaceHolder,
PostPlaceHolder,
ProfileSummaryPlaceHolder,
Tag,
TextWithIcon,
WalletLineItem,
ProfileSummaryPlaceHolder,
};

View File

@ -0,0 +1,28 @@
import React from 'react';
import { View } from 'react-native';
import Placeholder from 'rn-placeholder';
import styles from './postCardPlaceHolderStyles';
const PostCardPlaceHolder = () => (
<View style={styles.container}>
<View style={styles.textWrapper}>
<Placeholder.Media size={25} hasRadius animate="fade" />
<Placeholder.Line width="30%" lastLineWidth="30%" animate="fade" />
</View>
<Placeholder.Box animate="fade" height={200} width="100%" radius={5} />
<View style={styles.paragraphWrapper}>
<Placeholder.Paragraph
lineNumber={3}
textSize={16}
lineSpacing={5}
width="100%"
lastLineWidth="70%"
firstLineWidth="50%"
animate="fade"
/>
</View>
</View>
);
export default PostCardPlaceHolder;

View File

@ -2,18 +2,26 @@ import React from 'react';
import { View } from 'react-native';
import Placeholder from 'rn-placeholder';
import styles from './postPlaceHolderStyles';
import styles from './postCardPlaceHolderStyles';
const PostPlaceHolder = () => (
<View style={styles.container}>
<View style={styles.textWrapper}>
<Placeholder.Media size={25} hasRadius animate="fade" />
<Placeholder.Line width="30%" lastLineWidth="30%" animate="fade" />
<View>
<View style={styles.paragraphWrapper}>
<Placeholder.Paragraph
lineNumber={2}
textSize={16}
lineSpacing={5}
width="100%"
lastLineWidth="70%"
firstLineWidth="50%"
animate="fade"
/>
</View>
<View style={styles.paragraphWrapper} />
<Placeholder.Box animate="fade" height={200} width="100%" radius={5} />
<View style={styles.paragraphWrapper}>
<Placeholder.Paragraph
lineNumber={3}
lineNumber={18}
textSize={16}
lineSpacing={5}
width="100%"

View File

@ -0,0 +1,21 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: '$white',
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'space-between',
width: '$deviceWidth',
height: 50,
shadowOpacity: 0.2,
shadowOffset: {
height: 1.5,
},
},
fixedFooter: {
position: 'absolute',
bottom: 0,
},
});

View File

@ -0,0 +1,9 @@
import React from 'react';
import { View } from 'react-native';
import styles from './stickyBarStyles';
const StickyBar = ({ children, isFixedFooter }) => (
<View style={[styles.container, isFixedFooter && styles.fixedFooter]}>{children}</View>
);
export default StickyBar;

View File

@ -0,0 +1,19 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
text: {
color: '$white',
fontSize: 10,
},
isPin: {
backgroundColor: '$primaryBlue',
},
textWrapper: {
paddingHorizontal: 10,
justifyContent: 'center',
marginRight: 8,
height: 15,
backgroundColor: '$iconColor',
borderRadius: 50,
},
});

View File

@ -0,0 +1,15 @@
import React, { Fragment } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import styles from './tagStyles';
const Tag = ({ onPress, isPin, value }) => (
<Fragment>
<TouchableOpacity onPress={() => onPress && onPress(value)}>
<View style={[styles.textWrapper, isPin && styles.isPin]}>
<Text style={[styles.text]}>{value}</Text>
</View>
</TouchableOpacity>
</Fragment>
);
export default Tag;

View File

@ -10,12 +10,13 @@ export default EStyleSheet.create({
alignSelf: 'flex-start',
},
icon: {
color: '#c1c5c7',
color: '$iconColor',
fontSize: 12,
marginRight: 3,
},
text: {
color: '#788187',
color: '$primaryDarkGray',
alignSelf: 'center',
fontSize: 11,
},
});

View File

@ -1,22 +1,22 @@
import React from 'react';
import { View, TouchableHighlight, Text } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { Icon } from '../../icon';
import styles from './textWithIconStyles';
const TextWithIcon = ({
iconName, text, isClickable, onPress,
iconName, text, isClickable, onPress, iconStyle, iconType,
}) => (
<View style={styles.container}>
{isClickable || onPress ? (
<TouchableHighlight underlayColor="transparent" onPress={() => onPress && onPress()}>
<View style={styles.wrapper}>
{text && <Ionicons style={styles.icon} name={iconName} />}
<Text style={styles.text}>{text}</Text>
<Icon style={[styles.icon, iconStyle]} name={iconName} iconType={iconType} />
<Text style={[styles.text]}>{text}</Text>
</View>
</TouchableHighlight>
) : (
<View style={styles.wrapper}>
{text && <Ionicons style={styles.icon} name={iconName} />}
{text && <Icon style={[styles.icon, iconStyle]} name={iconName} iconType={iconType} />}
<Text style={styles.text}>{text}</Text>
</View>
)}

View File

@ -0,0 +1,65 @@
import React, { Component } from 'react';
import { getComments } from '../../../providers/steem/dsteem';
// Services and Actions
// Middleware
// Constants
// Utilities
// Component
import { CommentsView } from '..';
/*
* Props Name Description Value
*@props --> props name here description here Value Type Here
*
*/
class CommentsContainer extends Component {
constructor(props) {
super(props);
this.state = {
comments: [],
};
}
// Component Life Cycle Functions
componentDidMount() {
const { author, permlink } = this.props;
getComments(author, permlink)
.then((comments) => {
this.setState({
comments,
});
console.log(comments);
})
.catch((error) => {
alert(error);
});
}
// Component Functions
_handleOnReplyPress = () => {
alert(
'Reply functions not working yet. Thank you for your understanding. Your friends at eSteem :)',
);
};
render() {
const { comments } = this.state;
return (
<CommentsView
handleOnReplyPress={this._handleOnReplyPress}
comments={comments}
{...this.props}
/>
);
}
}
export default CommentsContainer;

View File

@ -0,0 +1,5 @@
import CommentsView from './view/commentsView';
import Comments from './container/commentsContainer';
export { CommentsView, Comments };
export default Comments;

View File

@ -0,0 +1,8 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
text: {
color: '$primaryBlack',
fontSize: 10,
},
});

View File

@ -0,0 +1,142 @@
import React, { Component, Fragment } from 'react';
import { View, FlatList, Text } from 'react-native';
// Constants
// Components
import { Comments } from '..';
import { PostBody, PostHeaderDescription } from '../../postElements';
import { Upvote } from '../../upvote';
import { IconButton } from '../../iconButton';
// Styles
// import styles from './commentStyles';
class CommentsView extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
_handleOnDropdownSelect = () => {};
_keyExtractor = (item, index) => item.permlink;
render() {
const {
comments,
avatarSize,
marginLeft,
handleOnUserPress,
currentUser,
commentNumber,
handleOnReplyPress,
} = this.props;
// commentNumber === 8 && alert('sekkiz:');
return (
<View>
{!!comments && (
<FlatList
data={comments}
keyExtractor={this._keyExtractor}
renderItem={({ item, index }) => (
<View key={index}>
<PostHeaderDescription
key={item.permlink}
date={item.created}
name={item.author}
reputation={item.author_reputation}
avatar={item.avatar}
size={avatarSize || 24}
/>
<View
style={{
marginLeft: marginLeft || 35,
flexDirection: 'column',
marginTop: -10,
}}
>
<PostBody isComment handleOnUserPress={handleOnUserPress} body={item.body} />
<View style={{ flexDirection: 'row' }}>
<Upvote isShowpayoutValue content={item} user={currentUser} isLoggedIn />
<IconButton
iconStyle={{ color: '#c1c5c7' }}
style={{ marginLeft: 20 }}
name="reply"
onPress={() => handleOnReplyPress && handleOnReplyPress()}
iconType="FontAwesome"
/>
</View>
</View>
<View style={{ marginLeft: marginLeft || 32 }}>
{commentNumber !== 8 && (
<Comments
commentNumber={commentNumber ? commentNumber * 2 : 1}
marginLeft={20}
avatarSize={avatarSize || 16}
author={item.author}
permlink={item.permlink}
/>
)}
</View>
</View>
)}
/>
)}
{/* {comments
&& comments.map((comment, i) => (
<View key={i}>
<PostHeaderDescription
key={item.permlink}
date={item.created}
name={item.author}
reputation={item.author_reputation}
avatar={item.avatar}
size={avatarSize || 24}
/>
<View
style={{
marginLeft: marginLeft || 35,
flexDirection: 'column',
marginTop: -15,
}}
>
<PostBody isComment handleOnUserPress={handleOnUserPress} body={item.body} />
<View style={{ flexDirection: 'row' }}>
<Upvote isShowpayoutValue content={comment} user={currentUser} isLoggedIn />
<IconButton
iconStyle={{ color: '#c1c5c7' }}
style={{ marginLeft: 20 }}
name="reply"
onPress={() => handleOnReplyPress && handleOnReplyPress()}
iconType="FontAwesome"
/>
</View>
</View>
<View style={{ marginLeft: marginLeft || 32 }}>
{commentNumber !== 8 && (
<Comments
commentNumber={commentNumber ? commentNumber * 2 : 1}
marginLeft={20}
avatarSize={avatarSize || 16}
author={item.author}
permlink={item.permlink}
/>
)}
</View>
</View>
))} */}
</View>
);
}
}
export default CommentsView;

View File

@ -0,0 +1,25 @@
import React, { Component } from 'react';
import { CommentsDisplayView } from '..';
/*
* Props Name Description Value
*@props --> props name here description here Value Type Here
*
*/
class CommentsContainer extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycle Functions
// Component Functions
render() {
return <CommentsDisplayView {...this.props} />;
}
}
export default CommentsContainer;

View File

@ -0,0 +1,5 @@
import CommentsDisplayView from './view/commentsDisplayView';
import CommentsDisplay from './container/commentsDisplayContainer';
export { CommentsDisplayView, CommentsDisplay };
export default CommentsDisplay;

View File

@ -0,0 +1,56 @@
import React, { Component, Fragment } from 'react';
import { View } from 'react-native';
// Constants
// Components
import { FilterBar } from '../../filterBar';
import { Comments } from '../../comments';
// Styles
// import styles from './commentsDisplayStyles';
class CommentsDisplayView extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
_handleOnDropdownSelect = () => {
alert('This feature not read. Thanks for understanding.');
};
render() {
const {
currentUser, author, permlink, commentCount,
} = this.props;
return (
<Fragment>
{commentCount > 0 && (
<Fragment>
<FilterBar
dropdownIconName="md-arrow-dropdown"
options={['NEW COMMENTS', 'VOTES', 'REPLIES', 'MENTIONS', 'FOLLOWS', 'REBLOGS']}
defaultText="NEW COMMENTS"
onDropdownSelect={this._handleOnDropdownSelect}
/>
<View style={{ padding: 16 }}>
<Comments currentUser={currentUser} author={author} permlink={permlink} />
</View>
</Fragment>
)}
</Fragment>
);
}
}
export default CommentsDisplayView;

View File

@ -72,7 +72,7 @@ export default class TagAreaView extends Component {
};
render() {
const { chipsData, isPreviewActive } = this.props;
const { isPreviewActive } = this.props;
const { chips } = this.state;
return (

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { withNavigation } from 'react-navigation';
// Constants
import { default as ROUTES } from '../../../constants/routeNames';
// import { default as ROUTES } from '../../../constants/routeNames';
// Components
import { EditorHeaderView } from '..';
@ -24,7 +24,7 @@ class EditorHeaderContainer extends Component {
_handleOnPressBackButton = () => {
const { navigation } = this.props;
navigation.navigate(ROUTES.SCREENS.HOME);
navigation.goBack();
};
render() {

View File

@ -8,13 +8,18 @@ export default EStyleSheet.create({
padding: 16,
width: '$deviceWidth',
backgroundColor: '$white',
alignItems: 'center',
},
backIcon: {
fontSize: 24,
color: '$iconColor',
},
backWrapper: {
flexGrow: 2,
flexDirection: 'row',
alignItems: 'center',
},
quickTitle: {
flexGrow: 1,
fontSize: 10,
color: '$iconColor',
marginLeft: 24,
@ -40,4 +45,12 @@ export default EStyleSheet.create({
textButtonWrapper: {
justifyContent: 'center',
},
title: {
color: '$iconColor',
alignSelf: 'center',
fontSize: 16,
marginLeft: 16,
flexGrow: 1,
fontWeight: '500',
},
});

View File

@ -1,10 +1,11 @@
import React, { Component } from 'react';
import React, { Component, Fragment } from 'react';
import { View, SafeAreaView, Text } from 'react-native';
import { TextButton } from '../..';
import { IconButton } from '../../iconButton';
// Constants
// Components
import { DropdownButton } from '../../dropdownButton';
// Styles
import styles from './editorHeaderStyles';
@ -33,6 +34,8 @@ class EditorHeaderView extends Component {
}
};
_handleOnDropdownSelect = () => {};
render() {
const {
handleOnPressBackButton,
@ -40,39 +43,63 @@ class EditorHeaderView extends Component {
isPreviewActive,
quickTitle,
isFormValid,
title,
isHasIcons,
isHasDropdown,
} = this.props;
return (
<SafeAreaView>
<View style={styles.container}>
<IconButton
iconStyle={styles.backIcon}
name="md-arrow-back"
onPress={() => handleOnPressBackButton()}
/>
<Text style={styles.quickTitle}>{quickTitle}</Text>
<IconButton
style={styles.iconButton}
iconStyle={styles.rightIcon}
size={20}
name="ios-timer"
/>
<IconButton
style={styles.iconButton}
size={25}
onPress={() => handleOnPressPreviewButton()}
iconStyle={styles.rightIcon}
name={isPreviewActive ? 'ios-eye' : 'ios-eye-off'}
/>
<TextButton
textStyle={[
styles.textButton,
isFormValid ? styles.textButtonEnable : styles.textButtonDisable,
]}
onPress={isFormValid && this._handleOnPress}
style={styles.textButtonWrapper}
text="Publish"
/>
<View style={styles.backWrapper}>
<IconButton
iconStyle={styles.backIcon}
name="md-arrow-back"
onPress={() => handleOnPressBackButton()}
/>
<Text style={[title && styles.title, quickTitle && styles.quickTitle]}>
{quickTitle || title}
</Text>
{isHasDropdown && (
<View>
<DropdownButton
isHasChildIcon
iconName="md-more"
options={['ALL ACTIVITIES', 'VOTES', 'REPLIES', 'MENTIONS', 'FOLLOWS', 'REBLOGS']}
onSelect={this._handleOnDropdownSelect}
/>
</View>
)}
</View>
{isHasIcons && (
<Fragment>
<IconButton
style={styles.iconButton}
iconStyle={styles.rightIcon}
size={20}
name="ios-timer"
/>
<IconButton
style={styles.iconButton}
size={25}
onPress={() => handleOnPressPreviewButton()}
iconStyle={styles.rightIcon}
name={isPreviewActive ? 'ios-eye' : 'ios-eye-off'}
/>
<TextButton
textStyle={[
styles.textButton,
isFormValid ? styles.textButtonEnable : styles.textButtonDisable,
]}
onPress={isFormValid && this._handleOnPress}
style={styles.textButtonWrapper}
text="Publish"
/>
</Fragment>
)}
</View>
</SafeAreaView>
);

View File

@ -1,5 +1,5 @@
import Logo from './logo/logo';
import Comment from './comment/comment';
// import Comment from './comment/comment';
// import PostCard from "./postCard";
import Reply from './reply/reply';
// import Search from './search/search';
@ -12,7 +12,7 @@ import Modal from './modal';
export {
Logo,
Comment,
// Comment,
// PostCard,
Reply,
// Search,

View File

@ -17,17 +17,6 @@ export default EStyleSheet.create({
inlinePadding: {
padding: 8,
},
editorButtons: {
flexDirection: 'row',
backgroundColor: '$white',
alignItems: 'center',
justifyContent: 'space-between',
height: 50,
shadowOpacity: 0.2,
shadowOffset: {
height: 1.5,
},
},
leftButtonsWrapper: {
marginLeft: 16,
flexDirection: 'row',
@ -41,14 +30,14 @@ export default EStyleSheet.create({
},
editorButton: {
color: '$primaryDarkGray',
paddingRight: 22,
marginRight: 15,
height: 24,
},
dropdownStyle: {
marginRight: 8,
},
rightIcons: {
paddingRight: 21,
marginRight: 20,
},
dropdownIconStyle: {
color: '$primaryDarkGray',

View File

@ -8,6 +8,7 @@ import { MarkdownView } from 'react-native-markdown-view';
import Formats from './formats/formats';
import { IconButton } from '../../iconButton';
import { DropdownButton } from '../../dropdownButton';
import { StickyBar } from '../../basicUIElements';
// Styles
import styles from './markdownEditorStyles';
@ -85,7 +86,7 @@ export default class MarkdownEditorView extends Component {
);
_renderEditorButtons = ({ getState, setState }) => (
<View style={styles.editorButtons}>
<StickyBar>
<View style={styles.leftButtonsWrapper}>
<FlatList
data={Formats}
@ -111,7 +112,7 @@ export default class MarkdownEditorView extends Component {
isHasChildIcon
/>
</View>
</View>
</StickyBar>
);
render() {

View File

@ -1,11 +1,12 @@
import React, { Component } from 'react';
import {
Image, TouchableOpacity, FlatList,
Image, TouchableOpacity, FlatList, View, Text,
} from 'react-native';
import {
Card, CardItem, Left, Right, Thumbnail, View, Icon, Body, Text,
Card, CardItem, Left, Right, Thumbnail, Icon, Body,
} from 'native-base';
import Modal from 'react-native-modal';
import { PostHeaderDescription } from '../../postElements';
// STEEM
import { Upvote } from '../../upvote';
@ -43,14 +44,18 @@ class PostCard extends Component {
const { handleOnUserPress, content, user } = this.props;
if (handleOnUserPress && content && content.author !== user.name) {
handleOnUserPress(content.author);
handleOnUserPress(content.author, content.author);
}
};
_handleOnContentPress = () => {
const { handleOnContentPress, content } = this.props;
handleOnContentPress(content.author, content.permlink);
};
render() {
const {
content, isLoggedIn, user,
} = this.props;
const { content, isLoggedIn, user } = this.props;
const { isModalVisible } = this.state;
// TODO: Should seperate bunch of component REFACTOR ME!
@ -58,38 +63,26 @@ class PostCard extends Component {
<Card style={styles.post}>
<CardItem style={styles.header}>
<Left>
<TouchableOpacity onPress={() => this._handleOnUserPress()}>
<Thumbnail style={styles.avatar} source={{ uri: content && content.avatar }} />
</TouchableOpacity>
<Body style={styles.body}>
<View style={styles.author}>
<TouchableOpacity
onPress={() => this._handleOnUserPress()}
>
<Text style={styles.authorName}>{content.author}</Text>
</TouchableOpacity>
</View>
<View style={styles.badge}>
<Text style={styles.text}>{content.author_reputation}</Text>
</View>
<View style={styles.category}>
<Text style={styles.categoryText}>{content.category}</Text>
</View>
<Text style={styles.timeAgo} note>
{content.created}
</Text>
</Body>
<PostHeaderDescription
date={content.created}
profileOnPress={this._handleOnUserPress}
name={content.author}
reputation={content.author_reputation}
tag={content.category}
avatar={content && content.avatar}
size={32}
/>
</Left>
<Right>
<Icon name="md-more" />
</Right>
</CardItem>
<Image
source={{ uri: content && content.image }}
defaultSource={require('../../../assets/no_image.png')}
style={styles.image}
/>
<TouchableOpacity>
<TouchableOpacity onPress={() => this._handleOnContentPress()}>
<Image
source={{ uri: content && content.image }}
defaultSource={require('../../../assets/no_image.png')}
style={styles.image}
/>
<CardItem>
<Body>
<Text style={styles.title}>{content.title}</Text>

View File

@ -0,0 +1,56 @@
import React, { Component } from 'react';
import {
View, Text, TouchableOpacity, Dimensions,
} from 'react-native';
import HTML from 'react-native-html-renderer';
// Components
// Styles
import styles from './postBodyStyles';
// Constants
const DEFAULT_IMAGE = require('../../../../assets/esteem.png');
class BodyView extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
alterNode(node) {
if (node.name == 'img') {
node.attribs.style = `max-width: ${Dimensions.get('window').width
+ 10}px; left: -10px; width: 100% !important`;
} else if (node.name == 'iframe') {
node.attribs.style = `max-width: ${Dimensions.get('window').width}px; left: -10px`;
node.attribs.height = 200;
}
}
render() {
const { body } = this.props;
return (
<View style={styles.container}>
<HTML
html={body}
onLinkPress={(evt, href, hrefatr) => this.onLinkPress(evt, href, hrefatr)}
containerStyle={{ padding: 10 }}
textSelectable
tagsStyles={styles}
ignoredTags={['script']}
debug={false}
alterNode={(node) => {
this.alterNode(node);
}}
imagesMaxWidth={Dimensions.get('window').width}
/>
</View>
);
}
}
export default BodyView;

View File

@ -0,0 +1,20 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
text: {
fontSize: 12,
color: '$primaryBlack',
fontFamily: '$primaryFont',
},
container: {
paddingHorizontal: 0,
marginTop: 12,
},
a: {
color: '$primaryBlue',
fontFamily: '$primaryFont',
},
img: {
left: -16,
},
});

View File

@ -0,0 +1,86 @@
import React, { Component } from 'react';
import { View, Dimensions, Linking } from 'react-native';
import { withNavigation } from 'react-navigation';
import HTML from 'react-native-html-renderer';
// Styles
import styles from './postBodyStyles';
// Constants
import { default as ROUTES } from '../../../../constants/routeNames';
// Components
const WIDTH = Dimensions.get('window').width;
class PostBody extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
// alterNode(node) {
// // if (node.name === 'img') {
// // node.attribs.style = `max-width: ${WIDTH + 16}px; left: -16px; width: 100% !important`;
// // } else if (node.name == 'iframe') {
// // node.attribs.style = `max-width: ${WIDTH}px; left: -20px`;
// // node.attribs.height = 216;
// // }
// // if (node.name === 'a') {
// // node.attribs.style = 'text-decoration: underline';
// // }
// }
_handleOnLinkPress = (evt, href, hrefatr) => {
const { handleOnUserPress } = this.props;
if (hrefatr.class === 'markdown-author-link') {
!handleOnUserPress ? this._handleOnUserPress(href) : handleOnUserPress(href);
} else {
Linking.canOpenURL(href).then((supported) => {
if (supported) {
Linking.openURL(href);
} else {
alert(`Field to open: ${href}`);
}
});
}
};
_handleOnUserPress = (username) => {
const { navigation } = this.props;
navigation.navigate({
routeName: ROUTES.SCREENS.PROFILE,
params: {
username,
},
key: username + Math.random() * 100,
});
};
render() {
const { body, isComment } = this.props;
const _initialDimensions = isComment ? {} : { width: WIDTH, height: 216 };
return (
<View>
<HTML
html={body}
onLinkPress={(evt, href, hrefatr) => this._handleOnLinkPress(evt, href, hrefatr)}
containerStyle={isComment ? {} : styles.container}
textSelectable
tagsStyles={isComment ? {} : styles}
ignoredTags={['script']}
debug={false}
imagesInitialDimensions={_initialDimensions}
baseFontStyle={styles.text}
imagesMaxWidth={isComment ? null : WIDTH}
/>
</View>
);
}
}
export default withNavigation(PostBody);

View File

@ -0,0 +1,72 @@
import React, { Component } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { withNavigation } from 'react-navigation';
import FastImage from 'react-native-fast-image';
// Components
import { Tag } from '../../../basicUIElements';
// Styles
import styles from './postHeaderDescriptionStyles';
import { default as ROUTES } from '../../../../constants/routeNames';
// Constants
const DEFAULT_IMAGE = require('../../../../assets/esteem.png');
class PostHeaderDescription extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
_handleOnUserPress = (username) => {
const { navigation } = this.props;
navigation.navigate({
routeName: ROUTES.SCREENS.PROFILE,
params: {
username,
},
key: username + Math.random() * 100,
});
};
render() {
const {
date, avatar, name, reputation, size, tag, profileOnPress, tagOnPress,
} = this.props;
const _reputationText = `(${reputation})`;
const _avatar = avatar && { uri: avatar };
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.avatarNameWrapper}
onPress={() => (profileOnPress ? profileOnPress(name) : this._handleOnUserPress(name))}
>
<FastImage
style={[styles.avatar, { width: size, height: size, borderRadius: size / 2 }]}
source={_avatar}
defaultSource={DEFAULT_IMAGE}
/>
<Text style={styles.name}>{name}</Text>
</TouchableOpacity>
<Text style={styles.reputation}>{_reputationText}</Text>
{tag && (
<TouchableOpacity onPress={() => tagOnPress && tagOnPress()}>
<Tag isPin value={tag} />
</TouchableOpacity>
)}
<Text style={styles.date}>{date}</Text>
</View>
);
}
}
export default withNavigation(PostHeaderDescription);

View File

@ -0,0 +1,33 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
},
avatar: {
borderColor: '$borderColor',
borderWidth: 1,
},
name: {
marginHorizontal: 3,
fontSize: 10,
color: '$primaryBlack',
fontFamily: '$primaryFont',
fontWeight: 'bold',
alignSelf: 'center',
},
reputation: {
fontSize: 10,
color: '$primaryDarkGray',
marginRight: 8,
alignSelf: 'center',
},
date: {
fontSize: 10,
color: '$primaryDarkGray',
},
avatarNameWrapper: {
flexDirection: 'row',
},
});

View File

@ -0,0 +1,5 @@
import PostHeaderDescription from './headerDescription/view/postHeaderDescription';
import PostBody from './body/view/postBodyView';
import Tags from './tags/view/tagsView';
export { PostHeaderDescription, PostBody, Tags };

View File

@ -0,0 +1,7 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flexDirection: 'row',
},
});

View File

@ -0,0 +1,38 @@
import React, { Component } from 'react';
import { View, FlatList } from 'react-native';
// Components
import { Tag } from '../../../basicUIElements';
// Styles
import styles from './tagsStyles';
// Constants
class TagsView extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
render() {
const { tags, handleOnTagPress } = this.props;
return (
<View style={styles.container}>
<FlatList
data={tags}
horizontal
renderItem={({ item, index }) => (
<Tag key={index} value={item} isPin={index === 0} onPress={handleOnTagPress} />
)}
/>
</View>
);
}
}
export default TagsView;

View File

@ -0,0 +1,38 @@
import React, { Component } from 'react';
// import { connect } from 'react-redux';
// Services and Actions
// Middleware
// Constants
// Utilities
// Component
import { PostDisplayView } from '..';
/*
* Props Name Description Value
*@props --> props name here description here Value Type Here
*
*/
class PostDisplayContainer extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycle Functions
// Component Functions
render() {
const { post, currentUser } = this.props;
return <PostDisplayView currentUser={currentUser} post={post} />;
}
}
export default PostDisplayContainer;

View File

@ -0,0 +1,5 @@
import PostDisplayView from './view/postDisplayView';
import PostDisplay from './container/postDisplayContainer';
export { PostDisplay, PostDisplayView };
export default PostDisplayView;

View File

@ -0,0 +1,67 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flexDirection: 'column',
},
header: {
marginHorizontal: 16,
},
title: {
fontSize: 24,
color: '$primaryBlack',
fontWeight: '900',
fontFamily: '$primaryFont',
marginBottom: 11,
},
description: {
flexDirection: 'row',
},
scroll: {
height: '$deviceHeight / 1.135',
},
footer: {
flexDirection: 'column',
marginTop: 19,
marginBottom: 50,
},
footerText: {
fontSize: 10,
fontFamily: '$primaryFont',
color: '$primaryDarkGray',
marginVertical: 12,
},
footerName: {
color: '$primaryBlack',
fontWeight: 'bold',
},
stickyWrapper: {
flexDirection: 'row',
paddingHorizontal: 16,
width: '$deviceWidth',
marginBottom: 5,
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'center',
},
barIcons: {
color: '$primaryDarkGray',
fontSize: 20,
marginRight: 8,
marginLeft: 25,
opacity: 0.7,
},
barIconRight: {
color: '$primaryDarkGray',
fontSize: 16,
opacity: 0.7,
},
barIconButton: {
marginLeft: 16,
},
stickyRightWrapper: {
flexGrow: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
},
});

View File

@ -0,0 +1,154 @@
import React, { Component } from 'react';
import {
View, Text, ScrollView, Dimensions,
} from 'react-native';
// Constants
// Components
import { PostHeaderDescription, PostBody, Tags } from '../../postElements';
import { PostPlaceHolder, StickyBar, TextWithIcon } from '../../basicUIElements';
import { Upvote } from '../../upvote';
import { IconButton } from '../../iconButton';
import { CommentsDisplay } from '../../commentsDisplay';
// Styles
import styles from './postDisplayStyles';
const HEIGHT = Dimensions.get('window').width;
class PostDisplayView extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {
postHeight: 0,
scrollHeight: 0,
};
}
// Component Life Cycles
// Component Functions
_handleOnScroll = (event) => {
const { y } = event.nativeEvent.contentOffset;
this.setState({
scrollHeight: HEIGHT + y,
});
};
_handleOnPostLayout = (event) => {
const { height } = event.nativeEvent.layout;
this.setState({
postHeight: height,
});
};
_getTabBar = (isFixedFooter = false) => {
const {
post, currentUser, handleOnReplyPress, handleOnEditPress,
} = this.props;
return (
<StickyBar isFixedFooter={isFixedFooter}>
<View style={styles.stickyWrapper}>
<Upvote isShowpayoutValue content={post} user={currentUser} isLoggedIn={!!currentUser} />
<TextWithIcon
isClickable
iconStyle={styles.barIcons}
textMarginLeft={20}
text={post && post.vote_count}
iconName="ios-people"
/>
<TextWithIcon
isClickable
iconStyle={styles.barIcons}
textMarginLeft={20}
text={post && post.children}
iconName="comments"
iconType="FontAwesome"
/>
<View style={styles.stickyRightWrapper}>
{post
&& currentUser
&& currentUser.name === post.author && (
<IconButton
iconStyle={styles.barIconRight}
style={styles.barIconButton}
name="pencil"
iconType="SimpleLineIcons"
onPress={() => handleOnEditPress && handleOnEditPress()}
/>
)}
<IconButton
iconStyle={styles.barIconRight}
style={styles.barIconButton}
name="reply"
onPress={() => handleOnReplyPress && handleOnReplyPress()}
iconType="FontAwesome"
/>
</View>
</View>
</StickyBar>
);
};
render() {
const { post, currentUser } = this.props;
const { postHeight, scrollHeight } = this.state;
const isPostEnd = scrollHeight > postHeight;
return (
<View style={styles.container}>
<ScrollView style={styles.scroll} onScroll={event => this._handleOnScroll(event)}>
<View style={styles.header}>
{!post ? (
<PostPlaceHolder />
) : (
<View onLayout={event => this._handleOnPostLayout(event)}>
<Text style={styles.title}>{post.title}</Text>
<PostHeaderDescription
date={post.created}
name={post.author}
reputation={post.author_reputation}
tag={post.category}
avatar={post.avatar}
size={16}
/>
{post && post.body && <PostBody body={post.body} />}
<View style={styles.footer}>
<Tags tags={post.json_metadata && post.json_metadata.tags} />
<Text style={styles.footerText}>
Posted by
{' '}
<Text style={styles.footerName}>{post.author}</Text>
{' '}
{post.created}
</Text>
{isPostEnd && this._getTabBar()}
</View>
</View>
)}
</View>
{post && (
<CommentsDisplay
currentUser={currentUser}
author={post.author}
permlink={post.permlink}
commentCount={post.children}
/>
)}
</ScrollView>
{!isPostEnd && this._getTabBar(true)}
</View>
);
}
}
export default PostDisplayView;

View File

@ -41,8 +41,29 @@ class PostsContainer extends Component {
});
};
_handleOnContentPress = (author, permlink) => {
const { navigation } = this.props;
if (author && permlink) {
navigation.navigate({
routeName: ROUTES.SCREENS.POST,
params: {
author,
permlink,
},
key: permlink,
});
}
};
render() {
return <PostsView handleOnUserPress={this._handleOnUserPress} {...this.props} />;
return (
<PostsView
handleOnUserPress={this._handleOnUserPress}
handleOnContentPress={this._handleOnContentPress}
{...this.props}
/>
);
}
}

View File

@ -1,7 +1,5 @@
import React, { Component, Fragment } from 'react';
import {
FlatList, View, ActivityIndicator,
} from 'react-native';
import { FlatList, View, ActivityIndicator } from 'react-native';
// import Placeholder from 'rn-placeholder';
@ -11,8 +9,7 @@ import { getPosts } from '../../../providers/steem/dsteem';
// COMPONENTS
import { PostCard } from '../../postCard';
import { FilterBar } from '../../filterBar';
import { PostPlaceHolder } from '../../basicUIElements';
import { NoPost } from '../../basicUIElements';
import { PostCardPlaceHolder, NoPost } from '../../basicUIElements';
// Styles
import styles from './postsStyles';
@ -32,7 +29,10 @@ class PostsView extends Component {
}
componentDidMount() {
this._loadPosts(this.state.user);
const { user, isLoggedIn, isLoginMust } = this.state;
const isCanLoad = isLoginMust ? isLoggedIn : true;
isCanLoad && this._loadPosts(user);
}
componentWillReceiveProps(nextProps) {
@ -45,7 +45,6 @@ class PostsView extends Component {
}
}
_loadPosts = (user, _tag = null) => {
const { getFor, tag } = this.props;
const options = { tag: _tag || tag, limit: 10 };
@ -57,8 +56,8 @@ class PostsView extends Component {
this.setState({
isReady: true,
posts: result,
startAuthor: result[result.length - 1].author,
startPermlink: result[result.length - 1].permlink,
startAuthor: result[result.length - 1] && result[result.length - 1].author,
startPermlink: result[result.length - 1] && result[result.length - 1].permlink,
refreshing: false,
});
}
@ -127,7 +126,14 @@ class PostsView extends Component {
const {
isReady, refreshing, posts, user,
} = this.state;
const { componentId, handleOnUserPress, filterOptions } = this.props;
const {
componentId,
handleOnUserPress,
filterOptions,
isLoginMust,
handleOnContentPress,
isLoggedIn,
} = this.props;
if (user && posts && posts.length > 0) {
return (
@ -148,8 +154,9 @@ class PostsView extends Component {
componentId={componentId}
content={item}
user={user}
isLoggedIn
isLoggedIn={isLoggedIn}
handleOnUserPress={handleOnUserPress}
handleOnContentPress={handleOnContentPress}
/>
)}
keyExtractor={(post, index) => index.toString()}
@ -177,10 +184,14 @@ class PostsView extends Component {
);
}
// if (isLoginMust && !isLoggedIn) {
// return <NoPost defaultText="Login to see!" />;
// }
return (
<Fragment>
<PostPlaceHolder />
<PostPlaceHolder />
<PostCardPlaceHolder />
<PostCardPlaceHolder />
</Fragment>
);
};

View File

@ -57,4 +57,10 @@ export default EStyleSheet.create({
overlay: {
backgroundColor: '#403c4449',
},
payoutValue: {
alignSelf: 'center',
fontSize: 10,
color: '$primaryDarkGray',
marginLeft: 8,
},
});

View File

@ -103,7 +103,7 @@ class UpvoteView extends Component {
};
render() {
const { isLoggedIn } = this.props;
const { isLoggedIn, isShowpayoutValue, content } = this.props;
const {
isVoting, isModalVisible, amount, value, isVoted,
} = this.state;
@ -126,11 +126,14 @@ class UpvoteView extends Component {
{isVoting ? (
<ActivityIndicator />
) : (
<Icon
style={[styles.upvoteIcon, { color: '#007ee5' }]}
active={!isLoggedIn}
name={isVoted ? 'ios-arrow-dropup-circle' : 'ios-arrow-dropup-outline'}
/>
<Fragment>
<Icon
style={[styles.upvoteIcon, { color: '#007ee5' }]}
active={!isLoggedIn}
name={isVoted ? 'ios-arrow-dropup-circle' : 'ios-arrow-dropup-outline'}
/>
{isShowpayoutValue && <Text style={styles.payoutValue}>$ {content && content.pending_payout_value}</Text> }
</Fragment>
)}
</TouchableOpacity>

View File

@ -1,16 +1,27 @@
import { DrawerNavigator, SwitchNavigator, createStackNavigator } from 'react-navigation';
import {
createDrawerNavigator,
createSwitchNavigator,
createStackNavigator,
} from 'react-navigation';
import { BaseNavigator } from '../navigation';
import { default as ROUTES } from '../constants/routeNames';
// Screens
import {
Splash, Login, PinCode, SteemConnect, Editor, Profile, RootComponent,
Splash,
Login,
PinCode,
SteemConnect,
Editor,
Profile,
Post,
RootComponent,
} from '../screens';
// Components
import { SideMenu } from '../components';
const mainNavigation = DrawerNavigator(
const mainNavigation = createDrawerNavigator(
{
[ROUTES.SCREENS.HOME]: {
screen: BaseNavigator,
@ -29,13 +40,18 @@ const stackNavigatior = createStackNavigator(
header: () => null,
},
},
[ROUTES.SCREENS.PROFILE]: {
screen: RootComponent()(Profile),
navigationOptions: {
header: () => null,
},
},
[ROUTES.SCREENS.POST]: {
screen: Post,
navigationOptions: {
header: () => null,
},
},
[ROUTES.SCREENS.EDITOR]: {
screen: RootComponent()(Editor),
navigationOptions: {
@ -50,7 +66,7 @@ const stackNavigatior = createStackNavigator(
},
);
export default SwitchNavigator({
export default createSwitchNavigator({
stackNavigatior,
[ROUTES.SCREENS.LOGIN]: { screen: RootComponent()(Login) },
[ROUTES.SCREENS.PINCODE]: { screen: RootComponent()(PinCode) },

View File

@ -7,6 +7,7 @@ export default {
HOME: `Home${SCREEN_SUFFIX}`,
LOGIN: `Login${SCREEN_SUFFIX}`,
PINCODE: `PinCode${SCREEN_SUFFIX}`,
POST: `Post${SCREEN_SUFFIX}`,
PROFILE: `Profile${SCREEN_SUFFIX}`,
SPLASH: `Splash${SCREEN_SUFFIX}`,
STEEM_CONNECT: `SteemConnect${SCREEN_SUFFIX}`,

View File

@ -22,7 +22,7 @@ EStyleSheet.build({
$primaryBlack: '#3c4449',
// General Colors
$borderColor: '#CED0CE',
$borderColor: '#c5c5c5',
$bubblesBlue: '#5CCDFF',
$iconColor: '#c1c5c7',
$dangerColor: '#fff',

View File

@ -5,7 +5,7 @@
import { Client, PrivateKey } from 'dsteem';
import { AsyncStorage } from 'react-native';
import { parsePosts, parseComments } from '../../utils/postParser';
import { parsePosts, parsePost, parseComments } from '../../utils/postParser';
let rewardFund = null;
let medianPrice = null;
@ -140,8 +140,7 @@ export const isFolllowing = (author, user) => new Promise((resolve, reject) => {
export const getPosts = async (by, query, user) => {
try {
let posts = await client.database.getDiscussions(by, query);
console.log('comments');
console.log(posts);
posts = await parsePosts(posts, user);
return posts;
} catch (error) {
@ -165,14 +164,16 @@ export const getUserComments = async (query) => {
* @param user post author
* @param permlink post permlink
*/
export const getPost = (user, permlink) => new Promise((resolve, reject) => {
export const getPost = async (user, permlink) => {
try {
const post = client.database.call('get_content', [user, permlink]);
resolve(post);
let posts = await client.database.call('get_content', [user, permlink]);
posts = await parsePost(posts, user);
return posts;
} catch (error) {
reject(error);
return error;
}
});
};
/**
* @method getUser get user data

View File

@ -13,15 +13,11 @@ import {
View,
} from 'native-base';
import ScrollableTabView from '@esteemapp/react-native-scrollable-tab-view';
//import { Navigation } from 'react-native-navigation';
import FastImage from 'react-native-fast-image';
// Internal Components
import { TabBar } from '../../../components/tabBar';
import { PostCard } from '../../../components/postCard';
import Comment from '../../../components/comment/comment';
import { getTimeFromNow } from '../../../utils/time';
// Styles

View File

@ -99,6 +99,7 @@ export class EditorScreen extends Component {
quickTitle={wordsCount > 0 && `${wordsCount} words`}
handleOnPressPreviewButton={this._handleOnPressPreviewButton}
isFormValid={isFormValid}
isHasIcons
handleOnSubmit={this._handleOnSubmit}
/>
<PostForm

View File

@ -78,7 +78,7 @@ export default class HomeScreen extends PureComponent {
const { componentId } = this.props;
return (
<Fragment>
<Header userName={user.name} reputation={user && user.reputation} />
<Header userName={user && user.name} reputation={user && user.reputation} />
<View style={styles.root} key="overlay">
<ScrollableTabView
style={styles.tabView}
@ -94,26 +94,15 @@ export default class HomeScreen extends PureComponent {
)}
>
<View tabLabel="Feed" style={styles.tabbarItem}>
{isLoggedIn ? (
<Posts
filterOptions={[
'NEW POSTS',
'VOTES',
'REPLIES',
'MENTIONS',
'FOLLOWS',
'REBLOGS',
]}
isLoginMust
getFor="feed"
tag={user.name}
user={user}
isLoggedIn={isLoggedIn}
componentId={componentId}
/>
) : (
<Text>Login to see your Feed</Text>
)}
<Posts
filterOptions={['NEW POSTS', 'VOTES', 'REPLIES', 'MENTIONS', 'FOLLOWS', 'REBLOGS']}
isLoginMust
getFor="feed"
tag={user.name}
user={user}
isLoggedIn={isLoggedIn}
componentId={componentId}
/>
</View>
<View tabLabel="Hot" style={styles.tabbarItem}>
<Posts

View File

@ -1,10 +1,11 @@
import PinCode from './pinCode';
import Splash from './splash';
import SteemConnect from './steem-connect/steemConnect';
import { Editor } from './editor';
import { Home } from './home';
import { Login } from './login';
import { Notification } from './notification';
import SteemConnect from './steem-connect/steemConnect';
import { Post } from './post';
import { Profile } from './profile';
import RootComponent from './root';
@ -29,6 +30,7 @@ export {
Profile,
SteemConnect,
Splash,
Post,
RootComponent,
// Author,
// SideMenu,

View File

@ -0,0 +1,88 @@
import React, { Component } from 'react';
// import { connect } from 'react-redux';
// Services and Actions
import { getUserData, getAuthStatus } from '../../../realm/realm';
import { getPost, getUser } from '../../../providers/steem/dsteem';
// Middleware
// Constants
// Utilities
// Component
import { PostScreen } from '..';
/*
* Props Name Description Value
*@props --> content which is include all post data Object
*
*/
class PostContainer extends Component {
constructor(props) {
super(props);
this.state = {
post: null,
error: null,
currentUser: null,
};
}
// Component Life Cycle Functions
componentDidMount() {
const { navigation } = this.props;
const { author, permlink } = navigation.state && navigation.state.params;
this._loadPost(author, permlink);
this._getUser();
}
// Component Functions
_loadPost = (author, permlink) => {
const { currentUser } = this.state;
// TODO: get from redux for cureentUser
getPost(author, permlink)
.then((result) => {
if (result) {
this.setState({ post: result });
}
})
.catch((err) => {
this.setState({ error: err });
});
};
async _getUser() {
let _currentUser;
let userData;
let isLoggedIn;
await getAuthStatus().then((res) => {
isLoggedIn = res;
});
if (isLoggedIn) {
await getUserData().then((res) => {
_currentUser = Array.from(res);
});
userData = _currentUser && (await getUser(_currentUser[0].username));
await this.setState({
currentUser: userData,
});
}
}
render() {
const { post, error, currentUser } = this.state;
return (
<PostScreen currentUser={currentUser} key={Math.random * 100} post={post} error={error} />
);
}
}
export default PostContainer;

View File

@ -0,0 +1,5 @@
import PostScreen from './screen/postScreen';
import Post from './container/postContainer';
export { PostScreen, Post };
export default Post;

View File

@ -0,0 +1,39 @@
import React, { Component, Fragment } from 'react';
// Constants
// Components
import { EditorHeader } from '../../../components/editorHeader';
import { PostDisplay } from '../../../components/postView';
// Styles
// eslint-disable-next-line
//import styles from './_styles';
class PostScreen extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
render() {
const { post, currentUser } = this.props;
return (
<Fragment>
<EditorHeader isHasDropdown title="Post" />
<PostDisplay post={post} currentUser={currentUser} />
</Fragment>
);
}
}
export default PostScreen;

View File

@ -13,7 +13,7 @@ import ScrollableTabView from "@esteemapp/react-native-scrollable-tab-view";
import { TabBar } from "../../components/tabBar";
import DiscoverPage from "../discover/discover";
import { PostCard } from "../../components/postCard";
import Comment from "../../components/comment/comment";
//import Comment from "../../components/comment/comment";
import { getUserData, getAuthStatus } from '../../realm/realm';

View File

@ -5,7 +5,13 @@ import { ProfileScreen } from '..';
// Utilitites
import {
getFollows, getPosts, getUser, getUserComments,
followUser,
unfollowUser,
getFollows,
getPosts,
getUserComments,
getUser,
isFolllowing,
} from '../../../providers/steem/dsteem';
import { getUserData, getAuthStatus } from '../../../realm/realm';
@ -14,8 +20,8 @@ class ProfileContainer extends Component {
super(props);
this.state = {
user: null,
posts: [],
commments: [],
currentUser: null,
comments: [],
replies: [],
about: {},
follows: {},
@ -51,7 +57,7 @@ class ProfileContainer extends Component {
.then((result) => {
this.setState({
isReady: true,
commments: result,
comments: result,
refreshing: false,
isLoading: false,
});
@ -61,6 +67,79 @@ class ProfileContainer extends Component {
});
};
// _unfollow = async () => {
// let userData;
// let privateKey;
// await this.setState({
// follow_loader: true,
// });
// await getUserData().then((result) => {
// userData = Array.from(result);
// });
// console.log(userData);
// privateKey = decryptKey(userData[0].postingKey, '1234');
// unfollowUser(
// {
// follower: userData[0].username,
// following: this.state.author.name,
// },
// privateKey,
// )
// .then((result) => {
// this.setState({
// follow_loader: false,
// isFolllowing: false,
// });
// })
// .catch((err) => {
// this.setState({
// follow_loader: false,
// });
// });
// };
// _follow = async () => {
// let userData;
// let privateKey;
// await this.setState({
// follow_loader: true,
// });
// await getUserData().then((result) => {
// userData = Array.from(result);
// });
// console.log(userData);
// privateKey = decryptKey(userData[0].postingKey, '1234');
// followUser(
// {
// follower: userData[0].username,
// following: this.state.author.name,
// },
// privateKey,
// )
// .then((result) => {
// console.log(result);
// this.setState({
// follow_loader: false,
// isFolllowing: true,
// });
// })
// .catch((err) => {
// console.log(err);
// this.setState({
// follow_loader: false,
// isFolllowing: false,
// });
// });
// };
async _loadProfile(selectedUser = null) {
// TODO: use from redux store.
let isLoggedIn;
@ -111,7 +190,7 @@ class ProfileContainer extends Component {
render() {
const {
about,
commments,
comments,
follows,
isReverseHeader,
isLoading,
@ -127,7 +206,7 @@ class ProfileContainer extends Component {
isReady={isReady}
about={about}
isReverseHeader={isReverseHeader}
commments={commments}
comments={comments}
follows={follows}
isLoading={isLoading}
isLoggedIn={isLoggedIn}

View File

@ -1,10 +1,10 @@
/* eslint-disable no-unused-vars */
import React, { Component, Fragment } from 'react';
import { FlatList, ActivityIndicator, View } from 'react-native';
import { View, ScrollView } from 'react-native';
// Components
import ScrollableTabView from '@esteemapp/react-native-scrollable-tab-view';
import Comment from '../../../components/comment/comment';
import { Comments } from '../../../components/comments';
import { CollapsibleCard } from '../../../components/collapsibleCard';
import { Header } from '../../../components/header';
import { NoPost, ProfileSummaryPlaceHolder } from '../../../components/basicUIElements';
@ -28,7 +28,7 @@ class ProfileScreen extends Component {
render() {
const {
about,
commments,
comments,
follows,
isLoading,
isLoggedIn,
@ -131,15 +131,10 @@ class ProfileScreen extends Component {
)}
</View>
<View tabLabel="Comments" style={styles.commentsTabBar}>
{commments && commments.length > 0 ? (
<FlatList
data={commments}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => <Comment comment={item} isLoggedIn user={user} />}
keyExtractor={(post, index) => index.toString()}
onEndThreshold={0}
bounces={false}
/>
{comments && comments.length > 0 ? (
<ScrollView>
<Comments comments={comments} />
</ScrollView>
) : (
<NoPost
name={username}

View File

@ -1,17 +0,0 @@
import React, { Component } from 'react';
// Components
import { SinglePostScreen } from '..';
class SinglePostContainer extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return <SinglePostScreen {...this.props} />;
}
}
export default SinglePostContainer;

View File

@ -1,5 +0,0 @@
import SinglePost from './container/singlePostContainer';
import SinglePostScreen from './screen/singlePostScreen';
export { SinglePost, SinglePostScreen };
export default SinglePost;

View File

@ -1,189 +0,0 @@
/* eslint-disable no-console */
/* eslint-disable no-unused-vars */
import React from 'react';
import {
Dimensions,
ActivityIndicator,
StatusBar,
FlatList,
BackHandler,
ScrollView,
TextInput,
Image,
View,
} from 'react-native';
import {
Card, Button, Icon, Text, Title,
} from 'native-base';
import HTML from 'react-native-html-renderer';
import { Navigation } from 'react-native-navigation';
import styles from './singlePostStyles';
/* eslint-enable no-unused-vars */
class SinglePostScreen extends React.Component {
static get options() {
return {
_statusBar: {
visible: true,
drawBehind: false,
},
topBar: {
animate: true,
hideOnScroll: false,
drawBehind: false,
leftButtons: {
id: 'back',
},
},
layout: {
backgroundColor: '#f5fcff',
},
bottomTabs: {
visible: false,
drawBehind: true,
},
};
}
constructor(props) {
super(props);
Navigation.events().bindComponent(this);
this.state = {
comments: [],
comment: '',
isLoading: false,
};
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', () => {
Navigation.pop(this.props.componentId);
return true;
});
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress');
}
onLinkPress(evt, href, attribs) {}
alterNode(node) {
if (node.name == 'img') {
node.attribs.style = `max-width: ${Dimensions.get('window').width
+ 10}px; left: -10px; width: 100% !important`;
} else if (node.name == 'iframe') {
node.attribs.style = `max-width: ${
Dimensions.get('window').width
}px; left: -10px`;
node.attribs.height = 200;
}
}
navigationButtonPressed({ buttonId }) {
// will be called when "buttonOne" is clicked
if (buttonId === 'back') {
Navigation.pop(this.props.componentId);
}
}
render() {
return (
<View style={{ flex: 1 }}>
<ScrollView style={{ flex: 1 }}>
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 0.2 }}>
<Image
style={{
height: 40,
width: 40,
borderWidth: 1,
borderColor: 'lightgray',
}}
source={{
uri: this.props.content.avatar,
}}
/>
</View>
<View style={{ flex: 0.4 }}>
<Text>{this.props.content.author}</Text>
<Text note>
#
{this.props.content.category}
</Text>
</View>
<View style={{ flex: 0.4, alignItems: 'flex-end' }}>
<Text note>{this.props.content.created}</Text>
</View>
</View>
<View>
<Text style={{ fontWeight: 'bold' }}>
{this.props.content.title}
</Text>
</View>
<HTML
html={this.props.content.body}
onLinkPress={(evt, href, hrefatr) => this.onLinkPress(evt, href, hrefatr)
}
containerStyle={{ padding: 10 }}
textSelectable
tagsStyles={styles}
ignoredTags={['script']}
debug={false}
alterNode={(node) => {
this.alterNode(node);
}}
imagesMaxWidth={Dimensions.get('window').width}
/>
<View style={{ padding: 10 }}>
<TextInput
style={{
borderWidth: 1,
borderColor: 'lightgray',
borderRadius: 5,
padding: 10,
minHeight: 100,
}}
multiline
numberOfLines={4}
placeholder="What do you think about this story?"
onChangeText={comment => this.setState({ comment })}
value={this.state.comment}
/>
<View style={{ flexDirection: 'row-reverse' }}>
<Button
onPress={this.postComment}
style={{
alignSelf: 'flex-end',
marginTop: 10,
borderRadius: 20,
}}
>
{this.state.isLoading ? (
<ActivityIndicator
style={{ marginHorizontal: 50 }}
/>
) : (
<Text>Post a Comment</Text>
)}
</Button>
<Button
style={{
alignSelf: 'flex-end',
marginRight: 10,
borderRadius: 50,
}}
>
<Icon name="images" />
</Button>
</View>
</View>
</ScrollView>
</View>
);
}
}
export default SinglePostScreen;

View File

@ -1,13 +0,0 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
comments: {
flex: 1,
backgroundColor: 'white',
},
});

1
src/utils/post.js Normal file
View File

@ -0,0 +1 @@
// ^ (http: \/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$

View File

@ -107,8 +107,10 @@ export const parsePost = (post) => {
const voteRshares = post.active_votes.reduce((a, b) => a + parseFloat(b.rshares), 0);
const ratio = totalPayout / voteRshares;
//post.is_voted = false;
for (const i in post.active_votes) {
// post.is_voted = post.active_votes[i].voter === "u-e" && post.active_votes[i].percent > 0;
post.active_votes[i].value = (post.active_votes[i].rshares * ratio).toFixed(2);
post.active_votes[i].reputation = getReputation(post.active_votes[i].reputation);
post.active_votes[i].avatar = `https://steemitimages.com/u/${