Authored by 王钱钧

Merge branch 'develop' of http://git.yoho.cn/mobile/YH_RNComponent into develop

Conflicts:
	js/community/containers/HomeContainer.js
  1 +'use strict';
  2 +
  3 +import React, {Component} from 'react'
  4 +import {
  5 + StyleSheet,
  6 + View,
  7 + Text,
  8 + Dimensions,
  9 + ActivityIndicator,
  10 + Platform,
  11 +} from 'react-native';
  12 +
  13 +export default class LoadingIndicator extends Component {
  14 +
  15 + static propTypes = {
  16 + isVisible: React.PropTypes.bool.isRequired,
  17 + size: React.PropTypes.string,
  18 + color: React.PropTypes.string,
  19 + overlayWidth: React.PropTypes.number,
  20 + overlayHeight: React.PropTypes.number,
  21 + overlayColor: React.PropTypes.string,
  22 + text: React.PropTypes.string,
  23 + textColor: React.PropTypes.string,
  24 + textFontSize: React.PropTypes.number,
  25 + };
  26 +
  27 + static defaultProps = {
  28 + isDismissible: false,
  29 + overlayWidth: 100,
  30 + overlayHeight: 100,
  31 + overlayColor: 'rgba(0,0,0,0.6)',
  32 + size: (Platform.OS === 'ios') ? 'large' : 'Normal',
  33 + color: (Platform.OS === 'ios') ? 'white' : 'gray',
  34 + text: '加载中...',
  35 + textColor: '#eeeeee',
  36 + textFontSize: 14,
  37 + };
  38 +
  39 + render() {
  40 +
  41 + if (!this.props.isVisible) {
  42 + return null;
  43 + }
  44 +
  45 + let customStyles = StyleSheet.create({
  46 + overlay: {
  47 + alignItems: 'center',
  48 + justifyContent: 'center',
  49 + borderRadius: 10,
  50 + backgroundColor: this.props.overlayColor,
  51 + width: this.props.overlayWidth,
  52 + height: this.props.overlayHeight,
  53 + },
  54 + text: {
  55 + color: this.props.textColor,
  56 + fontSize: this.props.textFontSize,
  57 + marginTop: 8,
  58 + },
  59 + });
  60 +
  61 + return (
  62 + <View style={styles.container}>
  63 + <View style={customStyles.overlay}>
  64 + <ActivityIndicator color={this.props.color} size={this.props.size}/>
  65 + <Text style={customStyles.text}>{this.props.text}</Text>
  66 + </View>
  67 + </View>
  68 + );
  69 + }
  70 +}
  71 +
  72 +const styles = StyleSheet.create({
  73 + container: {
  74 + position: 'absolute',
  75 + backgroundColor: 'transparent',
  76 + justifyContent: 'center',
  77 + alignItems: 'center',
  78 + top: 0,
  79 + bottom: 0,
  80 + left: 0,
  81 + right: 0,
  82 + },
  83 +});
1 'use strict'; 1 'use strict';
2 2
3 import React from 'react'; 3 import React from 'react';
4 -import {AppRegistry, Platform, StyleSheet, Dimensions, Text, Alert} from 'react-native'; 4 +import ReactNative, {
  5 + AppRegistry,
  6 + Platform,
  7 + StyleSheet,
  8 + Dimensions,
  9 + TouchableOpacity,
  10 + View,
  11 + Text,
  12 + Image,
  13 + Alert,
  14 + Animated,
  15 +} from 'react-native';
5 16
6 import { 17 import {
7 Provider, 18 Provider,
@@ -35,9 +46,13 @@ import NavBar from './components/NavBar'; @@ -35,9 +46,13 @@ import NavBar from './components/NavBar';
35 import { 46 import {
36 setPlatform, 47 setPlatform,
37 setContianer, 48 setContianer,
38 - setDot 49 + setChannel,
39 } from './reducers/app/appActions'; 50 } from './reducers/app/appActions';
40 51
  52 +import {
  53 + syncUser,
  54 +} from './reducers/home/homeActions';
  55 +
41 56
42 /** 57 /**
43 * 58 *
@@ -70,6 +85,8 @@ export default function community(platform) { @@ -70,6 +85,8 @@ export default function community(platform) {
70 85
71 store.dispatch(setPlatform(platform)); 86 store.dispatch(setPlatform(platform));
72 store.dispatch(setContianer(this.props.container)); 87 store.dispatch(setContianer(this.props.container));
  88 + store.dispatch(setChannel(this.props.channel));
  89 +
73 // setup the router table with App selected as the initial component 90 // setup the router table with App selected as the initial component
74 return ( 91 return (
75 <Provider store={store}> 92 <Provider store={store}>
@@ -80,9 +97,12 @@ export default function community(platform) { @@ -80,9 +97,12 @@ export default function community(platform) {
80 hideTabBar={true} 97 hideTabBar={true}
81 navBar={NavBar} 98 navBar={NavBar}
82 titleStyle={styles.navTitle} 99 titleStyle={styles.navTitle}
  100 + leftButtonStyle={styles.button}
  101 + rightButtonStyle={styles.button}
83 getSceneStyle={(props) => { 102 getSceneStyle={(props) => {
84 return this.navPushStyle(props); 103 return this.navPushStyle(props);
85 }} 104 }}
  105 + getChannel={() => store.getState().app.channel}
86 > 106 >
87 <Scene 107 <Scene
88 key="Home" 108 key="Home"
@@ -92,10 +112,13 @@ export default function community(platform) { @@ -92,10 +112,13 @@ export default function community(platform) {
92 initial={true} 112 initial={true}
93 leftTitle={null} 113 leftTitle={null}
94 leftButtonImage={require('./images/home/menu_burger.png')} 114 leftButtonImage={require('./images/home/menu_burger.png')}
95 - onLeft={() => {}} 115 + onLeft={() => {
  116 + ReactNative.NativeModules.YH_CommunityHelper.toggleDrawer();
  117 + }}
96 rightTitle={null} 118 rightTitle={null}
97 rightButtonImage={require('./images/home/menu_write.png')} 119 rightButtonImage={require('./images/home/menu_write.png')}
98 - onRight={() => {Actions.Posting();}} 120 + onRight={this.homeOnRight}
  121 + renderTitle={this.renderHomeTitle}
99 /> 122 />
100 123
101 <Scene 124 <Scene
@@ -164,6 +187,51 @@ export default function community(platform) { @@ -164,6 +187,51 @@ export default function community(platform) {
164 ); 187 );
165 }, 188 },
166 189
  190 + renderHomeTitle(navProps) {
  191 + let {width, height} = Dimensions.get('window');
  192 + let distance = Math.ceil(width * 90 / 375);
  193 + let distance2 = Math.ceil(width * 60 / 375);
  194 + let distance3 = Math.ceil(width * 35 / 375);
  195 + let line = 375 - (distance + distance2);
  196 +
  197 + return (
  198 + <Animated.View style={[styles.title,]}>
  199 + <TouchableOpacity onPress={() => {
  200 + ReactNative.NativeModules.YH_CommunityHelper.hideRNNavBar(0);
  201 + }}>
  202 + <Text style={[styles.text, {flex: 0, marginLeft: distance,}]}></Text>
  203 + </TouchableOpacity>
  204 + <Text style={[styles.text, {flex: 0, marginLeft: distance2,}]}>社区</Text>
  205 + <TouchableOpacity onPress={() => {
  206 + ReactNative.NativeModules.YH_CommunityHelper.hideRNNavBar(2);
  207 + }}>
  208 + <Image style={{marginLeft: distance3,}} source={require('./images/home/sd_show_ic.png')}/>
  209 + </TouchableOpacity>
  210 + <View style={{
  211 + backgroundColor: 'white',
  212 + position: 'absolute',
  213 + width: 45,
  214 + height: 2,
  215 + left: 165,
  216 + top: 30,
  217 + }}/>
  218 + </Animated.View>
  219 + );
  220 + },
  221 +
  222 + homeOnRight(state) {
  223 + ReactNative.NativeModules.YH_CommunityHelper.uid()
  224 + .then(uid => {
  225 + state.dispatch(syncUser(uid));
  226 + })
  227 + .catch(error => {
  228 + ReactNative.NativeModules.YH_CommunityHelper.login()
  229 + .then(uid => {
  230 + state.dispatch(syncUser(uid));
  231 + });
  232 + });
  233 + },
  234 +
167 /* 235 /*
168 * 自定义导航push动画 236 * 自定义导航push动画
169 * 237 *
@@ -214,13 +282,16 @@ export default function community(platform) { @@ -214,13 +282,16 @@ export default function community(platform) {
214 282
215 let styles = StyleSheet.create({ 283 let styles = StyleSheet.create({
216 scene: { 284 scene: {
217 - backgroundColor:'#F0F0F0', 285 + backgroundColor: '#F0F0F0',
218 }, 286 },
219 navTitle: { 287 navTitle: {
220 color: 'white', 288 color: 'white',
221 marginLeft: 60, 289 marginLeft: 60,
222 marginRight: 60, 290 marginRight: 60,
223 }, 291 },
  292 + button: {
  293 + width: 60,
  294 + },
224 rightButton: { 295 rightButton: {
225 width: 100, 296 width: 100,
226 height: 37, 297 height: 37,
@@ -242,4 +313,30 @@ let styles = StyleSheet.create({ @@ -242,4 +313,30 @@ let styles = StyleSheet.create({
242 textAlign: 'right', 313 textAlign: 'right',
243 fontSize: 17, 314 fontSize: 17,
244 }, 315 },
  316 + title: {
  317 + flexDirection: 'row',
  318 + // justifyContent: 'space-around',
  319 + alignItems: 'center',
  320 +
  321 + marginTop: 12,
  322 + // width: Dimensions.get('window').width - 2 * 50,
  323 + position: 'absolute',
  324 + ...Platform.select({
  325 + ios: {
  326 + top: 20,
  327 + },
  328 + android: {
  329 + top: 5,
  330 + },
  331 + }),
  332 + left: 0,
  333 + right: 0,
  334 + backgroundColor: 'transparent',
  335 + },
  336 + text: {
  337 + textAlign: 'center',
  338 + fontSize: 18,
  339 + fontWeight: 'bold',
  340 + color: '#ffffff',
  341 + },
245 }); 342 });
@@ -454,6 +454,28 @@ class NavBar extends React.Component { @@ -454,6 +454,28 @@ class NavBar extends React.Component {
454 ); 454 );
455 } 455 }
456 456
  457 + getNavBarBackgroundImage(channel) {
  458 + let img = require('../images/nav/boy/navbar_bg.png');
  459 + switch (parseInt(channel)) {
  460 + case 1:
  461 + img = require('../images/nav/boy/navbar_bg.png');
  462 + break;
  463 + case 2:
  464 + img = require('../images/nav/girl/navbar_bg.png');
  465 + break;
  466 + case 3:
  467 + img = require('../images/nav/kid/navbar_bg.png');
  468 + break;
  469 + case 4:
  470 + img = require('../images/nav/lifestyle/navbar_bg.png');
  471 + break;
  472 + case 5:
  473 + img = require('../images/nav/yoho/navbar_bg.png');
  474 + break;
  475 + }
  476 + return img;
  477 + }
  478 +
457 render() { 479 render() {
458 let state = this.props.navigationState; 480 let state = this.props.navigationState;
459 let selected = state.children[state.index]; 481 let selected = state.children[state.index];
@@ -474,6 +496,7 @@ class NavBar extends React.Component { @@ -474,6 +496,7 @@ class NavBar extends React.Component {
474 const renderTitle = selected.renderTitle || 496 const renderTitle = selected.renderTitle ||
475 selected.component.renderTitle || 497 selected.component.renderTitle ||
476 this.props.renderTitle; 498 this.props.renderTitle;
  499 +
477 return ( 500 return (
478 <Animated.View 501 <Animated.View
479 style={[ 502 style={[
@@ -484,7 +507,7 @@ class NavBar extends React.Component { @@ -484,7 +507,7 @@ class NavBar extends React.Component {
484 ]} 507 ]}
485 > 508 >
486 <Image 509 <Image
487 - source={require('../images/navbar.png')} 510 + source={this.getNavBarBackgroundImage(this.props.getChannel())}
488 style={styles.image} 511 style={styles.image}
489 > 512 >
490 {renderTitle ? renderTitle(navProps) : state.children.map(this.renderTitle, this)} 513 {renderTitle ? renderTitle(navProps) : state.children.map(this.renderTitle, this)}
@@ -8,6 +8,7 @@ import Notice from './Notice'; @@ -8,6 +8,7 @@ import Notice from './Notice';
8 import YH_SectionView from './YH_SectionView'; 8 import YH_SectionView from './YH_SectionView';
9 import ListCell from './ListCell'; 9 import ListCell from './ListCell';
10 import UploadProgress from './UploadProgress'; 10 import UploadProgress from './UploadProgress';
  11 +import LoadingIndicator from '../../../common/components/LoadingIndicator';
11 import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator'; 12 import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';
12 13
13 14
@@ -172,11 +173,10 @@ export default class Home extends React.Component { @@ -172,11 +173,10 @@ export default class Home extends React.Component {
172 /> 173 />
173 ); 174 );
174 case 'section': 175 case 'section':
175 - console.log(rowData.toJS());  
176 return ( 176 return (
177 <YH_SectionView 177 <YH_SectionView
178 style={styles.carouselSection} 178 style={styles.carouselSection}
179 - items={rowData} 179 + items={rowData.toJS()}
180 onClick={(info) => { 180 onClick={(info) => {
181 let item = rowData.get(info.index); 181 let item = rowData.get(info.index);
182 let section = { 182 let section = {
@@ -241,7 +241,7 @@ export default class Home extends React.Component { @@ -241,7 +241,7 @@ export default class Home extends React.Component {
241 } 241 }
242 242
243 render() { 243 render() {
244 - let {banner, notice, section, recommendation, isRefreshing, isLoadingMore, isFetching} = this.props; 244 + let {banner, notice, section, recommendation, isRefreshing, isLoadingMore, isFetching, isSyncFetching} = this.props;
245 let dataSource = { 245 let dataSource = {
246 progressing: this.props.progressing.toArray(), 246 progressing: this.props.progressing.toArray(),
247 banner: banner.toArray(), 247 banner: banner.toArray(),
@@ -251,30 +251,35 @@ export default class Home extends React.Component { @@ -251,30 +251,35 @@ export default class Home extends React.Component {
251 } 251 }
252 252
253 return ( 253 return (
254 - <ListView  
255 - dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)}  
256 - renderRow={this._renderRow}  
257 - renderSectionHeader={this._renderSectionHeader}  
258 - renderSeparator={this._renderSeparator}  
259 - enableEmptySections={true}  
260 - refreshControl={  
261 - <RefreshControl  
262 - refreshing={isRefreshing}  
263 - onRefresh={() => {  
264 - this.props.onRefresh && this.props.onRefresh();  
265 - }}  
266 - />  
267 - }  
268 - onEndReached={() => {  
269 - this.props.onEndReached && this.props.onEndReached();  
270 - }}  
271 - renderFooter={()=>{  
272 - return <LoadMoreIndicator  
273 - isVisible={isLoadingMore}  
274 - animating={isFetching} 254 + <View>
  255 + <ListView
  256 + dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)}
  257 + renderRow={this._renderRow}
  258 + renderSectionHeader={this._renderSectionHeader}
  259 + renderSeparator={this._renderSeparator}
  260 + enableEmptySections={true}
  261 + refreshControl={
  262 + <RefreshControl
  263 + refreshing={isRefreshing}
  264 + onRefresh={() => {
  265 + this.props.onRefresh && this.props.onRefresh();
  266 + }}
275 /> 267 />
276 - }}  
277 - /> 268 + }
  269 + onEndReached={() => {
  270 + this.props.onEndReached && this.props.onEndReached();
  271 + }}
  272 + renderFooter={()=>{
  273 + return <LoadMoreIndicator
  274 + isVisible={isLoadingMore}
  275 + animating={isFetching}
  276 + />
  277 + }}
  278 + />
  279 + <LoadingIndicator
  280 + isVisible={isSyncFetching}
  281 + />
  282 + </View>
278 ); 283 );
279 284
280 } 285 }
@@ -26,15 +26,14 @@ class SectionView extends React.Component { @@ -26,15 +26,14 @@ class SectionView extends React.Component {
26 } 26 }
27 27
28 render() { 28 render() {
29 -  
30 - return <YH_SectionView {...this.props} items={this.props.items.toJS()} onClick={this._onClick} />; 29 + return <YH_SectionView {...this.props} items={this.props.items} onClick={this._onClick} />;
31 } 30 }
32 } 31 }
33 32
34 SectionView.propTypes = { 33 SectionView.propTypes = {
35 - items: ImmutablePropTypes.listOf(  
36 - ImmutablePropTypes.contains({  
37 - header: ImmutablePropTypes.contains({ 34 + items: React.PropTypes.arrayOf(
  35 + React.PropTypes.shape({
  36 + header: React.PropTypes.shape({
38 id: React.PropTypes.number.isRequired, 37 id: React.PropTypes.number.isRequired,
39 logo: React.PropTypes.string.isRequired, 38 logo: React.PropTypes.string.isRequired,
40 title: React.PropTypes.string.isRequired, 39 title: React.PropTypes.string.isRequired,
@@ -42,15 +41,15 @@ SectionView.propTypes = { @@ -42,15 +41,15 @@ SectionView.propTypes = {
42 commentNum: React.PropTypes.number.isRequired, 41 commentNum: React.PropTypes.number.isRequired,
43 laudCount: React.PropTypes.number.isRequired, 42 laudCount: React.PropTypes.number.isRequired,
44 }), 43 }),
45 - hot: ImmutablePropTypes.contains({ 44 + hot: React.PropTypes.shape({
46 avatar: React.PropTypes.string, 45 avatar: React.PropTypes.string,
47 content: React.PropTypes.string.isRequired, 46 content: React.PropTypes.string.isRequired,
48 }), 47 }),
49 - new: ImmutablePropTypes.contains({ 48 + new: React.PropTypes.shape({
50 avatar: React.PropTypes.string, 49 avatar: React.PropTypes.string,
51 content: React.PropTypes.string.isRequired, 50 content: React.PropTypes.string.isRequired,
52 }), 51 }),
53 - num: ImmutablePropTypes.contains({ 52 + num: React.PropTypes.shape({
54 onedayAddNum: React.PropTypes.number.isRequired, 53 onedayAddNum: React.PropTypes.number.isRequired,
55 }), 54 }),
56 }) 55 })
@@ -4,6 +4,11 @@ export default keyMirror({ @@ -4,6 +4,11 @@ export default keyMirror({
4 4
5 SET_PLATFORM: null, 5 SET_PLATFORM: null,
6 SET_CONTAINER: null, 6 SET_CONTAINER: null,
  7 + SET_CHANNEL: null,
  8 +
  9 + SYNC_USER_REQUEST: null,
  10 + SYNC_USER_SUCCESS: null,
  11 + SYNC_USER_FAILURE: null,
7 12
8 GO_TO_SECTION: null, 13 GO_TO_SECTION: null,
9 14
@@ -11,6 +11,7 @@ import Immutable, {Map, List} from 'immutable'; @@ -11,6 +11,7 @@ import Immutable, {Map, List} from 'immutable';
11 import Home from '../components/home/Home'; 11 import Home from '../components/home/Home';
12 12
13 import * as homeActions from '../reducers/home/homeActions'; 13 import * as homeActions from '../reducers/home/homeActions';
  14 +import * as appActions from '../reducers/app/appActions';
14 15
15 import {Actions} from 'react-native-router-flux'; 16 import {Actions} from 'react-native-router-flux';
16 17
@@ -22,6 +23,7 @@ const { @@ -22,6 +23,7 @@ const {
22 Platform, 23 Platform,
23 NativeModules, 24 NativeModules,
24 InteractionManager, 25 InteractionManager,
  26 + NativeAppEventEmitter,
25 } = ReactNative; 27 } = ReactNative;
26 28
27 /** 29 /**
@@ -30,6 +32,7 @@ const { @@ -30,6 +32,7 @@ const {
30 */ 32 */
31 const actions = [ 33 const actions = [
32 homeActions, 34 homeActions,
  35 + appActions,
33 ]; 36 ];
34 37
35 /** 38 /**
@@ -74,16 +77,35 @@ class HomeContainer extends React.Component { @@ -74,16 +77,35 @@ class HomeContainer extends React.Component {
74 this._onRefresh = this._onRefresh.bind(this); 77 this._onRefresh = this._onRefresh.bind(this);
75 this._onEndReached = this._onEndReached.bind(this); 78 this._onEndReached = this._onEndReached.bind(this);
76 79
  80 + if (parseInt(this.props.app.container) === 1) {
  81 + this.subscription = NativeAppEventEmitter.addListener(
  82 + 'ChannelReminder',
  83 + (reminder) => {
  84 + this.props.actions.setChannel(reminder.channel);
  85 + Actions.refresh({channel: reminder.channel});
  86 + }
  87 + );
  88 + }
77 } 89 }
78 90
79 componentDidMount() { 91 componentDidMount() {
80 - let RNNativeConfig = NativeModules.RNNativeConfig;  
81 - RNNativeConfig.hideNavBar();  
82 InteractionManager.runAfterInteractions(() => { 92 InteractionManager.runAfterInteractions(() => {
83 this._onRefresh(); 93 this._onRefresh();
84 }); 94 });
85 } 95 }
86 96
  97 + componentWillReceiveProps(nextProps) {
  98 + if (nextProps.showNativeTabBar) {
  99 + ReactNative.NativeModules.YH_CommunityHelper.showTabBar();
  100 + }
  101 + }
  102 +
  103 + componentWillUnmount() {
  104 + if (parseInt(this.props.app.container) === 1) {
  105 + this.subscription && this.subscription.remove();
  106 + }
  107 + }
  108 +
87 _onPressBanner(url) { 109 _onPressBanner(url) {
88 console.log('banner'); 110 console.log('banner');
89 111
@@ -94,7 +116,7 @@ class HomeContainer extends React.Component { @@ -94,7 +116,7 @@ class HomeContainer extends React.Component {
94 } 116 }
95 117
96 _onPressSection(section) { 118 _onPressSection(section) {
97 - this.props.actions.goToSection(section); 119 + this.props.actions.goToSection(section, this.props.navigationState.name);
98 } 120 }
99 121
100 _onPressPost(url) { 122 _onPressPost(url) {
@@ -155,10 +177,9 @@ class HomeContainer extends React.Component { @@ -155,10 +177,9 @@ class HomeContainer extends React.Component {
155 image:'', 177 image:'',
156 }]; 178 }];
157 179
158 -  
159 progressing = Immutable.fromJS(progressing); 180 progressing = Immutable.fromJS(progressing);
160 181
161 - let {banner, notice, section, recommendation, isFetching, ptr} = this.props.home; 182 + let {banner, notice, section, recommendation, isFetching, ptr, sync} = this.props.home;
162 let bannerData = Immutable.fromJS([banner.list]); 183 let bannerData = Immutable.fromJS([banner.list]);
163 let noticeData = notice.open === 'Y' ? Immutable.fromJS([notice.list]) : List(); 184 let noticeData = notice.open === 'Y' ? Immutable.fromJS([notice.list]) : List();
164 let sectionData = Immutable.fromJS([section]); 185 let sectionData = Immutable.fromJS([section]);
@@ -196,6 +217,8 @@ class HomeContainer extends React.Component { @@ -196,6 +217,8 @@ class HomeContainer extends React.Component {
196 onUploadSuccess={this._onUploadSuccess} 217 onUploadSuccess={this._onUploadSuccess}
197 onUploadRetry={this._onUploadRetry} 218 onUploadRetry={this._onUploadRetry}
198 onUploadDelete={this._onUploadDelete} 219 onUploadDelete={this._onUploadDelete}
  220 + isSyncFetching={sync.isFetching}
  221 +
199 /> 222 />
200 </View> 223 </View>
201 ); 224 );
@@ -73,17 +73,23 @@ class SectionContainer extends React.Component { @@ -73,17 +73,23 @@ class SectionContainer extends React.Component {
73 this._onPressLike = this._onPressLike.bind(this); 73 this._onPressLike = this._onPressLike.bind(this);
74 this._onRefresh = this._onRefresh.bind(this); 74 this._onRefresh = this._onRefresh.bind(this);
75 this._onEndReached = this._onEndReached.bind(this); 75 this._onEndReached = this._onEndReached.bind(this);
76 -  
77 - this.page = 0;  
78 } 76 }
79 77
80 componentDidMount() { 78 componentDidMount() {
  79 + if (this.props.section.previousScene === 'Home') {
  80 + ReactNative.NativeModules.YH_CommunityHelper.hideTabBar();
  81 + }
  82 +
81 InteractionManager.runAfterInteractions(() => { 83 InteractionManager.runAfterInteractions(() => {
82 this._onRefresh(); 84 this._onRefresh();
83 }); 85 });
84 } 86 }
85 87
86 componentWillUnmount() { 88 componentWillUnmount() {
  89 + if (this.props.section.previousScene === 'Home') {
  90 + Actions.refresh({key: 'Home', showNativeTabBar: true});
  91 + }
  92 +
87 this.props.actions.sectionClean(); 93 this.props.actions.sectionClean();
88 } 94 }
89 95
@@ -189,7 +195,7 @@ let navbarHeight = (Platform.OS === 'android') ? 50 : 64; @@ -189,7 +195,7 @@ let navbarHeight = (Platform.OS === 'android') ? 50 : 64;
189 let styles = StyleSheet.create({ 195 let styles = StyleSheet.create({
190 container: { 196 container: {
191 top: navbarHeight, 197 top: navbarHeight,
192 - height: height - navbarHeight - 49, 198 + height: height - navbarHeight,
193 flex: 1, 199 flex: 1,
194 }, 200 },
195 201
@@ -11,7 +11,7 @@ import {Actions} from 'react-native-router-flux'; @@ -11,7 +11,7 @@ import {Actions} from 'react-native-router-flux';
11 const { 11 const {
12 SET_PLATFORM, 12 SET_PLATFORM,
13 SET_CONTAINER, 13 SET_CONTAINER,
14 - 14 + SET_CHANNEL,
15 } = require('../../constants/actionTypes').default; 15 } = require('../../constants/actionTypes').default;
16 16
17 export function setPlatform(platform) { 17 export function setPlatform(platform) {
@@ -27,3 +27,10 @@ export function setContianer(container) { @@ -27,3 +27,10 @@ export function setContianer(container) {
27 payload: container 27 payload: container
28 }; 28 };
29 } 29 }
  30 +
  31 +export function setChannel(channel) {
  32 + return {
  33 + type: SET_CHANNEL,
  34 + payload: channel
  35 + };
  36 +}
@@ -16,7 +16,8 @@ import {Record, List, Map} from 'immutable'; @@ -16,7 +16,8 @@ import {Record, List, Map} from 'immutable';
16 */ 16 */
17 let InitialState = Record({ 17 let InitialState = Record({
18 platform: 'ios', // ios, android 18 platform: 'ios', // ios, android
19 - container: 1, // 1:有货APP,2:YOHO! 19 + container: 1, // 1:有货APP, 2:YOHO!
  20 + channel: 1, // 1 - boy, 2 - girl, 3 - kid, 4 - lifestyle, 5 - yoho
20 }); 21 });
21 22
22 export default InitialState; 23 export default InitialState;
@@ -14,7 +14,7 @@ import InitialState from './appInitialState'; @@ -14,7 +14,7 @@ import InitialState from './appInitialState';
14 const { 14 const {
15 SET_PLATFORM, 15 SET_PLATFORM,
16 SET_CONTAINER, 16 SET_CONTAINER,
17 - 17 + SET_CHANNEL,
18 } = require('../../constants/actionTypes').default; 18 } = require('../../constants/actionTypes').default;
19 19
20 const initialState = new InitialState; 20 const initialState = new InitialState;
@@ -32,6 +32,8 @@ export default function appReducer(state = initialState, action) { @@ -32,6 +32,8 @@ export default function appReducer(state = initialState, action) {
32 return state.set('platform', action.payload); 32 return state.set('platform', action.payload);
33 case SET_CONTAINER: 33 case SET_CONTAINER:
34 return state.set('container', action.payload); 34 return state.set('container', action.payload);
  35 + case SET_CHANNEL:
  36 + return state.set('channel', action.payload);
35 } 37 }
36 38
37 return state; 39 return state;
@@ -21,9 +21,46 @@ const { @@ -21,9 +21,46 @@ const {
21 HOME_RECOMMENDATION_FAILURE, 21 HOME_RECOMMENDATION_FAILURE,
22 22
23 GO_TO_SECTION, 23 GO_TO_SECTION,
  24 + SYNC_USER_REQUEST,
  25 + SYNC_USER_SUCCESS,
  26 + SYNC_USER_FAILURE,
24 27
25 } = require('../../constants/actionTypes').default; 28 } = require('../../constants/actionTypes').default;
26 29
  30 +export function syncUserRequest() {
  31 + return {
  32 + type: SYNC_USER_REQUEST,
  33 + };
  34 +}
  35 +
  36 +export function syncUserSuccess(json) {
  37 + return {
  38 + type: SYNC_USER_SUCCESS,
  39 + payload: json
  40 + };
  41 +}
  42 +
  43 +export function syncUserFailure(error) {
  44 + return {
  45 + type: SYNC_USER_FAILURE,
  46 + payload: error
  47 + };
  48 +}
  49 +
  50 +export function syncUser(uid) {
  51 + return (dispatch, getState) => {
  52 + dispatch(syncUserRequest());
  53 + let {app} = getState();
  54 + return new HomeService().syncUser(uid, app.container)
  55 + .then(json => {
  56 + dispatch(syncUserSuccess(json.ssouid));
  57 + })
  58 + .catch(error => {
  59 + dispatch(syncUserFailure(error));
  60 + });
  61 + };
  62 +}
  63 +
27 export function bnsRequest() { 64 export function bnsRequest() {
28 return { 65 return {
29 type: HOME_BNS_REQUEST, 66 type: HOME_BNS_REQUEST,
@@ -83,7 +120,7 @@ export function bannerNoticeSection() { @@ -83,7 +120,7 @@ export function bannerNoticeSection() {
83 export function recommendation(ptr = false) { 120 export function recommendation(ptr = false) {
84 return (dispatch, getState) => { 121 return (dispatch, getState) => {
85 let {home} = getState(); 122 let {home} = getState();
86 - if (home.isFetching) { 123 + if (home.isFetching || home.recommendation.endReached) {
87 return; 124 return;
88 } 125 }
89 dispatch(recommendationRequest(ptr)); 126 dispatch(recommendationRequest(ptr));
@@ -110,11 +147,11 @@ export function recommendation(ptr = false) { @@ -110,11 +147,11 @@ export function recommendation(ptr = false) {
110 }; 147 };
111 } 148 }
112 149
113 -export function goToSection(section) { 150 +export function goToSection(section, previousScene) {
114 Actions.Section(); 151 Actions.Section();
115 return { 152 return {
116 type: GO_TO_SECTION, 153 type: GO_TO_SECTION,
117 - payload: section, 154 + payload: {...section, previousScene},
118 }; 155 };
119 } 156 }
120 157
@@ -223,8 +260,10 @@ function parseRecommendation(json) { @@ -223,8 +260,10 @@ function parseRecommendation(json) {
223 posts.push(post); 260 posts.push(post);
224 }); 261 });
225 262
  263 + let endReached = posts.length == 0;
226 return { 264 return {
227 lastedTime, 265 lastedTime,
228 list: posts, 266 list: posts,
  267 + endReached,
229 } 268 }
230 } 269 }
@@ -31,6 +31,12 @@ let InitialState = Record({ @@ -31,6 +31,12 @@ let InitialState = Record({
31 recommendation: new (Record({ 31 recommendation: new (Record({
32 lastedTime: 0, 32 lastedTime: 0,
33 list: List(), 33 list: List(),
  34 + endReached: false,
  35 + })),
  36 + sync: new (Record({
  37 + isFetching: false,
  38 + error: null,
  39 + ssouid: 0,
34 })), 40 })),
35 }); 41 });
36 42
@@ -22,6 +22,9 @@ const { @@ -22,6 +22,9 @@ const {
22 HOME_RECOMMENDATION_SUCCESS, 22 HOME_RECOMMENDATION_SUCCESS,
23 HOME_RECOMMENDATION_FAILURE, 23 HOME_RECOMMENDATION_FAILURE,
24 24
  25 + SYNC_USER_REQUEST,
  26 + SYNC_USER_SUCCESS,
  27 + SYNC_USER_FAILURE,
25 28
26 } = require('../../constants/actionTypes').default; 29 } = require('../../constants/actionTypes').default;
27 30
@@ -55,10 +58,11 @@ export default function homeReducer(state = initialState, action) { @@ -55,10 +58,11 @@ export default function homeReducer(state = initialState, action) {
55 return nextState; 58 return nextState;
56 } 59 }
57 case HOME_RECOMMENDATION_SUCCESS: { 60 case HOME_RECOMMENDATION_SUCCESS: {
58 - let {lastedTime, list} = action.payload; 61 + let {lastedTime, list, endReached} = action.payload;
59 let nextState = state.set('isFetching', false) 62 let nextState = state.set('isFetching', false)
60 .set('error', null) 63 .set('error', null)
61 .setIn(['recommendation', 'lastedTime'], lastedTime) 64 .setIn(['recommendation', 'lastedTime'], lastedTime)
  65 + .setIn(['recommendation', 'endReached'], endReached)
62 .setIn(['recommendation', 'list'], Immutable.fromJS(list)); 66 .setIn(['recommendation', 'list'], Immutable.fromJS(list));
63 return nextState; 67 return nextState;
64 } 68 }
@@ -67,6 +71,23 @@ export default function homeReducer(state = initialState, action) { @@ -67,6 +71,23 @@ export default function homeReducer(state = initialState, action) {
67 return state.set('isFetching', false) 71 return state.set('isFetching', false)
68 .set('error', action.payload); 72 .set('error', action.payload);
69 73
  74 + case SYNC_USER_REQUEST: {
  75 + let nextState = state.setIn(['sync', 'isFetching'], true)
  76 + .setIn(['sync', 'error'], null);
  77 + return nextState;
  78 + }
  79 +
  80 + case SYNC_USER_SUCCESS: {
  81 + let nextState = state.setIn(['sync', 'isFetching'], false)
  82 + .setIn(['sync', 'error'], null)
  83 + .setIn(['sync', 'ssouid'], action.payload);
  84 + return nextState;
  85 + }
  86 +
  87 + case SYNC_USER_FAILURE:
  88 + return state.setIn(['sync', 'isFetching'], false)
  89 + .setIn(['sync', 'error'], action.payload);
  90 +
70 } 91 }
71 92
72 return state; 93 return state;
@@ -105,7 +105,7 @@ export function header() { @@ -105,7 +105,7 @@ export function header() {
105 export function newPost(ptr = false) { 105 export function newPost(ptr = false) {
106 return (dispatch, getState) => { 106 return (dispatch, getState) => {
107 let {section} = getState(); 107 let {section} = getState();
108 - if (section.new.isFetching) { 108 + if (section.new.isFetching || section.new.endReached) {
109 return; 109 return;
110 } 110 }
111 dispatch(newPostRequest(ptr)); 111 dispatch(newPostRequest(ptr));
@@ -135,7 +135,7 @@ export function newPost(ptr = false) { @@ -135,7 +135,7 @@ export function newPost(ptr = false) {
135 export function hotPost(ptr = false) { 135 export function hotPost(ptr = false) {
136 return (dispatch, getState) => { 136 return (dispatch, getState) => {
137 let {section} = getState(); 137 let {section} = getState();
138 - if (section.hot.isFetching) { 138 + if (section.hot.isFetching || section.hot.endReached) {
139 return; 139 return;
140 } 140 }
141 dispatch(hotPostRequest(ptr)); 141 dispatch(hotPostRequest(ptr));
@@ -252,8 +252,11 @@ function parseNewPost(json) { @@ -252,8 +252,11 @@ function parseNewPost(json) {
252 posts.push(post); 252 posts.push(post);
253 }); 253 });
254 254
  255 + let endReached = posts.length == 0;
  256 +
255 return { 257 return {
256 lastedTime, 258 lastedTime,
257 list: posts, 259 list: posts,
  260 + endReached,
258 } 261 }
259 } 262 }
@@ -38,13 +38,16 @@ let InitialState = Record({ @@ -38,13 +38,16 @@ let InitialState = Record({
38 error: null, 38 error: null,
39 lastedTime: 0, 39 lastedTime: 0,
40 list: List(), 40 list: List(),
  41 + endReached: false,
41 })), 42 })),
42 new: new (Record({ 43 new: new (Record({
43 isFetching: false, 44 isFetching: false,
44 error: null, 45 error: null,
45 lastedTime: 0, 46 lastedTime: 0,
46 list: List(), 47 list: List(),
  48 + endReached: false,
47 })), 49 })),
  50 + previousScene: '',
48 }); 51 });
49 52
50 export default InitialState; 53 export default InitialState;
@@ -70,19 +70,21 @@ export default function sectionReducer(state = initialState, action) { @@ -70,19 +70,21 @@ export default function sectionReducer(state = initialState, action) {
70 } 70 }
71 71
72 case SECTION_HOT_POST_SUCCESS: { 72 case SECTION_HOT_POST_SUCCESS: {
73 - let {lastedTime, list} = action.payload; 73 + let {lastedTime, list, endReached} = action.payload;
74 let nextState = state.setIn(['hot', 'isFetching'], false) 74 let nextState = state.setIn(['hot', 'isFetching'], false)
75 .setIn(['hot', 'error'], null) 75 .setIn(['hot', 'error'], null)
76 .setIn(['hot', 'lastedTime'], lastedTime) 76 .setIn(['hot', 'lastedTime'], lastedTime)
  77 + .setIn(['hot', 'endReached'], endReached)
77 .setIn(['hot', 'list'], Immutable.fromJS(list)); 78 .setIn(['hot', 'list'], Immutable.fromJS(list));
78 return nextState; 79 return nextState;
79 } 80 }
80 81
81 case SECTION_NEW_POST_SUCCESS: { 82 case SECTION_NEW_POST_SUCCESS: {
82 - let {lastedTime, list} = action.payload; 83 + let {lastedTime, list, endReached} = action.payload;
83 let nextState = state.setIn(['new', 'isFetching'], false) 84 let nextState = state.setIn(['new', 'isFetching'], false)
84 .setIn(['new', 'error'], null) 85 .setIn(['new', 'error'], null)
85 .setIn(['new', 'lastedTime'], lastedTime) 86 .setIn(['new', 'lastedTime'], lastedTime)
  87 + .setIn(['new', 'endReached'], endReached)
86 .setIn(['new', 'list'], Immutable.fromJS(list)); 88 .setIn(['new', 'list'], Immutable.fromJS(list));
87 return nextState; 89 return nextState;
88 } 90 }
@@ -104,7 +106,8 @@ export default function sectionReducer(state = initialState, action) { @@ -104,7 +106,8 @@ export default function sectionReducer(state = initialState, action) {
104 106
105 case GO_TO_SECTION: 107 case GO_TO_SECTION:
106 return state.set('id', action.payload.id) 108 return state.set('id', action.payload.id)
107 - .set('name', action.payload.name); 109 + .set('name', action.payload.name)
  110 + .set('previousScene', action.payload.previousScene);
108 111
109 case SECTION_CLEAN: 112 case SECTION_CLEAN:
110 return initialState; 113 return initialState;
@@ -42,5 +42,21 @@ export default class HomeService { @@ -42,5 +42,21 @@ export default class HomeService {
42 }); 42 });
43 } 43 }
44 44
  45 + async syncUser(uid, appChannel) {
  46 + return await this.api.get({
  47 + url: '',
  48 + body: {
  49 + method: 'app.social.synCommunityUser',
  50 + uid,
  51 + appChannel,
  52 + }
  53 + })
  54 + .then((json) => {
  55 + return json;
  56 + })
  57 + .catch((error) => {
  58 + throw(error);
  59 + });
  60 + }
45 61
46 } 62 }