This commit is contained in:
Feruz 2018-08-01 22:24:34 +03:00
parent 38ce6a741f
commit ce6376d50d
25 changed files with 2880 additions and 2271 deletions

View File

@ -1,280 +1,341 @@
import React, { Component } from 'react';
import React, { Component } from 'react';
import { StyleSheet, Image, TouchableOpacity } from 'react-native';
import { Button, Card, CardItem,
Left, Right, Thumbnail, View,
Icon, Body, Text, Container, Content } from 'native-base';
import {
Button,
Card,
CardItem,
Left,
Right,
Thumbnail,
View,
Icon,
Body,
Text,
Container,
Content,
} from 'native-base';
class PostCard extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
this.state = {};
}
}
componentDidMount() {
componentDidMount() {}
}
onError() {}
onError() {
}
render() {
return (
<Card style={styles.post}>
<CardItem style={styles.header}>
<Left>
<TouchableOpacity onPress={() => this.props.navigate('Author', { author: this.props.content.author })}>
<Thumbnail
style={styles.avatar}
source={{ uri: this.props.content.avatar }} />
</TouchableOpacity>
<Body style={styles.body}>
<View style={styles.author}>
<Text style={styles.authorName}>{ this.props.content.author }</Text>
</View>
<View style={ styles.badge }>
<Text style={styles.text}>{ this.props.content.author_reputation }</Text>
</View>
<View style={ styles.category }>
<Text style={styles.categoryText}>{ this.props.content.category }</Text>
</View>
<Text style={styles.timeAgo} note> { this.props.content.created } </Text>
</Body>
</Left>
<Right>
<Icon name='md-more'/>
</Right>
</CardItem>
<Image
source={{ uri: this.props.content.image }}
defaultSource={require('../assets/no_image.png')}
style={styles.image}/>
<CardItem>
<Body>
<Text style={styles.title}>
{ this.props.content.title }
</Text>
<Text style={styles.summary}>
{ this.props.content.summary }
</Text>
</Body>
</CardItem>
<CardItem>
<Left>
<TouchableOpacity start style={styles.upvoteButton}>
<Icon style={styles.upvoteIcon} active name="ios-arrow-dropup-outline" />
</TouchableOpacity>
<TouchableOpacity style={styles.payoutButton}>
<Text style={styles.payout}>${ this.props.content.pending_payout_value }</Text>
<Icon name='md-arrow-dropdown' style={styles.payoutIcon} />
</TouchableOpacity>
</Left>
<Right>
<TouchableOpacity start style={styles.commentButton}>
<Icon style={styles.commentIcon} active name="ios-chatbubbles-outline" />
<Text style={styles.comment}>{ this.props.content.children }</Text>
</TouchableOpacity>
</Right>
</CardItem>
{ this.props.content.top_likers ? (
<CardItem style={styles.topLikers}>
<Thumbnail source={{ uri: `https://steemitimages.com/u/${this.props.content.top_likers[0]}/avatar/small` }} style={styles.likers_1}/>
<Thumbnail source={{ uri: `https://steemitimages.com/u/${this.props.content.top_likers[1]}/avatar/small` }} style={styles.likers_2}/>
<Thumbnail source={{ uri: `https://steemitimages.com/u/${this.props.content.top_likers[2]}/avatar/small` }} style={styles.likers_3}/>
<Text style={styles.footer}>
@{ this.props.content.top_likers[0] },
@{ this.props.content.top_likers[1] },
@{ this.props.content.top_likers[2] }
<Text style={styles.footer}> & </Text>
{ this.props.content.vote_count - this.props.content.top_likers.length } others like this
</Text>
</CardItem>
) : (
<CardItem>
<Text style={styles.footer}>
{ this.props.content.vote_count } likes
</Text>
</CardItem>
)}
</Card>
)
}
render() {
return (
<Card style={styles.post}>
<CardItem style={styles.header}>
<Left>
<TouchableOpacity
onPress={() =>
this.props.navigate('Author', {
author: this.props.content.author,
})
}
>
<Thumbnail
style={styles.avatar}
source={{ uri: this.props.content.avatar }}
/>
</TouchableOpacity>
<Body style={styles.body}>
<View style={styles.author}>
<Text style={styles.authorName}>
{this.props.content.author}
</Text>
</View>
<View style={styles.badge}>
<Text style={styles.text}>
{this.props.content.author_reputation}
</Text>
</View>
<View style={styles.category}>
<Text style={styles.categoryText}>
{this.props.content.category}
</Text>
</View>
<Text style={styles.timeAgo} note>
{' '}
{this.props.content.created}{' '}
</Text>
</Body>
</Left>
<Right>
<Icon name="md-more" />
</Right>
</CardItem>
<Image
source={{ uri: this.props.content.image }}
defaultSource={require('../assets/no_image.png')}
style={styles.image}
/>
<CardItem>
<Body>
<Text style={styles.title}>
{this.props.content.title}
</Text>
<Text style={styles.summary}>
{this.props.content.summary}
</Text>
</Body>
</CardItem>
<CardItem>
<Left>
<TouchableOpacity start style={styles.upvoteButton}>
<Icon
style={styles.upvoteIcon}
active
name="ios-arrow-dropup-outline"
/>
</TouchableOpacity>
<TouchableOpacity style={styles.payoutButton}>
<Text style={styles.payout}>
${this.props.content.pending_payout_value}
</Text>
<Icon
name="md-arrow-dropdown"
style={styles.payoutIcon}
/>
</TouchableOpacity>
</Left>
<Right>
<TouchableOpacity start style={styles.commentButton}>
<Icon
style={styles.commentIcon}
active
name="ios-chatbubbles-outline"
/>
<Text style={styles.comment}>
{this.props.content.children}
</Text>
</TouchableOpacity>
</Right>
</CardItem>
{this.props.content.top_likers ? (
<CardItem style={styles.topLikers}>
<Thumbnail
source={{
uri: `https://steemitimages.com/u/${
this.props.content.top_likers[0]
}/avatar/small`,
}}
style={styles.likers_1}
/>
<Thumbnail
source={{
uri: `https://steemitimages.com/u/${
this.props.content.top_likers[1]
}/avatar/small`,
}}
style={styles.likers_2}
/>
<Thumbnail
source={{
uri: `https://steemitimages.com/u/${
this.props.content.top_likers[2]
}/avatar/small`,
}}
style={styles.likers_3}
/>
<Text style={styles.footer}>
@{this.props.content.top_likers[0]}, @
{this.props.content.top_likers[1]}, @
{this.props.content.top_likers[2]}
<Text style={styles.footer}> & </Text>
{this.props.content.vote_count -
this.props.content.top_likers.length}{' '}
others like this
</Text>
</CardItem>
) : (
<CardItem>
<Text style={styles.footer}>
{this.props.content.vote_count} likes
</Text>
</CardItem>
)}
</Card>
);
}
}
const styles = StyleSheet.create({
post: {
shadowColor: 'white',
padding: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 0,
marginBottom: 0,
borderWidth: 0,
borderColor: 'white',
borderRadius: 5,
},
avatar: {
width: 30,
height: 30,
borderRadius: 15,
borderColor: 'lightgray',
borderWidth: 1
},
author: {
backgroundColor: 'white',
alignSelf: 'flex-start',
paddingVertical: 5
},
timeAgo: {
alignSelf: 'center',
fontSize: 9,
fontWeight: '100',
marginHorizontal: 3
},
authorName: {
color: '#222',
fontWeight: '600',
fontSize: 10
},
upvoteButton: {
margin: 0,
flexDirection: 'row',
paddingVertical: 0
},
upvoteIcon: {
alignSelf: 'flex-start',
fontSize: 20,
color: '#007ee5',
margin:0,
width: 18
},
payout: {
alignSelf: 'center',
fontSize: 10,
color: '#626262',
marginLeft: 3
},
payoutIcon: {
fontSize: 15,
marginHorizontal: 3,
color: '#a0a0a0',
alignSelf: 'center'
},
payoutButton: {
flexDirection: 'row',
alignSelf: 'flex-start',
paddingVertical: 2
},
commentButton: {
padding: 0,
margin: 0,
flexDirection: 'row'
},
comment: {
alignSelf: 'center',
fontSize: 10,
color: '#626262',
marginLeft: 3
},
commentIcon: {
alignSelf: 'flex-start',
fontSize: 20,
color: '#007ee5',
margin:0,
width: 20
},
title: {
fontSize: 12,
fontWeight: '500',
marginVertical: 5
},
summary: {
fontSize: 10,
fontWeight: '200',
overflow: 'hidden'
},
header: {
height: 50
},
body: {
justifyContent: 'flex-start',
flexDirection: 'row'
},
image: {
margin: 0,
width: '100%',
height: 160,
},
badge: {
alignSelf: 'center',
borderColor: 'lightgray',
borderWidth: 1,
borderRadius: 10,
width: 15,
height: 15,
padding: 2,
backgroundColor: 'lightgray',
marginHorizontal: 5
},
category: {
alignSelf: 'center',
borderRadius: 10,
height: 15,
backgroundColor: '#007EE5',
paddingHorizontal: 5,
paddingVertical: 1.5
},
categoryText: {
fontSize: 9,
color: 'white',
fontWeight: '600'
},
text: {
fontSize: 7,
alignSelf: 'center',
textAlignVertical: 'center',
color: 'white',
fontWeight: 'bold'
},
topLikers: {
backgroundColor: '#f8f8f8',
borderWidth: 0,
padding:0
},
likers_1: {
width: 14,
height: 14,
borderRadius: 7,
borderWidth: 0.5,
borderColor: 'lightgray',
marginVertical: -5,
},
likers_2: {
width: 14,
height: 14,
borderRadius: 7,
borderWidth: 0.5,
borderColor: 'lightgray',
marginVertical: -5,
marginLeft: -3
},
likers_3: {
width: 14,
height: 14,
borderRadius: 7,
borderWidth: 0.5,
borderColor: 'lightgray',
marginVertical: -5,
marginLeft: -3
},
footer: {
marginLeft: 5,
fontSize: 7,
fontWeight: '100',
color: '#777777'
}
post: {
shadowColor: 'white',
padding: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 0,
marginBottom: 0,
borderWidth: 0,
borderColor: 'white',
borderRadius: 5,
},
avatar: {
width: 30,
height: 30,
borderRadius: 15,
borderColor: 'lightgray',
borderWidth: 1,
},
author: {
backgroundColor: 'white',
alignSelf: 'flex-start',
paddingVertical: 5,
},
timeAgo: {
alignSelf: 'center',
fontSize: 9,
fontWeight: '100',
marginHorizontal: 3,
},
authorName: {
color: '#222',
fontWeight: '600',
fontSize: 10,
},
upvoteButton: {
margin: 0,
flexDirection: 'row',
paddingVertical: 0,
},
upvoteIcon: {
alignSelf: 'flex-start',
fontSize: 20,
color: '#007ee5',
margin: 0,
width: 18,
},
payout: {
alignSelf: 'center',
fontSize: 10,
color: '#626262',
marginLeft: 3,
},
payoutIcon: {
fontSize: 15,
marginHorizontal: 3,
color: '#a0a0a0',
alignSelf: 'center',
},
payoutButton: {
flexDirection: 'row',
alignSelf: 'flex-start',
paddingVertical: 2,
},
commentButton: {
padding: 0,
margin: 0,
flexDirection: 'row',
},
comment: {
alignSelf: 'center',
fontSize: 10,
color: '#626262',
marginLeft: 3,
},
commentIcon: {
alignSelf: 'flex-start',
fontSize: 20,
color: '#007ee5',
margin: 0,
width: 20,
},
title: {
fontSize: 12,
fontWeight: '500',
marginVertical: 5,
},
summary: {
fontSize: 10,
fontWeight: '200',
overflow: 'hidden',
},
header: {
height: 50,
},
body: {
justifyContent: 'flex-start',
flexDirection: 'row',
},
image: {
margin: 0,
width: '100%',
height: 160,
},
badge: {
alignSelf: 'center',
borderColor: 'lightgray',
borderWidth: 1,
borderRadius: 10,
width: 15,
height: 15,
padding: 2,
backgroundColor: 'lightgray',
marginHorizontal: 5,
},
category: {
alignSelf: 'center',
borderRadius: 10,
height: 15,
backgroundColor: '#007EE5',
paddingHorizontal: 5,
paddingVertical: 1.5,
},
categoryText: {
fontSize: 9,
color: 'white',
fontWeight: '600',
},
text: {
fontSize: 7,
alignSelf: 'center',
textAlignVertical: 'center',
color: 'white',
fontWeight: 'bold',
},
topLikers: {
backgroundColor: '#f8f8f8',
borderWidth: 0,
padding: 0,
},
likers_1: {
width: 14,
height: 14,
borderRadius: 7,
borderWidth: 0.5,
borderColor: 'lightgray',
marginVertical: -5,
},
likers_2: {
width: 14,
height: 14,
borderRadius: 7,
borderWidth: 0.5,
borderColor: 'lightgray',
marginVertical: -5,
marginLeft: -3,
},
likers_3: {
width: 14,
height: 14,
borderRadius: 7,
borderWidth: 0.5,
borderColor: 'lightgray',
marginVertical: -5,
marginLeft: -3,
},
footer: {
marginLeft: 5,
fontSize: 7,
fontWeight: '100',
color: '#777777',
},
});
export default PostCard;
export default PostCard;

View File

@ -1,6 +1,6 @@
import {
createStackNavigator,
createBottomTabNavigator
createStackNavigator,
createBottomTabNavigator,
} from 'react-navigation';
import React from 'react';
@ -19,196 +19,196 @@ import SinglePostPage from '../screens/single-post/Post';
import LoginPage from '../screens/login/Login';
import AuthorPage from '../screens/author-profile/Author';
const HomeScreen = ({ navigation }) => (
<HomePage navigation={navigation}></HomePage>
);
const HomeScreen = ({ navigation }) => <HomePage navigation={navigation} />;
HomeScreen.navigationOptions = {
tabBarLabel: 'Home',
title: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<MaterialCommunityIcons
name={focused ? 'home' : 'home'}
size={26}
style={{ color: tintColor }}
/>
),
tabBarLabel: 'Home',
title: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<MaterialCommunityIcons
name={focused ? 'home' : 'home'}
size={26}
style={{ color: tintColor }}
/>
),
};
const ProfileScreen = ({ navigation }) => (
<ProfilePage navigation={navigation}></ProfilePage>
<ProfilePage navigation={navigation} />
);
ProfileScreen.navigationOptions = {
tabBarLabel: 'Profile',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'md-contact' : 'md-contact'}
size={26}
style={{ color: tintColor }}
/>
),
tabBarLabel: 'Profile',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'md-contact' : 'md-contact'}
size={26}
style={{ color: tintColor }}
/>
),
};
const EditorScreen = ({ navigation }) => (
<EditorPage navigation={navigation}></EditorPage>
);
const EditorScreen = ({ navigation }) => <EditorPage navigation={navigation} />;
EditorScreen.navigationOptions = {
tabBarLabel: 'Editor',
tabBarIcon: ({ tintColor, focused }) => (
<Entypo
name={focused ? 'pencil' : 'pencil'}
size={26}
style={styles.post}
style={{ color: tintColor }}
/>
),
tabBarLabel: 'Editor',
tabBarIcon: ({ tintColor, focused }) => (
<Entypo
name={focused ? 'pencil' : 'pencil'}
size={26}
style={styles.post}
style={{ color: tintColor }}
/>
),
};
const WalletScreen = ({ navigation }) => (
<WalletPage navigation={navigation}></WalletPage>
);
const WalletScreen = ({ navigation }) => <WalletPage navigation={navigation} />;
WalletScreen.navigationOptions = {
tabBarLabel: 'Settings',
tabBarIcon: ({ tintColor, focused }) => (
<Entypo
name={focused ? 'wallet' : 'wallet'}
size={26}
style={{ color: tintColor }}
/>
),
tabBarLabel: 'Settings',
tabBarIcon: ({ tintColor, focused }) => (
<Entypo
name={focused ? 'wallet' : 'wallet'}
size={26}
style={{ color: tintColor }}
/>
),
};
const NotificationScreen = ({ navigation }) => (
<NotificationPage navigation={navigation}></NotificationPage>
<NotificationPage navigation={navigation} />
);
NotificationScreen.navigationOptions = {
tabBarLabel: 'Notifications',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-notifications' : 'ios-notifications'}
size={26}
style={{ color: tintColor }}
/>
),
tabBarLabel: 'Notifications',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-notifications' : 'ios-notifications'}
size={26}
style={{ color: tintColor }}
/>
),
};
const SinglePostScreen = ({ navigation }) => (
<SinglePostPage navigation={navigation}></SinglePostPage>
<SinglePostPage navigation={navigation} />
);
const LoginScreen = ({ navigation }) => (
<LoginPage navigation={navigation}></LoginPage>
);
const LoginScreen = ({ navigation }) => <LoginPage navigation={navigation} />;
const AuthorScreen = ({ navigation }) => (
<AuthorPage navigation={navigation}></AuthorPage>
);
const AuthorScreen = ({ navigation }) => <AuthorPage navigation={navigation} />;
const BottomTabs = createBottomTabNavigator(
{
Home: {
screen: HomeScreen,
path: '',
{
Home: {
screen: HomeScreen,
path: '',
},
Profile: {
screen: ProfileScreen,
path: 'profile',
},
Editor: {
screen: EditorScreen,
path: 'editor',
},
Wallet: {
screen: WalletScreen,
path: 'wallet',
},
Notifications: {
screen: NotificationScreen,
path: 'settings',
},
},
Profile: {
screen: ProfileScreen,
path: 'profile',
},
Editor: {
screen: EditorScreen,
path: 'editor',
},
Wallet: {
screen: WalletScreen,
path: 'wallet',
},
Notifications: {
screen: NotificationScreen,
path: 'settings',
{
tabBarOptions: {
activeTintColor: '#373c3f',
inactiveTintColor: '#AFB1B3',
style: {
backgroundColor: 'white',
borderTopColor: '#dedede',
borderWidth: 0,
},
showLabel: false,
},
}
},
{
tabBarOptions: {
activeTintColor: '#373c3f',
inactiveTintColor: '#AFB1B3',
style: {
backgroundColor: 'white',
borderTopColor: '#dedede',
borderWidth: 0
},
showLabel: false,
}
},
);
BottomTabs.navigationOptions = ({navigation})=> ({
header: null,
style: {
backgroundColor: 'white',
BottomTabs.navigationOptions = ({ navigation }) => ({
header: null,
style: {
backgroundColor: 'white',
},
});
const StacksOverTabs = createStackNavigator({
Root: {
screen: BottomTabs,
},
Post: {
screen: SinglePostScreen,
path: '/:category/:user/:permlink',
navigationOptions: ({ navigation }) => ({
header: null
}),
},
Login: {
screen: LoginScreen,
path: '/login',
},
Author: {
screen: AuthorScreen,
path: '/author',
}
}, {
headerMode: 'none'
});
const StacksOverTabs = createStackNavigator(
{
Root: {
screen: BottomTabs,
},
Post: {
screen: SinglePostScreen,
path: '/:category/:user/:permlink',
navigationOptions: ({ navigation }) => ({
header: null,
}),
},
Login: {
screen: LoginScreen,
path: '/login',
},
Author: {
screen: AuthorScreen,
path: '/author',
},
},
{
headerMode: 'none',
}
);
class Tabs extends React.Component {
static router = StacksOverTabs.router;
_s0;
_s1;
_s2;
_s3;
static router = StacksOverTabs.router;
_s0;
_s1;
_s2;
_s3;
componentDidMount() {
this._s0 = this.props.navigation.addListener('willFocus', this._onAction);
this._s1 = this.props.navigation.addListener('didFocus', this._onAction);
this._s2 = this.props.navigation.addListener('willBlur', this._onAction);
this._s3 = this.props.navigation.addListener('didBlur', this._onAction);
}
componentWillUnmount() {
this._s0.remove();
this._s1.remove();
this._s2.remove();
this._s3.remove();
}
_onAction = a => {
console.log('TABS EVENT', a.type, a);
};
render() {
return <StacksOverTabs navigation={this.props.navigation} />;
}
componentDidMount() {
this._s0 = this.props.navigation.addListener(
'willFocus',
this._onAction
);
this._s1 = this.props.navigation.addListener(
'didFocus',
this._onAction
);
this._s2 = this.props.navigation.addListener(
'willBlur',
this._onAction
);
this._s3 = this.props.navigation.addListener('didBlur', this._onAction);
}
componentWillUnmount() {
this._s0.remove();
this._s1.remove();
this._s2.remove();
this._s3.remove();
}
_onAction = a => {
console.log('TABS EVENT', a.type, a);
};
render() {
return <StacksOverTabs navigation={this.props.navigation} />;
}
}
const styles = StyleSheet.create({
post: {
borderWidth: 22,
borderColor: 'blue',
}
post: {
borderWidth: 22,
borderColor: 'blue',
},
});
export default Tabs;

View File

@ -3,103 +3,129 @@ import { getAccount } from './Dsteem';
import { AsyncStorage } from 'react-native';
export const Login = (username, password) => {
let account;
let publicKeys;
let privateKeys;
let isPassword;
let isPostingKey;
let account;
let publicKeys;
let privateKeys;
let isPassword;
let isPostingKey;
return new Promise((resolve, reject) => {
getAccount(username)
.then(result => {
if (result.length < 1) {
reject(new Error('Wrong @username'));
}
return new Promise((resolve,reject) => {
getAccount(username).then((result) => {
account = result[0];
if (result.length < 1) {
reject(new Error('Wrong @username'));
}
account = result[0];
// Public keys of user
publicKeys = {
active: account['active'].key_auths.map(x => x[0]),
memo: account['memo_key'],
owner: account['owner'].key_auths.map(x => x[0]),
posting: account['posting'].key_auths.map(x => x[0])
};
}).then(() => {
try {
// Set private keys of user
privateKeys = {
active: dsteem.PrivateKey.fromLogin(username, password, 'active').toString(),
memo: dsteem.PrivateKey.fromLogin(username, password, 'memo').toString(),
owner: dsteem.PrivateKey.fromLogin(username, password, 'owner').toString(),
posting: dsteem.PrivateKey.fromLogin(username, password, 'posting').toString()
}
} catch (error) {
reject(new Error('Wrong Key/Password'));
}
}).then(() => {
try {
isPassword = (dsteem.PrivateKey.fromLogin(username, password, 'posting').createPublic()).toString() === (publicKeys.posting).toString()
if (isPassword) {
let authType = {
'username': username,
'auth_type': 'master_key',
'posting_key': privateKeys.posting,
'active_key': privateKeys.active,
'memo_key': privateKeys.memo,
'owner_key': privateKeys.owner
}
AsyncStorage.setItem('isLoggedIn', 'true', () => {
AsyncStorage.setItem('user', JSON.stringify(authType), () => {
resolve(isPassword);
// Public keys of user
publicKeys = {
active: account['active'].key_auths.map(x => x[0]),
memo: account['memo_key'],
owner: account['owner'].key_auths.map(x => x[0]),
posting: account['posting'].key_auths.map(x => x[0]),
};
})
.then(() => {
try {
// Set private keys of user
privateKeys = {
active: dsteem.PrivateKey.fromLogin(
username,
password,
'active'
).toString(),
memo: dsteem.PrivateKey.fromLogin(
username,
password,
'memo'
).toString(),
owner: dsteem.PrivateKey.fromLogin(
username,
password,
'owner'
).toString(),
posting: dsteem.PrivateKey.fromLogin(
username,
password,
'posting'
).toString(),
};
} catch (error) {
reject(new Error('Wrong Key/Password'));
}
})
.then(() => {
try {
isPassword =
dsteem.PrivateKey.fromLogin(
username,
password,
'posting'
)
.createPublic()
.toString() === publicKeys.posting.toString();
if (isPassword) {
let authType = {
username: username,
auth_type: 'master_key',
posting_key: privateKeys.posting,
active_key: privateKeys.active,
memo_key: privateKeys.memo,
owner_key: privateKeys.owner,
};
AsyncStorage.setItem('isLoggedIn', 'true', () => {
AsyncStorage.setItem(
'user',
JSON.stringify(authType),
() => {
resolve(isPassword);
}
);
});
} else {
isPostingKey =
publicKeys.posting.toString() ===
dsteem.PrivateKey.fromString(password)
.createPublic()
.toString();
let authType = {
username: username,
auth_type: 'posting_key',
posting_key: password,
};
try {
if (isPostingKey) {
AsyncStorage.setItem(
'isLoggedIn',
'true',
() => {
AsyncStorage.setItem(
'user',
JSON.stringify(authType),
() => {
resolve(isPostingKey);
}
);
}
);
} else {
reject(new Error('Wrong Key/Password'));
}
} catch (error) {
reject(new Error('Wrong Key/Password'));
}
}
} catch (error) {
reject(new Error('Wrong Key/Password'));
}
})
.catch(err => {
reject(new Error('Check your username'));
});
})
} else {
isPostingKey = (publicKeys.posting).toString() === (dsteem.PrivateKey.fromString(password).createPublic()).toString();
let authType = {
'username': username,
'auth_type': 'posting_key',
'posting_key': password
}
try {
if (isPostingKey) {
AsyncStorage.setItem('isLoggedIn', 'true', () => {
AsyncStorage.setItem('user', JSON.stringify(authType), () => {
resolve(isPostingKey)
})
})
} else {
reject(new Error('Wrong Key/Password'));
}
} catch (error) {
reject(new Error('Wrong Key/Password'));
}
}
} catch (error) {
reject(new Error('Wrong Key/Password'));
}
}).catch((err) => {
reject(new Error('Check your username'));
});
})
}
};

View File

@ -5,78 +5,84 @@ import { parsePosts } from '../../utils/PostParser';
import Remarkable from 'remarkable';
var md = new Remarkable({
html: true, // Enable HTML tags in source
xhtmlOut: false, // Use '/' to close single tags (<br />)
breaks: true, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks
linkify: true, // Autoconvert URL-like text to links
html: true, // Enable HTML tags in source
xhtmlOut: false, // Use '/' to close single tags (<br />)
breaks: true, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks
linkify: true, // Autoconvert URL-like text to links
// Enable some language-neutral replacement + quotes beautification
typographer: true,
// Enable some language-neutral replacement + quotes beautification
typographer: true,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes: '“”‘’'
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes: '“”‘’',
});
/**
* @method getAccount get account data
* @param user username
*/
export const getAccount = (user) => {
/**
* @method getAccount get account data
* @param user username
*/
export const getAccount = user => {
return new Promise((resolve, reject) => {
let account = client.database.getAccounts([user]);
resolve(account);
})
}
let account = client.database.getAccounts([user]);
resolve(account);
});
};
/**
* @method getPosts get posts method
* @param by get discussions by trending, created, active etc.
* @param query tag, limit, start_author?, start_permalink?
*/
export const getPosts = async (by, query) => {
/**
* @method getPosts get posts method
* @param by get discussions by trending, created, active etc.
* @param query tag, limit, start_author?, start_permalink?
*/
export const getPosts = async (by, query) => {
let posts = await client.database.getDiscussions(by, query);
posts = await parsePosts(posts);
return posts;
}
};
/**
* @method getUser get user data
* @param user post author
* @param permlink post permlink
*/
export const getPost = (user, permlink) => {
/**
* @method getUser get user data
* @param user post author
* @param permlink post permlink
*/
export const getPost = (user, permlink) => {
return new Promise((resolve, reject) => {
let post = client.database.call('get_content',[user,permlink]);
resolve(post);
let post = client.database.call('get_content', [user, permlink]);
resolve(post);
});
}
};
/**
* @method getUser get user data
* @param user post author
* @param permlink post permlink
*/
export const getComments = (user, permlink) => {
/**
* @method getUser get user data
* @param user post author
* @param permlink post permlink
*/
export const getComments = (user, permlink) => {
return new Promise((resolve, reject) => {
let comments = client.database.call('get_content_replies',[user, permlink]);
resolve(comments);
let comments = client.database.call('get_content_replies', [
user,
permlink,
]);
resolve(comments);
});
}
};
/**
* @method getPostWithComments get user data
* @param user post author
* @param permlink post permlink
*/
export const getPostWithComments = async (user, permlink) => {
/**
* @method getPostWithComments get user data
* @param user post author
* @param permlink post permlink
*/
export const getPostWithComments = async (user, permlink) => {
let post;
let comments;
await getPost(user,permlink).then((result) => { post = result });
await getComments(user,permlink).then((result) => { comments = result });
await getPost(user, permlink).then(result => {
post = result;
});
await getComments(user, permlink).then(result => {
comments = result;
});
return([post, comments])
}
return [post, comments];
};

View File

@ -1,58 +1,69 @@
import * as React from 'react';
import { StatusBar } from 'react-native';
import { Container, Header, Left, Body, Right, Button, Icon, Title, Content, Text } from 'native-base';
import {
Container,
Header,
Left,
Body,
Right,
Button,
Icon,
Title,
Content,
Text,
} from 'native-base';
import { getAccount } from '../../providers/steem/Dsteem';
class AuthorPage extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
author: 'author'
this.state = {
author: 'author',
};
}
}
componentDidMount() {
getAccount(this.props.navigation.state.params.author).then((author) => {
this.setState({
author: author[0]
})
}).catch((err) => {
});
}
componentDidMount() {
getAccount(this.props.navigation.state.params.author)
.then(author => {
this.setState({
author: author[0],
});
})
.catch(err => {});
}
render() {
return (
<Container style={{ top: StatusBar.currentHeight }}>
<Header>
<Left>
<Button transparent
onPress={() => this.props.navigation.goBack()}>
<Icon name='arrow-back' />
</Button>
</Left>
<Body>
<Title> { this.state.author.name } </Title>
</Body>
<Right>
<Button transparent>
<Icon name='heart' />
</Button>
<Button transparent>
<Icon name='more' />
</Button>
</Right>
</Header>
render() {
return (
<Container style={{ top: StatusBar.currentHeight }}>
<Header>
<Left>
<Button
transparent
onPress={() => this.props.navigation.goBack()}
>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title> {this.state.author.name} </Title>
</Body>
<Right>
<Button transparent>
<Icon name="heart" />
</Button>
<Button transparent>
<Icon name="more" />
</Button>
</Right>
</Header>
<Content>
<Text>
{ JSON.stringify(this.state.author) }
</Text>
</Content>
</Container>
)
}
<Content>
<Text>{JSON.stringify(this.state.author)}</Text>
</Content>
</Container>
);
}
}
export default AuthorPage;
export default AuthorPage;

View File

@ -1,41 +1,49 @@
import * as React from 'react';
import { Container, Header, Left, Body, Right, Button, Icon, Title } from 'native-base';
import {
Container,
Header,
Left,
Body,
Right,
Button,
Icon,
Title,
} from 'native-base';
class EditorPage extends React.Component {
constructor(props) {
super(props)
}
constructor(props) {
super(props);
}
componentDidMount() {
}
componentDidMount() {}
render() {
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon name='menu' />
</Button>
</Left>
<Body>
<Title>Editor</Title>
</Body>
<Right>
<Button transparent>
<Icon name='search' />
</Button>
<Button transparent>
<Icon name='heart' />
</Button>
<Button transparent>
<Icon name='more' />
</Button>
</Right>
</Header>
</Container>
)
}
render() {
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>Editor</Title>
</Body>
<Right>
<Button transparent>
<Icon name="search" />
</Button>
<Button transparent>
<Icon name="heart" />
</Button>
<Button transparent>
<Icon name="more" />
</Button>
</Right>
</Header>
</Container>
);
}
}
export default EditorPage;
export default EditorPage;

View File

@ -1,15 +1,14 @@
import React,{Component} from 'react'
import {StyleSheet,
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Animated,
TouchableNativeFeedback,
TouchableOpacity,
Platform,
Dimensions
} from 'react-native'
Dimensions,
} from 'react-native';
export default class CustomTabBar extends Component {
constructor(props) {
@ -17,39 +16,48 @@ export default class CustomTabBar extends Component {
this.state = {
activeDefaultColor: '#08086b',
inactiveDefaultColor: '#666666'
}
inactiveDefaultColor: '#666666',
};
}
_renderTab(name, page, isTabActive, onPressHandler) {
const { textStyle } = this.props;
const textColor = isTabActive ? this.props.activeColor : this.props.inactiveColor;
const textColor = isTabActive
? this.props.activeColor
: this.props.inactiveColor;
const fontWeight = isTabActive ? 'bold' : 'normal';
const Button = Platform.OS == 'ios' ? ButtonIos : ButtonAndroid;
return (<Button
style={{flex: 1}}
key={name}
accessible={true}
accessibilityLabel={name}
accessibilityTraits='button'
onPress={() => onPressHandler(page)}>
<View style={styles.tab}>
<Text style={[{color: textColor, fontWeight } ]}>
{name}
</Text>
</View>
</Button>);
}
_renderUnderline() {
return (
<Button
style={{ flex: 1 }}
key={name}
accessible={true}
accessibilityLabel={name}
accessibilityTraits="button"
onPress={() => onPressHandler(page)}
>
<View style={styles.tab}>
<Text style={[{ color: textColor, fontWeight }]}>
{name}
</Text>
</View>
</Button>
);
}
_renderUnderline() {
const containerWidth = Dimensions.get('window').width / 1;
const numberOfTabs = this.props.tabs.length;
const underlineWidth = this.props.tabUnderlineDefaultWidth ? this.props.tabUnderlineDefaultWidth : containerWidth / (numberOfTabs * 2);
const scale = this.props.tabUnderlineScaleX ? this.props.tabUnderlineScaleX : 3;
const deLen = (containerWidth / numberOfTabs - underlineWidth ) / 2;
const underlineWidth = this.props.tabUnderlineDefaultWidth
? this.props.tabUnderlineDefaultWidth
: containerWidth / (numberOfTabs * 2);
const scale = this.props.tabUnderlineScaleX
? this.props.tabUnderlineScaleX
: 3;
const deLen = (containerWidth / numberOfTabs - underlineWidth) / 2;
const tabUnderlineStyle = {
position: 'absolute',
width: underlineWidth,
@ -57,87 +65,98 @@ export default class CustomTabBar extends Component {
borderRadius: 2,
backgroundColor: this.props.activeColor,
bottom: 3,
left: deLen
left: deLen,
};
const translateX = this.props.scrollValue.interpolate({
inputRange: [0, 1],
outputRange: [0, containerWidth / numberOfTabs],
outputRange: [0, containerWidth / numberOfTabs],
});
const scaleValue = (defaultScale) => {
let number = 4
let arr = new Array(number * 2)
return arr.fill(0).reduce(function(pre, cur, idx){
idx == 0 ? pre.inputRange.push(cur) : pre.inputRange.push(pre.inputRange[idx-1] + 0.5);
idx%2 ? pre.outputRange.push(defaultScale) : pre.outputRange.push(1)
return pre
}, {inputRange: [], outputRange: []})
}
const scaleValue = defaultScale => {
let number = 4;
let arr = new Array(number * 2);
return arr.fill(0).reduce(
function(pre, cur, idx) {
idx == 0
? pre.inputRange.push(cur)
: pre.inputRange.push(pre.inputRange[idx - 1] + 0.5);
idx % 2
? pre.outputRange.push(defaultScale)
: pre.outputRange.push(1);
return pre;
},
{ inputRange: [], outputRange: [] }
);
};
const scaleX = this.props.scrollValue.interpolate(scaleValue(scale));
return(
<Animated.View
style={[
tabUnderlineStyle,
{
transform: [
{ translateX },
{ scaleX }
],
},
this.props.underlineStyle,
]}
/>
)
}
render() {
return (
<View style={[styles.tabs, {backgroundColor: this.props.backgroundColor}, this.props.style]}>
<Animated.View
style={[
tabUnderlineStyle,
{
transform: [{ translateX }, { scaleX }],
},
this.props.underlineStyle,
]}
/>
);
}
render() {
return (
<View
style={[
styles.tabs,
{ backgroundColor: this.props.backgroundColor },
this.props.style,
]}
>
{this.props.tabs.map((name, page) => {
const isTabActive = this.props.activeTab === page;
return this._renderTab(name, page, isTabActive, this.props.goToPage)
const isTabActive = this.props.activeTab === page;
return this._renderTab(
name,
page,
isTabActive,
this.props.goToPage
);
})}
{
this._renderUnderline()
}
{this._renderUnderline()}
</View>
);
};
}
}
const ButtonAndroid = props => (
<TouchableNativeFeedback
delayPressIn={0}
background={TouchableNativeFeedback.SelectableBackground()}
{...props}
>
{props.children}
</TouchableNativeFeedback>
);
const ButtonAndroid = (props) => (
<TouchableNativeFeedback
delayPressIn={0}
background={TouchableNativeFeedback.SelectableBackground()}
{...props}
>
{props.children}
</TouchableNativeFeedback>);
const ButtonIos = (props) => (<TouchableOpacity {...props}>
{props.children}
</TouchableOpacity>);
const ButtonIos = props => (
<TouchableOpacity {...props}>{props.children}</TouchableOpacity>
);
const styles = StyleSheet.create({
tab: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
tabs: {
height: 50,
flexDirection: 'row',
justifyContent: 'space-around',
borderWidth: 1,
borderTopWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 0,
borderColor: '#f4f4f4',
},
});
tab: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
tabs: {
height: 50,
flexDirection: 'row',
justifyContent: 'space-around',
borderWidth: 1,
borderTopWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 0,
borderColor: '#f4f4f4',
},
});

View File

@ -1,10 +1,28 @@
import React from 'react';
import { StyleSheet, FlatList, View, AsyncStorage, StatusBar, Dimensions, TouchableHighlight, ActivityIndicator } from 'react-native';
import { Container, Header, Button,
Thumbnail, Right, Text, Tabs,
Tab, Icon, ScrollableTab } from "native-base";
import {
StyleSheet,
FlatList,
View,
AsyncStorage,
StatusBar,
Dimensions,
TouchableHighlight,
ActivityIndicator,
} from 'react-native';
import {
Container,
Header,
Button,
Thumbnail,
Right,
Text,
Tabs,
Tab,
Icon,
ScrollableTab,
} from 'native-base';
// STEEM
// STEEM
import { getPosts, getAccount } from '../../providers/steem/Dsteem';
// LIBRARIES
@ -18,195 +36,216 @@ import HotPage from './hot';
import TrendingPage from './trending';
class FeedPage extends React.Component {
constructor(props) {
super(props)
this.state = {
isReady: false,
posts: [],
user: [],
start_author: '',
start_permlink: '',
refreshing: false,
loading: false,
isLoggedIn: false,
constructor(props) {
super(props);
this.state = {
isReady: false,
posts: [],
user: [],
start_author: '',
start_permlink: '',
refreshing: false,
loading: false,
isLoggedIn: false,
};
}
}
componentDidMount() {
AsyncStorage.getItem('isLoggedIn').then((result) => {
let res = JSON.parse(result);
if (res) {
this.setState({
isLoggedIn: true
}, () => {
AsyncStorage.getItem('user').then((result) => {
let user = JSON.parse(result);
getAccount(user.username).then((result) => {
this.setState({
user: result[0]
}, () => {
this.getFeed();
})
componentDidMount() {
AsyncStorage.getItem('isLoggedIn').then(result => {
let res = JSON.parse(result);
if (res) {
this.setState(
{
isLoggedIn: true,
},
() => {
AsyncStorage.getItem('user').then(result => {
let user = JSON.parse(result);
getAccount(user.username).then(result => {
this.setState(
{
user: result[0],
},
() => {
this.getFeed();
}
);
});
});
}
);
}
});
}
getFeed = () => {
getPosts('feed', { tag: this.state.user.name, limit: 5 })
.then(result => {
this.setState({
isReady: true,
posts: result,
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
refreshing: false,
});
})
});
})
}
})
}
.catch(err => {
alert(err);
});
};
getMore = () => {
this.setState({ loading: true });
getPosts('feed', {
tag: this.state.user.name,
limit: 10,
start_author: this.state.start_author,
start_permlink: this.state.start_permlink,
}).then(result => {
let posts = result;
posts.shift();
this.setState({
posts: [...this.state.posts, ...posts],
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
});
});
};
getFeed = () => {
getPosts('feed', { "tag": this.state.user.name, "limit": 5 }).then((result) => {
this.setState({
isReady: true,
posts: result,
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
refreshing: false
});
}).catch((err) => {
alert(err);
});
}
refreshPosts = () => {
this.setState(
{
refreshing: true,
},
() => {
this.getFeed();
}
);
};
getMore = () => {
this.setState({ loading: true })
getPosts('feed', { "tag": this.state.user.name, "limit": 10, "start_author": this.state.start_author, "start_permlink": this.state.start_permlink }).then((result) => {
let posts = result;
posts.shift();
this.setState({
posts: [...this.state.posts, ...posts],
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink
});
});
}
renderFooter = () => {
if (!this.state.loading) return null;
refreshPosts = () => {
this.setState({
refreshing: true
}, () => {
this.getFeed();
});
}
return (
<View
style={{
alignContent: 'center',
alignItems: 'center',
marginTop: 10,
borderColor: '#CED0CE',
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
alignContent: 'center',
alignItems: 'center',
marginTop: 10,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
const navigate = this.props.navigation;
return (
<View style={{ flex: 1 }}>
{ this.state.isReady ? (
<FlatList
style={{ flex: 1 }}
data={this.state.posts}
showsVerticalScrollIndicator={false}
renderItem={({item}) =>
<View style={styles.card}>
<TouchableHighlight
onPress={() => { navigate('Post',{ content: item }) }}>
<PostCard navigate={navigate} content={item}></PostCard>
</TouchableHighlight>
</View>
}
keyExtractor={(post, index) => index.toString()}
onEndReached={this.getMore}
refreshing={this.state.refreshing}
onRefresh={() => this.refreshPosts()}
onEndThreshold={0}
ListFooterComponent={this.renderFooter}
/>
) : (
<View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
</View>
) }
</View>
)
}
render() {
const navigate = this.props.navigation;
return (
<View style={{ flex: 1 }}>
{this.state.isReady ? (
<FlatList
style={{ flex: 1 }}
data={this.state.posts}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<View style={styles.card}>
<TouchableHighlight
onPress={() => {
navigate('Post', { content: item });
}}
>
<PostCard
navigate={navigate}
content={item}
/>
</TouchableHighlight>
</View>
)}
keyExtractor={(post, index) => index.toString()}
onEndReached={this.getMore}
refreshing={this.state.refreshing}
onRefresh={() => this.refreshPosts()}
onEndThreshold={0}
ListFooterComponent={this.renderFooter}
/>
) : (
<View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
</View>
)}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F9F9F9',
flex: 1,
top: StatusBar.currentHeight
},
placeholder: {
backgroundColor: 'white',
padding: 20,
borderStyle: 'solid',
borderWidth: 1,
borderTopWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 10,
},
card: {
backgroundColor: 'white',
shadowColor: 'white',
marginRight: 0,
marginLeft: 0,
marginTop: 10,
marginBottom: 0,
borderWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 5,
paddingHorizontal: 0,
paddingVertical: 0,
},
tabs: {
position: 'absolute',
top: Dimensions.get("window").width / 30,
alignItems: 'center'
},
container: {
backgroundColor: '#F9F9F9',
flex: 1,
top: StatusBar.currentHeight,
},
placeholder: {
backgroundColor: 'white',
padding: 20,
borderStyle: 'solid',
borderWidth: 1,
borderTopWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 10,
},
card: {
backgroundColor: 'white',
shadowColor: 'white',
marginRight: 0,
marginLeft: 0,
marginTop: 10,
marginBottom: 0,
borderWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 5,
paddingHorizontal: 0,
paddingVertical: 0,
},
tabs: {
position: 'absolute',
top: Dimensions.get('window').width / 30,
alignItems: 'center',
},
});
export default FeedPage;
export default FeedPage;

View File

@ -1,10 +1,26 @@
import React from 'react';
import { StyleSheet, View, AsyncStorage, StatusBar, Dimensions } from 'react-native';
import { Container, Header, Button, Left,
Thumbnail, Right, Text, Tabs,
Tab, Icon, ScrollableTab } from "native-base";
import {
StyleSheet,
View,
AsyncStorage,
StatusBar,
Dimensions,
} from 'react-native';
import {
Container,
Header,
Button,
Left,
Thumbnail,
Right,
Text,
Tabs,
Tab,
Icon,
ScrollableTab,
} from 'native-base';
// STEEM
// STEEM
import { getAccount } from '../../providers/steem/Dsteem';
// SCREENS
@ -12,113 +28,180 @@ import FeedPage from './feed';
import HotPage from './hot';
import TrendingPage from './trending';
import ScrollableTabView, { DefaultTabBar, ScrollableTabBar } from 'react-native-scrollable-tab-view'
import CustomTabBar from './CustomTabBar'
import ScrollableTabView, {
DefaultTabBar,
ScrollableTabBar,
} from 'react-native-scrollable-tab-view';
import CustomTabBar from './CustomTabBar';
class HomePage extends React.Component {
constructor(props) {
super(props)
this.state = {
user: [],
isLoggedIn: false,
constructor(props) {
super(props);
this.state = {
user: [],
isLoggedIn: false,
};
}
}
componentDidMount() {
AsyncStorage.getItem('isLoggedIn').then((result) => {
let res = JSON.parse(result);
if (res) {
this.setState({
isLoggedIn: true
}, () => {
AsyncStorage.getItem('user').then((result) => {
let user = JSON.parse(result);
getAccount(user.username).then((result) => {
this.setState({
user: result[0]
}, () => {
})
})
});
})
}
})
}
componentDidMount() {
AsyncStorage.getItem('isLoggedIn').then(result => {
let res = JSON.parse(result);
if (res) {
this.setState(
{
isLoggedIn: true,
},
() => {
AsyncStorage.getItem('user').then(result => {
let user = JSON.parse(result);
getAccount(user.username).then(result => {
this.setState(
{
user: result[0],
},
() => {}
);
});
});
}
);
}
});
}
render() {
const { navigate } = this.props.navigation;
return (
<Container style={{ flex: 1, top: StatusBar.currentHeight }}>
<StatusBar translucent={true} backgroundColor={'transparent'}/>
<Header noShadow style={{ backgroundColor: '#284b78', borderBottomWidth: 0, borderColor: '#284b78' }}>
<Left>
<Button
transparent
style={{ zIndex: 2 }}
onPress={() => this.props.navigation.toggleDrawer()}>
<Thumbnail square small source={{uri: `https://steemitimages.com/u/${this.state.user.name}/avatar/small` }} style={{ width: 30, height: 30, borderRadius: 15, borderWidth: 1, borderColor: 'white' }}/>
</Button>
</Left>
<Right>
<Button transparent>
<Icon style={{ color: 'white', fontWeight: 'bold' }} name='search' />
</Button>
</Right>
</Header>
render() {
const { navigate } = this.props.navigation;
return (
<Container style={{ flex: 1, top: StatusBar.currentHeight }}>
<StatusBar translucent={true} backgroundColor={'transparent'} />
<Header
noShadow
style={{
backgroundColor: '#284b78',
borderBottomWidth: 0,
borderColor: '#284b78',
}}
>
<Left>
<Button
transparent
style={{ zIndex: 2 }}
onPress={() => this.props.navigation.toggleDrawer()}
>
<Thumbnail
square
small
source={{
uri: `https://steemitimages.com/u/${
this.state.user.name
}/avatar/small`,
}}
style={{
width: 30,
height: 30,
borderRadius: 15,
borderWidth: 1,
borderColor: 'white',
}}
/>
</Button>
</Left>
<Right>
<Button transparent>
<Icon
style={{ color: 'white', fontWeight: 'bold' }}
name="search"
/>
</Button>
</Right>
</Header>
<ScrollableTabView
style={{ alignSelf: 'center', backgroundColor: 'transparent' }}
renderTabBar={() => (
<CustomTabBar
style={{ alignSelf: 'center', height: 40, backgroundColor: '#284b78' }}
tabUnderlineDefaultWidth={30} // default containerWidth / (numberOfTabs * 4)
tabUnderlineScaleX={3} // default 3
activeColor={"#fff"}
inactiveColor={"#fff"}/>
)}>
<View tabLabel='Feed'
style={{ paddingHorizontal: 7, backgroundColor: '#f9f9f9', flex: 1, minWidth: Dimensions.get('window').width / 1 }}>
{ this.state.isLoggedIn ?
<FeedPage navigation={navigate}/>
: (
<View style={{ alignItems: 'center' }}>
<Button light
onPress={() => this.props.navigation.navigate('Login')}
style={{ alignSelf: 'center', marginTop: 100 }}>
<Text>
Login to setup your custom Feed!
</Text>
</Button>
</View> )
}
</View>
<View tabLabel='Hot'
style={{ paddingHorizontal: 7, backgroundColor: '#f9f9f9', flex: 1, minWidth: Dimensions.get('window').width / 1 }}>
<HotPage navigation={navigate}/>
</View>
<View tabLabel='Trending'
style={{ paddingHorizontal: 7, backgroundColor: '#f9f9f9', flex: 1, minWidth: Dimensions.get('window').width / 1 }}>
<TrendingPage navigation={navigate}/>
</View>
</ScrollableTabView>
</Container>
)
}
<ScrollableTabView
style={{
alignSelf: 'center',
backgroundColor: 'transparent',
}}
renderTabBar={() => (
<CustomTabBar
style={{
alignSelf: 'center',
height: 40,
backgroundColor: '#284b78',
}}
tabUnderlineDefaultWidth={30} // default containerWidth / (numberOfTabs * 4)
tabUnderlineScaleX={3} // default 3
activeColor={'#fff'}
inactiveColor={'#fff'}
/>
)}
>
<View
tabLabel="Feed"
style={{
paddingHorizontal: 7,
backgroundColor: '#f9f9f9',
flex: 1,
minWidth: Dimensions.get('window').width / 1,
}}
>
{this.state.isLoggedIn ? (
<FeedPage navigation={navigate} />
) : (
<View style={{ alignItems: 'center' }}>
<Button
light
onPress={() =>
this.props.navigation.navigate('Login')
}
style={{
alignSelf: 'center',
marginTop: 100,
}}
>
<Text>
Login to setup your custom Feed!
</Text>
</Button>
</View>
)}
</View>
<View
tabLabel="Hot"
style={{
paddingHorizontal: 7,
backgroundColor: '#f9f9f9',
flex: 1,
minWidth: Dimensions.get('window').width / 1,
}}
>
<HotPage navigation={navigate} />
</View>
<View
tabLabel="Trending"
style={{
paddingHorizontal: 7,
backgroundColor: '#f9f9f9',
flex: 1,
minWidth: Dimensions.get('window').width / 1,
}}
>
<TrendingPage navigation={navigate} />
</View>
</ScrollableTabView>
</Container>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F9F9F9',
flex: 1
},
tabs: {
flex: 1
}
container: {
backgroundColor: '#F9F9F9',
flex: 1,
},
tabs: {
flex: 1,
},
});
export default HomePage;
export default HomePage;

View File

@ -1,8 +1,16 @@
import React from 'react';
import { StyleSheet, FlatList, View, StatusBar, Dimensions, TouchableHighlight, ActivityIndicator } from 'react-native';
import { Container } from "native-base";
import {
StyleSheet,
FlatList,
View,
StatusBar,
Dimensions,
TouchableHighlight,
ActivityIndicator,
} from 'react-native';
import { Container } from 'native-base';
// STEEM
// STEEM
import { getPosts, getAccount } from '../../providers/steem/Dsteem';
// LIBRARIES
@ -15,170 +23,186 @@ import PostCard from '../../components/PostCard';
import PostPage from '../../screens/single-post/Post';
class HotPage extends React.Component {
constructor(props) {
super(props)
this.state = {
isReady: false,
posts: [],
user: [],
start_author: '',
start_permlink: '',
refreshing: false,
loading: false,
constructor(props) {
super(props);
this.state = {
isReady: false,
posts: [],
user: [],
start_author: '',
start_permlink: '',
refreshing: false,
loading: false,
};
}
}
componentDidMount() {
this.getHotPosts();
}
componentDidMount() {
this.getHotPosts();
}
getHotPosts = () => {
getPosts('hot', { "tag": "", "limit": 5 }).then((result) => {
this.setState({
isReady: true,
posts: result,
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
refreshing: false
});
}).catch((err) => {
alert(err);
});
}
getHotPosts = () => {
getPosts('hot', { tag: '', limit: 5 })
.then(result => {
this.setState({
isReady: true,
posts: result,
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
refreshing: false,
});
})
.catch(err => {
alert(err);
});
};
getMoreHot = () => {
this.setState({ loading: true })
getPosts('hot', { "tag": "", "limit": 10, "start_author": this.state.start_author, "start_permlink": this.state.start_permlink }).then((result) => {
let posts = result;
posts.shift();
this.setState({
posts: [...this.state.posts, ...posts],
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink
});
});
}
getMoreHot = () => {
this.setState({ loading: true });
getPosts('hot', {
tag: '',
limit: 10,
start_author: this.state.start_author,
start_permlink: this.state.start_permlink,
}).then(result => {
let posts = result;
posts.shift();
this.setState({
posts: [...this.state.posts, ...posts],
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
});
});
};
refreshHotPosts = () => {
this.setState({
refreshing: true
}, () => {
this.getHotPosts();
});
}
refreshHotPosts = () => {
this.setState(
{
refreshing: true,
},
() => {
this.getHotPosts();
}
);
};
renderFooter = () => {
if (!this.state.loading) return null;
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
alignContent: 'center',
alignItems: 'center',
marginTop: 10,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
return (
<View
style={{
alignContent: 'center',
alignItems: 'center',
marginTop: 10,
borderColor: '#CED0CE',
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
const navigate = this.props.navigation;
return (
<View style={{ flex: 1 }}>
{ this.state.isReady ? (
<FlatList
style={{ flex: 1 }}
data={this.state.posts}
showsVerticalScrollIndicator={false}
renderItem={({item}) =>
<View style={styles.card}>
<TouchableHighlight
onPress={() => { navigate('Post',{ content: item }) }}>
<PostCard navigate={navigate} content={item}></PostCard>
</TouchableHighlight>
</View>
}
keyExtractor={(post, index) => index.toString()}
onEndReached={this.getMoreHot}
refreshing={this.state.refreshing}
onRefresh={() => this.refreshHotPosts()}
onEndThreshold={0}
ListFooterComponent={this.renderFooter}
/>
) : (
<View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
</View>
) }
</View>
)
}
render() {
const navigate = this.props.navigation;
return (
<View style={{ flex: 1 }}>
{this.state.isReady ? (
<FlatList
style={{ flex: 1 }}
data={this.state.posts}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<View style={styles.card}>
<TouchableHighlight
onPress={() => {
navigate('Post', { content: item });
}}
>
<PostCard
navigate={navigate}
content={item}
/>
</TouchableHighlight>
</View>
)}
keyExtractor={(post, index) => index.toString()}
onEndReached={this.getMoreHot}
refreshing={this.state.refreshing}
onRefresh={() => this.refreshHotPosts()}
onEndThreshold={0}
ListFooterComponent={this.renderFooter}
/>
) : (
<View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
</View>
)}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F9F9F9',
flex: 1,
top: StatusBar.currentHeight
},
placeholder: {
backgroundColor: 'white',
padding: 20,
borderStyle: 'solid',
borderWidth: 1,
borderTopWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 10,
},
card: {
backgroundColor: 'white',
shadowColor: 'white',
marginRight: 0,
marginLeft: 0,
marginTop: 10,
marginBottom: 0,
borderWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 5,
paddingHorizontal: 0,
paddingVertical: 0,
},
container: {
backgroundColor: '#F9F9F9',
flex: 1,
top: StatusBar.currentHeight,
},
placeholder: {
backgroundColor: 'white',
padding: 20,
borderStyle: 'solid',
borderWidth: 1,
borderTopWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 10,
},
card: {
backgroundColor: 'white',
shadowColor: 'white',
marginRight: 0,
marginLeft: 0,
marginTop: 10,
marginBottom: 0,
borderWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 5,
paddingHorizontal: 0,
paddingVertical: 0,
},
});
export default HotPage;
export default HotPage;

View File

@ -1,7 +1,16 @@
import React from 'react';
import { StyleSheet, FlatList, View, AsyncStorage, StatusBar, Dimensions, TouchableHighlight, ActivityIndicator } from 'react-native';
import {
StyleSheet,
FlatList,
View,
AsyncStorage,
StatusBar,
Dimensions,
TouchableHighlight,
ActivityIndicator,
} from 'react-native';
// STEEM
// STEEM
import { getPosts, getAccount } from '../../providers/steem/Dsteem';
// LIBRARIES
@ -14,168 +23,185 @@ import PostCard from '../../components/PostCard';
import PostPage from '../../screens/single-post/Post';
class TrendingPage extends React.Component {
constructor(props) {
super(props)
this.state = {
isReady: false,
posts: [],
user: [],
start_author: '',
start_permlink: '',
refreshing: false,
loading: false,
constructor(props) {
super(props);
this.state = {
isReady: false,
posts: [],
user: [],
start_author: '',
start_permlink: '',
refreshing: false,
loading: false,
};
}
}
componentDidMount() {
this.getTrending();
}
componentDidMount() {
this.getTrending();
}
getTrending = () => {
getPosts('trending', { "tag": "", "limit": 5 }).then((result) => {
this.setState({
isReady: true,
posts: result,
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
refreshing: false
});
}).catch((err) => {
alert(err);
});
}
getTrending = () => {
getPosts('trending', { tag: '', limit: 5 })
.then(result => {
this.setState({
isReady: true,
posts: result,
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
refreshing: false,
});
})
.catch(err => {
alert(err);
});
};
getMore = () => {
this.setState({ loading: true })
getPosts('trending', { "tag": "", "limit": 10, "start_author": this.state.start_author, "start_permlink": this.state.start_permlink }).then((result) => {
let posts = result;
posts.shift();
this.setState({
posts: [...this.state.posts, ...posts],
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink
});
});
}
getMore = () => {
this.setState({ loading: true });
getPosts('trending', {
tag: '',
limit: 10,
start_author: this.state.start_author,
start_permlink: this.state.start_permlink,
}).then(result => {
let posts = result;
posts.shift();
this.setState({
posts: [...this.state.posts, ...posts],
start_author: result[result.length - 1].author,
start_permlink: result[result.length - 1].permlink,
});
});
};
refreshData = () => {
this.setState({
refreshing: true
}, () => {
this.getTrending();
});
}
refreshData = () => {
this.setState(
{
refreshing: true,
},
() => {
this.getTrending();
}
);
};
renderFooter = () => {
if (!this.state.loading) return null;
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
alignContent: 'center',
alignItems: 'center',
marginTop: 10,
marginBottom: 40,
borderColor: "#CED0CE"
}}>
<ActivityIndicator animating size="large" />
</View>
);
};
return (
<View
style={{
alignContent: 'center',
alignItems: 'center',
marginTop: 10,
marginBottom: 40,
borderColor: '#CED0CE',
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
const navigate = this.props.navigation;
return (
<View style={{ flex: 1 }}>
{ this.state.isReady ? (
<FlatList
data={this.state.posts}
showsVerticalScrollIndicator={false}
renderItem={({item}) =>
<View style={styles.card}>
<TouchableHighlight
onPress={() => { navigate('Post',{ content: item }) }}>
<PostCard navigate={navigate} content={item}></PostCard>
</TouchableHighlight>
</View>
}
keyExtractor={(post, index) => index.toString()}
onEndReached={this.getMore}
refreshing={this.state.refreshing}
onRefresh={() => this.refreshData()}
onEndThreshold={0}
ListFooterComponent={this.renderFooter}
/>
) : (
<View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
<View style={styles.placeholder} >
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
></Placeholder.ImageContent>
</View>
</View>
) }
</View>
)
}
render() {
const navigate = this.props.navigation;
return (
<View style={{ flex: 1 }}>
{this.state.isReady ? (
<FlatList
data={this.state.posts}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<View style={styles.card}>
<TouchableHighlight
onPress={() => {
navigate('Post', { content: item });
}}
>
<PostCard
navigate={navigate}
content={item}
/>
</TouchableHighlight>
</View>
)}
keyExtractor={(post, index) => index.toString()}
onEndReached={this.getMore}
refreshing={this.state.refreshing}
onRefresh={() => this.refreshData()}
onEndThreshold={0}
ListFooterComponent={this.renderFooter}
/>
) : (
<View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
<View style={styles.placeholder}>
<Placeholder.ImageContent
size={60}
animate="fade"
lineNumber={4}
lineSpacing={5}
lastLineWidth="30%"
onReady={this.state.isReady}
/>
</View>
</View>
)}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F9F9F9',
flex: 1,
},
placeholder: {
backgroundColor: 'white',
padding: 20,
borderStyle: 'solid',
borderWidth: 1,
borderTopWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 10,
},
card: {
backgroundColor: 'white',
shadowColor: 'white',
marginRight: 0,
marginLeft: 0,
marginTop: 10,
marginBottom: 0,
borderWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 5,
paddingHorizontal: 0,
paddingVertical: 0,
}
container: {
backgroundColor: '#F9F9F9',
flex: 1,
},
placeholder: {
backgroundColor: 'white',
padding: 20,
borderStyle: 'solid',
borderWidth: 1,
borderTopWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 0,
marginRight: 0,
marginLeft: 0,
marginTop: 10,
},
card: {
backgroundColor: 'white',
shadowColor: 'white',
marginRight: 0,
marginLeft: 0,
marginTop: 10,
marginBottom: 0,
borderWidth: 1,
borderColor: '#e2e5e8',
borderRadius: 5,
paddingHorizontal: 0,
paddingVertical: 0,
},
});
export default TrendingPage;
export default TrendingPage;

View File

@ -1,157 +1,317 @@
import React, { Component } from 'react';
import { View, ActivityIndicator, Text, StyleSheet, Image, StatusBar } from 'react-native';
import { Item, Header, Input, Card, Button, Container, Icon, Left, Right, Body, Label, Thumbnail } from 'native-base';
import {
View,
ActivityIndicator,
Text,
StyleSheet,
Image,
StatusBar,
} from 'react-native';
import {
Item,
Header,
Input,
Card,
Button,
Container,
Icon,
Left,
Right,
Body,
Label,
Thumbnail,
} from 'native-base';
import { Login } from '../../providers/steem/Auth';
class LoginPage extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
isLoading: false
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
isLoading: false,
};
}
}
doLogin = () => {
this.setState({ isLoading: true });
let password = this.state.password;
let username = this.state.username;
doLogin = () => {
this.setState({ isLoading: true });
Login(username, password).then((result) => {
let password = this.state.password;
let username = this.state.username;
if (result === true) {
this.props.navigation.navigate('LoggedIn');
}
}).catch((err) => {
alert(err)
this.setState({ isLoading: false });
})
}
Login(username, password)
.then(result => {
if (result === true) {
this.props.navigation.navigate('LoggedIn');
}
})
.catch(err => {
alert(err);
this.setState({ isLoading: false });
});
};
render() {
return (
<Container style={styles.container}>
<StatusBar translucent={true} backgroundColor={'transparent'}/>
<Header style={{ backgroundColor: 'white', height: 80 }}>
<Left>
<Button transparent
onPress={() => this.props.navigation.toggleDrawer()}>
<Thumbnail
style={{ width: 32, height: 32, borderRadius: 16, margin:10 }}
source={require('../../assets/esteem.jpg')}/>
</Button>
</Left>
<Body>
</Body>
<Right>
<Text style={{ color: '#a7adaf', marginHorizontal: 20, fontWeight: 'bold' }}>Sign Up</Text>
</Right>
</Header>
<View style={styles.header}>
<View style={{ flex: 0.5, alignItems: 'center', paddingLeft: 10 }}>
<Text style={{ fontSize: 40, fontWeight: '600', color: '#626262', marginTop: 35 }}>Sign in</Text>
<Text style={{ color: '#a7adaf', marginTop: 20 }}>with your username {"\n"} and password {"\n"} to get all the {"\n"} <Text style={{ fontWeight: 'bold',color: '#a7adaf' }}>benefits of eSteem</Text> </Text>
</View>
<View style={{ flex: 0.5, overflow: 'hidden', padding: 0 }}>
<Image
style={{ width: 220, height: 304, marginTop: 10, marginLeft: 20 }}
source={require('../../assets/love_mascot.png')}/>
</View>
</View>
render() {
return (
<Container style={styles.container}>
<StatusBar translucent={true} backgroundColor={'transparent'} />
<Header style={{ backgroundColor: 'white', height: 80 }}>
<Left>
<Button
transparent
onPress={() => this.props.navigation.toggleDrawer()}
>
<Thumbnail
style={{
width: 32,
height: 32,
borderRadius: 16,
margin: 10,
}}
source={require('../../assets/esteem.jpg')}
/>
</Button>
</Left>
<Body />
<Right>
<Text
style={{
color: '#a7adaf',
marginHorizontal: 20,
fontWeight: 'bold',
}}
>
Sign Up
</Text>
</Right>
</Header>
<View style={styles.header}>
<View
style={{
flex: 0.5,
alignItems: 'center',
paddingLeft: 10,
}}
>
<Text
style={{
fontSize: 40,
fontWeight: '600',
color: '#626262',
marginTop: 35,
}}
>
Sign in
</Text>
<Text style={{ color: '#a7adaf', marginTop: 20 }}>
with your username {'\n'} and password {'\n'} to get
all the {'\n'}{' '}
<Text
style={{ fontWeight: 'bold', color: '#a7adaf' }}
>
benefits of eSteem
</Text>{' '}
</Text>
</View>
<View style={{ flex: 0.5, overflow: 'hidden', padding: 0 }}>
<Image
style={{
width: 220,
height: 304,
marginTop: 10,
marginLeft: 20,
}}
source={require('../../assets/love_mascot.png')}
/>
</View>
</View>
<View style={{ padding: 30, backgroundColor: 'white', flex:0.4 }}>
<View>
<Item rounded
style={{ margin: 5, backgroundColor: '#f6f6f6', height: 40, marginVertical: 10, overflow: 'hidden', borderColor: 'white' }}>
<Icon
name='at'
style={{ backgroundColor: '#ececec', height: 40, width: 40, alignItems: 'center', padding: 8, color: '#a7adaf', fontWeight: 'bold' }}/>
<Input
autoCapitalize='none'
placeholder='username'
onChangeText={(text) => this.setState({username: text})} value={this.state.username}/>
</Item>
<View
style={{ padding: 30, backgroundColor: 'white', flex: 0.4 }}
>
<View>
<Item
rounded
style={{
margin: 5,
backgroundColor: '#f6f6f6',
height: 40,
marginVertical: 10,
overflow: 'hidden',
borderColor: 'white',
}}
>
<Icon
name="at"
style={{
backgroundColor: '#ececec',
height: 40,
width: 40,
alignItems: 'center',
padding: 8,
color: '#a7adaf',
fontWeight: 'bold',
}}
/>
<Input
autoCapitalize="none"
placeholder="username"
onChangeText={text =>
this.setState({ username: text })
}
value={this.state.username}
/>
</Item>
<Item rounded
style={{ margin: 5, backgroundColor: '#f6f6f6', height: 40, marginVertical: 10, overflow: 'hidden', borderColor: 'white' }}>
<Icon
name='md-lock'
style={{ backgroundColor: '#ececec', height: 40, width: 40, alignItems: 'center', paddingVertical: 7, paddingLeft: 13, color: '#a7adaf', fontWeight: 'bold' }}/>
<Input secureTextEntry={true} placeholder='Password or WIF' onChangeText={(text) => this.setState({password: text})} value={this.state.password}/>
</Item>
<View>
</View>
<Item
rounded
style={{
margin: 5,
backgroundColor: '#f6f6f6',
height: 40,
marginVertical: 10,
overflow: 'hidden',
borderColor: 'white',
}}
>
<Icon
name="md-lock"
style={{
backgroundColor: '#ececec',
height: 40,
width: 40,
alignItems: 'center',
paddingVertical: 7,
paddingLeft: 13,
color: '#a7adaf',
fontWeight: 'bold',
}}
/>
<Input
secureTextEntry={true}
placeholder="Password or WIF"
onChangeText={text =>
this.setState({ password: text })
}
value={this.state.password}
/>
</Item>
<View />
</View>
<View
style={{
borderBottomColor: 'lightgray',
borderBottomWidth: 0.7,
marginVertical: 20,
}}
/>
<View
style={{ flexDirection: 'row', alignItems: 'center' }}
>
<Icon
name="information-circle"
style={{
flex: 0.15,
color: '#a7adaf',
fontSize: 25,
paddingLeft: 10,
}}
/>
<Text style={{ flex: 0.85, color: '#a7adaf' }}>
Don't worry! {'\n'}
Your password is kept locally on your device and
removed upon logout!
</Text>
</View>
</View>
</View>
<View style={{ borderBottomColor: 'lightgray', borderBottomWidth: 0.7, marginVertical: 20 }}/>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Icon name='information-circle' style={{ flex: 0.15, color: '#a7adaf', fontSize: 25, paddingLeft: 10 }}/>
<Text style={{ flex: 0.85, color: '#a7adaf' }}>
Don't worry! {"\n"}
Your password is kept locally on your device and removed upon logout!
</Text>
</View>
</View>
<View style={styles.footer}>
<View style={{ flex: 0.6, alignItems: 'flex-end' }}>
<Text
onPress={() => { this.props.navigation.goBack() }}
style={{ color: '#a7adaf', fontSize: 18, margin: 25 }}>
Skip this screen
</Text>
</View>
<View style={{ flex: 0.4, alignItems: 'center' }}>
{ this.state.isLoading ? (
<Button
style={{ borderRadius: 25, padding: 5, backgroundColor: '#007EE5', width: 130, height: 35, marginTop: 20 }}>
<ActivityIndicator color='white' style={{ marginHorizontal: 50 }}/>
</Button>
) : (
<Button
style={{ borderRadius: 25, padding: 5, backgroundColor: '#007EE5', width: 130, height: 35, marginTop: 20 }}
onPress={() => { this.doLogin() }}>
<Text
style={{ color: 'white', fontWeight: 'bold', marginHorizontal: 40 }}>
Login
</Text>
</Button>
)}
</View>
</View>
</Container>
)
}
<View style={styles.footer}>
<View style={{ flex: 0.6, alignItems: 'flex-end' }}>
<Text
onPress={() => {
this.props.navigation.goBack();
}}
style={{
color: '#a7adaf',
fontSize: 18,
margin: 25,
}}
>
Skip this screen
</Text>
</View>
<View style={{ flex: 0.4, alignItems: 'center' }}>
{this.state.isLoading ? (
<Button
style={{
borderRadius: 25,
padding: 5,
backgroundColor: '#007EE5',
width: 130,
height: 35,
marginTop: 20,
}}
>
<ActivityIndicator
color="white"
style={{ marginHorizontal: 50 }}
/>
</Button>
) : (
<Button
style={{
borderRadius: 25,
padding: 5,
backgroundColor: '#007EE5',
width: 130,
height: 35,
marginTop: 20,
}}
onPress={() => {
this.doLogin();
}}
>
<Text
style={{
color: 'white',
fontWeight: 'bold',
marginHorizontal: 40,
}}
>
Login
</Text>
</Button>
)}
</View>
</View>
</Container>
);
}
}
const styles = StyleSheet.create({
container: {
margin: 0,
padding: 0,
backgroundColor: '#f1f1f1',
top: StatusBar.currentHeight,
flexDirection: 'column'
},
header: {
flexDirection: 'row',
padding: 0,
backgroundColor: 'white',
marginVertical: 10,
height: 200,
flex: 0.4
},
footer: {
flex: 0.2,
bottom: 0,
marginTop: 10,
height: 80,
backgroundColor: 'white',
flexDirection: 'row',
}
container: {
margin: 0,
padding: 0,
backgroundColor: '#f1f1f1',
top: StatusBar.currentHeight,
flexDirection: 'column',
},
header: {
flexDirection: 'row',
padding: 0,
backgroundColor: 'white',
marginVertical: 10,
height: 200,
flex: 0.4,
},
footer: {
flex: 0.2,
bottom: 0,
marginTop: 10,
height: 80,
backgroundColor: 'white',
flexDirection: 'row',
},
});
export default LoginPage;
export default LoginPage;

View File

@ -1,37 +1,46 @@
import * as React from 'react';
import { Container, Header, Left, Body, Right, Button, Icon, Title } from 'native-base';
import {
Container,
Header,
Left,
Body,
Right,
Button,
Icon,
Title,
} from 'native-base';
class NotificationPage extends React.Component {
static navigationOptions = {
title: 'Notifications',
};
static navigationOptions = {
title: 'Notifications',
};
render() {
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon name='menu' />
</Button>
</Left>
<Body>
<Title>Notifications</Title>
</Body>
<Right>
<Button transparent>
<Icon name='search' />
</Button>
<Button transparent>
<Icon name='heart' />
</Button>
<Button transparent>
<Icon name='more' />
</Button>
</Right>
</Header>
</Container>
)
}
render() {
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>Notifications</Title>
</Body>
<Right>
<Button transparent>
<Icon name="search" />
</Button>
<Button transparent>
<Icon name="heart" />
</Button>
<Button transparent>
<Icon name="more" />
</Button>
</Right>
</Header>
</Container>
);
}
}
export default NotificationPage;
export default NotificationPage;

View File

@ -1,40 +1,50 @@
import * as React from 'react';
import { StatusBar} from 'react-native';
import { Container, Header, Left, Body, Right, Button, Icon, Title, Text } from 'native-base';
import { StatusBar } from 'react-native';
import {
Container,
Header,
Left,
Body,
Right,
Button,
Icon,
Title,
Text,
} from 'native-base';
class ProfilePage extends React.Component {
static navigationOptions = {
title: 'Profile',
};
static navigationOptions = {
title: 'Profile',
};
render() {
return (
<Container style={{ flex: 1, top: StatusBar.currentHeight }}>
<Header>
<Left>
<Button transparent>
<Icon name='menu' />
</Button>
</Left>
<Body>
<Title>Profile</Title>
</Body>
<Right>
<Button transparent>
<Icon name='search' />
</Button>
<Button transparent>
<Icon name='heart' />
</Button>
<Button transparent>
<Icon name='more' />
</Button>
</Right>
</Header>
<Text>Profile</Text>
</Container>
)
}
render() {
return (
<Container style={{ flex: 1, top: StatusBar.currentHeight }}>
<Header>
<Left>
<Button transparent>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>Profile</Title>
</Body>
<Right>
<Button transparent>
<Icon name="search" />
</Button>
<Button transparent>
<Icon name="heart" />
</Button>
<Button transparent>
<Icon name="more" />
</Button>
</Right>
</Header>
<Text>Profile</Text>
</Container>
);
}
}
export default ProfilePage;
export default ProfilePage;

View File

@ -1,33 +1,33 @@
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
StatusBar,
StyleSheet,
View,
ActivityIndicator,
AsyncStorage,
StatusBar,
StyleSheet,
View,
} from 'react-native';
export class AuthLoadingScreen extends React.Component {
constructor(props) {
super(props);
this.checkAuth();
}
constructor(props) {
super(props);
this.checkAuth();
}
// Fetch the login state from storage then navigate to our appropriate place
checkAuth = async () => {
isLoggedIn = await AsyncStorage.getItem('isLoggedIn');
// Fetch the login state from storage then navigate to our appropriate place
checkAuth = async () => {
isLoggedIn = await AsyncStorage.getItem('isLoggedIn');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(isLoggedIn ? 'LoggedIn' : 'LoggedOut');
}
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(isLoggedIn ? 'LoggedIn' : 'LoggedOut');
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
}
}
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
}
}

View File

@ -1,5 +1,12 @@
import React from 'react';
import { AsyncStorage, StyleSheet, StatusBar, ActivityIndicator, View, Dimensions } from 'react-native';
import {
AsyncStorage,
StyleSheet,
StatusBar,
ActivityIndicator,
View,
Dimensions,
} from 'react-native';
import { createDrawerNavigator, createSwitchNavigator } from 'react-navigation';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
@ -8,87 +15,91 @@ import { LoggedInSideBar } from './LoggedInMenu';
import { LoggedOutSideBar } from './LoggedOutMenu';
import LoginPage from '../login/Login';
const LoggedInMenu = createDrawerNavigator({
Tabs: {
screen: Tabs,
navigationOptions: {
drawer: () => ({
label: 'Home',
icon: ({ tintColor }) => (
<MaterialIcons
name="Home"
size={24}
style={{ color: tintColor }}
/>
),
}),
const LoggedInMenu = createDrawerNavigator(
{
Tabs: {
screen: Tabs,
navigationOptions: {
drawer: () => ({
label: 'Home',
icon: ({ tintColor }) => (
<MaterialIcons
name="Home"
size={24}
style={{ color: tintColor }}
/>
),
}),
},
},
},
}
},
{
contentComponent: LoggedInSideBar,
drawerWidth: Dimensions.get('window').width / 1.2
});
{
contentComponent: LoggedInSideBar,
drawerWidth: Dimensions.get('window').width / 1.2,
}
);
const LoggedOutMenu = createDrawerNavigator({
Tabs: {
screen: Tabs,
},
Login: {
screen: LoginPage,
navigationOptions: ({ navigation }) => ({
}),
},
},
{
contentComponent: LoggedOutSideBar,
drawerWidth: Dimensions.get('window').width / 1.2
});
const LoggedOutMenu = createDrawerNavigator(
{
Tabs: {
screen: Tabs,
},
Login: {
screen: LoginPage,
navigationOptions: ({ navigation }) => ({}),
},
},
{
contentComponent: LoggedOutSideBar,
drawerWidth: Dimensions.get('window').width / 1.2,
}
);
class AuthLoadingScreen extends React.Component {
constructor(props) {
super(props);
this.checkAuth();
}
constructor(props) {
super(props);
this.checkAuth();
}
// Fetch the login state from storage then navigate to our appropriate place
checkAuth = async () => {
const isLoggedIn = await AsyncStorage.getItem('isLoggedIn');
// Fetch the login state from storage then navigate to our appropriate place
checkAuth = async () => {
const isLoggedIn = await AsyncStorage.getItem('isLoggedIn');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(isLoggedIn === null ? 'LoggedOut' : 'LoggedIn');
}
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(
isLoggedIn === null ? 'LoggedOut' : 'LoggedIn'
);
};
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
// Render any loading content that you like here
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
export default createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
LoggedIn: LoggedInMenu,
LoggedOut: LoggedOutMenu,
},
{
initialRouteName: 'AuthLoading',
}
{
AuthLoading: AuthLoadingScreen,
LoggedIn: LoggedInMenu,
LoggedOut: LoggedOutMenu,
},
{
initialRouteName: 'AuthLoading',
}
);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
text: {
fontSize: 32
}
})
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontSize: 32,
},
});

View File

@ -1,249 +1,274 @@
import React, { Component } from "react";
import { Image, AsyncStorage } from "react-native";
import React, { Component } from 'react';
import { Image, AsyncStorage } from 'react-native';
import {
Content,
Text,
List,
ListItem,
Icon,
Container,
Left,
Right,
View,
Badge,
Thumbnail
} from "native-base";
import styles from "./style";
Content,
Text,
List,
ListItem,
Icon,
Container,
Left,
Right,
View,
Badge,
Thumbnail,
} from 'native-base';
import styles from './style';
import { getAccount } from '../../providers/steem/Dsteem'
import { getAccount } from '../../providers/steem/Dsteem';
const drawerCover = require("../../assets/drawer-cover.png");
const drawerCover = require('../../assets/drawer-cover.png');
const masterKeyMenuOptions = [
{
name: "Home",
route: "Home",
icon: "home",
bg: "#C5F442"
},
{
name: "Bookmarks",
route: "bookmarks",
icon: "bookmarks",
bg: "#DA4437",
},
{
name: "Drafts",
route: "drafts",
icon: "create",
bg: "#DA4437",
},
{
name: "Favorites",
route: "favorites",
icon: "heart",
bg: "#DA4437",
},
{
name: "Schedules",
route: "schedules",
icon: "time",
bg: "#DA4437",
},
{
name: "Transfer",
route: "transfer",
icon: "md-send",
bg: "#DA4437",
},
{
name: "Exchange",
route: "exchange",
icon: "repeat",
bg: "#DA4437",
},
{
name: "Marketplace",
route: "marketplace",
icon: "cube",
bg: "#DA4437",
},
{
name: "Settings",
route: "settings",
icon: "settings",
bg: "#DA4437",
},
{
name: "FAQ",
route: "faq",
icon: "ios-information-circle-outline",
bg: "#DA4437",
},
{
name: "About",
route: "about",
icon: "information-circle",
bg: "#DA4437",
},
{
name: 'Home',
route: 'Home',
icon: 'home',
bg: '#C5F442',
},
{
name: 'Bookmarks',
route: 'bookmarks',
icon: 'bookmarks',
bg: '#DA4437',
},
{
name: 'Drafts',
route: 'drafts',
icon: 'create',
bg: '#DA4437',
},
{
name: 'Favorites',
route: 'favorites',
icon: 'heart',
bg: '#DA4437',
},
{
name: 'Schedules',
route: 'schedules',
icon: 'time',
bg: '#DA4437',
},
{
name: 'Transfer',
route: 'transfer',
icon: 'md-send',
bg: '#DA4437',
},
{
name: 'Exchange',
route: 'exchange',
icon: 'repeat',
bg: '#DA4437',
},
{
name: 'Marketplace',
route: 'marketplace',
icon: 'cube',
bg: '#DA4437',
},
{
name: 'Settings',
route: 'settings',
icon: 'settings',
bg: '#DA4437',
},
{
name: 'FAQ',
route: 'faq',
icon: 'ios-information-circle-outline',
bg: '#DA4437',
},
{
name: 'About',
route: 'about',
icon: 'information-circle',
bg: '#DA4437',
},
];
const postingKeyMenuOptions = [
{
name: "Home",
route: "Home",
icon: "home",
bg: "#C5F442"
},
{
name: "Bookmarks",
route: "bookmarks",
icon: "bookmarks",
bg: "#DA4437",
},
{
name: "Drafts",
route: "drafts",
icon: "create",
bg: "#DA4437",
},
{
name: "Favorites",
route: "favorites",
icon: "heart",
bg: "#DA4437",
},
{
name: "Schedules",
route: "schedules",
icon: "time",
bg: "#DA4437",
},
{
name: "Marketplace",
route: "marketplace",
icon: "cube",
bg: "#DA4437",
},
{
name: "Settings",
route: "settings",
icon: "settings",
bg: "#DA4437",
},
{
name: "FAQ",
route: "faq",
icon: "ios-information-circle-outline",
bg: "#DA4437",
},
{
name: "About",
route: "about",
icon: "information-circle",
bg: "#DA4437",
},
{
name: 'Home',
route: 'Home',
icon: 'home',
bg: '#C5F442',
},
{
name: 'Bookmarks',
route: 'bookmarks',
icon: 'bookmarks',
bg: '#DA4437',
},
{
name: 'Drafts',
route: 'drafts',
icon: 'create',
bg: '#DA4437',
},
{
name: 'Favorites',
route: 'favorites',
icon: 'heart',
bg: '#DA4437',
},
{
name: 'Schedules',
route: 'schedules',
icon: 'time',
bg: '#DA4437',
},
{
name: 'Marketplace',
route: 'marketplace',
icon: 'cube',
bg: '#DA4437',
},
{
name: 'Settings',
route: 'settings',
icon: 'settings',
bg: '#DA4437',
},
{
name: 'FAQ',
route: 'faq',
icon: 'ios-information-circle-outline',
bg: '#DA4437',
},
{
name: 'About',
route: 'about',
icon: 'information-circle',
bg: '#DA4437',
},
];
export class LoggedInSideBar extends Component {
constructor(props) {
super(props);
this.state = {
shadowOffsetWidth: 1,
shadowRadius: 4,
user: [],
loginType: '',
json_metadata: {}
constructor(props) {
super(props);
this.state = {
shadowOffsetWidth: 1,
shadowRadius: 4,
user: [],
loginType: '',
json_metadata: {},
};
}
componentDidMount() {
AsyncStorage.getItem('user')
.then(result => {
let res = JSON.parse(result);
if (res.auth_type === 'master_key') {
this.setState({ loginType: 'master_key' });
} else {
this.setState({ loginType: 'posting_key' });
}
getAccount(res.username)
.then(result => {
let json_metadata = JSON.parse(result[0].json_metadata);
this.setState({
user: result[0],
avatar: `https://steemitimages.com/u/${
result[0].name
}/avatar/small`,
json_metadata: json_metadata.profile,
});
})
.catch(err => {});
})
.catch(err => {});
}
Logout = () => {
AsyncStorage.clear().then(() => {
this.props.navigation.navigate('LoggedOut');
});
};
}
componentDidMount() {
AsyncStorage.getItem('user').then((result) => {
let res = JSON.parse(result);
if (res.auth_type === 'master_key') {
this.setState({ loginType: 'master_key' });
} else {
this.setState({ loginType: 'posting_key' });
}
getAccount(res.username).then((result) => {
let json_metadata = JSON.parse(result[0].json_metadata)
this.setState({
user: result[0],
avatar:`https://steemitimages.com/u/${result[0].name}/avatar/small`,
json_metadata: json_metadata.profile
})
}).catch((err) => {
});
}).catch((err) => {
});
}
Logout = () => {
AsyncStorage.clear().then(() => {
this.props.navigation.navigate('LoggedOut');
});
}
render() {
return (
<Container>
<Content
bounces={false}
style={{ flex: 1, backgroundColor: "#fff", top: -1 }}
>
<Image source={drawerCover} style={styles.drawerCover} />
<Thumbnail square style={styles.drawerImage} source={{uri: this.state.avatar}} />
<View style={styles.info}>
<Text style={styles.userLabel}>{ this.state.json_metadata.name || '' }</Text>
<Text style={styles.userLabel}>{ this.state.user.name }</Text>
</View>
<List
dataArray={ this.state.loginType === 'master_key' ? masterKeyMenuOptions : postingKeyMenuOptions }
renderRow={data =>
<ListItem
button
noBorder
onPress={() => this.props.navigation.navigate(data.route)}
>
<Left>
<Icon
active
name={data.icon}
style={{ color: "#777", fontSize: 26, width: 30 }}
/>
<Text style={styles.text}>
{data.name}
</Text>
</Left>
{data.types &&
<Right style={{ flex: 1 }}>
<Badge
style={{
borderRadius: 3,
height: 25,
width: 72,
backgroundColor: data.bg
}}
>
<Text
style={styles.badgeText}
>{`${data.types} Types`}</Text>
</Badge>
</Right>}
</ListItem>}
/>
<ListItem noBorder onPress={() => this.Logout() }>
<Left>
<Icon active name="log-out" style={{ color: "#777", fontSize: 26, width: 30 }}/>
<Text style={styles.text}>
Logout
</Text>
</Left>
</ListItem>
</Content>
</Container>
);
}
}
render() {
return (
<Container>
<Content
bounces={false}
style={{ flex: 1, backgroundColor: '#fff', top: -1 }}
>
<Image source={drawerCover} style={styles.drawerCover} />
<Thumbnail
square
style={styles.drawerImage}
source={{ uri: this.state.avatar }}
/>
<View style={styles.info}>
<Text style={styles.userLabel}>
{this.state.json_metadata.name || ''}
</Text>
<Text style={styles.userLabel}>
{this.state.user.name}
</Text>
</View>
<List
dataArray={
this.state.loginType === 'master_key'
? masterKeyMenuOptions
: postingKeyMenuOptions
}
renderRow={data => (
<ListItem
button
noBorder
onPress={() =>
this.props.navigation.navigate(data.route)
}
>
<Left>
<Icon
active
name={data.icon}
style={{
color: '#777',
fontSize: 26,
width: 30,
}}
/>
<Text style={styles.text}>{data.name}</Text>
</Left>
{data.types && (
<Right style={{ flex: 1 }}>
<Badge
style={{
borderRadius: 3,
height: 25,
width: 72,
backgroundColor: data.bg,
}}
>
<Text style={styles.badgeText}>{`${
data.types
} Types`}</Text>
</Badge>
</Right>
)}
</ListItem>
)}
/>
<ListItem noBorder onPress={() => this.Logout()}>
<Left>
<Icon
active
name="log-out"
style={{
color: '#777',
fontSize: 26,
width: 30,
}}
/>
<Text style={styles.text}>Logout</Text>
</Left>
</ListItem>
</Content>
</Container>
);
}
}

View File

@ -1,91 +1,101 @@
import React, { Component } from "react";
import { Image } from "react-native";
import React, { Component } from 'react';
import { Image } from 'react-native';
import {
Content,
Text,
List,
ListItem,
Icon,
Container,
Left,
Right,
Badge
} from "native-base";
import styles from "./style";
Content,
Text,
List,
ListItem,
Icon,
Container,
Left,
Right,
Badge,
} from 'native-base';
import styles from './style';
const drawerCover = require("../../assets/drawer-cover.png");
const drawerImage = require("../../assets/esteem.jpg");
const drawerCover = require('../../assets/drawer-cover.png');
const drawerImage = require('../../assets/esteem.jpg');
const datas = [
{
name: "Home",
route: "Home",
icon: "home",
bg: "#C5F442"
},
{
name: "Login",
route: "Login",
icon: "log-in",
bg: "#C5F442"
}
{
name: 'Home',
route: 'Home',
icon: 'home',
bg: '#C5F442',
},
{
name: 'Login',
route: 'Login',
icon: 'log-in',
bg: '#C5F442',
},
];
export class LoggedOutSideBar extends Component {
constructor(props) {
super(props);
this.state = {
shadowOffsetWidth: 1,
shadowRadius: 4
};
}
constructor(props) {
super(props);
this.state = {
shadowOffsetWidth: 1,
shadowRadius: 4,
};
}
render() {
return (
<Container>
<Content
bounces={false}
style={{ flex: 1, backgroundColor: "#fff", top: -1 }}
>
<Image source={drawerCover} style={styles.drawerCover} />
<Image square style={styles.drawerImage} source={drawerImage} />
render() {
return (
<Container>
<Content
bounces={false}
style={{ flex: 1, backgroundColor: '#fff', top: -1 }}
>
<Image source={drawerCover} style={styles.drawerCover} />
<Image
square
style={styles.drawerImage}
source={drawerImage}
/>
<List
dataArray={datas}
renderRow={data =>
<ListItem
button
noBorder
onPress={() => this.props.navigation.navigate(data.route)}
>
<Left>
<Icon
active
name={data.icon}
style={{ color: "#777", fontSize: 26, width: 30 }}
/>
<Text style={styles.text}>
{data.name}
</Text>
</Left>
{data.types &&
<Right style={{ flex: 1 }}>
<Badge
style={{
borderRadius: 3,
height: 25,
width: 72,
backgroundColor: data.bg
}}
>
<Text
style={styles.badgeText}
>{`${data.types} Types`}</Text>
</Badge>
</Right>}
</ListItem>}
/>
</Content>
</Container>
);
}
}
<List
dataArray={datas}
renderRow={data => (
<ListItem
button
noBorder
onPress={() =>
this.props.navigation.navigate(data.route)
}
>
<Left>
<Icon
active
name={data.icon}
style={{
color: '#777',
fontSize: 26,
width: 30,
}}
/>
<Text style={styles.text}>{data.name}</Text>
</Left>
{data.types && (
<Right style={{ flex: 1 }}>
<Badge
style={{
borderRadius: 3,
height: 25,
width: 72,
backgroundColor: data.bg,
}}
>
<Text style={styles.badgeText}>{`${
data.types
} Types`}</Text>
</Badge>
</Right>
)}
</ListItem>
)}
/>
</Content>
</Container>
);
}
}

View File

@ -1,48 +1,47 @@
const React = require("react-native");
const React = require('react-native');
const { Platform, Dimensions } = React;
const deviceHeight = Dimensions.get("window").height;
const deviceWidth = Dimensions.get("window").width;
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
export default {
drawerCover: {
alignSelf: "stretch",
height: deviceHeight / 4,
width: null,
position: "relative",
marginBottom: 10
},
drawerImage: {
position: "absolute",
left: Platform.OS === "android" ? deviceWidth / 10 : deviceWidth / 30,
top: Platform.OS === "android" ? deviceHeight / 13 : deviceHeight / 15,
width: 60,
height: 60,
resizeMode: "cover",
borderWidth: 1,
borderColor: 'white',
borderRadius: 30,
},
text: {
fontWeight: Platform.OS === "ios" ? "500" : "400",
fontSize: 16,
marginLeft: 20
},
badgeText: {
fontSize: Platform.OS === "ios" ? 13 : 11,
fontWeight: "400",
textAlign: "center",
marginTop: Platform.OS === "android" ? -3 : undefined
},
info: {
position: 'absolute',
top: Platform.OS === "android" ? deviceHeight / 13 : deviceHeight / 5.8,
left: Platform.OS === "android" ? deviceWidth / 10 : deviceWidth / 40,
},
userLabel: {
fontWeight: 'bold',
color: 'white',
marginBottom: 3
}
drawerCover: {
alignSelf: 'stretch',
height: deviceHeight / 4,
width: null,
position: 'relative',
marginBottom: 10,
},
drawerImage: {
position: 'absolute',
left: Platform.OS === 'android' ? deviceWidth / 10 : deviceWidth / 30,
top: Platform.OS === 'android' ? deviceHeight / 13 : deviceHeight / 15,
width: 60,
height: 60,
resizeMode: 'cover',
borderWidth: 1,
borderColor: 'white',
borderRadius: 30,
},
text: {
fontWeight: Platform.OS === 'ios' ? '500' : '400',
fontSize: 16,
marginLeft: 20,
},
badgeText: {
fontSize: Platform.OS === 'ios' ? 13 : 11,
fontWeight: '400',
textAlign: 'center',
marginTop: Platform.OS === 'android' ? -3 : undefined,
},
info: {
position: 'absolute',
top: Platform.OS === 'android' ? deviceHeight / 13 : deviceHeight / 5.8,
left: Platform.OS === 'android' ? deviceWidth / 10 : deviceWidth / 40,
},
userLabel: {
fontWeight: 'bold',
color: 'white',
marginBottom: 3,
},
};

View File

@ -1,6 +1,16 @@
import React from 'react';
import { Dimensions, StyleSheet, StatusBar } from 'react-native';
import { Container, Content, Header, Left, Body, Right, Button, Icon, Title } from 'native-base';
import {
Container,
Content,
Header,
Left,
Body,
Right,
Button,
Icon,
Title,
} from 'native-base';
import HTMLView from 'react-native-htmlview';
import HTML from 'react-native-render-html';
import { Client } from 'dsteem';
@ -9,98 +19,106 @@ const client = new Client('https://api.steemit.com');
import { parsePost, protocolUrl2Obj } from '../../utils/PostParser';
class SinglePostPage extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
}
onLinkPress(evt, href, attribs) {
let steemPost = href.match(/^https?:\/\/(.*)\/(.*)\/(@[\w\.\d-]+)\/(.*)/i)
if (attribs.class === "markdown-author-link") {
this.props.navigation.navigate('Author', { author: href })
} else if (steemPost.length > 3) {
steemPost[3] = steemPost[3].replace('@', '')
client.database.call('get_content', [steemPost[3], steemPost[4]]).then((result) => {
let content = parsePost(result);
this.props.navigation.push('Post',{ content: content })
}).catch((err) => {
alert(err)
});
constructor(props) {
super(props);
}
}
alterNode(node) {
if (node.name == 'img' || node.name == 'a') {
// console.log(node);
} else if (node.name == 'iframe') {
node.attribs.height = 200
componentDidMount() {}
onLinkPress(evt, href, attribs) {
let steemPost = href.match(
/^https?:\/\/(.*)\/(.*)\/(@[\w\.\d-]+)\/(.*)/i
);
if (attribs.class === 'markdown-author-link') {
this.props.navigation.navigate('Author', { author: href });
} else if (steemPost.length > 3) {
steemPost[3] = steemPost[3].replace('@', '');
client.database
.call('get_content', [steemPost[3], steemPost[4]])
.then(result => {
let content = parsePost(result);
this.props.navigation.push('Post', { content: content });
})
.catch(err => {
alert(err);
});
}
}
}
render() {
return (
<Container style={{ top: StatusBar.currentHeight }}>
<Header>
<Left>
<Button transparent onPress={() => this.props.navigation.goBack()}>
<Icon name='arrow-back' />
</Button>
</Left>
<Body>
<Title></Title>
</Body>
<Right>
<Button transparent>
<Icon name='bookmark' />
</Button>
<Button transparent>
<Icon name='more' />
</Button>
</Right>
</Header>
<Content>
<HTML
html={this.props.navigation.state.params.content.body}
staticContentMaxWidth={ Dimensions.get('window').width - 20 }
onLinkPress={ (evt, href, hrefatr) => this.onLinkPress(evt, href, hrefatr) }
containerStyle={{ padding: 10 }}
textSelectable={true}
tagsStyles={styles}
ignoredTags={['script']}
debug={true}
alterNode={ (node) => { this.alterNode(node) } }
imagesMaxWidth={ Dimensions.get('window').width } />
</Content>
</Container>
)
}
alterNode(node) {
if (node.name == 'img' || node.name == 'a') {
// console.log(node);
} else if (node.name == 'iframe') {
node.attribs.height = 200;
}
}
render() {
return (
<Container style={{ top: StatusBar.currentHeight }}>
<Header>
<Left>
<Button
transparent
onPress={() => this.props.navigation.goBack()}
>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title />
</Body>
<Right>
<Button transparent>
<Icon name="bookmark" />
</Button>
<Button transparent>
<Icon name="more" />
</Button>
</Right>
</Header>
<Content>
<HTML
html={this.props.navigation.state.params.content.body}
staticContentMaxWidth={
Dimensions.get('window').width - 20
}
onLinkPress={(evt, href, hrefatr) =>
this.onLinkPress(evt, href, hrefatr)
}
containerStyle={{ padding: 10 }}
textSelectable={true}
tagsStyles={styles}
ignoredTags={['script']}
debug={true}
alterNode={node => {
this.alterNode(node);
}}
imagesMaxWidth={Dimensions.get('window').width}
/>
</Content>
</Container>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
iframe: {
maxWidth: Dimensions.get('window').width,
marginVertical: 10,
left: -10
},
p: {
},
img: {
left: -10,
marginVertical: 10
}
})
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
iframe: {
maxWidth: Dimensions.get('window').width,
marginVertical: 10,
left: -10,
},
p: {},
img: {
left: -10,
marginVertical: 10,
},
});
export default SinglePostPage;

View File

@ -1,37 +1,46 @@
import * as React from 'react';
import { Container, Header, Left, Body, Right, Button, Icon, Title } from 'native-base';
import {
Container,
Header,
Left,
Body,
Right,
Button,
Icon,
Title,
} from 'native-base';
class WalletPage extends React.Component {
static navigationOptions = {
title: 'Wallet',
};
static navigationOptions = {
title: 'Wallet',
};
render() {
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon name='menu' />
</Button>
</Left>
<Body>
<Title>Wallet</Title>
</Body>
<Right>
<Button transparent>
<Icon name='search' />
</Button>
<Button transparent>
<Icon name='heart' />
</Button>
<Button transparent>
<Icon name='more' />
</Button>
</Right>
</Header>
</Container>
)
}
render() {
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>Wallet</Title>
</Body>
<Right>
<Button transparent>
<Icon name="search" />
</Button>
<Button transparent>
<Icon name="heart" />
</Button>
<Button transparent>
<Icon name="more" />
</Button>
</Right>
</Header>
</Container>
);
}
}
export default WalletPage;
export default WalletPage;

View File

@ -1,34 +1,71 @@
// TODO: Refactor
export const sanitizeNode = (node) => {
export const sanitizeNode = node => {
const ALLOWED_TAGS = [
'A',
'STRONG',
'B',
'I',
'EM',
'CODE',
'BLOCKQUOTE',
'SUP',
'SUB',
'H2',
'H1',
'H3',
'H4',
'H5',
'H6',
'DIV',
'P',
'IFRAME',
'CENTER',
'UL',
'OL',
'LI',
'TABLE',
'THEAD',
'TBODY',
'TR',
'TD',
'TH',
'HR',
'BR',
'IMG',
];
const ALLOWED_TAGS = [
'A', 'STRONG', 'B', 'I', 'EM', 'CODE', 'BLOCKQUOTE', 'SUP', 'SUB',
'H2', 'H1', 'H3', 'H4', 'H5', 'H6',
'DIV', 'P', 'IFRAME', 'CENTER',
'UL', 'OL', 'LI',
'TABLE', 'THEAD', 'TBODY', 'TR', 'TD', 'TH',
'HR', 'BR', 'IMG'
];
const ALLOWED_ATTRS = [
'data-permlink',
'data-tag',
'data-author',
'data-href',
'class',
'src',
'alt',
'title',
'width',
'height',
'border',
'frameborder',
'allowfullscreen',
'mozallowfullscreen',
'webkitallowfullscreen',
];
const ALLOWED_ATTRS = [
'data-permlink', 'data-tag', 'data-author', 'data-href',
'class', 'src', 'alt', 'title', 'width', 'height', 'border',
'frameborder', 'allowfullscreen', 'mozallowfullscreen', 'webkitallowfullscreen'
];
const allElems = node.querySelectorAll('*');
allElems.forEach(el => {
if (ALLOWED_TAGS.indexOf(el.tagName) === -1) {
el.outerHTML = `<span>${el.innerText
.replace('>', '&gt;')
.replace('<', '&lt;')}</span>`;
}
const allElems = node.querySelectorAll('*');
allElems.forEach((el) => {
for (let attr of el.attributes) {
if (ALLOWED_ATTRS.indexOf(attr.name) === -1) {
el.removeAttribute(attr.name);
}
}
});
if (ALLOWED_TAGS.indexOf(el.tagName) === -1) {
el.outerHTML = `<span>${el.innerText.replace('>', '&gt;').replace('<', '&lt;')}</span>`;
}
for (let attr of el.attributes) {
if (ALLOWED_ATTRS.indexOf(attr.name) === -1) {
el.removeAttribute(attr.name)
}
}
});
return node;
};
return node;
};

View File

@ -3,105 +3,123 @@ import { postSummary } from './PostSummary';
import { reputation } from './Reputation';
import moment from 'moment';
const md = new Remarkable({html: true, breaks: true, linkify: true});
const md = new Remarkable({ html: true, breaks: true, linkify: true });
export const replaceAuthorNames = (input) => {
return input.replace(
/(^|[^a-zA-Z0-9_!#$%&*@\/]|(^|[^a-zA-Z0-9_+~.-\/]))[@]([a-z][-\.a-z\d]+[a-z\d])/gi,
(match, preceeding1, preceeding2, user) => {
const userLower = user.toLowerCase();
const preceedings = (preceeding1 || '') + (preceeding2 || '');
export const replaceAuthorNames = input => {
return input.replace(
/(^|[^a-zA-Z0-9_!#$%&*@\/]|(^|[^a-zA-Z0-9_+~.-\/]))[@]([a-z][-\.a-z\d]+[a-z\d])/gi,
(match, preceeding1, preceeding2, user) => {
const userLower = user.toLowerCase();
const preceedings = (preceeding1 || '') + (preceeding2 || '');
return `${preceedings}<a class="markdown-author-link" href="${userLower}" data-author="${userLower}">@${user}</a>`
}
);
return `${preceedings}<a class="markdown-author-link" href="${userLower}" data-author="${userLower}">@${user}</a>`;
}
);
};
export const replaceTags = (input) => {
return input.replace(/(^|\s|>)(#[-a-z\d]+)/gi, tag => {
if (/#[\d]+$/.test(tag)) return tag; // do not allow only numbers (like #1)
const preceding = /^\s|>/.test(tag) ? tag[0] : ''; // space or closing tag (>)
tag = tag.replace('>', ''); // remove closing tag
const tag2 = tag.trim().substring(1);
const tagLower = tag2.toLowerCase();
return preceding + `<a class="markdown-tag-link" href="${tagLower}" data-tag="${tagLower}">${tag.trim()}</a>`;
});
};
export const markDown2Html = (input) => {
if (!input) {
return '';
}
// Start replacing user names
let output = replaceAuthorNames(input);
// Replace tags
output = replaceTags(output);
output = md.render(output);
const imgRegex = /(https?:\/\/.*\.(?:tiff?|jpe?g|gif|png|svg|ico))/gim;
const postRegex = /^https?:\/\/(.*)\/(.*)\/(@[\w\.\d-]+)\/(.*)/i;
const youTubeRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^& \n<]+)(?:[^ \n<]+)?/g;
const vimeoRegex = /(https?:\/\/)?(www\.)?(?:vimeo)\.com.*(?:videos|video|channels|)\/([\d]+)/i;
const dTubeRegex = /(https?:\/\/d.tube.#!\/v\/)(\w+)\/(\w+)/g;
// TODO: Implement Regex
return output;
};
export const parsePosts = (posts) => {
posts.map(post => {
post.json_metadata = JSON.parse(post.json_metadata);
(post.json_metadata.image) ? post.image = post.json_metadata.image[0] : '';
post.pending_payout_value = parseFloat(post.pending_payout_value).toFixed(2);
post.created = moment.utc(post.created).local().fromNow();
post.vote_count = post.active_votes.length;
post.author_reputation = reputation(post.author_reputation);
post.avatar = `https://steemitimages.com/u/${post.author}/avatar/small`;
post.body = markDown2Html(post.body)
post.summary = postSummary(post.body, 100);
post.raw_body = post.body;
post.active_votes.sort((a,b) => {
return b.rshares - a.rshares
export const replaceTags = input => {
return input.replace(/(^|\s|>)(#[-a-z\d]+)/gi, tag => {
if (/#[\d]+$/.test(tag)) return tag; // do not allow only numbers (like #1)
const preceding = /^\s|>/.test(tag) ? tag[0] : ''; // space or closing tag (>)
tag = tag.replace('>', ''); // remove closing tag
const tag2 = tag.trim().substring(1);
const tagLower = tag2.toLowerCase();
return (
preceding +
`<a class="markdown-tag-link" href="${tagLower}" data-tag="${tagLower}">${tag.trim()}</a>`
);
});
if (post.active_votes.length > 2) {
post.top_likers = [post.active_votes[0].voter, post.active_votes[1].voter, post.active_votes[2].voter]
};
export const markDown2Html = input => {
if (!input) {
return '';
}
});
return posts;
}
export const protocolUrl2Obj = (url) => {
let urlPart = url.split('://')[1];
// Start replacing user names
let output = replaceAuthorNames(input);
// remove last char if /
if(urlPart.endsWith('/')){
urlPart = urlPart.substring(0, urlPart.length - 1);
}
// Replace tags
output = replaceTags(output);
const parts = urlPart.split('/');
output = md.render(output);
// filter
if (parts.length === 1 && filters.includes(parts[0])) {
return {type: 'filter', filter: parts[0]};
}
const imgRegex = /(https?:\/\/.*\.(?:tiff?|jpe?g|gif|png|svg|ico))/gim;
const postRegex = /^https?:\/\/(.*)\/(.*)\/(@[\w\.\d-]+)\/(.*)/i;
const youTubeRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^& \n<]+)(?:[^ \n<]+)?/g;
const vimeoRegex = /(https?:\/\/)?(www\.)?(?:vimeo)\.com.*(?:videos|video|channels|)\/([\d]+)/i;
const dTubeRegex = /(https?:\/\/d.tube.#!\/v\/)(\w+)\/(\w+)/g;
// filter with tag
if (parts.length === 2 && filters.includes(parts[0])) {
return {type: 'filter-tag', filter: parts[0], tag: parts[1]};
}
// TODO: Implement Regex
// account
if (parts.length === 1 && parts[0].startsWith('@')) {
return {type: 'account', account: parts[0].replace('@', '')};
}
return output;
};
// post
if (parts.length === 3 && parts[1].startsWith('@')) {
return {type: 'post', cat: parts[0], author: parts[1].replace('@', ''), permlink: parts[2]};
}
};
export const parsePosts = posts => {
posts.map(post => {
post.json_metadata = JSON.parse(post.json_metadata);
post.json_metadata.image
? (post.image = post.json_metadata.image[0])
: '';
post.pending_payout_value = parseFloat(
post.pending_payout_value
).toFixed(2);
post.created = moment
.utc(post.created)
.local()
.fromNow();
post.vote_count = post.active_votes.length;
post.author_reputation = reputation(post.author_reputation);
post.avatar = `https://steemitimages.com/u/${post.author}/avatar/small`;
post.body = markDown2Html(post.body);
post.summary = postSummary(post.body, 100);
post.raw_body = post.body;
post.active_votes.sort((a, b) => {
return b.rshares - a.rshares;
});
if (post.active_votes.length > 2) {
post.top_likers = [
post.active_votes[0].voter,
post.active_votes[1].voter,
post.active_votes[2].voter,
];
}
});
return posts;
};
export const protocolUrl2Obj = url => {
let urlPart = url.split('://')[1];
// remove last char if /
if (urlPart.endsWith('/')) {
urlPart = urlPart.substring(0, urlPart.length - 1);
}
const parts = urlPart.split('/');
// filter
if (parts.length === 1 && filters.includes(parts[0])) {
return { type: 'filter', filter: parts[0] };
}
// filter with tag
if (parts.length === 2 && filters.includes(parts[0])) {
return { type: 'filter-tag', filter: parts[0], tag: parts[1] };
}
// account
if (parts.length === 1 && parts[0].startsWith('@')) {
return { type: 'account', account: parts[0].replace('@', '') };
}
// post
if (parts.length === 3 && parts[1].startsWith('@')) {
return {
type: 'post',
cat: parts[0],
author: parts[1].replace('@', ''),
permlink: parts[2],
};
}
};

View File

@ -1,19 +1,19 @@
export const postSummary = (postBody, length) => {
if (!postBody) {
return '';
}
if (!postBody) {
return '';
}
postBody = postBody
.replace(/(<([^>]+)>)/ig, '') // Remove html tags
.replace(/\r?\n|\r/g, ' ') // Remove new lines
.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '') // Remove urls
.trim()
.replace(/ +(?= )/g, ''); // Remove all multiple spaces
postBody = postBody
.replace(/(<([^>]+)>)/gi, '') // Remove html tags
.replace(/\r?\n|\r/g, ' ') // Remove new lines
.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '') // Remove urls
.trim()
.replace(/ +(?= )/g, ''); // Remove all multiple spaces
if (length) {
// Truncate
postBody = postBody.substring(0, length);
}
return postBody;
};
if (length) {
// Truncate
postBody = postBody.substring(0, length);
}
return postBody;
};

View File

@ -1,10 +1,10 @@
export const reputation = (reputation) => {
if (reputation == null) return reputation;
reputation = parseInt(reputation);
let log = Math.log10(reputation);
log = log - 9;
log = log * 9;
log = log + 25;
log = Math.floor(log);
return log;
}
export const reputation = reputation => {
if (reputation == null) return reputation;
reputation = parseInt(reputation);
let log = Math.log10(reputation);
log = log - 9;
log = log * 9;
log = log + 25;
log = Math.floor(log);
return log;
};