diff --git a/src/component/customedList.js b/src/component/customedList.js new file mode 100644 index 0000000..d1b6caf --- /dev/null +++ b/src/component/customedList.js @@ -0,0 +1,97 @@ +import React, {Component} from 'react'; +import {StyleSheet, Text, View, InteractionManager, FlatList} from 'react-native'; + + +export default class CustomedList extends Component { + + constructor(props) { + super(props); + + this.listType = props.listType || 'undefined'; + this.dataSource = props.dataSource; + + this.state = { + listData: [], + hasMore: false, + + refreshing: false, + refreshFailed: false + }; + } + + componentDidMount() { + InteractionManager.runAfterInteractions(() => { + this.refresh(); + }); + } + + refresh(loadMore = false) { + if (this.state.refreshing) { + return; + } + + this.setState({hasMore: false, refreshing: true, refreshFailed: false}); + this.dataSource.refresh(loadMore) + .then(result => { + if(!result) { + throw { + message: 'refresh ' + this.listType + ' no result' + } + + } else { + console.log('refresh ' + this.listType + ' result:', result); + + this.setState({ + listData: result.list ? result.list : [], + hasMore: result.more, + refreshFailed: false + }); + } + + }).catch(e => { + this.setState({ + listData: [], + hasMore: false, + refreshFailed: true + }); + + }).done(() => { + this.setState({ + refreshing: false + }); + }); + } + + loadMore() { + if (this.state.refreshing) { + return; + } + + this.refresh(true); + } + + render() { + return ( + { + return item.id ? item.id.toString() : index; + }} + + renderItem={this.props.renderItem} + + refreshing={this.state.refreshing} + onRefresh={this.refresh.bind(this)} + + onEndReachedThreshold={5} + onEndReached={this.state.hasMore ? this.loadMore.bind(this) : null} + /> + ); + } +} + +const localStyle = StyleSheet.create({ + +}); diff --git a/src/component/follow/followUserList.js b/src/component/follow/followUserList.js new file mode 100644 index 0000000..7d5c5b9 --- /dev/null +++ b/src/component/follow/followUserList.js @@ -0,0 +1,72 @@ +import React, {Component} from 'react'; +import {StyleSheet, Text, View, InteractionManager, FlatList} from 'react-native'; +import Ionicons from 'react-native-vector-icons/Ionicons'; + +import Touchable from '../touchable'; +import Color from '../../style/color'; + +import UserIcon from '../userIcon'; +import CustomedList from '../customedList'; + + +export default class FollowUserList extends Component { + + constructor(props) { + super(props); + + this.dataSource = props.dataSource; + this.listType = props.listType; + } + + render() { + return ( + + { + return ( + {}}> + + + {item.name} + {}}> + + + + + ); + }} + /> + + ); + } +} + +const localStyle = StyleSheet.create({ + container: { + flex: 1 + }, + list: { + height: '100%' + }, + box: { + flexDirection: 'row', + borderBottomWidth: 1, + borderColor: Color.line, + alignItems: 'center', + backgroundColor: 'white', + paddingLeft: 25 + }, + userName: { + flex: 1, + color: Color.text, + fontSize: 16 + }, + removeIcon: { + padding: 20 + } +}); diff --git a/src/dataLoader/followedByUserData.js b/src/dataLoader/followedByUserData.js new file mode 100644 index 0000000..6966f77 --- /dev/null +++ b/src/dataLoader/followedByUserData.js @@ -0,0 +1,30 @@ +import Api from '../util/api' + + +const PAGE_SIZE = 20; + +export default class FollowedByUserData { + + page: 1; + list: []; + + async refresh(loadMore = false) { + let page = !loadMore ? 1 : this.page + 1; + let data = await Api.getRelationReverseUsers(page, PAGE_SIZE) + let more = data.users.length === PAGE_SIZE; + + if(!loadMore) { + this.page = page; + this.list = data.users.slice(0, PAGE_SIZE - 1); + + } else if(data.users.length > 0) { + this.page = page; + this.list = this.list.concat(data.users.slice(0, PAGE_SIZE - 1)); + } + + return { + list: this.list, + more + }; + } +} \ No newline at end of file diff --git a/src/dataLoader/followingUserData.js b/src/dataLoader/followingUserData.js new file mode 100644 index 0000000..fd3fe0d --- /dev/null +++ b/src/dataLoader/followingUserData.js @@ -0,0 +1,30 @@ +import Api from '../util/api' + + +const PAGE_SIZE = 20; + +export default class FollowingUserData { + + page: 1; + list: []; + + async refresh(loadMore = false) { + let page = !loadMore ? 1 : this.page + 1; + let data = await Api.getRelationUsers(page, PAGE_SIZE) + let more = data.users.length === PAGE_SIZE; + + if(!loadMore) { + this.page = page; + this.list = data.users.slice(0, PAGE_SIZE - 1); + + } else if(data.users.length > 0) { + this.page = page; + this.list = this.list.concat(data.users.slice(0, PAGE_SIZE - 1)); + } + + return { + list: this.list, + more + }; + } +} \ No newline at end of file diff --git a/src/page/FollowPage.js b/src/page/FollowPage.js index cc4e444..01378a4 100644 --- a/src/page/FollowPage.js +++ b/src/page/FollowPage.js @@ -54,7 +54,11 @@ export default class FollowPage extends Component { name: 'FollowUser', options: { bottomTabs: { - visible: false + visible: false, + + // hide bottom tab for android + drawBehind: true, + animate: true } } } diff --git a/src/page/FollowUserPage.js b/src/page/FollowUserPage.js index 629c75e..500d551 100644 --- a/src/page/FollowUserPage.js +++ b/src/page/FollowUserPage.js @@ -1,16 +1,38 @@ import React, {Component} from 'react'; -import {StyleSheet, Text, View} from 'react-native'; +import {StyleSheet, Text, View, Animated} from 'react-native'; +import { + PagerScroll, + TabView, + TabBar, + SceneMap +} from 'react-native-tab-view'; + +import Api from '../util/api'; +import Color from '../style/color'; +import FollowUserList from '../component/follow/followUserList' +import FollowingUserData from '../dataLoader/followingUserData' +import FollowedByUserData from '../dataLoader/followedByUserData' export default class FollowPage extends Component { constructor(props) { super(props); + this.state = { + index: 0, + routes: [ + { key: 'following', title: '我关注的' }, + { key: 'followedBy', title: '关注我的' } + ] + }; } static options(passProps) { return { topBar: { + noBorder: true, // ios + elevation: 0, // android + title: { text: '关注用户' } @@ -18,25 +40,87 @@ export default class FollowPage extends Component { }; } - render() { + _renderLabel = props => ({route}) => { + let routes = props.navigationState.routes; + let index = props.navigationState.index; + + let color = route.key == routes[index].key ? Color.primary : '#222'; + return ( - - Follow User Page ! - + + {route.title} + ); + }; + + _renderTabBar = props => { + return ( + + + ); + }; + + _renderScene = SceneMap({ + following: () => , + followedBy: () => + }); + + render() { + return ( + } /* android */ + + renderTabBar={this._renderTabBar} + renderScene={this._renderScene} + + navigationState={this.state} + onIndexChange={index => { + this.setState({index}); + }} + + /> + ); } } const localStyle = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, + welcome: { fontSize: 20, textAlign: 'center', margin: 10, + marginTop: 35 + }, + + container: { + flex: 1 + }, + tabBar: { + backgroundColor: '#fff', + paddingTop: 10, + paddingBottom: 5 + }, + indicator: { + backgroundColor: Color.primary + }, + label: { + fontSize: 13, + fontWeight: 'bold' } }); diff --git a/src/util/api.js b/src/util/api.js index 6ab025e..34fdb9e 100644 --- a/src/util/api.js +++ b/src/util/api.js @@ -72,6 +72,14 @@ async function getSelfNotebooks() { return call('GET', '/notebooks/my') } +async function getRelationUsers(page, page_size) { + return call('GET', `/relation?page=${page}&page_size=${page_size}`); +} + +async function getRelationReverseUsers(page, page_size) { + return call('GET', `/relation/reverse?page=${page}&page_size=${page_size}`); +} + async function call(method, api, body, _timeout = 10000) { let token = await TokenManager.getUserToken(); @@ -159,8 +167,13 @@ export default { IS_IPHONEX, login, + getTodayDiaries, getFollowDiaries, + getDiaryComments, - getSelfNotebooks + getSelfNotebooks, + + getRelationUsers, + getRelationReverseUsers } \ No newline at end of file