... ... @@ -338,8 +338,14 @@ const ScrollView = React.createClass({
mixins: [ScrollResponder.Mixin],
endPullToRefresh: function() {
RCTScrollViewManager.endPullToRefresh(
startPullToRefresh: function() {
RCTScrollViewManager.startPullToRefresh(
ReactNative.findNodeHandle(this)
);
},
stopPullToRefresh: function() {
RCTScrollViewManager.stopPullToRefresh(
ReactNative.findNodeHandle(this._scrollViewRef)
);
},
... ...
... ... @@ -17,6 +17,9 @@ export default class SlicedImage extends React.Component {
constructor(props) {
super (props);
// http://developer.qiniu.com/code/v6/api/kodo-api/index.html#image
this.mode = 1;
}
_generateImageUrl(src) {
... ... @@ -26,9 +29,9 @@ export default class SlicedImage extends React.Component {
height = PixelRatio.getPixelSizeForLayoutSize(height);
let newSrc = src;
if (src.indexOf('imageView2') === -1) {
newSrc = src + '?imageView2/2/w/' + width + '/h/' + height;
newSrc = src + '?imageView2/' + this.mode + '/w/' + width + '/h/' + height;
} else {
newSrc = src.replace('{mode}', 2)
newSrc = src.replace('{mode}', this.mode)
.replace('{width}', width)
.replace('{height}', height);
}
... ...
... ... @@ -106,10 +106,10 @@ export default function community(platform) {
//Connect w/ the Router
const NewRouter = connect()(Router);
let contaner = parseInt(this.props.container);
let container = parseInt(this.props.container);
store.dispatch(setPlatform(platform));
store.dispatch(setContianer(contaner));
store.dispatch(setContianer(container));
store.dispatch(setChannel(this.props.channel));
store.dispatch(mergeCachedPosting());
... ...
... ... @@ -23,6 +23,7 @@ const {
Platform,
StyleSheet,
Dimensions,
InteractionManager,
} = ReactNative;
let {width, height} = Dimensions.get('window');
... ... @@ -143,12 +144,11 @@ export default class Home extends React.Component {
});
}
// componentDidMount() {
// if (this.props.ptrError) {
// this.listView.getScrollResponder().endPullToRefresh();
// }
//
// }
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
this.listView && this.listView.getScrollResponder().startPullToRefresh();
});
}
_renderRow(rowData, sectionID, rowID, highlightRow) {
switch (sectionID) {
... ... @@ -285,9 +285,7 @@ export default class Home extends React.Component {
this.props.onRefresh && this.props.onRefresh();
}}
onEndReached={() => {
if (!isRefreshing && !isLoadingMore && !isFetching) {
this.props.onEndReached && this.props.onEndReached();
}
this.props.onEndReached && this.props.onEndReached();
}}
renderFooter={()=>{
if (endReached) {
... ...
... ... @@ -3,6 +3,7 @@
import React from 'react';
import ReactNative from 'react-native';
import ImmutablePropTypes from 'react-immutable-proptypes';
import SlicedImage from '../../../common/components/SlicedImage';
const {
View,
... ... @@ -52,7 +53,7 @@ export default class UserBrief extends React.Component {
<TouchableOpacity onPress={() => {
this.props.onPressAvatar && this.props.onPressAvatar();
}}>
<Image style={styles.avatar} source={{uri: this.props.avatar}} resizeMode={'cover'}/>
<SlicedImage style={styles.avatar} source={{uri: this.props.avatar}} resizeMode={'cover'} defaultSource={require('../../images/user/avatar-default.png')}/>
</TouchableOpacity>
<View style={styles.text}>
... ...
... ... @@ -10,6 +10,7 @@ import ScrollableTabView, {DefaultTabBar} from 'react-native-scrollable-tab-view
import SectionList from './SectionList';
import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';
import UploadProgress from '../home/UploadProgress';
import SuperMan from '../home/SuperMan';
const {
View,
... ... @@ -22,6 +23,7 @@ const {
StyleSheet,
Dimensions,
Animated,
InteractionManager,
} = ReactNative;
let {width, height} = Dimensions.get('window');
... ... @@ -145,6 +147,12 @@ export default class Section extends React.Component {
};
}
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
this.listView && this.listView.getScrollResponder().startPullToRefresh();
});
}
_renderRow(rowData, sectionID, rowID, highlightRow) {
switch (sectionID) {
case 'progressing':
... ... @@ -238,7 +246,7 @@ export default class Section extends React.Component {
}
render() {
let {header, notice, list, endReached, isRefreshing, isLoadingMore, isFetching} = this.props;
let {header, notice, list, user, endReached, isRefreshing, isLoadingMore, isFetching} = this.props;
let dataSource = {
progressing: this.props.progressing.toArray(),
header: header.toArray(),
... ... @@ -247,35 +255,44 @@ export default class Section extends React.Component {
};
return (
<ListView
dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)}
renderRow={this._renderRow}
renderSectionHeader={this._renderSectionHeader}
renderSeparator={this._renderSeparator}
enableEmptySections={true}
isOnPullToRefresh={isRefreshing}
onRefreshData={() => {
this.props.onRefresh && this.props.onRefresh();
}}
onEndReached={() => {
if (!isRefreshing && !isLoadingMore && !isFetching) {
<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}
isOnPullToRefresh={isRefreshing}
onRefreshData={() => {
this.props.onRefresh && this.props.onRefresh();
}}
onEndReached={() => {
this.props.onEndReached && this.props.onEndReached(this.currentPage);
}
}}
renderFooter={() => {
if (endReached) {
return <LoadMoreIndicator
isVisible={true}
text={'没有更多啦'}
/>
} else {
return <LoadMoreIndicator
isVisible={isLoadingMore}
animating={isFetching}
/>
}
}}
/>
}}
renderFooter={() => {
if (endReached) {
return <LoadMoreIndicator
isVisible={true}
text={'没有更多啦'}
/>
} else {
return <LoadMoreIndicator
isVisible={isLoadingMore}
animating={isFetching}
/>
}
}}
/>
<SuperMan
fly={styles.fly}
avatar={user.avatar}
msgCount={user.msgCount}
onSaveingTheWorld={this.props.onSaveingTheWorld}
/>
</View>
);
}
... ... @@ -289,5 +306,9 @@ let styles = StyleSheet.create({
height: 0.5,
backgroundColor: '#e0e0e0',
},
fly: {
position: 'absolute',
right: 20,
bottom: 20,
},
});
... ...
... ... @@ -56,7 +56,7 @@ let styles = StyleSheet.create({
container: {
flexDirection: 'column',
// alignItems: 'center',
backgroundColor: 'gray',
backgroundColor: '#b0b0b0',
},
title: {
color: 'white',
... ...
... ... @@ -100,10 +100,8 @@ class HomeContainer extends React.Component {
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
this.props.actions.bannerNoticeSectionOnlyDispathSuccess();
this.props.actions.getUserInfo(false);
});
}
componentWillReceiveProps(nextProps) {
... ...
... ... @@ -15,13 +15,10 @@ import {
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {Map} from 'immutable';
import Posting from '../components/posting/Posting';
import * as postingActions from '../reducers/posting/postingActions';
import {Actions} from 'react-native-router-flux';
import store from 'react-native-simple-store';
import {shouldShowTabBar, shouldHideTabBar} from '../utils/tabBar';
/**
* ## Actions
... ... @@ -67,8 +64,9 @@ class PostingContainer extends Component{
}
componentDidMount() {
NativeModules.YH_CommunityHelper.hideTabBar();
if (shouldHideTabBar(this.props.navigationState)) {
NativeModules.YH_CommunityHelper.hideTabBar();
}
InteractionManager.runAfterInteractions(() => {
this._onGetBordList();
... ... @@ -80,9 +78,7 @@ class PostingContainer extends Component{
}
componentWillUnmount() {
let key = this.props.navigationState.key;
let index = key.substring(0, 1);
if (index == 1) {
if (shouldShowTabBar(this.props.navigationState)) {
Actions.refresh({key: 'Home', showNativeTabBar: true});
}
}
... ...
... ... @@ -11,10 +11,9 @@ import Immutable, {Map, List} from 'immutable';
import Section from '../components/section/Section';
import * as sectionActions from '../reducers/section/sectionActions';
import {Actions} from 'react-native-router-flux';
import * as postingActions from '../reducers/posting/postingActions';
import {Actions} from 'react-native-router-flux';
import {shouldShowTabBar, shouldHideTabBar} from '../utils/tabBar';
const {
StatusBar,
... ... @@ -81,17 +80,13 @@ class SectionContainer extends React.Component {
}
componentDidMount() {
if (parseInt(this.props.app.container) === 1 && this.props.section.previousScene === 'Home') {
ReactNative.NativeModules.YH_CommunityHelper.hideTabBar();
if (shouldHideTabBar(this.props.navigationState)) {
NativeModules.YH_CommunityHelper.hideTabBar();
}
InteractionManager.runAfterInteractions(() => {
this.props.actions.headerOnlyDispatchSuccess();
});
}
componentWillUnmount() {
if (this.props.section.previousScene === 'Home') {
if (shouldShowTabBar(this.props.navigationState)) {
Actions.refresh({key: 'Home', showNativeTabBar: true});
}
... ... @@ -216,6 +211,7 @@ class SectionContainer extends React.Component {
let headerData = Immutable.fromJS([header]);
let listData = Immutable.fromJS([{new: newPost.list, hot: hotPost.list}]);
let noticeData = notice.open === 'Y' ? Immutable.fromJS([notice.list]) : List();
let {profile} = this.props.user;
return (
<View style={styles.container}>
... ... @@ -226,6 +222,7 @@ class SectionContainer extends React.Component {
noticeOpen={notice.open}
noticeDuration={notice.duration}
list={listData}
user={profile}
onPressBanner={this._onPressBanner}
onPressNotice={this._onPressNotice}
onPressPost={this._onPressPost}
... ...
... ... @@ -68,24 +68,24 @@ export function bannerNoticeSection() {
};
}
export function bannerNoticeSectionOnlyDispathSuccess() {
return (dispatch, getState) => {
let {app, home} = getState();
if (home.isFetching) {
return;
}
// dispatch(bnsRequest());
return new HomeService().bannerNoticeSection(app.container)
.then(json => {
let payload = parseBNS(json);
dispatch(bnsSuccess(payload));
})
.catch(error => {
// dispatch(bnsFailure(error));
});
};
}
// export function bannerNoticeSectionOnlyDispathSuccess() {
// return (dispatch, getState) => {
//
// let {app, home} = getState();
// if (home.isFetching) {
// return;
// }
// // dispatch(bnsRequest());
// return new HomeService().bannerNoticeSection(app.container)
// .then(json => {
// let payload = parseBNS(json);
// dispatch(bnsSuccess(payload));
// })
// .catch(error => {
// // dispatch(bnsFailure(error));
// });
// };
// }
export function recommendationRequest(ptr) {
return {
... ... @@ -111,13 +111,22 @@ export function recommendationFailure(error) {
export function recommendation(ptr = false) {
return (dispatch, getState) => {
let {home, user} = getState();
if (home.recommendation.isFetching || (!ptr && home.recommendation.endReached) || home.recommendation.error !== null) {
return;
// 接口请求跳出的条件:
// 前置条件:下拉刷新优先级高于上拉加载
if (ptr) {
//下拉刷新直接执行
} else {
// 1.当次请求不是下拉刷新,同时正在进行下拉刷新的请求,跳出
// 2.当次请求不是下拉刷新,同时接口请求正在加载中, 跳出
// 3.当次请求不是下拉刷新,数据已全部加载完成,跳出
if (home.ptr || home.recommendation.isFetching || home.recommendation.endReached) {
return;
}
}
dispatch(recommendationRequest(ptr));
let uid = user.profile.uid;
let lastedTime = 0;
if (!ptr) {
... ... @@ -141,36 +150,6 @@ export function recommendation(ptr = false) {
};
}
function shouldFetchRecommendation(dispatch, getState) {
let {home} = getState();
if (home.recommendation.isFetching || (!home.ptr && home.recommendation.endReached) || home.recommendation.error) {
return false;
}
// return false;
// let errorCount = home.recommendation.errorCount;
// let firstErrorTime = home.recommendation.firstErrorTime;
// let nowSeconds = (new Date()).getTime();
// let timePass = nowSeconds - firstErrorTime;
// console.log('timePass');
// console.log(firstErrorTime);
// console.log(nowSeconds);
// console.log(timePass);
// console.log('errorCount');
// console.log(timePass);
// if (timePass < 60 * 1000) {
// if (errorCount > 3) {
// return false;
// } else {
// return true;
// }
// } else {
// dispatch(resetErrorCount());
// return true;
// }
return true;
}
export function increaseErrorCount(number) {
return {
type: INCREASE_ERROR_COUNT,
... ... @@ -219,8 +198,8 @@ function parseBNS(json) {
if (textNoticeList.time) {
noticeDuration = textNoticeList.time;
};
if (noticeList.open) {
noticeOpen = noticeList.open;
if (textNoticeList.open) {
noticeOpen = textNoticeList.open;
}
}
... ...
... ... @@ -17,7 +17,7 @@ import {Record, List, Map} from 'immutable';
let InitialState = Record({
isFetching: false,
error: null,
ptr: false,
ptr: true,
banner: new (Record({
duration: 3,
list: List(),
... ...
... ... @@ -41,12 +41,14 @@ export default function homeReducer(state = initialState, action) {
switch (action.type) {
case HOME_BNS_REQUEST:
return state.set('isFetching', true)
.set('error', null);
.set('error', null)
.set('ptr', true);
case HOME_BNS_SUCCESS: {
let {banner, notice, section} = action.payload;
let nextState = state.set('isFetching', false)
.set('error', false)
.set('ptr', false)
.set('section', Immutable.fromJS(section))
.setIn(['banner', 'duration'], banner.duration)
.setIn(['banner', 'list'], Immutable.fromJS(banner.list))
... ... @@ -58,7 +60,8 @@ export default function homeReducer(state = initialState, action) {
case HOME_BNS_FAILURE:
return state.set('isFetching', false)
.set('error', action.payload);
.set('error', action.payload)
.set('ptr', false);
case HOME_RECOMMENDATION_REQUEST: {
let nextState = state.setIn(['recommendation', 'isFetching'], true)
... ...
... ... @@ -107,30 +107,41 @@ export function header() {
};
}
export function headerOnlyDispatchSuccess() {
return (dispatch, getState) => {
let {section} = getState();
if (section.isFetching) {
return;
}
// dispatch(headerRequest());
return new SectionService().header(section.id)
.then(json => {
let payload = parseHeader(json);
dispatch(headerSuccess(payload));
})
.catch(error => {
// dispatch(headerFailure());
});
};
}
// export function headerOnlyDispatchSuccess() {
// return (dispatch, getState) => {
// let {section} = getState();
// if (section.isFetching) {
// return;
// }
// // dispatch(headerRequest());
// return new SectionService().header(section.id)
// .then(json => {
// let payload = parseHeader(json);
// dispatch(headerSuccess(payload));
// })
// .catch(error => {
// // dispatch(headerFailure());
// });
// };
// }
export function newPost(ptr = false) {
return (dispatch, getState) => {
let {section, user} = getState();
if (section.new.isFetching || (!ptr && section.new.endReached) || section.new.error !== null) {
return;
// 接口请求跳出的条件:
// 前置条件:下拉刷新优先级高于上拉加载
if (ptr) {
//下拉刷新直接执行
} else {
// 1.当次请求不是下拉刷新,同时正在进行下拉刷新的请求,跳出
// 2.当次请求不是下拉刷新,同时接口请求正在加载中, 跳出
// 3.当次请求不是下拉刷新,数据已全部加载完成,跳出
if (section.ptr || section.new.isFetching || section.new.endReached) {
return;
}
}
dispatch(newPostRequest(ptr));
let uid = user.profile.uid;
let forumCode = section.id;
... ... @@ -158,9 +169,20 @@ export function newPost(ptr = false) {
export function hotPost(ptr = false) {
return (dispatch, getState) => {
let {section, user} = getState();
if (section.hot.isFetching || (!ptr && section.hot.endReached) || section.hot.error !== null) {
return;
// 接口请求跳出的条件:
// 前置条件:下拉刷新优先级高于上拉加载
if (ptr) {
//下拉刷新直接执行
} else {
// 1.当次请求不是下拉刷新,同时正在进行下拉刷新的请求,跳出
// 2.当次请求不是下拉刷新,同时接口请求正在加载中, 跳出
// 3.当次请求不是下拉刷新,数据已全部加载完成,跳出
if (section.ptr || section.hot.isFetching || section.hot.endReached) {
return;
}
}
dispatch(hotPostRequest(ptr));
let uid = user.profile.uid;
let forumCode = section.id;
... ...
... ... @@ -20,7 +20,7 @@ let InitialState = Record({
id: 0,
name: '',
activeTab: 0,
ptr: false,
ptr: true,
notice: new (Record({
duration: 3,
open: 'N',
... ...
'use strict';
import Request from '../../common/services/Request';
export default class RouterService {
constructor () {
this.api = new Request();
}
}
... ...
'use strict';
export function shouldShowTabBar(navigationState) {
let key = navigationState.key;
let index = key.substring(0, 1);
return index == 1;
}
export function shouldHideTabBar(navigationState) {
let key = navigationState.key;
let index = key.substring(0, 1);
return index != 0;
}
... ...
... ... @@ -7,17 +7,13 @@ export default function timeago(timestamp) {
let timeagoStr = TA().format(timestamp, 'zh_CN');
let isNSecondsAgo = timeagoStr.indexOf('秒');
if (timeagoStr === '刚刚' || isNSecondsAgo !== -1) {
return '1分钟前';
}
if (timeagoStr === '1天前') {
return '昨天';
if (timeagoStr === '刚刚' || timeagoStr === '1分钟前' || isNSecondsAgo !== -1) {
return '刚刚';
}
let isNDaysAgo = timeagoStr.indexOf('天');
if (isNDaysAgo !== -1) {
return moment(timestamp, 'x').format('YYYY-M-D');
if (timeagoStr === '1天前' || isNDaysAgo !== -1) {
return moment(timestamp, 'x').format('MM.DD.YYYY');
}
return timeagoStr;
... ...