Authored by 于良

潮流优选 优化 review by 草莓

... ... @@ -33,7 +33,7 @@ export default class LoadingIndicator extends Component {
color: (Platform.OS === 'ios') ? 'white' : 'gray',
text: '加载中...',
textColor: '#eeeeee',
textFontSize: 14,
textFontSize: 12,
};
render() {
... ...
... ... @@ -8,7 +8,7 @@ const {
const Button = (props) => {
return <TouchableNativeFeedback
delayPressIn={0}
background={TouchableNativeFeedback.SelectableBackground()}
background={TouchableNativeFeedback.SelectableBackground()} // eslint-disable-line new-cap
{...props}
>
{props.children}
... ...
... ... @@ -20,6 +20,7 @@ const DefaultTabBar = React.createClass({
inactiveTextColor: React.PropTypes.string,
textStyle: Text.propTypes.style,
tabStyle: View.propTypes.style,
renderTabName: React.PropTypes.func,
},
getDefaultProps() {
... ... @@ -29,29 +30,35 @@ const DefaultTabBar = React.createClass({
underlineColor: 'navy',
backgroundColor: null,
underlineHeight: 4,
renderTabName: this.renderTabName,
};
},
renderTabOption(name, page) {
const isTabActive = this.props.activeTab === page;
const { activeTextColor, inactiveTextColor, textStyle, } = this.props;
const textColor = isTabActive ? activeTextColor : inactiveTextColor;
const fontWeight = isTabActive ? 'bold' : 'normal';
return <Button
style={{flex: 1}}
style={{flex: 1, }}
key={name}
accessible={true}
accessibilityLabel={name}
accessibilityTraits='button'
onPress={() => this.props.goToPage(page)}
>
<View style={[styles.tab, this.props.tabStyle]}>
{this.renderTabName(name, page, isTabActive)}
</Button>;
},
renderTabName(name, page, isTabActive) {
const { activeTextColor, inactiveTextColor, textStyle, } = this.props;
const textColor = isTabActive ? activeTextColor : inactiveTextColor;
const fontWeight = isTabActive ? 'bold' : 'normal';
return <View style={[styles.tab, this.props.tabStyle, ]}>
<Text style={[{color: textColor, fontWeight, }, textStyle, ]}>
{name}
</Text>
</View>
</Button>;
</View>;
},
render() {
... ...
... ... @@ -28,6 +28,7 @@ const ScrollableTabBar = React.createClass({
tabStyle: View.propTypes.style,
tabsContainerStyle: View.propTypes.style,
textStyle: Text.propTypes.style,
renderTabName: React.PropTypes.func,
},
getDefaultProps() {
... ... @@ -41,6 +42,7 @@ const ScrollableTabBar = React.createClass({
style: {},
tabStyle: {},
tabsContainerStyle: {},
renderTabName: this.renderTabName,
};
},
... ... @@ -90,7 +92,7 @@ const ScrollableTabBar = React.createClass({
let newScrollX = tabOffset + absolutePageOffset;
// center tab and smooth tab change (for when tabWidth changes a lot between two tabs)
newScrollX -= (containerWidth - (1 - pageOffset) * tabWidth - pageOffset * nextTabWidth ) / 2 ;
newScrollX -= (containerWidth - (1 - pageOffset) * tabWidth - pageOffset * nextTabWidth) / 2;
newScrollX = newScrollX >= 0 ? newScrollX : 0;
if (Platform.OS === 'android') {
... ... @@ -124,9 +126,6 @@ const ScrollableTabBar = React.createClass({
renderTabOption(name, page) {
const isTabActive = this.props.activeTab === page;
const { activeTextColor, inactiveTextColor, textStyle, } = this.props;
const textColor = isTabActive ? activeTextColor : inactiveTextColor;
const fontWeight = isTabActive ? 'bold' : 'normal';
return <Button
key={`${name}_${page}`}
... ... @@ -136,12 +135,20 @@ const ScrollableTabBar = React.createClass({
onPress={() => this.props.goToPage(page)}
onLayout={this.measureTab.bind(this, page)}
>
<View style={[styles.tab, this.props.tabStyle]}>
{this.renderTabName(name, page, isTabActive)}
</Button>;
},
renderTabName(name, page, isTabActive) {
const { activeTextColor, inactiveTextColor, textStyle, } = this.props;
const textColor = isTabActive ? activeTextColor : inactiveTextColor;
const fontWeight = isTabActive ? 'bold' : 'normal';
return <View style={[styles.tab, this.props.tabStyle, ]}>
<Text style={[{color: textColor, fontWeight, }, textStyle, ]}>
{name}
</Text>
</View>
</Button>;
</View>;
},
measureTab(page, event) {
... ... @@ -164,7 +171,7 @@ const ScrollableTabBar = React.createClass({
};
return <View
style={[styles.container, {backgroundColor: this.props.backgroundColor, }, this.props.style]}
style={[styles.container, {backgroundColor: this.props.backgroundColor, }, this.props.style, ]}
onLayout={this.onContainerLayout}
>
<ScrollView
... ... @@ -174,9 +181,10 @@ const ScrollableTabBar = React.createClass({
showsVerticalScrollIndicator={false}
directionalLockEnabled={true}
bounces={false}
scrollsToTop={false}
>
<View
style={[styles.tabs, {width: this.state._containerWidth, }, this.props.tabsContainerStyle]}
style={[styles.tabs, {width: this.state._containerWidth, }, this.props.tabsContainerStyle, ]}
ref={'tabContainer'}
onLayout={this.onTabContainerLayout}
>
... ...
... ... @@ -39,7 +39,7 @@ const ScrollableTabView = React.createClass({
contentProps: PropTypes.object,
scrollWithoutAnimation: PropTypes.bool,
locked: PropTypes.bool,
prerenderingSiblingsNumber: PropTypes.number
prerenderingSiblingsNumber: PropTypes.number,
},
getDefaultProps() {
... ... @@ -52,7 +52,7 @@ const ScrollableTabView = React.createClass({
contentProps: {},
scrollWithoutAnimation: false,
locked: false,
prerenderingSiblingsNumber: 0
prerenderingSiblingsNumber: 0,
};
},
... ... @@ -67,13 +67,13 @@ const ScrollableTabView = React.createClass({
},
componentWillReceiveProps(props) {
if (props.page >= 0 && props.page !== this.state.currentPage) {
this.goToPage(props.page);
}
if (props.children !== this.props.children) {
this.updateSceneKeys({ page: this.state.currentPage, children: props.children, });
}
if (props.page >= 0 && props.page !== this.state.currentPage) {
this.goToPage(props.page);
}
},
goToPage(pageNumber) {
... ... @@ -167,20 +167,8 @@ const ScrollableTabView = React.createClass({
const offsetX = e.nativeEvent.contentOffset.x;
this._updateScrollValue(offsetX / this.state.containerWidth);
}}
onMomentumScrollBegin={(e) => {
const offsetX = e.nativeEvent.contentOffset.x;
const page = Math.round(offsetX / this.state.containerWidth);
if (this.state.currentPage !== page) {
this._updateSelectedPage(page);
}
}}
onMomentumScrollEnd={(e) => {
const offsetX = e.nativeEvent.contentOffset.x;
const page = Math.round(offsetX / this.state.containerWidth);
if (this.state.currentPage !== page) {
this._updateSelectedPage(page);
}
}}
onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}
onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}
scrollEventThrottle={16}
scrollsToTop={false}
showsHorizontalScrollIndicator={false}
... ... @@ -226,6 +214,14 @@ const ScrollableTabView = React.createClass({
});
},
_onMomentumScrollBeginAndEnd(e) {
const offsetX = e.nativeEvent.contentOffset.x;
const page = Math.round(offsetX / this.state.containerWidth);
if (this.state.currentPage !== page) {
this._updateSelectedPage(page);
}
},
_updateSelectedPage(nextPage) {
let localNextPage = nextPage;
if (typeof localNextPage === 'object') {
... ... @@ -245,7 +241,6 @@ const ScrollableTabView = React.createClass({
ref: this._children()[currentPage],
from: prevPage,
});
},
_updateScrollValue(value) {
... ...
{
"_args": [
[
"react-native-scrollable-tab-view@0.5.3",
"/Users/yl3016/Desktop/workspace/YH_RNComponent"
]
],
"_cnpm_publish_time": 1468347268973,
"_from": "react-native-scrollable-tab-view@0.5.3",
"_id": "react-native-scrollable-tab-view@0.5.3",
"_inCache": true,
"_installable": true,
"_location": "/react-native-scrollable-tab-view",
"_nodeVersion": "4.1.1",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/react-native-scrollable-tab-view-0.5.3.tgz_1468347266619_0.6885842669289559"
},
"_npmUser": {
"email": "skv-headless@yandex.ru",
"name": "headless"
},
"_npmVersion": "2.14.4",
"_phantomChildren": {},
"_requested": {
"name": "react-native-scrollable-tab-view",
"raw": "react-native-scrollable-tab-view@0.5.3",
"rawSpec": "0.5.3",
"scope": null,
"spec": "0.5.3",
"type": "version"
},
"_requiredBy": [
"/"
],
"_resolved": "http://registry.cnpmjs.org/react-native-scrollable-tab-view/download/react-native-scrollable-tab-view-0.5.3.tgz",
"_shasum": "fe8c905eacbe28e7ef91ab89925891db6e125c39",
"_shrinkwrap": null,
"_spec": "react-native-scrollable-tab-view@0.5.3",
"_where": "/Users/yl3016/Desktop/workspace/YH_RNComponent",
"author": {
"name": "Brent Vatne"
},
"bugs": {
"url": "https://github.com/brentvatne/react-native-scrollable-tab-view/issues"
},
"dependencies": {
"react-static-container": "^1.0.1",
"react-timer-mixin": "^0.13.3"
"version": "0.5.5",
"description": "",
"main": "index.js",
"scripts": {
"lint": "eslint -c .eslintrc .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"description": "[![npm version](https://badge.fury.io/js/react-native-scrollable-tab-view.svg)](https://badge.fury.io/js/react-native-scrollable-tab-view)",
"devDependencies": {},
"directories": {},
"dist": {
"noattachment": false,
"shasum": "fe8c905eacbe28e7ef91ab89925891db6e125c39",
"size": 9131,
"tarball": "http://registry.cnpmjs.org/react-native-scrollable-tab-view/download/react-native-scrollable-tab-view-0.5.3.tgz"
"repository": {
"type": "git",
"url": "git+https://github.com/brentvatne/react-native-scrollable-tab-view.git"
},
"gitHead": "a66720150307c4f1352a215151aadcdd28e25b37",
"homepage": "https://github.com/brentvatne/react-native-scrollable-tab-view#readme",
"keywords": [
"react-native-component",
"react-component",
... ... @@ -67,31 +19,21 @@
"tab",
"scrollable"
],
"author": "Brent Vatne",
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"email": "brentvatne@gmail.com",
"name": "brentvatne"
"bugs": {
"url": "https://github.com/brentvatne/react-native-scrollable-tab-view/issues"
},
{
"email": "skv-headless@yandex.ru",
"name": "headless"
}
],
"name": "react-native-scrollable-tab-view",
"optionalDependencies": {},
"peerDependencies": {
"react-native": ">=0.20.0"
},
"publish_time": 1468347268973,
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/brentvatne/react-native-scrollable-tab-view.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"homepage": "https://github.com/brentvatne/react-native-scrollable-tab-view#readme",
"dependencies": {
"react-static-container": "^1.0.1",
"react-timer-mixin": "^0.13.3"
},
"version": "0.5.3"
"devDependencies": {
"babel-eslint": "^6.1.2",
"eslint": "^3.1.1"
}
}
... ...
... ... @@ -14,15 +14,15 @@ export default class Request {
constructor(baseURL) {
if (baseURL) {
this.baseUrl= baseURL;
this.timeout = 30000;
} else {
this.config = process.env.NODE_ENV === `development` ? CONFIG.dev : CONFIG.prd;
this.baseUrl= this.config.baseUrl;
this.timeout = this.config.HTTPTimeout;
}
this.privateKey = RNNativeConfig.getPrivateKey();
this.timeout = this.config.HTTPTimeout;
}
... ...
... ... @@ -29,6 +29,7 @@ import {
import {
setSegment,
setGender,
} from './reducers/plustar/plustarActions';
function getInitialState() {
... ... @@ -77,8 +78,13 @@ export default function native(platform) {
render() {
const store = configureStore(getInitialState());
store.dispatch(setPlatform(platform));
let segment = getInitSegment(this.props.segmentType);
let segment = getInitSegment(this.props.initType);
store.dispatch(setSegment(segment));
if (this.props.initType == 0) {
let gender = this.props.genderType;
store.dispatch(setGender(gender));
}
return (
<Provider store={store}>
... ...
import React from 'react-native';
import { Provider } from 'react-redux/native';
import configureStore from '../store/configureStore';
import PlustarContainer from '../containers/PlustarContainer';
class PlustarComponent extends React.Component {
constructor(props) {
super(props);
let leftSegment, rightSegment;
if(this.props.initType == 1) {
//潮流优选
leftSegment = {
title:'设计新潮',
type:4
};
rightSegment = {
title:'潮流经典',
type:1
};
} else if(this.props.initType == 2) {
//明星原创
leftSegment = {
title:'明星潮品',
type:2
};
rightSegment = {
title:'原创潮牌',
type:3
};
}
let initialState = {
plustar: {
payload: {
left: {
segment: leftSegment,
},
right: {
segment: rightSegment,
},
selectedIndex: 0,
genderType: this.props.genderType,
}
},
};
this.store = configureStore(initialState);
}
render () {
return (
<Provider store={this.store}>
{() => <PlustarContainer />}
</Provider>
);
}
}
export default PlustarComponent;
 
\ No newline at end of file
'use strict';
import React from 'react';
import ReactNative from 'react-native';
import Swiper from 'react-native-swiper';
import ImmutablePropTypes from 'react-immutable-proptypes';
import SlicedImage from '../../../common/components/SlicedImage';
const {
View,
Image,
TouchableOpacity,
StyleSheet,
Dimensions,
} = ReactNative;
export default class Banner extends React.Component {
static propTypes = {
data: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
src: React.PropTypes.string.isRequired,
url: React.PropTypes.string.isRequired,
})
),
duration: React.PropTypes.number,
width: React.PropTypes.number.isRequired,
height: React.PropTypes.number.isRequired,
onPress: React.PropTypes.func,
};
constructor(props) {
super (props);
this.dot = <View
style={{
backgroundColor:'rgba(0,0,0,.2)',
width: 6,
height: 6,
borderRadius: 3,
marginLeft: 3,
marginRight: 3,
marginTop: 3,
marginBottom: 3,
}}
/>;
this.activeDot = <View
style={{
backgroundColor:'white',
width: 6,
height: 6,
borderRadius: 3,
marginLeft: 3,
marginRight: 3,
marginTop: 3,
marginBottom: 3,
}}
/>;
}
render() {
let width = this.props.width;
let height = this.props.height;
let data = this.props.data.toArray();
return (
<Swiper
style={styles.banner}
showsButtons={false}
loop={true}
autoplay={false}
autoplayTimeout={this.props.duration}
paginationStyle={{bottom: 8}}
dot={this.dot}
activeDot={this.activeDot}
height={height}
>
{data.map((item, i) => {
return (
<TouchableOpacity
key={i}
activeOpacity={1}
onPress={() => {
this.props.onPress && this.props.onPress(item.get('url'));
}}
>
<SlicedImage source={{uri: item.get('src')}} style={{width, height}}/>
</TouchableOpacity>
);
})}
</Swiper>
);
}
}
let styles = StyleSheet.create({
banner: {
},
});
... ...
... ... @@ -14,101 +14,66 @@ import ReactNative, {
} from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import PlustarGenderSelector from './PlustarGenderSelector';
import PlustarSegment from './PlustarSegment';
import PlustarList from './PlustarList';
import {swithSegment, switchGender, fetchPlustarIfNeeded, plustarRouter, popViewController} from '../../reducers/plustar/plustarActions';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
export default class Plustar extends Component {
constructor(props) {
super(props);
this._onPressSegment = this._onPressSegment.bind(this);
this._onChangeTab = this._onChangeTab.bind(this);
this._onScroll = this._onScroll.bind(this);
this._onPressRow = this._onPressRow.bind(this);
this.subscription = null;
}
componentWillMount() {
this.subscription = NativeAppEventEmitter.addListener(
"onChangeGender",
(reminder) => {
this.props.dispatch(switchGender(reminder.genderType));
}
);
}
componentDidMount() {
this.props.dispatch(fetchPlustarIfNeeded(0));
this.props.dispatch(fetchPlustarIfNeeded(1));
}
componentWillUnmount() {
this.subscription.remove();
_onPressRow(url) {
this.props.onPressRow && this.props.onPressRow(url);
}
render() {
let {left, right, selectedIndex} = this.props;
let segment = [left.segment, right.segment];
let {segment, activeTab, left, right, isCurrentTabFetching} = this.props;
return (
<View style={styles.container}>
<PlustarSegment
content={segment}
selectedIndex={selectedIndex}
onPressSegment={this._onPressSegment} />
selectedIndex={activeTab}
onPressSegment={(index) => {
this._scrollView.goToPage(index);
this.props.onChangeTab && this.props.onChangeTab(index);
}}
/>
<ScrollableTabView
ref={(c) => {this._scrollView = c}}
renderTabBar={false}
onChangeTab={this._onChangeTab}
onScroll={this._onScroll} >
onChangeTab={(tab) => {
this.props.onChangeTab && this.props.onChangeTab(tab.i);
}}
>
<PlustarList
dataSource={left.data}
list={left.list}
head={left.head}
foot={left.foot}
onPressRow={this._onPressRow} />
onPressRow={this._onPressRow}
/>
<PlustarList
dataSource={right.data}
list={right.list}
head={right.head}
foot={right.foot}
onPressRow={this._onPressRow} />
onPressRow={this._onPressRow}
/>
</ScrollableTabView>
{/*<PlustarGenderSelector visible={true} />*/}
<LoadingIndicator
isVisible={isCurrentTabFetching}
/>
</View>
);
}
_onPressSegment(index) {
this._scrollView.goToPage(index);
}
_onChangeTab(tab, ref) {
if (this.props.selectedIndex != tab.i) {
this.props.dispatch(swithSegment(tab.i));
this.props.dispatch(fetchPlustarIfNeeded(tab.i));
}
}
_onScroll(value) {
if(value < -0.12) {
this.props.dispatch(popViewController())
}
}
_onPressRow(url) {
this.props.dispatch(plustarRouter(url))
}
}
let styles = StyleSheet.create({
... ... @@ -116,9 +81,4 @@ let styles = StyleSheet.create({
flex: 1,
backgroundColor: '#f0f0f0',
},
centering: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
... ...
/*
* 潮流优选性别选择框
*/
'use strict'
import React, {Component} from 'react';
import {
View,
Text,
Image,
ListView,
Modal,
TouchableWithoutFeedback,
StyleSheet,
Dimensions,
Animated
} from 'react-native';
import uiUtil from '../../utils/UIUtil';
import Button from '../common/Button';
export default class PlustarGenderSelector extends Component {
constructor(props) {
super(props);
this._setModalVisible = this._setModalVisible.bind(this);
this._renderRow = this._renderRow.bind(this);
this._selectGender = this._selectGender.bind(this);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
const data = [{id:0, name:"All"}, {id:1, name:"Boy"}, {id:2, name:"Girl"}];
this.dataSource = ds.cloneWithRows(data);
this.state = {
visible: this.props.visible
};
}
render() {
return (
<Modal visible={this.state.visible} transparent={false}>
<TouchableWithoutFeedback onPress={()=>{this._setModalVisible()}} >
<View style={styles.container} >
<Image style={styles.listContainer} source={{uri:"tc", isStatic:true}} >
<ListView
dataSource={this.dataSource}
renderRow={this._renderRow}
/>
</Image>
</View>
</TouchableWithoutFeedback>
</Modal>
);
}
_renderRow(rowData: object, sectionID: number, rowID: number) {
return (
<TouchableWithoutFeedback onPress={this._selectGender(rowData.id)} >
<View style={styles.rowContainer}>
<Text style={styles.title} numberOfLines={1} >
{rowData.name}
</Text>
<View style={styles.seprator} />
</View>
</TouchableWithoutFeedback>
);
}
_setModalVisible() {
this.setState({
visible: false,
});
}
_pressRow(url) {
if (!this.props.onPressRow) {
return;
}
this.props.onPressRow(url);
}
_selectGender(id) {
if (!this.props.selectGender) {
return;
}
this.props.selectGender(url);
}
};
PlustarGenderSelector.propTypes = {
};
let deviceWidth = uiUtil.screen().width;
let deviceHeight = uiUtil.screen().height;
let width = uiUtil.sizeOnScreenScale(120, 320);
let rowHeight = uiUtil.sizeOnScreenScale(44, 320);
let height = rowHeight * 3;
let styles = StyleSheet.create({
container: {
width: deviceWidth,
height: deviceHeight,
backgroundColor: 'red'
},
bgImage: {
width: width,
height: height,
},
listContainer: {
width: width,
height: height,
position:'absolute',
left: deviceWidth - width - 10,
top: 64
},
rowContainer: {
width: width,
height: rowHeight,
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'center',
},
title: {
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'center',
width: width,
height: rowHeight - 1,
color: 'white',
fontSize: 15,
textAlign: 'center',
textAlignVertical: 'center',
backgroundColor: 'green',
position:'absolute',
// top: 0,
},
seprator: {
flex: 1,
width: width - 20,
height: 1,
backgroundColor: 'white',
}
});
... ... @@ -16,7 +16,10 @@ import ReactNative, {
StyleSheet,
} from 'react-native';
import ImmutablePropTypes from 'react-immutable-proptypes';
import uiUtil from '../../utils/UIUtil';
import Banner from './Banner';
import BannerView from '../common/BannerView';
... ... @@ -29,54 +32,35 @@ export default class PlustarList extends Component {
this._renderHeader = this._renderHeader.bind(this);
this._renderFooter = this._renderFooter.bind(this);
this._pressRow = this._pressRow.bind(this);
}
render() {
if(!this.props.dataSource) {
return (
<View style={styles.listContainer} />
);
}
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1.id !== r2.id});
let dataSource = ds.cloneWithRows(this.props.dataSource);
return (
<ListView
style={styles.listContainer}
dataSource={dataSource}
renderRow={this._renderRow}
renderHeader={this._renderHeader}
renderFooter={this._renderFooter}
initialListSize={3}
/>
);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => !Immutable.is(r1, r2),
});
}
_renderHeader() {
let data = this.props.head;
if(!data || data.length == 0) {
if(!data || data.size == 0) {
return null;
}
return (
<View style={styles.rowContainer}>
<BannerView style={styles.bannerView} items={data} autoLooping={true} onSelectBanner={this._pressRow} />
<BannerView style={styles.bannerView} items={data.toJS()} autoLooping={true} onSelectBanner={this._pressRow} />
</View>
);
}
_renderFooter() {
let data = this.props.foot;
if(!data || data.length == 0) {
if(!data || data.size == 0) {
return null;
}
return (
<View style={styles.rowContainer}>
<BannerView style={styles.bannerView} items={data} autoLooping={true} onSelectBanner={this._pressRow} />
<BannerView style={styles.bannerView} items={data.toJS()} autoLooping={true} onSelectBanner={this._pressRow} />
</View>
);
}
... ... @@ -97,9 +81,9 @@ export default class PlustarList extends Component {
return (
<View style={styles.rowContainer}>
<BannerView style={styles.bannerView} items={rowData.data} onSelectBanner={this._pressRow} />
<BannerView style={styles.bannerView} items={rowData.get('data').toJS()} onSelectBanner={this._pressRow} />
{text(rowData.brand_title)}
{text(rowData.get('brand_title'))}
</View>
);
... ... @@ -107,36 +91,46 @@ export default class PlustarList extends Component {
}
_pressRow(url: string) {
if (!this.props.onPressRow) {
return;
this.props.onPressRow && this.props.onPressRow(url);
}
this.props.onPressRow(url);
render() {
let data = this.props.list.toArray();
return (
<ListView
style={styles.listContainer}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(data)}
renderRow={this._renderRow}
renderHeader={this._renderHeader}
renderFooter={this._renderFooter}
/>
);
}
}
PlustarList.propTypes = {
dataSource: React.PropTypes.arrayOf(
React.PropTypes.shape({
list: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
id: React.PropTypes.string.isRequired,
brand_title: React.PropTypes.string.isRequired,
data: React.PropTypes.arrayOf(
React.PropTypes.shape({
data: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
src: React.PropTypes.string.isRequired,
url: React.PropTypes.string.isRequired,
})
)
})
),
head: React.PropTypes.arrayOf(
React.PropTypes.shape({
head: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
src: React.PropTypes.string.isRequired,
url: React.PropTypes.string.isRequired,
})
),
foot: React.PropTypes.arrayOf(
React.PropTypes.shape({
foot: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
src: React.PropTypes.string.isRequired,
url: React.PropTypes.string.isRequired,
})
... ...
... ... @@ -16,6 +16,8 @@ import {
Animated
} from 'react-native';
import ImmutablePropTypes from 'react-immutable-proptypes';
import uiUtil from '../../utils/UIUtil';
import Button from '../common/Button';
... ... @@ -79,12 +81,16 @@ export default class PlustarSegment extends Component {
};
PlustarSegment.propTypes = {
content: React.PropTypes.arrayOf(
React.PropTypes.shape({
content: ImmutablePropTypes.contains({
0: ImmutablePropTypes.contains({
title: React.PropTypes.string.isRequired,
type: React.PropTypes.number,
}),
1: ImmutablePropTypes.contains({
title: React.PropTypes.string.isRequired,
type: React.PropTypes.number.isRequired,
type: React.PropTypes.number,
})
),
}),
selectedIndex: React.PropTypes.oneOf([0, 1]),
onPressSegment: React.PropTypes.func,
};
... ...
... ... @@ -5,16 +5,15 @@ export default keyMirror({
SET_PLATFORM: null,
SET_CHANNEL: null,
SET_SEGMENT: null,
SET_GENDER: null,
PLUSTAR_LIST_REQUEST: null,
PLUSTAR_LIST_SUCCESS: null,
PLUSTAR_LIST_FAILURE: null,
});
SWITCH_SEGMENT: null,
SWITCH_GENDER: null,
JUMP_WITH_URL: null,
export const ROUTE_PLUSATAR = 'ROUTE_PLUSATAR';
export const ROUTE_POP_VIEW_CONTROLLER = 'ROUTE_POP_VIEW_CONTROLLER';
export const REQUEST_PLASTAR_DATA = 'REQUEST_PLASTAR_DATA';
export const RECEIVE_PLASTAR_DATA = 'RECEIVE_PLASTAR_DATA';
export const SWITCH_SEGMENT = 'SWITCH_SEGMENT';
export const SWITCH_GENDER = 'SWITCH_GENDER';
});
... ...
... ... @@ -8,6 +8,7 @@ import {
View,
NativeModules,
InteractionManager,
NativeAppEventEmitter,
} from 'react-native'
import {bindActionCreators} from 'redux';
... ... @@ -21,15 +22,8 @@ const actions = [
];
function mapStateToProps(state) {
let { plustar } = state;
let {left, right, segment, activeTab, genderType} = plustar;
return {
left,
right,
segment,
activeTab,
genderType,
...state
};
}
... ... @@ -50,7 +44,6 @@ class PlustarContainer extends Component {
constructor(props) {
super(props);
this._onPressSegment = this._onPressSegment.bind(this);
this._onChangeTab = this._onChangeTab.bind(this);
this._onPressRow = this._onPressRow.bind(this);
... ... @@ -59,53 +52,56 @@ class PlustarContainer extends Component {
componentDidMount() {
this.subscription = NativeAppEventEmitter.addListener(
"onChangeGender",
"GenderChangeReminder",
(reminder) => {
this.props.dispatch(switchGender(reminder.genderType));
this.props.actions.switchGender(reminder.genderType);
this.props.actions.plustarList(0, true);
this.props.actions.plustarList(1, true);
}
);
this.props.dispatch(plustarList(0));
this.props.dispatch(plustarList(1));
this.props.actions.plustarList(0);
this.props.actions.plustarList(1);
}
componentWillUnmount() {
this.subscription && this.subscription.remove();
}
_onPressSegment(index) {
this._scrollView.goToPage(index);
}
_onChangeTab(tab, ref) {
if (this.props.selectedIndex != tab.i) {
this.props.dispatch(swithSegment(tab.i));
this.props.dispatch(fetchPlustarIfNeeded(tab.i));
_onChangeTab(i) {
if (this.props.activeTab != i) {
this.props.actions.swithSegment(i);
this.props.actions.plustarList(i);
}
}
_onPressRow(url) {
this.props.dispatch(plustarRouter(url))
this.props.actions.jumpWithUrl(url);
}
render() {
let {plustar} = this.props;
let {segment, activeTab} = plustar;
let key = activeTab + '';
let isCurrentTabFetching = plustar.get(key).isFetching;
return (
<View style={styles.container}>
<Plustar
segment={segment}
activeTab={activeTab}
left={plustar.get('0')}
right={plustar.get('1')}
isCurrentTabFetching={isCurrentTabFetching}
onChangeTab={this._onChangeTab}
onPressRow={this._onPressRow}
/>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let navbarHeight = (Platform.OS === 'android') ? 50 : 64;
let styles = StyleSheet.create({
container: {
top: navbarHeight,
marginBottom: navbarHeight,
flex: 1,
},
... ...
'use strict';
import ReactNative from 'react-native';
import PlustarService from '../../services/PlustarService';
const {
SET_SEGMENT,
SET_GENDER,
PLUSTAR_LIST_REQUEST,
PLUSTAR_LIST_SUCCESS,
PLUSTAR_LIST_FAILURE,
SWITCH_SEGMENT,
SWITCH_GENDER,
JUMP_WITH_URL,
} = require('../../constants/actionTypes').default;
export function setSegment(segmentType) {
export function setSegment(segment) {
return {
type: SET_SEGMENT,
payload: segmentType,
payload: segment,
};
}
export function plustarListRequest() {
export function setGender(gender) {
return {
type: SET_GENDER,
payload: gender,
};
}
export function swithSegment(activeTab) {
return (dispatch, getState) => {
const {plustar} = getState();
if(activeTab == plustar.activeTab) {
return;
}
dispatch({
type: SWITCH_SEGMENT,
payload: activeTab
});
};
}
export function switchGender(genderType) {
return (dispatch, getState) => {
const {plustar} = getState();
if(genderType == plustar.genderType) {
return;
}
dispatch({
type: SWITCH_GENDER,
payload: genderType
});
};
}
export function plustarListRequest(key) {
return {
type: PLUSTAR_LIST_REQUEST,
payload: key
};
}
export function plustarListSuccess(json) {
export function plustarListSuccess(json, key) {
return {
type: PLUSTAR_LIST_SUCCESS,
payload: json
payload: {...json, key}
};
}
export function plustarListFailure(error) {
export function plustarListFailure(error, key) {
return {
type: PLUSTAR_LIST_FAILURE,
payload: error
payload: {error, key}
};
}
export function plustarList(activeTab, gender) {
/*
* index number 请求数据的index
* reload bool 是否需要强制重新请求数据,
*/
export function plustarList(index, reload = false) {
return (dispatch, getState) => {
let {app, plustar} = getState();
let {activeTab, segment} = plustar;
let item = plustar.get(activeTab);
if (item.isFetching) {
let key = index + '';
let item = plustar.get(key);
if (reload) {
// 强制刷新数据
} else {
if (item.isFetching || item.list.size > 0) {
return;
}
}
dispatch(plustarListRequest());
dispatch(plustarListRequest(key));
let brandType = segment.get(activeTab).type;
let gender = item.genderType;
return new PlustarService().fetchList(brandType, gender)
let {segment, gender} = plustar;
let brandType = segment.get(key).type;
let options = {};
// 如果gender>0,接口请求需要区分男女,需要传递gender参数
if (gender > 0) {
options = {gender};
}
return new PlustarService().fetchList(brandType, options)
.then(json => {
let payload = parsePlustarList(json);
dispatch(plustarListSuccess(payload));
dispatch(plustarListSuccess(payload, key));
})
.catch(error => {
dispatch(plustarListFailure(error));
dispatch(plustarListFailure(error, key));
});
};
}
function parsePlustarList(json) {
let {brand_type, brand_type_name, data} = json;
let parseListData = (list) => {
if (!Array.isArray(list) || list.length == 0) {
return [];
}
let allData = [];
let length = list.length;
for(let i = 0; i < length; i++) {
let data = list[i].data;
list.map((item, i) => {
let {data} = item;
if (data && data.length > 0) {
allData = [...allData, ...data];
}
});
return allData;
}
let header = parseListData(json.head);
let footer = parseListData(json.foot);
let list = parseListData(json.list);
let head = parseListData(data.head);
let foot = parseListData(data.foot);
let list = parseListData(data.list);
return {
header,
footer,
head,
foot,
list,
};
}
export function plustarRouter(url) {
RouterManager.jumpWithUrl(url, null);
export function jumpWithUrl(url) {
ReactNative.NativeModules.YH_PlustarHelper.jumpWithUrl(url);
return {
type: types.ROUTE_PLUSATAR,
};
}
export function popViewController() {
RouterManager.popViewController();
return {
type: types.ROUTE_POP_VIEW_CONTROLLER,
};
}
export function switchGender(genderType) {
return (dispatch, getState) => {
const {plustar} = getState();
if(genderType == plustar.payload.genderType) {
return;
}
dispatch({
type: types.SWITCH_GENDER,
payload: {
genderType,
}
});
dispatch(fetchPlustarIfNeeded(0, genderType));
dispatch(fetchPlustarIfNeeded(1, genderType));
type: JUMP_WITH_URL,
payload: url
};
}
export function swithSegment(selectedIndex) {
return (dispatch, getState) => {
const {plustar} = getState();
if(selectedIndex == plustar.payload.selectedIndex) {
return;
}
dispatch({
type: types.SWITCH_SEGMENT,
payload: {
selectedIndex,
}
});
};
}
export function fetchPlustarIfNeeded(index, gender=null) {
... ...
... ... @@ -4,19 +4,19 @@ import {Record, List, Map} from 'immutable';
let InitialState = Record({
activeTab: 0,
genderType: 0,
gender: -1,
0: new (Record({
isFetching: false,
error: null,
header: List(),
footer: List(),
head: List(),
foot: List(),
list: List(),
})),
1: new (Record({
isFetching: false,
error: null,
header: List(),
footer: List(),
head: List(),
foot: List(),
list: List(),
})),
segment: null,
... ...
'use strict';
import InitialState from './plustarInitialState';
import Immutable, {Map} from 'immutable';
const {
SET_SEGMENT,
SET_GENDER,
PLUSTAR_LIST_REQUEST,
PLUSTAR_LIST_SUCCESS,
PLUSTAR_LIST_FAILURE,
SWITCH_SEGMENT,
SWITCH_GENDER,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
... ... @@ -18,41 +22,38 @@ export default function plustarReducer(state=initialState, action) {
}
case PLUSTAR_LIST_REQUEST: {
let key = getKeyFromActiveTab(state.activeTab);
let key = action.payload;
return state.setIn([key, 'isFetching'], true)
.setIn([key, 'error'], null);
}
case PLUSTAR_LIST_SUCCESS: {
let {header, footer, list} = action.payload;
let key = getKeyFromActiveTab(state.activeTab);
let {head, foot, list, key} = action.payload;
return state.setIn([key, 'isFetching'], true)
return state.setIn([key, 'isFetching'], false)
.setIn([key, 'error'], null)
.setIn([key, 'header'], header)
.setIn([key, 'footer'], footer)
.setIn([key, 'list'], list);
.setIn([key, 'head'], Immutable.fromJS(head))
.setIn([key, 'foot'], Immutable.fromJS(foot))
.setIn([key, 'list'], Immutable.fromJS(list));
}
case PLUSTAR_LIST_FAILURE: {
let key = getKeyFromActiveTab(state.activeTab);
let {error, key} = action.payload;
return state.setIn([key, 'isFetching'], true)
.setIn([key, 'error'], action.payload);
}
return state.setIn([key, 'isFetching'], false)
.setIn([key, 'error'], error);
}
return state;
}
case SWITCH_SEGMENT: {
return state.set('activeTab', action.payload);
}
function getKeyFromActiveTab(activeTab) {
let key = 'left';
if (activeTab == 0) {
key = '0';
} else if (activeTab == 1) {
key = '1';
case SET_GENDER:
case SWITCH_GENDER: {
return state.set('gender', action.payload);
}
}
return key;
return state;
}
... ...
... ... @@ -9,12 +9,12 @@ export default class PlustarService {
this.api = new Request(baseURL);
}
async fetchList(brand_type, gender) {
async fetchList(brand_type, options) {
return await this.api.get({
url: '/guang/api/v3/plustar/getlist',
body: {
brand_type,
gender,
...options,
}
})
.then((json) => {
... ...
... ... @@ -13,8 +13,8 @@
"moment": "^2.13.0",
"object-assign": "^4.1.0",
"query-string": "^4.2.2",
"react": "15.3.0",
"react-immutable-proptypes": "^1.7.1",
"react": "^15.3.1",
"react-immutable-proptypes": "^2.1.0",
"react-native": "0.32.0",
"react-native-device-info": "^0.9.3",
"react-native-fabric": "0.2.2",
... ... @@ -22,7 +22,7 @@
"react-native-router-flux": "^3.32.0",
"react-native-scrollable-mixin": "^1.0.1",
"react-native-simple-store": "^1.0.1",
"react-native-swiper": "^1.4.7",
"react-native-swiper": "^1.4.11",
"react-redux": "^4.4.5",
"react-static-container": "^1.0.1",
"react-timer-mixin": "^0.13.3",
... ...