Browse Source

feat: support displaying topic detail

YooMooc is now actually usable!
🎉🎉🎉
pull/1/head 0.0.1a
kdxcxs 4 years ago
parent
commit
ce0b7a1a1a
  1. 15
      README.md
  2. 42
      src/component/YooForumTopic.js
  3. 1
      src/ui/YooForumTopicUI.js
  4. 45
      src/ui/YooForumUI.js
  5. 28
      src/ui/YooReply.js

15
README.md

@ -4,11 +4,19 @@
![screenshot](./screenshot.jpg)
## 🎞背景
## 🎞 背景
无论是电脑版还是手机版的优慕课客户端用起来似乎都不是那么令人满意,电脑版在课程页面只能看到标题不能看到详情,手机版从详情页退出后会回到最顶端。于是就有了做一个第三方客户端的想法,也当是 React Native 的一次练手了
## 📄TODO
## 🧨 版本说明
| 版本 | 说明 |
| ------ | ------------ |
| 0.0.1a | 首个可用版本 |
## 📄 TODO
- [ ] 弹出键盘不遮挡输入框
- [ ] 根据像素比例设置登录背景图片大小
@ -19,4 +27,7 @@
- [ ] Forum 初始化失败后 UI 显示错误信息
- [ ] 当数据获取完成后通过动画转到话题列表
- [ ] 解决当动画进行时点击话题标题动画会被打断的问题
- [ ] 支持显示回复图片
- [ ] 在回复中显示头像
- [ ] 当滑动到页面底部时显示"加载更多"

42
src/component/YooForumTopic.js

@ -1,13 +1,55 @@
import React, {Component} from 'react';
import YooForumTopicUI from '../ui/YooForumTopicUI';
import {gbkFetch} from '../api/HTTP';
import * as cheerio from 'cheerio';
export default class YooForumTopic extends Component {
constructor(props) {
super(props);
this.state = {
replies: [],
};
this.getReplies = this.getReplies.bind(this);
}
componentDidMount() {
this.getReplies();
}
getReplies() {
gbkFetch(
'GET',
`http://eol.ctbu.edu.cn/meol/common/faq/thread.jsp?threadid=${this.props.topic.threadID}`,
{
headers: 'YooMooc',
},
).then((response) => {
const newReplies = [];
const appendReply = (username, content) => {
newReplies.push({username, content});
};
const $ = cheerio.load(response, {ignoreWhitespace: true});
$('input[type=hidden]').each(function () {
const current = $(this);
const currentUserInfo = current.parent().parent().parent().parent();
if (currentUserInfo.html().slice(2, 4) === 'td') {
appendReply(
currentUserInfo.find('h6').text().split(' ')[1],
cheerio.load(current.attr('value')).text(),
);
}
});
this.setState({replies: [...this.state.replies, ...newReplies]});
});
}
render() {
return (
<YooForumTopicUI
topic={this.props.topic}
showDetail={this.props.showDetail}
hideDetail={this.props.hideDetail}
replies={this.state.replies}
/>
);
}

1
src/ui/YooForumTopicUI.js

@ -49,6 +49,7 @@ export default class YooForumTopicUI extends Component {
this.state.translate,
this.state.layoutY,
this.onAnimationFinished,
this.props.replies,
);
} else {
this.props.hideDetail(this.state.translate, this.onAnimationFinished);

45
src/ui/YooForumUI.js

@ -1,4 +1,4 @@
import React, {Component} from 'react';
import React, {Component, createRef} from 'react';
import {
View,
ScrollView,
@ -10,13 +10,21 @@ import {
Dimensions,
} from 'react-native';
import YooForumTopic from '../component/YooForumTopic';
import YooReply from './YooReply';
const screenWidth = Dimensions.get('window').width;
const screenHeight = Dimensions.get('window').height;
const AnimatedScrollView = Animated.createAnimatedComponent(ScrollView);
const styles = StyleSheet.create({
container: {
width: screenWidth * 2,
},
repliesContainer: {
position: 'absolute',
left: screenWidth,
width: screenWidth,
height: screenHeight - 124,
},
hintContainer: {
flex: 1,
alignItems: 'center',
@ -44,13 +52,23 @@ export default class YooForumUI extends Component {
scrollEnabled: true,
currentPosition: 0,
translateX: new Animated.Value(0),
currentReplies: [],
replyTranslateY: new Animated.Value(0),
};
this.replyRef = createRef();
this.showDetail = this.showDetail.bind(this);
this.hideDetail = this.hideDetail.bind(this);
}
showDetail(translate, layoutY, onAnimationFinished) {
this.setState({scrollEnabled: false});
showDetail(translate, layoutY, onAnimationFinished, replies) {
this.replyRef.current.scrollTo({x: 0, y: 0, animated: false});
this.setState({
scrollEnabled: false,
currentReplies: replies,
});
this.state.replyTranslateY.setValue(
this.state.currentPosition + 100 + screenHeight,
);
Animated.parallel([
Animated.timing(translate, {
toValue: {
@ -65,6 +83,12 @@ export default class YooForumUI extends Component {
duration: 250,
useNativeDriver: true,
}),
Animated.timing(this.state.replyTranslateY, {
toValue: this.state.currentPosition + 100,
duration: 250,
delay: 250,
useNativeDriver: true,
}),
]).start(onAnimationFinished);
}
@ -84,6 +108,11 @@ export default class YooForumUI extends Component {
duration: 250,
useNativeDriver: true,
}),
Animated.timing(this.state.replyTranslateY, {
toValue: this.state.currentPosition + 100 + screenHeight,
duration: 250,
useNativeDriver: true,
}),
]).start(onAnimationFinished);
}
@ -127,6 +156,16 @@ export default class YooForumUI extends Component {
/>
</View>
)}
<AnimatedScrollView
ref={this.replyRef}
style={[
styles.repliesContainer,
{transform: [{translateY: this.state.replyTranslateY}]},
]}>
{this.state.currentReplies.map((reply, key) => (
<YooReply key={key} reply={reply} />
))}
</AnimatedScrollView>
</AnimatedScrollView>
);
}

28
src/ui/YooReply.js

@ -0,0 +1,28 @@
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
const styles = StyleSheet.create({
container: {
backgroundColor: 'lightgray',
borderRadius: 8,
padding: 16,
margin: 8,
},
username: {
fontSize: 16,
},
content: {
fontSize: 24,
},
});
export default class YooReply extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.username}>{this.props.reply.username}</Text>
<Text style={styles.content}>{this.props.reply.content}</Text>
</View>
);
}
}
Loading…
Cancel
Save