Skip to content

Commit 2ddcad5

Browse files
committed
新增分类详情页面
1 parent a9a07a6 commit 2ddcad5

File tree

8 files changed

+268
-19
lines changed

8 files changed

+268
-19
lines changed

.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
API_URL=http://baobab.kaiyanapp.com/api/
22
APP_NAME=Eyepetizer
3-
VERSIONCODE=2
4-
VERSIONNAME=1.0.1
3+
VERSIONCODE=3
4+
VERSIONNAME=1.0.2

ios/tmp.xcconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
API_URL=http:/$()/baobab.kaiyanapp.com/api/
22
APP_NAME=Eyepetizer
3-
VERSIONCODE=1
4-
VERSIONNAME=1.0.0
3+
VERSIONCODE=2
4+
VERSIONNAME=1.0.1
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import {Effect, Model} from 'dva-core-ts';
2+
import {Reducer} from 'redux';
3+
import axios from 'axios';
4+
import {RefreshState} from 'react-native-refresh-list-view';
5+
import {Item} from '@/model/Daily';
6+
import {RootState} from '@/model/dva/Models';
7+
import Toast from 'react-native-root-toast';
8+
9+
const CATEGOTY_DETAIL_URL = 'v4/categories/videoList?id=';
10+
const SUFFIX =
11+
'&udid=d2807c895f0348a180148c9dfa6f2feeac0781b5&deviceModel=Android';
12+
13+
export interface ICategoryDetailModelState {
14+
dataList: Item[];
15+
refreshState: number;
16+
nextPageUrl: string | null;
17+
}
18+
19+
export interface CategoryDetailModel extends Model {
20+
namespace: 'categoryDetail';
21+
state: ICategoryDetailModelState;
22+
reducers: {
23+
setState: Reducer<ICategoryDetailModelState>;
24+
};
25+
effects: {
26+
onRefresh: Effect;
27+
onLoadMore: Effect;
28+
};
29+
}
30+
31+
const initialState: ICategoryDetailModelState = {
32+
dataList: [],
33+
refreshState: RefreshState.Idle,
34+
nextPageUrl: null,
35+
};
36+
37+
const categoryDetailModel: CategoryDetailModel = {
38+
namespace: 'categoryDetail',
39+
state: initialState,
40+
reducers: {
41+
setState(state = initialState, {payload}) {
42+
return {
43+
...state,
44+
...payload,
45+
};
46+
},
47+
},
48+
effects: {
49+
*onRefresh({payload}, {call, put}) {
50+
try {
51+
yield put({
52+
type: 'setState',
53+
payload: {
54+
refreshState: RefreshState.HeaderRefreshing,
55+
},
56+
});
57+
const url = `${CATEGOTY_DETAIL_URL}${payload.id}${SUFFIX}`;
58+
const {data} = yield call(axios.get, url);
59+
const {itemList, nextPageUrl} = data;
60+
yield put({
61+
type: 'setState',
62+
payload: {
63+
dataList: itemList,
64+
nextPageUrl: nextPageUrl,
65+
refreshState:
66+
nextPageUrl === null
67+
? RefreshState.NoMoreData
68+
: RefreshState.Idle,
69+
},
70+
});
71+
} catch (error) {
72+
Toast.show(error.message);
73+
yield put({
74+
type: 'setState',
75+
payload: {
76+
refreshState: RefreshState.Failure,
77+
},
78+
});
79+
}
80+
},
81+
*onLoadMore({payload}, {call, put, select}) {
82+
try {
83+
if (payload && payload.nextPageUrl == null) {
84+
return;
85+
}
86+
87+
yield put({
88+
type: 'setState',
89+
payload: {
90+
refreshState: RefreshState.FooterRefreshing,
91+
},
92+
});
93+
const url = `${payload.nextPageUrl}${SUFFIX}`;
94+
const {dataList} = yield select(
95+
(state: RootState) => state.categoryDetail,
96+
);
97+
const {data} = yield call(axios.get, url);
98+
const {itemList, nextPageUrl} = data;
99+
100+
yield put({
101+
type: 'setState',
102+
payload: {
103+
dataList: dataList.concat(itemList),
104+
nextPageUrl: nextPageUrl,
105+
refreshState:
106+
nextPageUrl === null
107+
? RefreshState.NoMoreData
108+
: RefreshState.Idle,
109+
},
110+
});
111+
} catch (error) {
112+
Toast.show(error.message);
113+
yield put({
114+
type: 'setState',
115+
payload: {
116+
refreshState: RefreshState.Failure,
117+
},
118+
});
119+
}
120+
},
121+
},
122+
};
123+
124+
export default categoryDetailModel;

ts/model/dva/Models.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import daily from './DailyModel';
22
import category from './CategoryModel';
3+
import categoryDetail from './CategoryDetailModel';
34
import topicList from './TopicListModel';
45
import news from './NewsModel';
56
import follow from './FollowModel';
@@ -13,6 +14,7 @@ import topicDetail from './TopicDetailModel';
1314
const models = [
1415
daily,
1516
category,
17+
categoryDetail,
1618
topicList,
1719
news,
1820
follow,
@@ -27,6 +29,7 @@ const models = [
2729
export type RootState = {
2830
daily: typeof daily.state;
2931
category: typeof category.state;
32+
categoryDetail: typeof categoryDetail.state;
3033
topicList: typeof topicList.state;
3134
news: typeof news.state;
3235
follow: typeof follow.state;

ts/navigator/Router.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import RecommendImageGallery, {
1818
import {IMasonry} from '@/model/Masonry';
1919
import RecommendVideoPage from '@/page/discover/RecommendVideoPage';
2020
import TopicDetailPage from '@/page/discover/TopicDetailPage';
21+
import CategoryDetailPage from '@/page/discover/CategoryDetailPage';
22+
import {ICategory} from '@/model/Category';
2123

2224
//定义每一个页面的名称以及进入页面传递参数的类型
2325
export type RootStackParamList = {
@@ -32,6 +34,9 @@ export type RootStackParamList = {
3234
VideoDetail: {
3335
item: Item;
3436
};
37+
CategoryDetail: {
38+
item: ICategory;
39+
};
3540
};
3641

3742
//导出堆栈导航器对于的Navigation,方便各个页面之间进行跳转
@@ -80,6 +85,7 @@ function RootStackScreen() {
8085
component={VideoDetailPage}
8186
options={{headerShown: false}}
8287
/>
88+
<Stack.Screen name="CategoryDetail" component={CategoryDetailPage} />
8389
</Stack.Navigator>
8490
);
8591
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React from 'react';
2+
import {connect, ConnectedProps} from 'react-redux';
3+
import RefreshListView, {RefreshState} from 'react-native-refresh-list-view';
4+
import {RootState} from '@/model/dva/Models';
5+
import {ListRenderItemInfo, StyleSheet, View} from 'react-native';
6+
import {RouteProp} from '@react-navigation/native';
7+
import {RootNavigation, RootStackParamList} from '@/navigator/Router';
8+
import {Item} from '@/model/Daily';
9+
import ImageTextItem from '@/components/ImageTextItem';
10+
11+
const CLEAR_TYPE = 'categoryDetail/setState';
12+
const REFRESH_TYPE = 'categoryDetail/onRefresh';
13+
const LOAD_MORE_TYPE = 'categoryDetail/onLoadMore';
14+
15+
const mapStateToProps = ({categoryDetail}: RootState) => {
16+
return {
17+
dataList: categoryDetail.dataList,
18+
refreshState: categoryDetail.refreshState,
19+
nextPageUrl: categoryDetail.nextPageUrl,
20+
};
21+
};
22+
23+
const connector = connect(mapStateToProps);
24+
25+
type ModelState = ConnectedProps<typeof connector>;
26+
27+
interface IProps extends ModelState {
28+
navigation: RootNavigation;
29+
route: RouteProp<RootStackParamList, 'CategoryDetail'>;
30+
}
31+
32+
class CategoryDetailPage extends React.Component<IProps> {
33+
componentDidMount() {
34+
const {navigation, route} = this.props;
35+
navigation.setOptions({title: route.params.item.name});
36+
this.onHeaderRefresh();
37+
}
38+
39+
componentWillUnmount() {
40+
const {dispatch} = this.props;
41+
dispatch({
42+
type: CLEAR_TYPE,
43+
payload: {
44+
dataList: [],
45+
refreshState: RefreshState.Idle,
46+
nextPageUrl: null,
47+
},
48+
});
49+
}
50+
51+
onHeaderRefresh = () => {
52+
const {dispatch, route} = this.props;
53+
dispatch({
54+
type: REFRESH_TYPE,
55+
payload: {
56+
id: route.params.item.id,
57+
},
58+
});
59+
};
60+
61+
onFooterRefresh = () => {
62+
const {nextPageUrl} = this.props;
63+
if (nextPageUrl == null) {
64+
return;
65+
}
66+
const {dispatch} = this.props;
67+
dispatch({
68+
type: LOAD_MORE_TYPE,
69+
payload: {
70+
nextPageUrl: nextPageUrl,
71+
},
72+
});
73+
};
74+
75+
renderItem = ({item}: ListRenderItemInfo<Item>) => {
76+
return <ImageTextItem item={item} />;
77+
};
78+
79+
keyExtractor = (item: Item) => {
80+
return `${item.data.id}`;
81+
};
82+
83+
render() {
84+
const {dataList, refreshState} = this.props;
85+
return (
86+
<View style={styles.container}>
87+
<RefreshListView
88+
data={dataList}
89+
renderItem={this.renderItem}
90+
keyExtractor={this.keyExtractor}
91+
refreshState={refreshState}
92+
onHeaderRefresh={this.onHeaderRefresh}
93+
onFooterRefresh={this.onFooterRefresh}
94+
showsVerticalScrollIndicator={false}
95+
/>
96+
</View>
97+
);
98+
}
99+
}
100+
101+
const styles = StyleSheet.create({
102+
container: {
103+
backgroundColor: '#fff',
104+
},
105+
});
106+
107+
export default connector(CategoryDetailPage);

ts/page/discover/CategoryPage.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ import React from 'react';
22
import {connect, ConnectedProps} from 'react-redux';
33
import {RootState} from '@/model/dva/Models';
44
import {ICategory} from '@/model/Category';
5-
import {FlatList, Text, View, StyleSheet, RefreshControl} from 'react-native';
5+
import {
6+
FlatList,
7+
Text,
8+
View,
9+
StyleSheet,
10+
RefreshControl,
11+
TouchableWithoutFeedback,
12+
} from 'react-native';
613
import FastImage from 'react-native-fast-image';
14+
import {navigate} from '@/utils/Utils';
715

816
const REFRESH_TYPE = 'category/onRefresh';
917

@@ -34,17 +42,23 @@ class CategoryPage extends React.Component<ModelState> {
3442
return item.name;
3543
};
3644

45+
go2CategoryDetail = (item: ICategory) => {
46+
navigate('CategoryDetail', {item: item});
47+
};
48+
3749
renderItem = ({item, index}: {item: ICategory; index: number}) => {
3850
return (
39-
<View style={styles.item}>
40-
<FastImage
41-
source={{uri: item.bgPicture}}
42-
style={index % 2 === 0 ? styles.leftImage : styles.rightImage}
43-
/>
44-
<View style={styles.category}>
45-
<Text style={styles.text}>#{item.name}</Text>
51+
<TouchableWithoutFeedback onPress={() => this.go2CategoryDetail(item)}>
52+
<View style={styles.item}>
53+
<FastImage
54+
source={{uri: item.bgPicture}}
55+
style={index % 2 === 0 ? styles.leftImage : styles.rightImage}
56+
/>
57+
<View style={styles.category}>
58+
<Text style={styles.text}>#{item.name}</Text>
59+
</View>
4660
</View>
47-
</View>
61+
</TouchableWithoutFeedback>
4862
);
4963
};
5064
render() {

ts/page/discover/FollowPage.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import RefreshListView from 'react-native-refresh-list-view';
44
import {RootState} from '@/model/dva/Models';
55
import {IFollowModel} from '@/model/Follow';
66
import FollowItem from '@/components/FollowItem';
7-
import {RootNavigation} from '@/navigator/Router';
87

98
const REFRESH_TYPE = 'follow/onRefresh';
109
const LOAD_MORE_TYPE = 'follow/onLoadMore';
@@ -21,11 +20,7 @@ const connector = connect(mapStateToProps);
2120

2221
type ModelState = ConnectedProps<typeof connector>;
2322

24-
interface IProps extends ModelState {
25-
navigation: RootNavigation;
26-
}
27-
28-
class FollowPage extends React.Component<IProps> {
23+
class FollowPage extends React.Component<ModelState> {
2924
componentDidMount() {
3025
this.onHeaderRefresh();
3126
}

0 commit comments

Comments
 (0)