Skip to content

Commit 4b1db7f

Browse files
authored
Merge pull request #6 from funnyzak/feat/tab_node
2 parents 17fb301 + 160939c commit 4b1db7f

File tree

11 files changed

+141
-29
lines changed

11 files changed

+141
-29
lines changed

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { name as appName } from './app.json'
88
import 'react-native-gesture-handler'
99

1010
// Ignore log notification by message:
11-
LogBox.ignoreLogs(['required dispatch_sync'])
11+
LogBox.ignoreLogs(['required dispatch_sync', 'flexWrap'])
1212

1313
// Ignore all log notifications:
1414
// LogBox.ignoreAllLogs();

src/actions/RestActions.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import _ from 'lodash'
44
import { v2exLib } from '@src/v2ex'
55
import { v2exOptions } from '@src/config/v2ex'
66
import { MEMBER_TOKEN_KEY } from '@src/config/constants'
7-
import { APP_INIT, APP_SITE_STAT, APP_INIT_ERROR, APP_SITE_INFO, IState } from '../types'
7+
import { APP_INIT, APP_SITE_STAT, APP_INIT_ERROR, APP_SITE_INFO, APP_ALL_NODE_INFO, IState } from '../types'
88
import { logError } from '@src/helper/logger'
99
import DeviceInfo from 'react-native-device-info'
1010

@@ -26,6 +26,8 @@ export const initV2ex = () => {
2626

2727
dispatchSiteStat(dispatch)
2828

29+
dispatchAllNodeInfo(dispatch)
30+
2931
dispatch({
3032
type: APP_INIT,
3133
payload: {
@@ -72,6 +74,19 @@ const dispatchSiteInfo = async (dispatch: Dispatch) => {
7274
}
7375
}
7476

77+
const dispatchAllNodeInfo = async (dispatch: Dispatch) => {
78+
try {
79+
const nodes = await v2exLib.node.all()
80+
81+
dispatch({
82+
type: APP_ALL_NODE_INFO,
83+
payload: nodes
84+
})
85+
} catch (e) {
86+
logError(e)
87+
}
88+
}
89+
7590
const dispatchSiteStat = async (dispatch: Dispatch) => {
7691
try {
7792
const site_stat = await v2exLib.siteStat()

src/actions/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
export const APP_INIT = 'v2ex_init'
66
export const APP_LATEST_VERSION = 'v2ex_latest_version'
77
export const APP_SITE_INFO = 'v2ex_site_info'
8+
export const APP_ALL_NODE_INFO = 'v2ex_all_node_info'
89
export const APP_SITE_STAT = 'v2ex_site_stat'
910
export const APP_INIT_ERROR = 'v2ex_init_error'
1011

@@ -46,6 +47,7 @@ export const ActionTypes = {
4647
APP_LATEST_VERSION,
4748
APP_SITE_INFO,
4849
MEMBER_READ_TOPIC,
50+
APP_ALL_NODE_INFO,
4951
APP_INIT_ERROR,
5052
APP_NODE_NODE_TOPICS,
5153
APP_NODE_LOAD_MORE_TOPICS,

src/helper/node.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Created by leon<[email protected]> on 22/3/20.
3+
*/
4+
import { store } from '@src/store'
5+
import { V2exObject } from '@src/types'
6+
7+
/**
8+
* home tab nodes
9+
*/
10+
export interface TabNodeProps {
11+
title: string
12+
parentNodeNames: any[]
13+
children?: V2exObject.Node[]
14+
}
15+
16+
export let TabNodes: TabNodeProps[] = [
17+
{ title: 'V2EX', parentNodeNames: ['v2ex'] },
18+
{ title: 'Life', parentNodeNames: ['life'] },
19+
{ title: 'Geek', parentNodeNames: ['geek'] },
20+
{ title: 'Programming', parentNodeNames: ['programming'] },
21+
{ title: 'Earth', parentNodeNames: ['cn', 'us'] }
22+
]
23+
24+
export const nodeChildren = (rootNode: TabNodeProps): V2exObject.Node[] => {
25+
const { title, parentNodeNames: parentNodes } = rootNode
26+
27+
let nodes: V2exObject.Node[] = []
28+
29+
const all_node = store.getState().app.allNode
30+
if (!all_node) return nodes
31+
32+
return all_node.filter((v) => parentNodes.includes(v.parent_node_name))
33+
}

src/navigation/NavigationService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ function goTopicDetail(topicId: string) {
2626
navigate(ROUTES.TopicDetail, { topicId })
2727
}
2828

29+
function goNodeTopics(nodeName: string, nodeTitle: string) {
30+
navigate(ROUTES.NodeTopics, { nodeName, nodeTitle })
31+
}
32+
2933
export type NavigationType = NavigationContainerRefWithCurrent<RootStackParamList>
3034

3135
// add other navigation functions that you need and export them
@@ -34,5 +38,6 @@ export default {
3438
navigate,
3539
setTopLevelNavigator,
3640
goTopicDetail,
41+
goNodeTopics,
3742
goUserProfile
3843
}

src/reducers/AppReducer.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import { APP_INIT, APP_INIT_ERROR, APP_SITE_INFO, APP_LOGOUT, APP_LATEST_VERSION, APP_SITE_STAT, Action, IState } from '../types'
1+
import {
2+
APP_INIT,
3+
APP_INIT_ERROR,
4+
APP_SITE_INFO,
5+
APP_LOGOUT,
6+
APP_LATEST_VERSION,
7+
APP_SITE_STAT,
8+
Action,
9+
IState,
10+
APP_ALL_NODE_INFO
11+
} from '../types'
212
import { aboutUs } from '@src/config/v2ex'
313

414
const INITIAL_STATE: IState.AppState = {
@@ -18,6 +28,8 @@ export default (state: IState.AppState = INITIAL_STATE, action: Action): IState.
1828
return { ...state, siteInfo: action.payload }
1929
case APP_SITE_STAT:
2030
return { ...state, siteStat: action.payload }
31+
case APP_ALL_NODE_INFO:
32+
return { ...state, allNode: action.payload }
2133
case APP_INIT_ERROR:
2234
return { ...state, errorMessage: action.payload }
2335
case APP_LOGOUT:

src/screens/node/index.tsx

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,55 @@
1-
import React, { useState } from 'react'
1+
import React from 'react'
22
import { connect } from 'react-redux'
3-
import { StyleSheet, View, ViewStyle, TextStyle } from 'react-native'
3+
import { View, ViewStyle, SectionList, TouchableOpacity } from 'react-native'
44

5-
import { translate } from '@src/i18n'
65
import { useTheme, SylCommon } from '@src/theme'
76
import { IState, ITheme, V2exObject } from '@src/types'
8-
import * as CompS from '../components'
9-
import { Text, Spinner } from '@src/components'
10-
import { NodeScreenProps as ScreenProps } from '@src/navigation/routes'
7+
import { Text } from '@src/components'
8+
import { NodeScreenProps as ScreenProps, NavigationService } from '@src/navigation'
9+
import { TabNodes, nodeChildren } from '@src/helper/node'
1110

12-
const Node = ({ route, navigation, loading }: ScreenProps) => {
11+
const Node = ({ route, navigation }: ScreenProps) => {
1312
const { theme } = useTheme()
13+
14+
const Item = ({ node }: { node: V2exObject.Node }) => (
15+
<TouchableOpacity
16+
style={styles.item(theme)}
17+
onPress={() => {
18+
NavigationService.goNodeTopics(node.name, node.title)
19+
}}>
20+
<Text style={SylCommon.Node.nodeTitle(theme)}>{node.title}</Text>
21+
</TouchableOpacity>
22+
)
23+
24+
const sectionData = () => {
25+
return TabNodes.map((node) => ({
26+
title: node.title,
27+
data: nodeChildren(node),
28+
key: node.title
29+
}))
30+
}
31+
32+
const renderContent = () => {
33+
return (
34+
<View style={styles.container(theme)}>
35+
<SectionList
36+
sections={sectionData()}
37+
contentContainerStyle={styles.listContainer(theme)}
38+
keyExtractor={(item, index) => item.name + index}
39+
renderItem={({ item }) => <Item node={item} />}
40+
stickySectionHeadersEnabled={false}
41+
renderSectionHeader={({ section: { title } }) => (
42+
<View style={styles.section(theme)}>
43+
<Text style={SylCommon.Node.sectionTitle(theme)}>{title}</Text>
44+
</View>
45+
)}
46+
/>
47+
</View>
48+
)
49+
}
1450
return (
15-
<View style={[SylCommon.Layout.fill, SylCommon.View.background(theme)]}>
16-
<Text>Hello, Node.</Text>
51+
<View style={[SylCommon.Layout.fill, SylCommon.View.background(theme), { alignItems: 'center' }]}>
52+
{renderContent()}
1753
</View>
1854
)
1955
}
@@ -23,20 +59,23 @@ const Node = ({ route, navigation, loading }: ScreenProps) => {
2359
*/
2460
const styles = {
2561
container: (theme: ITheme): ViewStyle => ({
62+
width: theme.dimens.WINDOW_WIDTH - 40,
2663
flex: 1
64+
}),
65+
section: (theme: ITheme) => ({
66+
width: styles.container(theme).width,
67+
paddingVertical: theme.spacing.medium
68+
}),
69+
listContainer: (theme: ITheme): ViewStyle => ({
70+
flexDirection: 'row',
71+
flexWrap: 'wrap',
72+
justifyContent: 'flex-start'
73+
}),
74+
item: (theme: ITheme): ViewStyle => ({
75+
width: 'auto',
76+
marginRight: theme.spacing.small,
77+
marginVertical: theme.spacing.tiny
2778
})
2879
}
2980

30-
/**
31-
* default props
32-
*/
33-
Node.defaultProps = {
34-
loading: false
35-
}
36-
37-
const mapStateToProps = ({ ui: { login } }: { ui: IState.UIState }) => {
38-
const { error, success, loading } = login
39-
return { error, success, loading }
40-
}
41-
42-
export default connect(mapStateToProps)(Node)
81+
export default Node

src/screens/topic/TopicDetail.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const TopicDetail = ({ route, navigation }: ScreenProps) => {
5151
nodeTitle: topic.node?.title || 'HOT'
5252
})
5353
}}>
54-
<Text style={SylCommon.Node.node(theme)}>{topic.node?.name}</Text>
54+
<Text style={SylCommon.Node.nodeTitle(theme)}>{topic.node?.name}</Text>
5555
</Pressable>
5656
</View>
5757
</View>

src/store/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ export declare module IState {
5353

5454
siteStat?: V2exObject.SiteStat
5555

56+
allNode?: V2exObject.Node[]
57+
5658
errorMessage?: Error[]
5759
}
5860

src/theme/common.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,19 @@ export const View = {
2828
}
2929

3030
export const Node = {
31-
node: (theme: ITheme) => ({
31+
sectionTitle: (theme: ITheme) => ({
32+
...theme.typography.subheadingText
33+
}),
34+
nodeTitle: (theme: ITheme) => ({
3235
fontSize: 12,
3336
paddingVertical: 1,
3437
paddingHorizontal: 8,
3538
backgroundColor: theme.colors.surface,
3639
borderRadius: 4,
3740
color: theme.colors.secondary
3841
}),
39-
small: (theme: ITheme) => ({
42+
smallTitle: (theme: ITheme) => ({
43+
...Node.nodeTitle(theme),
4044
fontSize: 10
4145
})
4246
}

0 commit comments

Comments
 (0)