Section.js 13.7 KB
'use strict';

import React from 'react';
import ReactNative from 'react-native';
import ImmutablePropTypes from 'react-immutable-proptypes';
import SectionHeader from './SectionHeader';
import Notice from '../home/Notice';
import SectionTabBar from './SectionTabBar';
import ScrollableTabView, {DefaultTabBar} from 'react-native-scrollable-tab-view';
import SectionList from './SectionList';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';
import UploadProgress from '../home/UploadProgress';
import SuperMan from '../home/SuperMan';

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

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

export default class Section 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,
            }),
        ),
        header: ImmutablePropTypes.listOf(
            ImmutablePropTypes.contains({
                uri: React.PropTypes.string.isRequired,
                title: React.PropTypes.string.isRequired,
                post: React.PropTypes.string.isRequired,
                comment: React.PropTypes.string.isRequired,
                like: React.PropTypes.string.isRequired,
            }),
        ),
        notice: ImmutablePropTypes.listOf(
            ImmutablePropTypes.listOf(
                ImmutablePropTypes.contains({
                    title: React.PropTypes.string.isRequired,
                    url: React.PropTypes.string,
                }),
            ),
        ),
        list: ImmutablePropTypes.listOf(
            ImmutablePropTypes.contains({
                new: 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,
                    })
                ),
                hot: 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,
                    })
                ),
            })
        ),
        onPressNotice: React.PropTypes.func,
        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,
        onSaveingTheWorld: React.PropTypes.func,
    };

    constructor(props) {
        super (props);

        this.scrollableTabView = null;

        this._renderSectionHeader = this._renderSectionHeader.bind(this);
        this._renderRow = this._renderRow.bind(this);
        this._renderSeparator = this._renderSeparator.bind(this);
        this._updateScrollValue = this._updateScrollValue.bind(this);
        this._getCurrentPageHeight = this._getCurrentPageHeight.bind(this);

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

        this.initialPageHeight = height - bannerHeight - sectionBarHeight;
        this.currentPage = 0;
        this.tabs = ['最新', '热门'];

        this.state = {
            currentPage: this.currentPage,
            scrollValue: new Animated.Value(this.currentPage),
        };
    }

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

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

    componentWillUnmount() {
        this.timer && clearTimeout(this.timer);
    }

    _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 'header':
                return (
                    <SectionHeader
                        data={rowData}
                    />
                );
			case 'notice':
				return (
                    <Notice
                        data={rowData}
                        duration={this.props.noticeDuration}
                        width={width}
                        height={40}
                        onPress={this.props.onPressNotice}
                    />
				);
			case 'list':
				return (
                    <ScrollableTabView
                        ref={(c) => {
                            this.scrollableTabView = c;
                        }}
                        renderTabBar={false}
                        initialPage={this.currentPage}
                        onScroll={this._updateScrollValue}
                        getCurrentPageHeight={this._getCurrentPageHeight}
                        prerenderingSiblingsNumber={Infinity}
                        onChangeTab={(tab) => {
                            this.currentPage = tab.i;
                        }}
                    >
                        <SectionList
                            ref={(c) => {
                                this.tab1 = c;
                            }}
                            data={rowData.get('new')}
                            onPressPost={this.props.onPressPost}
                            onPressAvatar={this.props.onPressAvatar}
                            onPressSectionTag={this.props.onPressSectionTag}
                            onPressComment={this.props.onPressComment}
                            onPressLike={this.props.onPressLike}
                            onContentSizeChange={() => {
                                if (this.currentPage == 0) {
                                    this.scrollableTabView && this.scrollableTabView.goToPage(this.scrollableTabView.state.currentPage);
                                }
                            }}
                        />
                        <SectionList
                            ref={(c) => {
                                this.tab2 = c;
                            }}
                            data={rowData.get('hot')}
                            onPressPost={this.props.onPressPost}
                            onPressAvatar={this.props.onPressAvatar}
                            onPressSectionTag={this.props.onPressSectionTag}
                            onPressComment={this.props.onPressComment}
                            onPressLike={this.props.onPressLike}
                            onContentSizeChange={() => {
                                if (this.currentPage == 1) {
                                    this.scrollableTabView && this.scrollableTabView.goToPage(this.scrollableTabView.state.currentPage);
                                }
                            }}
                        />
                    </ScrollableTabView>
				);
            default:
                return null;
		}
    }

    _renderSectionHeader(sectionData, sectionID) {
        switch (sectionID) {
			case 'list':
				return (
                    <SectionTabBar
                        style={{borderBottomWidth: 0.5, borderBottomColor: '#e0e0e0',}}
                        tabs={this.tabs}
                        activeTab={this.currentPage}
                        scrollValue={this.state.scrollValue}
                        goToPage={(page) => this._goToPage(page)}
                    />
				);
            default:
                return null;
		}
    }

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

    _goToPage(page) {
        this.currentPage = page;
        // this.setState({
        //     currentPage: this.currentPage,
        // });
        this.scrollableTabView && this.scrollableTabView.goToPage(page);
    }

    _updateScrollValue(value) {
        this.state.scrollValue.setValue(value);
    }

    _getCurrentPageHeight(page) {
        let ref = null;
        if (page == 0) {
            ref = this.tab1;
        } else {
            ref = this.tab2;
        }

        if (!ref) {
            return this.initialPageHeight;
        }

        let height = ref.state.contentHeight;
        return height;
    }

	render() {
        let {header, notice, list, user, endReached, isRefreshing, isLoadingMore, isFetching, isUserStateFetching} = this.props;
        let dataSource = {
            progressing: this.props.progressing.toArray(),
            header: header.toArray(),
            notice: notice.toArray(),
            list: list.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.timer = setTimeout(() => {
                            this.props.onEndReached && this.props.onEndReached(this.currentPage);
                        }, 500);
                    }}
                    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,
    },
    separator: {
        height: 0.5,
        backgroundColor: '#e0e0e0',
    },
    fly: {
        position: 'absolute',
        right: 20,
        bottom: 20,
    },
});