diff --git a/index.js b/index.js index c4b0584..01363f0 100644 --- a/index.js +++ b/index.js @@ -15,8 +15,8 @@ import BottomNav from './src/nav/bottomNav' async function init() { await loadIcon(); - // let token = await Token.getUserToken(); - let token; + let token = await Token.getUserToken(); + // let token; if (!token) { Navigation.startSingleScreenApp({ screen: { diff --git a/src/component/diary/diaryList.js b/src/component/diary/diaryList.js new file mode 100644 index 0000000..58b4ccb --- /dev/null +++ b/src/component/diary/diaryList.js @@ -0,0 +1,196 @@ +import React, {Component} from 'react'; +import { + InteractionManager, + ActivityIndicator, + StyleSheet, + FlatList, + Text, View +} from 'react-native'; +import {Divider} from "react-native-elements"; + +import Color from '../../style/color' +import Msg from '../../util/msg' +import Api from '../../util/api' + +import Touchable from '../touchable' +import DiaryBrief from './diaryBrief' + + +export default class DiaryList extends Component { + + constructor(props) { + super(props); + + this.dataSource = props.dataSource; + this.state = { + isLoading: true, + + diaries: [], + hasMore: false, + + refreshing: false, + refreshFailed: false + }; + } + + componentDidMount() { + console.log('diaryList mounted.'); + InteractionManager.runAfterInteractions(() => { + this.refresh(); + }); + } + + async refresh(loadMore = false) { + if (this.state.refreshing) { + return; + } + + this.setState({hasMore: false, refreshing: true, refreshFailed: false}); + this.dataSource.refresh(loadMore) + .then(result => { + console.log('diaryList refresh:', result); + + if(!result) { + throw { + message: 'refresh no result' + } + + } else { + let diaries = this.state.diaries; + let newDiaries = result.list; + if (!loadMore && diaries.length > 0 && newDiaries.length > 0 + && diaries[0].id === newDiaries[0].id) { + + Msg.showMsg('没有新内容'); + } + + this.setState({ + diaries: result.list ? result.list : [], + hasMore: result.more, + refreshFailed: false + }); + } + + }).catch(e => { + if (e.code === 401) { + this.props.navigator.showModal({ + screen: "App" + }); + } + + this.setState({ + diaries: [], + hasMore: false, + refreshFailed: true + }); + + }).done(() => { + this.setState({ + isLoading: false, + refreshing: false + }); + }); + } + + async loadMore() { + if (this.state.refreshing) { + return; + } + + this.refresh(true); + } + + _onDiaryPress(diary) { + /* + this.props.navigator.push({ + screen: 'DiaryDetail', + title: '日记详情', + passProps: { diary: diary } + }); + */ + } + + render() { + return ( + + { + return item.id.toString() + }} + + ListHeaderComponent={this.state.isLoading ? null : this.props.header} + + renderItem={({item}) => { + return ( + this._onDiaryPress(item)}> + + + ) + }} + + ItemSeparatorComponent={({highlighted}) => } + + ListFooterComponent={this.renderFooter()} + + refreshing={this.state.refreshing} + onRefresh={this.refresh.bind(this)} + + automaticallyAdjustContentInsets={true} + onEndReachedThreshold={2} + onEndReached={this.state.hasMore ? this.loadMore.bind(this) : null} + > + + + ); + } + + renderFooter() { + if (this.state.refreshing || this.state.diaries.length === 0) { + return null; + } + + if (this.state.refreshFailed) { + return ( + + {this.loadMore();}}> + 加载失败,请点击重试 + + + ); + } + + if (!this.state.hasMore) { + return ( + + —— THE END —— + + ); + } + + return ( + + + + ); + } +} + +const localStyle = StyleSheet.create({ + container: { + flex: 1 + }, + list: { + height: '100%' + }, + footer: { + height: 60, + justifyContent: 'center', + alignItems: 'center', + paddingBottom: 15 + } +}); \ No newline at end of file diff --git a/src/component/loading.js b/src/component/loading.js index 9ee2543..1eb1852 100644 --- a/src/component/loading.js +++ b/src/component/loading.js @@ -1,30 +1,23 @@ import React, { Component } from 'react'; -import { StyleSheet, Text, View, ActivityIndicator, Dimensions } from 'react-native'; +import {StyleSheet, Text, View, ActivityIndicator} from 'react-native'; -const { width, height } = Dimensions.get('window') +import Api from '../util/api' export default class Loading extends Component { constructor(props) { super(props); + this.state = { + color: props.color ? props.color : '#aaa' + } } - /* - show() { - this.setState({visible: true}) - } - - hide() { - this.setState({visible: false}) - } - */ - render() { if (this.props.visible) { return ( - - + + ); @@ -34,13 +27,13 @@ export default class Loading extends Component { } } -const styles = StyleSheet.create({ +const localStyle = StyleSheet.create({ loading: { - position: "absolute", + position: 'absolute', left: 0, - width: width, + width: Api.DEVICE_WINDOW.width, top: 200, - justifyContent: "center", - alignItems: "center" + justifyContent: 'center', + alignItems: 'center' } }); \ No newline at end of file diff --git a/src/dataLoader/followListData.js b/src/dataLoader/followListData.js new file mode 100644 index 0000000..df5accd --- /dev/null +++ b/src/dataLoader/followListData.js @@ -0,0 +1,30 @@ +import Api from '../util/api' + + +const PAGE_SIZE = 21; + +export default class FollowListData { + + list: []; + last_id: 0; + + async refresh(loadMore = false) { + let lastId = !loadMore ? 0 : this.last_id; + let data = await Api.getFollowDiaries(0, PAGE_SIZE, lastId); + let more = data.diaries.length === PAGE_SIZE; + + if(!loadMore) { + this.list = data.diaries.slice(0, PAGE_SIZE - 1); + + } else 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/entity/homeListData.js b/src/dataLoader/homeListData.js similarity index 100% rename from src/entity/homeListData.js rename to src/dataLoader/homeListData.js diff --git a/src/page/FollowPage.js b/src/page/FollowPage.js index f3be4a9..57b8618 100644 --- a/src/page/FollowPage.js +++ b/src/page/FollowPage.js @@ -1,33 +1,55 @@ import React, {Component} from 'react'; -import {Platform, StyleSheet, Text, View} from 'react-native'; +import {StyleSheet, Text, View} from 'react-native'; + +import Api from '../util/api' + +import DiaryList from '../component/diary/diaryList' +import FollowListData from '../dataLoader/followListData'; export default class FollowPage extends Component { + constructor(props) { + super(props); + this.dataSource = new FollowListData(); + } + + renderHeader() { + return ( + + 关注 + + ); + } + render() { - return ( - - Follow Page ! - - ); + return ( + + this.list = r} + dataSource={this.dataSource} + header={this.renderHeader.bind(this)} + + navigator={this.props.navigator} + + > + + ); } } -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: { + flex: 1, + backgroundColor: '#fff', + paddingTop: Api.IS_IPHONEX || Api.IS_ANDROID ? 44 : 20 + }, + header: { + paddingLeft: 20, + flexDirection: "row" + }, + title: { + flex: 1, + fontSize: 30, + color: '#000' + } }); diff --git a/src/page/HomePage.js b/src/page/HomePage.js index 7e82254..b7f8ffe 100644 --- a/src/page/HomePage.js +++ b/src/page/HomePage.js @@ -1,211 +1,55 @@ import React, {Component} from 'react'; -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 {StyleSheet, Text, View} from 'react-native'; -import Color from '../style/color' -import Msg from '../util/msg' +import Api from '../util/api' -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'; +import DiaryList from '../component/diary/diaryList' +import HomeListData from '../dataLoader/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 { constructor(props) { super(props); - this.dataSource = new HomeListData(); - this.state = { - isLoading: true, - - diaries: [], - hasMore: false, - - refreshing: false, - refreshFailed: false - }; } - componentDidMount() { - InteractionManager.runAfterInteractions(() => { - this.refresh(); - }); - } - - async refresh(loadMore = false) { - if (this.state.refreshing) { - return; - } - - this.setState({refreshing: true, hasMore: false, refreshFailed: false}); - this.dataSource.refresh(loadMore) - .then(data => { - console.log('homepage data:', data); - if(!data) { - throw { - message: 'empty data' - } - - } else { - let diaries = this.state.diaries; - let newDiaries = data.list; - if (!loadMore && diaries.length > 0 && newDiaries.length > 0 - && diaries[0].id === newDiaries[0].id) { - - Msg.showMsg('没有新内容'); - } - - this.setState({ - diaries: data.list ? data.list : [], - hasMore: data.more, - refreshFailed: false - }); - } - - }).catch(e => { - if (e.code && e.code === 401) { - this.props.navigator.showModal({ - screen: "App" - }); - } - - this.setState({ - diaries: [], - hasMore: false, - refreshFailed: true - }); - - }).done(() => { - this.setState({ - isLoading: false, - refreshing: false - }); - }); - } - - async loadMore() { - if (this.state.refreshing) { - return; - } - - this.refresh(true); - } - - _checkResult(result) { - - } - - _onDiaryPress(diary) { - /* - this.props.navigator.push({ - screen: 'DiaryDetail', - title: '日记详情', - passProps: { diary: diary } - }); - */ + renderHeader() { + return ( + + 胶囊日记 + + ); } render() { return ( - + this.list = r} + dataSource={this.dataSource} + header={this.renderHeader.bind(this)} - { - return item.id.toString() - }} - - renderItem={({item}) => { - return ( - this._onDiaryPress(item)}> - - - ) - }} - - ItemSeparatorComponent={({highlighted}) => } - - ListFooterComponent={this.renderFooter()} - - refreshing={this.state.refreshing} - onRefresh={this.refresh.bind(this)} - - automaticallyAdjustContentInsets={true} - onEndReachedThreshold={2} - onEndReached={this.state.hasMore ? this.loadMore.bind(this) : null} - /> + > ); } - - renderFooter() { - if (this.state.refreshing || this.state.diaries.length === 0) { - return null; - } - - if (this.state.refreshFailed) { - return ( - - {this.loadMore();}}> - 加载失败,请点击重试 - - - ); - } - - if (!this.state.hasMore) { - return ( - - —— THE END —— - - ); - } - - return ( - - - - ); - } } const localStyle = StyleSheet.create({ wrap: { - position: 'absolute', - backgroundColor: '#fff', flex: 1, - top: 0, - bottom: 0, - paddingTop: isIpx || isAndroid ? 44 : 20 + backgroundColor: '#fff', + paddingTop: Api.IS_IPHONEX || Api.IS_ANDROID ? 44 : 20 }, - list: { - backgroundColor: 'white', - height: '100%' + header: { + paddingLeft: 20, + flexDirection: "row" }, - footer: { - height: 60, - justifyContent: 'center', - alignItems: 'center', - paddingBottom: 15 + title: { + flex: 1, + fontSize: 30, + color: '#000' } }); diff --git a/src/util/api.js b/src/util/api.js index b53c12f..093e633 100644 --- a/src/util/api.js +++ b/src/util/api.js @@ -1,12 +1,21 @@ -import TokenManager from './token' +import {Platform, Dimensions} from 'react-native' import DeviceInfo from 'react-native-device-info'; +import {isIphoneX} from 'react-native-iphone-x-helper' +import TokenManager from './token' + + +const IS_ANDROID = Platform.OS === 'android'; +const DEVICE_WINDOW = Dimensions.get('window') const OS = DeviceInfo.getSystemName(); const OS_VERSION = DeviceInfo.getSystemVersion(); const DEVICE_ID = DeviceInfo.getUniqueID(); const VERSION = DeviceInfo.getVersion(); +const IS_IPHONEX = isIphoneX(); + + const baseUrl = 'http://open.timepill.net/api'; @@ -32,7 +41,7 @@ async function login(username, password) { } async function getSelfInfo() { - return call('GET', '/users/my') + return call('GET', '/users/my'); } async function getTodayDiaries(page = 1, page_size = 20, first_id = '') { @@ -45,6 +54,16 @@ async function getTodayDiaries(page = 1, page_size = 20, first_id = '') { }); } +async function getFollowDiaries(page = 1, page_size = 20, first_id = '') { + return call('GET', '/diaries/follow?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; + }); +} + @@ -125,6 +144,15 @@ function handleCatch(err) { export default { + IS_ANDROID, + DEVICE_WINDOW, + OS, + OS_VERSION, + DEVICE_ID, + VERSION, + IS_IPHONEX, + login, - getTodayDiaries + getTodayDiaries, + getFollowDiaries } \ No newline at end of file