Home.js 13.1 KB
'use strict';

import React from 'react';
import ReactNative from 'react-native';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Banner from './Banner';
import Notice from './Notice';
import YH_SectionView from './YH_SectionView';
import ListCell from './ListCell';
import UploadProgress from './UploadProgress';
import SuperMan from './SuperMan';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';


const {
    View,
    Text,
    Image,
    ListView,
    TouchableOpacity,
    RefreshControl,
    Platform,
    StyleSheet,
    Dimensions,
    InteractionManager,
} = ReactNative;

let {width, height} = Dimensions.get('window');
let bannerHeight = Math.ceil((363 / 750) * width);
let sectionHeight = Math.ceil((435 / 750) * width);

export default class Home extends React.Component {

    static propTypes = {

        progressing: ImmutablePropTypes.listOf(
            ImmutablePropTypes.contains({
                uploadState:React.PropTypes.number.isRequired,
                progress:React.PropTypes.number,
                image:React.PropTypes.string,
                onPressRetry:React.PropTypes.func,
                onPressDelete:React.PropTypes.func,
            }),
        ),
        banner: ImmutablePropTypes.listOf(
            ImmutablePropTypes.listOf(
                ImmutablePropTypes.contains({
                    src: React.PropTypes.string.isRequired,
                    url: React.PropTypes.string,
                }),
            ),
        ),
        notice: ImmutablePropTypes.listOf(
            ImmutablePropTypes.listOf(
                ImmutablePropTypes.contains({
                    title: React.PropTypes.string.isRequired,
                    url: React.PropTypes.string,
                }),
            ),
        ),
        section: ImmutablePropTypes.listOf(
            ImmutablePropTypes.listOf(
                ImmutablePropTypes.contains({
                    header: ImmutablePropTypes.contains({
                        id: React.PropTypes.number.isRequired,
                        logo: React.PropTypes.string.isRequired,
                        title: React.PropTypes.string.isRequired,
                        post: React.PropTypes.string.isRequired,
                        comment: React.PropTypes.string.isRequired,
                        like: React.PropTypes.string.isRequired,
                    }),
                    hot: ImmutablePropTypes.contains({
                        postId: React.PropTypes.number,
                        avatar: React.PropTypes.string,
                        content: React.PropTypes.string.isRequired,
                    }),
                    new: ImmutablePropTypes.contains({
                        postId: React.PropTypes.number,
                        avatar: React.PropTypes.string,
                        content: React.PropTypes.string.isRequired,
                    }),
                    num: ImmutablePropTypes.contains({
                        onedayAddNum: React.PropTypes.number.isRequired,
                    }),
                })
            ),
        ),
        recommendation: ImmutablePropTypes.listOf(
            ImmutablePropTypes.contains({
                author: ImmutablePropTypes.contains({
                    avatar: React.PropTypes.string,
                    uid: React.PropTypes.number,
                    name: React.PropTypes.string,
    			}),
                timeago: React.PropTypes.string.isRequired,
                isOwner: React.PropTypes.bool,
                isTop: React.PropTypes.bool,
                isLike: React.PropTypes.bool,
                id: React.PropTypes.number,
                title: React.PropTypes.string,
                desc: React.PropTypes.string,
                thumbs: ImmutablePropTypes.listOf(
                    ImmutablePropTypes.contains({
                        src: React.PropTypes.string,
                    })
                ),
                section: ImmutablePropTypes.contains({
    				id: React.PropTypes.number,
    				name: React.PropTypes.string,
    			}),
                commentCount: React.PropTypes.number,
                likeCount: React.PropTypes.number,
            }),
        ),
        user: ImmutablePropTypes.contains({
            avatar: React.PropTypes.string,
            uid: React.PropTypes.number,
            msgCount: React.PropTypes.string,
        }),

        bannerDuration: React.PropTypes.number,
        noticeOpen: React.PropTypes.oneOf(['Y', 'N']),
        noticeDuration: React.PropTypes.number,
        onPressPost: React.PropTypes.func,
        onPressAvatar: React.PropTypes.func,
        onPressSectionTag: React.PropTypes.func,
        onPressComment: React.PropTypes.func,
        onPressLike: React.PropTypes.func,
        onRefresh: React.PropTypes.func,
        onEndReached: React.PropTypes.func,
        onUploadRetry: React.PropTypes.func,
        onUploadSuccess: React.PropTypes.func,
        onUploadDelete: React.PropTypes.func,
        onSaveingTheWorld: React.PropTypes.func,
    };

    constructor(props) {
        super (props);

        this._renderRow = this._renderRow.bind(this);
        this._renderSectionHeader = this._renderSectionHeader.bind(this);
        this._renderSeparator = this._renderSeparator.bind(this);
        this.triggerPullToRefresh = this.triggerPullToRefresh.bind(this);

        this.dataSource = new ListView.DataSource({
            rowHasChanged: (r1, r2) => !Immutable.is(r1, r2),
            sectionHeaderHasChanged: (s1, s2) => !Immutable.is(s1, s2),
        });
    }

    componentDidMount() {
        this.triggerPullToRefresh();
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.scrollToTop) {
            this.listView.scrollTo({x: 0, y: 0, animated: false, });
        }
    }

    triggerPullToRefresh() {
        InteractionManager.runAfterInteractions(() => {
            this.listView && this.listView.getScrollResponder().startPullToRefresh();
        });
    }

    _renderRow(rowData, sectionID, rowID, highlightRow) {
        switch (sectionID) {

            case 'progressing':
                return (
                    <UploadProgress
                        data={rowData}
                        onPressRetry={this.props.onUploadRetry}
                        onPressDelete={this.props.onUploadDelete}
                        uploadSuccess={this.props.onUploadSuccess}
                    />
                );

			case 'banner':
                if (rowData.size == 0) {
                    return null;
                } else {
                    return (
                        <Banner
                            data={rowData}
                            duration={this.props.bannerDuration}
                            width={width}
                            height={bannerHeight}
                            onPress={this.props.onPressBanner}
                        />
                    );
                }
			case 'notice':
				return (
                    <Notice
                        data={rowData}
                        duration={this.props.noticeDuration}
                        width={width}
                        height={40}
                        onPress={this.props.onPressNotice}
                    />
				);
			case 'section':
                return (
                    <YH_SectionView
                        style={styles.carouselSection}
                        items={rowData.toJS()}
                        onClick={(info) => {
                            let type = info.type;
                            let item = rowData.get(info.index);
                            if (type == 0) {
                                // section
                                let section = {
                                    id: item.get('header').get('id'),
                                    name: item.get('header').get('title'),
                                }
                                this.props.onPressSection && this.props.onPressSection(section);
                            } else if (type == 1) {
                                // hot
                                let postId = item.get('hot').get('postId')
                                this.props.onPressPost && this.props.onPressPost(postId);
                            } else if (type == 2) {
                                // new
                                let postId = item.get('new').get('postId')
                                this.props.onPressPost && this.props.onPressPost(postId);
                            }
                        }}
                    />
                );
			case 'recommendation':
				return (
                    <ListCell
                        key={sectionID + rowID}
                        data={rowData}
                        onPressPost={this.props.onPressPost}
                        onPressAvatar={this.props.onPressAvatar}
                        onPressSectionTag={this.props.onPressSectionTag}
                        onPressComment={this.props.onPressComment}
                        onPressLike={this.props.onPressLike}
                    />
				);
            default:
                return null;
		}
    }

    _renderSectionHeader(sectionData, sectionID) {
        switch (sectionID) {
			case 'recommendation':
				return (
                    <View style={styles.sectionHeader}>
                        <Image style={styles.sectionHeaderImg} source={require('../../images/home/hot.png')}/>
                        <Text style={styles.sectionHeaderText}>热门推荐</Text>
                        <View style={styles.sectionHeaderTopLine}/>
                        <View style={styles.sectionHeaderBottomLine}/>
                    </View>
				);

            default:
                return null;
		}
    }

    _renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
        return (
            <View key={'separator' + sectionID + rowID} style={styles.separator}/>
        );
    }

	render() {
        let {progressing, banner, notice, section, recommendation, user, endReached, isRefreshing, isLoadingMore, isFetching, isUserStateFetching} = this.props;
        let dataSource = {
            progressing: progressing.toArray(),
            banner: banner.toArray(),
            notice: notice.toArray(),
            section: section.toArray(),
            recommendation: recommendation.toArray(),
        }

        return (
            <View style={styles.container}>
                <ListView
                    ref={(c) => {
                        this.listView = c;
                    }}
                    dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)}
                    renderRow={this._renderRow}
                    renderSectionHeader={this._renderSectionHeader}
                    renderSeparator={this._renderSeparator}
                    enableEmptySections={true}
                    enablePullToRefresh={true}
                    isOnPullToRefresh={isRefreshing}
                    onRefreshData={() => {
                        this.props.onRefresh && this.props.onRefresh();
                    }}
                    onEndReached={() => {
                        this.props.onEndReached && this.props.onEndReached();
                    }}
                    renderFooter={()=>{
                        if (endReached) {
                            return <LoadMoreIndicator
                                    isVisible={true}
                                    text={'暂无更多'}
                                />
                        } else {
                            return <LoadMoreIndicator
                                    isVisible={isLoadingMore}
                                    animating={isFetching}
                                />
                        }
                    }}
                />
                <LoadingIndicator
                    isVisible={isUserStateFetching}
                />
                <SuperMan
                    uid={user.uid}
                    avatar={user.avatar}
                    msgCount={user.msgCount}
                    onSaveingTheWorld={this.props.onSaveingTheWorld}
                />
            </View>
        );

    }
}

let styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    carouselSection: {
        width,
        height: sectionHeight,
    },
    sectionHeader: {
        flexDirection: 'row',
        height: 32,
        alignItems: 'center',
        backgroundColor: 'white',
        // borderTopWidth: 0.5,         // borderTopWidth 在iPhone 6P上显示有bug
        // borderTopColor: '#e0e0e0',
    },
    sectionHeaderImg: {
        width: 9,
        height: 12,
        marginLeft: 17,
    },
    sectionHeaderText: {
        fontSize: 12,
        marginLeft: 5,
    },
    sectionHeaderTopLine: {
        position: 'absolute',
        left: 0,
        top: 0,
        width: width,
        height: 0.5,
        backgroundColor: '#e0e0e0',
    },
    sectionHeaderBottomLine: {
        position: 'absolute',
        left: 17,
        bottom: 0,
        width: width - 17,
        height: 0.5,
        backgroundColor: '#e0e0e0',
    },
    separator: {
        height: 0.5,
        backgroundColor: '#e0e0e0',
    },
});