From 2951ea054cc85e4f4deaa1a9840e57ebcd84e2b8 Mon Sep 17 00:00:00 2001 From: xuwenyang Date: Wed, 8 May 2019 21:27:37 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E6=8F=90=E5=87=BA=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E7=BB=84=E4=BB=B6=202.=20=E6=8F=90=E5=87=BA?= =?UTF-8?q?=E5=8D=95=E6=9D=A1=E6=97=A5=E8=AE=B0=E7=BB=84=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E5=88=86=E4=B8=BA=E6=91=98=E8=A6=81=E6=A8=A1=E5=BC=8F=E5=92=8C?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E6=A8=A1=E5=BC=8F=EF=BC=88=E6=9C=AA=E5=AE=8C?= =?UTF-8?q?=E6=88=90=EF=BC=89=203.=20=E9=A6=96=E9=A1=B5=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=88=9D=E6=AD=A5=E6=88=90=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 10 +++ package.json | 2 + src/component/diary/diaryBrief.js | 75 ++++++++++++++++ src/component/diary/diaryFull.js | 75 ++++++++++++++++ src/component/diary/userIcon.js | 29 +++++++ src/component/loading.js | 3 +- src/component/loginForm.js | 2 - src/component/touchable.js | 22 +++++ src/entity/homeListData.js | 39 +++++++++ src/page/HomePage.js | 137 ++++++++++++++++++++++-------- src/util/api.js | 35 +++++--- 11 files changed, 380 insertions(+), 49 deletions(-) create mode 100644 src/component/diary/diaryBrief.js create mode 100644 src/component/diary/diaryFull.js create mode 100644 src/component/diary/userIcon.js create mode 100644 src/component/touchable.js create mode 100644 src/entity/homeListData.js diff --git a/package-lock.json b/package-lock.json index 7b02bc0..8d80773 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9830,6 +9830,11 @@ } } }, + "moment": { + "version": "2.24.0", + "resolved": "http://registry.npm.taobao.org/moment/download/moment-2.24.0.tgz", + "integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s=" + }, "morgan": { "version": "1.9.1", "resolved": "http://registry.npm.taobao.org/morgan/download/morgan-1.9.1.tgz", @@ -10814,6 +10819,11 @@ "prop-types": "^15.5.8" } }, + "react-native-iphone-x-helper": { + "version": "1.0.2", + "resolved": "http://registry.npm.taobao.org/react-native-iphone-x-helper/download/react-native-iphone-x-helper-1.0.2.tgz", + "integrity": "sha1-fbylMJMPfBzoYzzI/RO6lBApkuE=" + }, "react-native-navigation": { "version": "1.1.376", "resolved": "https://registry.npm.taobao.org/react-native-navigation/download/react-native-navigation-1.1.376.tgz", diff --git a/package.json b/package.json index 0ade7a3..8a348a7 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,12 @@ "dependencies": { "@react-native-community/async-storage": "^1.3.4", "base-64": "^0.1.0", + "moment": "^2.24.0", "react": "16.8.3", "react-native": "0.59.5", "react-native-device-info": "^1.6.1", "react-native-elements": "^0.19.0", + "react-native-iphone-x-helper": "^1.0.2", "react-native-navigation": "^1.1.376", "react-native-vector-icons": "^4.5.0" }, diff --git a/src/component/diary/diaryBrief.js b/src/component/diary/diaryBrief.js new file mode 100644 index 0000000..8805f9e --- /dev/null +++ b/src/component/diary/diaryBrief.js @@ -0,0 +1,75 @@ +import React, {Component} from 'react'; +import {Platform, StyleSheet, Text, View} from 'react-native'; +import moment from 'moment' + +import Color from '../../style/color' +import UserIcon from './userIcon' + + +export default class DiaryBrief extends Component { + + render() { + let diary = this.props.diary; + let user = diary.user; + + return ( + + + + + + {user.name} + + + 《{diary.notebook_subject}》 + + + {moment(diary.created).format('H:mm')} + + + + + {diary.content.trim()} + + + + ); + } +} + +const localStyle = StyleSheet.create({ + box: { + flexDirection: "row", + overflow: "hidden", + paddingHorizontal: 15, + paddingTop: 15 + }, + body: { + flexDirection: "column", + flexGrow: 1, + flexShrink: 1, + paddingTop: 2 + }, + title: { + flexDirection: "row", + alignItems: "flex-end", + paddingBottom: 5 + }, + titleName: { + fontWeight: 'bold', + color: Color.text, + fontSize: 14 + }, + titleText: { + fontSize: 12, + color: Color.inactiveText + }, + content: { + flexGrow: 1, + lineHeight: 24, + color: Color.text, + fontSize: 15, + textAlignVertical: 'bottom', + paddingBottom: 15 + } +}); diff --git a/src/component/diary/diaryFull.js b/src/component/diary/diaryFull.js new file mode 100644 index 0000000..9320b1f --- /dev/null +++ b/src/component/diary/diaryFull.js @@ -0,0 +1,75 @@ +import React, {Component} from 'react'; +import {Platform, StyleSheet, Text, View} from 'react-native'; +import moment from 'moment' + +import Color from '../../style/color' +import UserIcon from './userIcon' + + +export default class DiaryFull extends Component { + + render() { + let diary = this.props.diary; + let user = diary.user; + + return ( + + + + + + {user.name} + + + 《{diary.notebook_subject}》 + + + {moment(diary.created).format('H:mm')} + + + + + {diary.content} + + + + ); + } +} + +const localStyle = StyleSheet.create({ + box: { + flexDirection: "row", + overflow: "hidden", + paddingHorizontal: 15, + paddingTop: 15 + }, + body: { + flexDirection: "column", + flexGrow: 1, + flexShrink: 1, + paddingTop: 2 + }, + title: { + flexDirection: "row", + alignItems: "flex-end", + paddingBottom: 5 + }, + titleName: { + fontWeight: 'bold', + color: Color.text, + fontSize: 14 + }, + titleText: { + fontSize: 12, + color: Color.inactiveText + }, + content: { + flexGrow: 1, + lineHeight: 24, + color: Color.text, + fontSize: 15, + textAlignVertical: 'bottom', + paddingBottom: 15 + } +}); diff --git a/src/component/diary/userIcon.js b/src/component/diary/userIcon.js new file mode 100644 index 0000000..694b7f5 --- /dev/null +++ b/src/component/diary/userIcon.js @@ -0,0 +1,29 @@ +import React, {Component} from 'react'; +import {Platform, StyleSheet, Text, View} from 'react-native'; +import {Avatar} from "react-native-elements"; + + +export default class UserIcon extends Component { + + _defaultOnPress() { + // empty + } + + render() { + return ( + + ); + } +} + +const localStyle = StyleSheet.create({ + container: { + marginTop: 3, + marginRight: 8, + } +}); diff --git a/src/component/loading.js b/src/component/loading.js index a0cba0c..9ee2543 100644 --- a/src/component/loading.js +++ b/src/component/loading.js @@ -38,9 +38,8 @@ const styles = StyleSheet.create({ loading: { position: "absolute", left: 0, - top: 0, width: width, - height: 400, + top: 200, justifyContent: "center", alignItems: "center" } diff --git a/src/component/loginForm.js b/src/component/loginForm.js index b3b2251..e2399dd 100644 --- a/src/component/loginForm.js +++ b/src/component/loginForm.js @@ -71,8 +71,6 @@ export default class LoginForm extends Component { render() {return ( - - {'欢迎来到胶囊日记'} diff --git a/src/component/touchable.js b/src/component/touchable.js new file mode 100644 index 0000000..813ceee --- /dev/null +++ b/src/component/touchable.js @@ -0,0 +1,22 @@ +import React from "react"; +import {Platform, TouchableNativeFeedback, TouchableOpacity, View} from "react-native"; + + +let TouchableIOS = (props) => { + return +}; + +let TouchableAndroid = (props) => { + return ( + + + {props.children} + + + ) +}; + +const Touchable = Platform.OS === 'android' ? TouchableAndroid : TouchableIOS; +Touchable.propTypes = (Platform.OS === 'android' ? null : TouchableOpacity.propTypes); + +export default Touchable \ No newline at end of file diff --git a/src/entity/homeListData.js b/src/entity/homeListData.js new file mode 100644 index 0000000..bc3a591 --- /dev/null +++ b/src/entity/homeListData.js @@ -0,0 +1,39 @@ +import Api from '../util/api' + + +const PAGE_SIZE = 21; + +export default class HomeListData { + + list: []; + last_id: 0; + + async refresh() { + this.last_id = 0; + + let data = await Api.getTodayDiaries(0, PAGE_SIZE, this.last_id); + let more = data.diaries.length === PAGE_SIZE; + this.list = data.diaries.slice(0, PAGE_SIZE - 1); + this.last_id = more ? data.diaries[PAGE_SIZE - 1].id : 0; + + return { + list: this.list, + more + }; + } + + async load_more() { + let data = await Api.getTodayDiaries(0, PAGE_SIZE, this.last_id); + let more = data.diaries.length === PAGE_SIZE; + + if (data.diaries.length > 0) { + this.list = this.list.concat(data.diaries.slice(0, PAGE_SIZE - 1)); + } + this.last_id = more ? data.diaries[PAGE_SIZE - 1].id : 0; + + return { + list: this.list, + more + }; + } +} \ No newline at end of file diff --git a/src/page/HomePage.js b/src/page/HomePage.js index efe2d49..12c141a 100644 --- a/src/page/HomePage.js +++ b/src/page/HomePage.js @@ -1,50 +1,119 @@ import React, {Component} from 'react'; -import {Platform, StyleSheet, Text, View} from 'react-native'; +import { + ActivityIndicator, + FlatList, + InteractionManager, Platform, StyleSheet, Text, TouchableOpacity, View, + Alert, + Dimensions +} from 'react-native'; +import {Divider} from "react-native-elements"; +import {isIphoneX} from 'react-native-iphone-x-helper' +import Loading from '../component/loading' +import Touchable from '../component/touchable' +import DiaryBrief from '../component/diary/diaryBrief' +import DiaryFull from '../component/diary/diaryFull' +import HomeListData from '../entity/homeListData'; + + +const isIpx = isIphoneX(); +const isAndroid = Platform.OS === 'android'; +const HEADER_PADDING = Platform.OS === 'android' ? 20 : (isIpx ? 10 : 25); +const { width, height } = Dimensions.get('window') export default class HomePage extends Component { - - onPress() { + constructor(props) { + super(props); + + this.dataSource = new HomeListData(); + this.state = { + isLoading: true, + diaries: [] + }; + } + + componentDidMount() { + InteractionManager.runAfterInteractions(() => { + this.refresh() + .then(data => { + console.log('homepage data:', data); + + this.setState({ + isLoading: false, + diaries: data && data.list ? data.list : [] + }); + + }).catch(e => { + if (e.code && e.code === 401) { + this.props.navigator.showModal({ + screen: "App" + }); + + this.setState({ + diaries: [] + }); + } + }); + }); + } + + async refresh() { + return await this.dataSource.refresh(); + } + + _onDiaryPress(diary) { /* this.props.navigator.push({ - screen: 'Home' - }); - - Navigation.startSingleScreenApp({ - screen: { - screen: 'Home', - title: 'Home Title', - } + screen: 'DiaryDetail', + title: '日记详情', + passProps: { diary: diary } }); */ } - render() { - return ( - - Home Page ! - - ); + return ( + + + + { + return item.id.toString() + }} + + renderItem={({item}) => { + return ( + this._onDiaryPress(item)}> + + + ) + }} + + ItemSeparatorComponent={({highlighted}) => } + + automaticallyAdjustContentInsets={true} + onEndReachedThreshold={2} + /> + + ); } } -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - welcome: { - fontSize: 20, - textAlign: 'center', - margin: 10, - }, - instructions: { - textAlign: 'center', - color: '#333333', - marginBottom: 5, - }, +const localStyle = StyleSheet.create({ + wrap: { + position: 'absolute', + backgroundColor: '#fff', + flex: 1, + top: 0, + bottom: 0, + paddingTop: isIpx || isAndroid ? 44 : 20 + }, + list: { + backgroundColor: 'white', + height: '100%' + } }); diff --git a/src/util/api.js b/src/util/api.js index 12d8b0e..b53c12f 100644 --- a/src/util/api.js +++ b/src/util/api.js @@ -35,6 +35,19 @@ async function getSelfInfo() { return call('GET', '/users/my') } +async function getTodayDiaries(page = 1, page_size = 20, first_id = '') { + return call('GET', '/diaries/today?page=' + page + '&page_size=' + page_size + `&first_id=${first_id}`) + .then((json) => { + json.page = Number(json.page); + json.page_size = Number(json.page_size); + + return json; + }); +} + + + + async function call(method, api, body, _timeout = 10000) { let token = await TokenManager.getUserToken(); @@ -58,16 +71,6 @@ async function call(method, api, body, _timeout = 10000) { , _timeout); } -function timeout(promise, time) { - return Promise.race([ - promise, - new Promise(function (resolve, reject) { - setTimeout(() => reject(new Error('request timeout')), time) - }) - ]); -} - - async function checkStatus(response) { if (response.status >= 200 && response.status < 300) { return response; @@ -94,6 +97,15 @@ async function checkStatus(response) { } } +function timeout(promise, time) { + return Promise.race([ + promise, + new Promise(function (resolve, reject) { + setTimeout(() => reject(new Error('request timeout')), time) + }) + ]); +} + function parseJSON(response) { if (response.headers.get('content-type') === 'application/json') { return response.json(); @@ -113,5 +125,6 @@ function handleCatch(err) { export default { - login + login, + getTodayDiaries } \ No newline at end of file