Authored by 王钱钧

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

@@ -22,6 +22,10 @@ export default class SlicedImage extends React.Component { @@ -22,6 +22,10 @@ export default class SlicedImage extends React.Component {
22 this.mode = 1; 22 this.mode = 1;
23 } 23 }
24 24
  25 + setNativeProps(nativeProps) {
  26 + this._root.setNativeProps(nativeProps);
  27 + }
  28 +
25 _generateImageUrl(src) { 29 _generateImageUrl(src) {
26 let style = StyleSheet.flatten(this.props.style); 30 let style = StyleSheet.flatten(this.props.style);
27 let {width, height} = style; 31 let {width, height} = style;
@@ -55,12 +59,12 @@ export default class SlicedImage extends React.Component { @@ -55,12 +59,12 @@ export default class SlicedImage extends React.Component {
55 if (source && source.uri && this._isRemoteImageSrc(source.uri)) { 59 if (source && source.uri && this._isRemoteImageSrc(source.uri)) {
56 let uri = this._generateImageUrl(source.uri); 60 let uri = this._generateImageUrl(source.uri);
57 return ( 61 return (
58 - <Image {...this.props} source={{uri}}/> 62 + <Image ref={component => this._root = component} {...this.props} source={{uri}}/>
59 ); 63 );
60 } 64 }
61 65
62 return ( 66 return (
63 - <Image {...this.props}/> 67 + <Image ref={component => this._root = component} {...this.props}/>
64 ); 68 );
65 } 69 }
66 } 70 }
@@ -338,18 +338,6 @@ export default function community(platform) { @@ -338,18 +338,6 @@ export default function community(platform) {
338 state.dispatch(startEditPost(state.getPostingState())); 338 state.dispatch(startEditPost(state.getPostingState()));
339 }, 339 },
340 340
341 - pushPostingWithUID(uid) {  
342 - new PostingService().getPostUser(uid).then(json => {  
343 - if (json.forbidSpeaking === 'Y') {  
344 - Alert.alert('抱歉','您暂时被禁言,请等待禁言解除哦~');  
345 - } else {  
346 - Actions.Posting();  
347 - }  
348 - }).catch(error => {  
349 - Actions.Posting();  
350 - });  
351 - },  
352 -  
353 /* 341 /*
354 * 自定义导航push动画 342 * 自定义导航push动画
355 * 343 *
@@ -60,7 +60,7 @@ export default class ListCell extends React.Component { @@ -60,7 +60,7 @@ export default class ListCell extends React.Component {
60 let data = this.props.data.toJS(); 60 let data = this.props.data.toJS();
61 let {author, timeago, isOwner, isTop, isLike, title, desc, thumbs, section, commentCount, likeCount} = data; 61 let {author, timeago, isOwner, isTop, isLike, title, desc, thumbs, section, commentCount, likeCount} = data;
62 let likeImage = isLike ? require('../../images/home/like.png') : require('../../images/home/unlike.png'); 62 let likeImage = isLike ? require('../../images/home/like.png') : require('../../images/home/unlike.png');
63 - 63 +
64 return ( 64 return (
65 <TouchableOpacity 65 <TouchableOpacity
66 style={styles.row} 66 style={styles.row}
@@ -82,16 +82,9 @@ export default class ListCell extends React.Component { @@ -82,16 +82,9 @@ export default class ListCell extends React.Component {
82 /> 82 />
83 {isTop ? <Text style={styles.topTag}>置顶</Text> : null} 83 {isTop ? <Text style={styles.topTag}>置顶</Text> : null}
84 </View> 84 </View>
85 - <Text style={styles.title} numberOfLines={2}>  
86 - {title}  
87 - </Text>  
88 - <Text style={styles.desc} numberOfLines={2}>  
89 - {desc}  
90 - </Text>  
91 - <Thumbs  
92 - style={styles.thumbs}  
93 - data={thumbs}  
94 - /> 85 + {title ? <Text style={styles.title} numberOfLines={2}>{title}</Text> : null}
  86 + {desc ? <Text style={styles.desc} numberOfLines={2}>{desc}</Text> : null}
  87 + {thumbs.length > 0 ? <Thumbs style={styles.thumbs} data={thumbs}/> : null}
95 <View style={styles.bottom}> 88 <View style={styles.bottom}>
96 <SectionItem 89 <SectionItem
97 name={section.name} 90 name={section.name}
@@ -155,11 +148,11 @@ let styles = StyleSheet.create({ @@ -155,11 +148,11 @@ let styles = StyleSheet.create({
155 }, 148 },
156 thumbs: { 149 thumbs: {
157 marginTop: 15, 150 marginTop: 15,
158 - marginBottom: 15,  
159 }, 151 },
160 bottom: { 152 bottom: {
161 flexDirection: 'row', 153 flexDirection: 'row',
162 justifyContent: 'space-between', 154 justifyContent: 'space-between',
  155 + marginTop: 15,
163 marginBottom: 15, 156 marginBottom: 15,
164 }, 157 },
165 buttonContainer: { 158 buttonContainer: {
@@ -54,13 +54,14 @@ export default class SuperMan extends React.Component { @@ -54,13 +54,14 @@ export default class SuperMan extends React.Component {
54 render() { 54 render() {
55 let avatarContainerStyle = this.props.uid > 0 ? styles.avatarContainer : null; 55 let avatarContainerStyle = this.props.uid > 0 ? styles.avatarContainer : null;
56 let avatarStyle = this.props.uid > 0 ? styles.avatarBorder : null; 56 let avatarStyle = this.props.uid > 0 ? styles.avatarBorder : null;
  57 + let defaultSource = this.props.uid > 0 ? null : require('../../images/home/superman.png');
57 return ( 58 return (
58 <View style={[styles.container, this.props.fly]}> 59 <View style={[styles.container, this.props.fly]}>
59 <TouchableOpacity activeOpacity={0.8} onPress={() => { 60 <TouchableOpacity activeOpacity={0.8} onPress={() => {
60 this.props.onSaveingTheWorld && this.props.onSaveingTheWorld(); 61 this.props.onSaveingTheWorld && this.props.onSaveingTheWorld();
61 }}> 62 }}>
62 <View style={avatarContainerStyle}> 63 <View style={avatarContainerStyle}>
63 - <SlicedImage style={[styles.avatar, avatarStyle]} source={{uri: this.props.avatar}} resizeMode={'cover'} defaultSource={require('../../images/home/superman.png')}/> 64 + <SlicedImage style={[styles.avatar, avatarStyle]} source={{uri: this.props.avatar}} resizeMode={'cover'} defaultSource={defaultSource}/>
64 </View> 65 </View>
65 {this.renderText()} 66 {this.renderText()}
66 {this.renderMsgCount()} 67 {this.renderMsgCount()}
@@ -80,7 +80,6 @@ export default class UploadProgress extends React.Component { @@ -80,7 +80,6 @@ export default class UploadProgress extends React.Component {
80 } 80 }
81 81
82 return ( 82 return (
83 -  
84 <Animated.View style={[styles.container, {opacity: this.state.fadeAnim,}]}> 83 <Animated.View style={[styles.container, {opacity: this.state.fadeAnim,}]}>
85 <Image 84 <Image
86 style={styles.image} 85 style={styles.image}
@@ -99,7 +98,7 @@ export default class UploadProgress extends React.Component { @@ -99,7 +98,7 @@ export default class UploadProgress extends React.Component {
99 style={styles.bar} 98 style={styles.bar}
100 /> 99 />
101 {this._renderButton(uploadState)} 100 {this._renderButton(uploadState)}
102 - </Animated.View > 101 + </Animated.View>
103 ); 102 );
104 } 103 }
105 104
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 import React from 'react'; 3 import React from 'react';
4 import ReactNative from 'react-native'; 4 import ReactNative from 'react-native';
5 import ImmutablePropTypes from 'react-immutable-proptypes'; 5 import ImmutablePropTypes from 'react-immutable-proptypes';
  6 +import SlicedImage from '../../../common/components/SlicedImage';
6 7
7 const { 8 const {
8 View, 9 View,
@@ -44,7 +45,7 @@ export default class UserCenterTop extends React.Component { @@ -44,7 +45,7 @@ export default class UserCenterTop extends React.Component {
44 this.props.onPressBackgroundImg && this.props.onPressBackgroundImg(); 45 this.props.onPressBackgroundImg && this.props.onPressBackgroundImg();
45 }} 46 }}
46 > 47 >
47 - <Image 48 + <SlicedImage
48 style={styles.backgroundImage} 49 style={styles.backgroundImage}
49 defaultSource={require('../../images/user-bg.png')} 50 defaultSource={require('../../images/user-bg.png')}
50 source={{uri:backgroundImage}} 51 source={{uri:backgroundImage}}
@@ -54,12 +55,11 @@ export default class UserCenterTop extends React.Component { @@ -54,12 +55,11 @@ export default class UserCenterTop extends React.Component {
54 this.props.onPressUserAvatar && this.props.onPressUserAvatar(); 55 this.props.onPressUserAvatar && this.props.onPressUserAvatar();
55 }} 56 }}
56 > 57 >
57 - <Image 58 + <SlicedImage
58 style={styles.avatarImage} 59 style={styles.avatarImage}
59 defaultSource={require('../../images/avatar-default.png')} 60 defaultSource={require('../../images/avatar-default.png')}
60 source={{uri:avatar}} 61 source={{uri:avatar}}
61 - >  
62 - </Image> 62 + />
63 </TouchableOpacity> 63 </TouchableOpacity>
64 <Text 64 <Text
65 style={styles.name} 65 style={styles.name}
@@ -72,7 +72,7 @@ export default class UserCenterTop extends React.Component { @@ -72,7 +72,7 @@ export default class UserCenterTop extends React.Component {
72 > 72 >
73 {sign} 73 {sign}
74 </Text> 74 </Text>
75 - </Image> 75 + </SlicedImage>
76 </TouchableHighlight> 76 </TouchableHighlight>
77 </View> 77 </View>
78 ); 78 );
@@ -64,14 +64,16 @@ class PostingContainer extends Component{ @@ -64,14 +64,16 @@ class PostingContainer extends Component{
64 } 64 }
65 65
66 componentDidMount() { 66 componentDidMount() {
67 - if (this.props.section.name.length && this.props.section.id>0) {  
68 - this.boardSelectedWithName(this.props.section.name,this.props.section.id);  
69 67
70 - }else { 68 + if (this.props.section.sid>-1) {
  69 + let section = this.props.section.items.get(this.props.section.sid);
  70 + this.boardSelectedWithName(section.name,section.id);
  71 + } else {
71 InteractionManager.runAfterInteractions(() => { 72 InteractionManager.runAfterInteractions(() => {
72 this._onGetBordList(); 73 this._onGetBordList();
73 }); 74 });
74 } 75 }
  76 +
75 if (shouldHideTabBar(this.props.navigationState)) { 77 if (shouldHideTabBar(this.props.navigationState)) {
76 NativeModules.YH_CommunityHelper.hideTabBar(); 78 NativeModules.YH_CommunityHelper.hideTabBar();
77 } 79 }
@@ -120,6 +122,12 @@ class PostingContainer extends Component{ @@ -120,6 +122,12 @@ class PostingContainer extends Component{
120 this.props.actions.contentEdited (content); 122 this.props.actions.contentEdited (content);
121 } 123 }
122 render() { 124 render() {
  125 + let fromSection=false;
  126 + if (this.props.section.sid>-1) {
  127 + let section = this.props.section.items.get(this.props.section.sid);
  128 + fromSection = section.name.length && section.id>0;
  129 + }
  130 +
123 return( 131 return(
124 <View style={styles.container}> 132 <View style={styles.container}>
125 <Posting 133 <Posting
@@ -132,7 +140,7 @@ class PostingContainer extends Component{ @@ -132,7 +140,7 @@ class PostingContainer extends Component{
132 contentEdited={this.contentEdited} 140 contentEdited={this.contentEdited}
133 titleValue={this.props.posting.title} 141 titleValue={this.props.posting.title}
134 contentValue={this.props.posting.content} 142 contentValue={this.props.posting.content}
135 - fromSection={this.props.section.name.length && this.props.section.id>0} 143 + fromSection={fromSection}
136 /> 144 />
137 </View> 145 </View>
138 ); 146 );
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 8
9 import ReactNative from 'react-native'; 9 import ReactNative from 'react-native';
10 import {Actions} from 'react-native-router-flux'; 10 import {Actions} from 'react-native-router-flux';
  11 +import Immutable, {Map} from 'immutable';
11 import AppService from '../../services/AppService'; 12 import AppService from '../../services/AppService';
12 import RouterService from '../../services/RouterService'; 13 import RouterService from '../../services/RouterService';
13 import {goToSection, goToPost} from '../home/homeActions'; 14 import {goToSection, goToPost} from '../home/homeActions';
@@ -42,43 +43,41 @@ export function setChannel(channel) { @@ -42,43 +43,41 @@ export function setChannel(channel) {
42 43
43 export function goAction(inputUrl) { 44 export function goAction(inputUrl) {
44 return (dispatch, getState) => { 45 return (dispatch, getState) => {
45 - return new RouterService().parseUrl(inputUrl)  
46 - .then((json) => {  
47 - let {action, params} = json;  
48 - let {param, share, shareparam, title, url} = params; 46 + let json = new RouterService().parseUrl(inputUrl);
  47 + let {action, params} = json;
  48 + let {param, share, shareparam, title, url} = params;
49 49
50 - if (action == 'go.comm.forum') {  
51 - let id = params && params.forumid ? params.forumid : 0;  
52 - let name = '';  
53 - if (id != 0) {  
54 - dispatch(goToSection({id, name}));  
55 - } 50 + if (action == 'go.comm.forum') {
  51 + let id = params && params.forumid ? params.forumid : 0;
  52 + let name = '';
  53 + if (id != 0) {
  54 + dispatch(goToSection({id, name}));
  55 + }
56 56
57 - } else if (action == 'go.comm.postdetail') {  
58 - let id = params && params.postid ? params.postid : 0;  
59 - if (id != 0) {  
60 - dispatch(goToPost(id));  
61 - } 57 + } else if (action == 'go.comm.postdetail') {
  58 + let id = params && params.postid ? params.postid : 0;
  59 + if (id == 0) {
  60 + id = params && params.postId ? params.postId : 0;
  61 + }
  62 + if (id != 0) {
  63 + dispatch(goToPost(id));
  64 + }
62 65
63 - } else if (action == 'go.comm.h5') {  
64 - let title = params.title ? params.title : '';  
65 - let url = params.url ? params.url : '';  
66 - if (!url || url.length == 0) {  
67 - return;  
68 - }  
69 - ReactNative.NativeModules.YH_CommunityHelper.displayH5({url, title});  
70 - } else if (action == 'go.comm.productDetail') {  
71 - let productSkn = params.product_skn ? params.product_skn : '';  
72 - productSkn = productSkn + '';  
73 - let tag = params.tag ? params.tag : '';  
74 - if (!productSkn || productSkn.length == 0) {  
75 - return;  
76 - }  
77 - ReactNative.NativeModules.YH_CommunityHelper.displayProductDetail({productSkn, tag});  
78 - }  
79 - })  
80 - .catch(error => {  
81 - __DEV__ && console.log(error);  
82 - }); 66 + } else if (action == 'go.comm.h5') {
  67 + let title = params.title ? params.title : '';
  68 + let url = params.url ? params.url : '';
  69 + if (!url || url.length == 0) {
  70 + return;
  71 + }
  72 + ReactNative.NativeModules.YH_CommunityHelper.displayH5({url, title});
  73 + } else if (action == 'go.comm.productDetail') {
  74 + let productSkn = params.product_skn ? params.product_skn : '';
  75 + productSkn = productSkn + '';
  76 + let tag = params.tag ? params.tag : '';
  77 + if (!productSkn || productSkn.length == 0) {
  78 + return;
  79 + }
  80 + ReactNative.NativeModules.YH_CommunityHelper.displayProductDetail({productSkn, tag});
  81 + }
83 }; 82 };
84 } 83 }
@@ -277,14 +277,6 @@ export function resetErrorCount() { @@ -277,14 +277,6 @@ export function resetErrorCount() {
277 }; 277 };
278 } 278 }
279 279
280 -export function goToSection(section) {  
281 - Actions.Section();  
282 - return {  
283 - type: GO_TO_SECTION,  
284 - payload: section,  
285 - };  
286 -}  
287 -  
288 export function goToUser(user, previousScene) { 280 export function goToUser(user, previousScene) {
289 Actions.User(); 281 Actions.User();
290 return { 282 return {
@@ -70,9 +70,13 @@ function drillToEditPostPage(uid,postingPageFunc) { @@ -70,9 +70,13 @@ function drillToEditPostPage(uid,postingPageFunc) {
70 if (json.forbidSpeaking === 'Y') { 70 if (json.forbidSpeaking === 'Y') {
71 Alert.alert('抱歉','您暂时被禁言,请等待禁言解除哦~'); 71 Alert.alert('抱歉','您暂时被禁言,请等待禁言解除哦~');
72 } else { 72 } else {
  73 + console.log('yyyyyyyyyyyyyyyyyyy');
  74 +
73 Actions.Posting(); 75 Actions.Posting();
74 } 76 }
75 }).catch(error => { 77 }).catch(error => {
  78 + console.log('eeeeeeeeeeeeeee');
  79 + console.log(error);
76 Actions.Posting(); 80 Actions.Posting();
77 }) 81 })
78 } 82 }
@@ -8,7 +8,7 @@ export default class RouterService { @@ -8,7 +8,7 @@ export default class RouterService {
8 this.api = new Request(); 8 this.api = new Request();
9 } 9 }
10 10
11 - parseUrl(url) { 11 + parseUrlWithPromise(url) {
12 return new Promise((resolve, reject) => { 12 return new Promise((resolve, reject) => {
13 if (!url) { 13 if (!url) {
14 reject('Illegal url: ' + url); 14 reject('Illegal url: ' + url);
@@ -39,4 +39,34 @@ export default class RouterService { @@ -39,4 +39,34 @@ export default class RouterService {
39 } 39 }
40 }); 40 });
41 } 41 }
  42 +
  43 + parseUrl(url) {
  44 + if (!url) {
  45 + __DEV__ && console.log('Illegal url: ' + url);
  46 + }
  47 +
  48 + // url解码
  49 + url = decodeURI(url);
  50 + // 处理半角等号和全角等号
  51 + let mark = 'yohobuy=';
  52 + let markIndex = url.indexOf(mark);
  53 + if (markIndex == -1) {
  54 + mark = 'yohobuy=';
  55 + markIndex = url.indexOf(mark);
  56 + }
  57 +
  58 + if (markIndex == -1) {
  59 + __DEV__ && console.log('Can not find url rule: ' + url);
  60 + }
  61 +
  62 + let rule = url.substring(markIndex + mark.length);
  63 +
  64 + let json;
  65 + try {
  66 + json = JSON.parse(rule);
  67 + return json;
  68 + } catch (e) {
  69 + __DEV__ && console.log('Parse json string fail: ' + e);
  70 + }
  71 + }
42 } 72 }
@@ -7,12 +7,16 @@ export default function timeago(timestamp) { @@ -7,12 +7,16 @@ export default function timeago(timestamp) {
7 let timeagoStr = TA().format(timestamp, 'zh_CN'); 7 let timeagoStr = TA().format(timestamp, 'zh_CN');
8 8
9 let isNSecondsAgo = timeagoStr.indexOf('秒'); 9 let isNSecondsAgo = timeagoStr.indexOf('秒');
10 - if (timeagoStr === '刚刚' || timeagoStr === '1分钟前' || isNSecondsAgo !== -1) {  
11 - return '刚刚'; 10 + if (timeagoStr === '刚刚' || isNSecondsAgo !== -1) {
  11 + return '1分钟前';
  12 + }
  13 +
  14 + if (timeagoStr === '1天前') {
  15 + return '昨天';
12 } 16 }
13 17
14 let isNDaysAgo = timeagoStr.indexOf('天'); 18 let isNDaysAgo = timeagoStr.indexOf('天');
15 - if (timeagoStr === '1天前' || isNDaysAgo !== -1) { 19 + if (isNDaysAgo !== -1) {
16 return moment(timestamp, 'x').format('MM.DD.YYYY'); 20 return moment(timestamp, 'x').format('MM.DD.YYYY');
17 } 21 }
18 22