1. 关注/被关注用户列表切换

2. 抽象出customedList组件,应用于关注用户页面的列表展现。逐步将试用到各类日志列表,减少列表类组件数量
This commit is contained in:
xuwenyang 2019-05-17 00:26:44 +08:00
parent 7852b9e05a
commit 0b682dd777
7 changed files with 343 additions and 13 deletions

View file

@ -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 (
<FlatList
data={this.state.listData}
keyExtractor={(item, index) => {
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({
});

View file

@ -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 (
<View style={localStyle.container}>
<CustomedList listType={this.props.listType} style={localStyle.list}
dataSource={this.props.dataSource}
renderItem={({item}) => {
return (
<Touchable key={item.id} onPress={() => {}}>
<View style={localStyle.box}>
<UserIcon iconUrl={item.iconUrl}></UserIcon>
<Text style={localStyle.userName}>{item.name}</Text>
<Touchable onPress={() => {}}>
<Ionicons name="md-close" size={20}
style={localStyle.removeIcon}
color={Color.inactiveText} />
</Touchable>
</View>
</Touchable>
);
}}
/>
</View>
);
}
}
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
}
});

View file

@ -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
};
}
}

View file

@ -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
};
}
}

View file

@ -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
}
}
}

View file

@ -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 {
};
}
_renderLabel = props => ({route}) => {
let routes = props.navigationState.routes;
let index = props.navigationState.index;
let color = route.key == routes[index].key ? Color.primary : '#222';
return (
<Animated.Text
style={[localStyle.label, {color}]}>
{route.title}
</Animated.Text>
);
};
_renderTabBar = props => {
return (
<TabBar
{...props}
style={localStyle.tabBar}
indicatorStyle={localStyle.indicator}
renderLabel={this._renderLabel(props)}
>
</TabBar>
);
};
_renderScene = SceneMap({
following: () => <FollowUserList
listType={'followingUser'} dataSource={new FollowingUserData()}
/>,
followedBy: () => <FollowUserList
listType={'followedByUser'} dataSource={new FollowedByUserData()}
/>
});
render() {
return (
<View style={localStyle.container}>
<Text style={localStyle.welcome}>Follow User Page !</Text>
</View>
<TabView style={localStyle.container}
initialLayout={{
height: 0,
width: Api.DEVICE_WINDOW.width
}}
renderPager={(props) => <PagerScroll {...props}/>} /* 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'
}
});

View file

@ -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
}