mirror of
https://github.com/timepill/timepill-app.git
synced 2025-04-30 09:59:31 +08:00
1. 日记操作组件
2. 设置页面:启动密码,意见反馈,关于,退出登录 3. 设置页面:用户头像,名称,简介
This commit is contained in:
parent
3c8d338345
commit
d6331e6447
27 changed files with 1518 additions and 115 deletions
5
App.js
5
App.js
|
@ -13,7 +13,10 @@ import {
|
||||||
Animated,
|
Animated,
|
||||||
LayoutAnimation,
|
LayoutAnimation,
|
||||||
InteractionManager,
|
InteractionManager,
|
||||||
Alert, StatusBar, DeviceEventEmitter, Linking
|
Alert,
|
||||||
|
StatusBar,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
Linking
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import {Input} from "react-native-elements";
|
import {Input} from "react-native-elements";
|
||||||
import {Navigation} from 'react-native-navigation';
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
83
index.js
83
index.js
|
@ -19,6 +19,60 @@ for(let pageName in PageList) {
|
||||||
Navigation.registerComponent(pageName, () => PageList[pageName]);
|
Navigation.registerComponent(pageName, () => PageList[pageName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loginByAccount() {
|
||||||
|
Navigation.setRoot({
|
||||||
|
root: {
|
||||||
|
stack: {
|
||||||
|
children: [{
|
||||||
|
component: {
|
||||||
|
name: 'Timepill',
|
||||||
|
options: {
|
||||||
|
topBar: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide top bar for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginByPassword() {
|
||||||
|
Navigation.setRoot({
|
||||||
|
root: {
|
||||||
|
stack: {
|
||||||
|
children: [{
|
||||||
|
component: {
|
||||||
|
name: 'Password',
|
||||||
|
options: {
|
||||||
|
topBar: {
|
||||||
|
title: {
|
||||||
|
text: '请输入密码'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
passProps: {
|
||||||
|
type: 'login'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Navigation.events().registerAppLaunchedListener(async () => {
|
Navigation.events().registerAppLaunchedListener(async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -30,29 +84,16 @@ Navigation.events().registerAppLaunchedListener(async () => {
|
||||||
let token = await Token.getUserToken();
|
let token = await Token.getUserToken();
|
||||||
// let token;
|
// let token;
|
||||||
if(!token) {
|
if(!token) {
|
||||||
Navigation.setRoot({
|
loginByAccount();
|
||||||
root: {
|
|
||||||
stack: {
|
|
||||||
children: [{
|
|
||||||
component: {
|
|
||||||
name: 'Timepill',
|
|
||||||
options: {
|
|
||||||
topBar: {
|
|
||||||
visible: false,
|
|
||||||
|
|
||||||
// hide top bar for android
|
|
||||||
drawBehind: true,
|
|
||||||
animate: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Navigation.setRoot(BottomNav.config());
|
const password = await Token.getLoginPassword();
|
||||||
|
if(password) {
|
||||||
|
loginByPassword();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Navigation.setRoot(BottomNav.config());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
BIN
src/Icon.png
Normal file
BIN
src/Icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
61
src/component/diary/diaryAction.js
Normal file
61
src/component/diary/diaryAction.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
import {DeviceEventEmitter, Alert} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
||||||
|
import Api from '../../util/api';
|
||||||
|
import Msg from '../../util/msg';
|
||||||
|
import Event from '../../util/event';
|
||||||
|
|
||||||
|
|
||||||
|
function action(componentId, diary, callbacks) {
|
||||||
|
ActionSheet.showActionSheetWithOptions({
|
||||||
|
options:['修改','删除', '取消'],
|
||||||
|
cancelButtonIndex: 2,
|
||||||
|
destructiveButtonIndex: 1
|
||||||
|
|
||||||
|
}, (index) => {
|
||||||
|
if(index === 0) {
|
||||||
|
Navigation.push(componentId, {
|
||||||
|
component: {
|
||||||
|
name: 'Write',
|
||||||
|
options: {
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
passProps: {
|
||||||
|
diary: diary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (index === 1) {
|
||||||
|
Alert.alert('提示', '确认删除日记?', [
|
||||||
|
{text: '删除', style: 'destructive', onPress: () => {
|
||||||
|
Api.deleteDiary(diary.id)
|
||||||
|
.then(() => {
|
||||||
|
DeviceEventEmitter.emit(Event.updateDiarys, 'del');
|
||||||
|
|
||||||
|
Msg.showMsg('日记已删除');
|
||||||
|
if(callbacks && callbacks.onDelete){
|
||||||
|
callbacks.onDelete();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
Msg.showMsg('日记删除失败' + e.message);
|
||||||
|
})
|
||||||
|
.done();
|
||||||
|
}},
|
||||||
|
{text: '取消', onPress: () => {}},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
action
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ import Color from '../../style/color';
|
||||||
import UserIcon from '../userIcon';
|
import UserIcon from '../userIcon';
|
||||||
import Photo from '../photo';
|
import Photo from '../photo';
|
||||||
|
|
||||||
|
import DiaryAction from './diaryAction';
|
||||||
|
|
||||||
|
|
||||||
export default class DiaryBrief extends Component {
|
export default class DiaryBrief extends Component {
|
||||||
|
|
||||||
|
@ -26,6 +28,10 @@ export default class DiaryBrief extends Component {
|
||||||
return this.showField.indexOf(field) >= 0;
|
return this.showField.indexOf(field) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDiaryAction() {
|
||||||
|
DiaryAction.action(this.props.componentId, this.diary);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let diary = this.diary;
|
let diary = this.diary;
|
||||||
if(!diary) {
|
if(!diary) {
|
||||||
|
@ -79,7 +85,7 @@ export default class DiaryBrief extends Component {
|
||||||
<View style={{flex: 1}} />
|
<View style={{flex: 1}} />
|
||||||
{
|
{
|
||||||
this.editable
|
this.editable
|
||||||
? <TouchableOpacity onPress={this.props.onDiaryAction}>
|
? <TouchableOpacity onPress={this.onDiaryAction.bind(this)}>
|
||||||
<Ionicons name="ios-more" size={24}
|
<Ionicons name="ios-more" size={24}
|
||||||
color={Color.inactiveText}
|
color={Color.inactiveText}
|
||||||
style={localStyle.moreIcon} />
|
style={localStyle.moreIcon} />
|
||||||
|
|
|
@ -90,62 +90,12 @@ export default class DiaryList extends Component {
|
||||||
diary: diary,
|
diary: diary,
|
||||||
user: diary.user,
|
user: diary.user,
|
||||||
|
|
||||||
editable: this.editable,
|
editable: this.editable
|
||||||
onDiaryAction: this._onDiaryAction.bind(this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDiaryAction(diary) {
|
|
||||||
ActionSheet.showActionSheetWithOptions({
|
|
||||||
options:['修改','删除', '取消'],
|
|
||||||
cancelButtonIndex: 2,
|
|
||||||
destructiveButtonIndex: 1
|
|
||||||
|
|
||||||
}, (index) => {
|
|
||||||
if(index === 0) {
|
|
||||||
Navigation.push(this.props.componentId, {
|
|
||||||
component: {
|
|
||||||
name: 'Write',
|
|
||||||
options: {
|
|
||||||
bottomTabs: {
|
|
||||||
visible: false,
|
|
||||||
|
|
||||||
// hide bottom tab for android
|
|
||||||
drawBehind: true,
|
|
||||||
animate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
passProps: {
|
|
||||||
diary: diary
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if (index === 1) {
|
|
||||||
Alert.alert('提示', '确认删除日记?', [
|
|
||||||
{text: '删除', style: 'destructive', onPress: () => {
|
|
||||||
Api.deleteDiary(diary.id)
|
|
||||||
.then(() => {
|
|
||||||
let filterDiaries = this.state.diaries.filter((it) => it.id !== diary.id);
|
|
||||||
this.setState({
|
|
||||||
diaries: filterDiaries
|
|
||||||
});
|
|
||||||
|
|
||||||
Msg.showMsg('日记已删除');
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
Msg.showMsg('日记删除失败');
|
|
||||||
})
|
|
||||||
.done();
|
|
||||||
}},
|
|
||||||
{text: '取消', onPress: () => {}},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_onPhotoPress(photoUrl) {
|
_onPhotoPress(photoUrl) {
|
||||||
Navigation.push(this.props.componentId, {
|
Navigation.push(this.props.componentId, {
|
||||||
component: {
|
component: {
|
||||||
|
@ -253,12 +203,12 @@ export default class DiaryList extends Component {
|
||||||
renderItem={({item}) => {
|
renderItem={({item}) => {
|
||||||
return (
|
return (
|
||||||
<Touchable onPress={() => this._onDiaryPress(item)}>
|
<Touchable onPress={() => this._onDiaryPress(item)}>
|
||||||
<DiaryBrief diary={item}
|
<DiaryBrief {...this.props}
|
||||||
|
diary={item}
|
||||||
showField={this.props.showField}
|
showField={this.props.showField}
|
||||||
editable={this.editable}
|
editable={this.editable}
|
||||||
|
|
||||||
onUserIconPress={() => this._onUserIconPress(item)}
|
onUserIconPress={() => this._onUserIconPress(item)}
|
||||||
onDiaryAction={() => this._onDiaryAction(item)}
|
|
||||||
onPhotoPress={() => this._onPhotoPress(item.photoUrl)}
|
onPhotoPress={() => this._onPhotoPress(item.photoUrl)}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ async function resize(uri, oWidth, oHeight, maxPixel) {
|
||||||
height = Math.sqrt(oHeight * maxPixel / oWidth);
|
height = Math.sqrt(oHeight * maxPixel / oWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newUri = await ImageResizer.createResizedImage(uri, width, height);
|
const newUri = await ImageResizer.createResizedImage(uri, width, height, 'JPEG', 75);
|
||||||
return 'file://' + newUri.uri;
|
return 'file://' + newUri.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,8 @@ export default class NotebookDiaryList extends Component {
|
||||||
},
|
},
|
||||||
passProps: {
|
passProps: {
|
||||||
diary: diary,
|
diary: diary,
|
||||||
editable: this.editable
|
editable: this.editable,
|
||||||
|
expired: this.notebook.isExpired
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
142
src/component/passwordInput.js
Normal file
142
src/component/passwordInput.js
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
TextInput,
|
||||||
|
TouchableHighlight,
|
||||||
|
InteractionManager,
|
||||||
|
Keyboard,
|
||||||
|
Alert
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
import Api from '../util/api'
|
||||||
|
|
||||||
|
|
||||||
|
export default class PasswordInput extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
text: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
|
this._onPress();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnMount() {
|
||||||
|
Keyboard.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.setState({
|
||||||
|
text: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPress() {
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.inputText.focus();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<TouchableHighlight activeOpacity={1} underlayColor='transparent'
|
||||||
|
onPress={this._onPress.bind(this)}
|
||||||
|
>
|
||||||
|
<View style={[localStyle.container, this.props.style]}>
|
||||||
|
<TextInput ref={(r) => this.inputText = r}
|
||||||
|
style={localStyle.textInput}
|
||||||
|
|
||||||
|
maxLength={this.props.maxLength}
|
||||||
|
autoFocus={false}
|
||||||
|
keyboardType={Api.IS_IOS ? "number-pad" : 'numeric'}
|
||||||
|
blurOnSubmit={false}
|
||||||
|
|
||||||
|
value={this.state.text}
|
||||||
|
onChangeText={
|
||||||
|
(text) => {
|
||||||
|
this.setState({text});
|
||||||
|
if(text.length === this.props.maxLength) {
|
||||||
|
this.props.onEnd(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
this._getInputItem()
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_getInputItem() {
|
||||||
|
let inputItem = [];
|
||||||
|
let text = this.state.text;
|
||||||
|
|
||||||
|
for(let i=0; i<parseInt(this.props.maxLength); i++) {
|
||||||
|
if(i == 0) {
|
||||||
|
inputItem.push(
|
||||||
|
<View key={i} style={[localStyle.inputItem, this.props.inputItemStyle]}>
|
||||||
|
{i < text.length ? <View style={[localStyle.iconStyle, this.props.iconStyle]}/> : null}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
inputItem.push(
|
||||||
|
<View key={i} style={[localStyle.inputItem, localStyle.inputItemBorderLeftWidth, this.props.inputItemStyle]}>
|
||||||
|
{i < text.length ? <View style={[localStyle.iconStyle, this.props.iconStyle]}/> : null}
|
||||||
|
</View>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStyle = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '#ccc',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderRadius: 5
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: 1,
|
||||||
|
height:1,
|
||||||
|
padding: 0,
|
||||||
|
margin: 0
|
||||||
|
},
|
||||||
|
inputItem: {
|
||||||
|
height: 45,
|
||||||
|
width: 45,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: 'white'
|
||||||
|
},
|
||||||
|
inputItemBorderLeftWidth: {
|
||||||
|
borderLeftWidth: 1,
|
||||||
|
borderColor: '#ccc'
|
||||||
|
},
|
||||||
|
iconStyle: {
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
backgroundColor: '#222',
|
||||||
|
borderRadius: 8
|
||||||
|
}
|
||||||
|
});
|
|
@ -5,6 +5,13 @@ import {Avatar} from "react-native-elements";
|
||||||
|
|
||||||
export default class UserIcon extends Component {
|
export default class UserIcon extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
iconUrl : props.iconUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
_defaultOnPress() {
|
_defaultOnPress() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
@ -15,7 +22,7 @@ export default class UserIcon extends Component {
|
||||||
containerStyle={localStyle.container}
|
containerStyle={localStyle.container}
|
||||||
width={this.props.width || 40}
|
width={this.props.width || 40}
|
||||||
height={this.props.height || 40}
|
height={this.props.height || 40}
|
||||||
source={{uri: this.props.iconUrl}}
|
source={{uri: this.state.iconUrl}}
|
||||||
onPress={this.props.onPress ? this.props.onPress : this._defaultOnPress.bind(this)}
|
onPress={this.props.onPress ? this.props.onPress : this._defaultOnPress.bind(this)}
|
||||||
activeOpacity={0.7}
|
activeOpacity={0.7}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -23,14 +23,19 @@ export default class UserIntro extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
InteractionManager.runAfterInteractions(() => {
|
Api.getSelfInfoByStore()
|
||||||
this.loadUser();
|
.then(user => {
|
||||||
});
|
this.selfInfo = user;
|
||||||
|
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
|
this.refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadUser() {
|
refresh() {
|
||||||
let user = this.state.user;
|
let userId = this.state.user ? this.state.user.id : this.selfInfo.id;
|
||||||
(user ? Api.getUserInfo(user.id) : Api.getSelfInfoByStore())
|
Api.getUserInfo(userId)
|
||||||
.then(user => {
|
.then(user => {
|
||||||
this.setState({
|
this.setState({
|
||||||
user: user
|
user: user
|
||||||
|
|
60
src/page/AboutPage.js
Normal file
60
src/page/AboutPage.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
Image,
|
||||||
|
DeviceEventEmitter
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
import Api from '../util/api';
|
||||||
|
import TokenManager from '../util/token';
|
||||||
|
import Event from '../util/event';
|
||||||
|
import Color from '../style/color';
|
||||||
|
import UpdateInfo from '../updateInfo';
|
||||||
|
|
||||||
|
|
||||||
|
export default class AboutPage extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
info: null,
|
||||||
|
news: UpdateInfo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static options(passProps) {
|
||||||
|
return {
|
||||||
|
topBar: {
|
||||||
|
title: {
|
||||||
|
text: '关于'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
TokenManager.setUpdateVersion(UpdateInfo.version)
|
||||||
|
.then(() => {
|
||||||
|
DeviceEventEmitter.emit(Event.updateNewsRead);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const label = this.state.info ? ` (${this.state.info.label})` : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{flex: 1, backgroundColor: 'white'}}>
|
||||||
|
<View style={{flex: 1, padding: 15, alignItems: 'center', paddingTop: 80}}>
|
||||||
|
<Image source={require('../Icon.png')}
|
||||||
|
style={{width: 128, height: 128, borderRadius: 28, borderWidth: 1, borderColor:"#d9d9d9"}} />
|
||||||
|
<Text style={{paddingTop: 20, paddingBottom: 60}}>版本: {Api.VERSION}{label}</Text>
|
||||||
|
<Text style={{color: Color.inactiveText}}>{this.state.news.date} 更新日志</Text>
|
||||||
|
<Text style={{lineHeight: 20}}>{this.state.news.info}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,8 @@ import Api from '../util/api'
|
||||||
import Event from '../util/event';
|
import Event from '../util/event';
|
||||||
|
|
||||||
import DiaryFull from '../component/diary/diaryFull';
|
import DiaryFull from '../component/diary/diaryFull';
|
||||||
import CommentInput from '../component/comment/commentInput'
|
import DiaryAction from '../component/diary/diaryAction';
|
||||||
|
import CommentInput from '../component/comment/commentInput';
|
||||||
|
|
||||||
|
|
||||||
export default class DiaryDetailPage extends Component {
|
export default class DiaryDetailPage extends Component {
|
||||||
|
@ -35,31 +36,40 @@ export default class DiaryDetailPage extends Component {
|
||||||
user: props.user,
|
user: props.user,
|
||||||
|
|
||||||
editable: props.editable || false,
|
editable: props.editable || false,
|
||||||
|
expired: props.expired || false,
|
||||||
needScrollToBottom: false
|
needScrollToBottom: false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onDiaryAction = props.onDiaryAction || (() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static options(passProps) {
|
static options(passProps) {
|
||||||
return {
|
let topBar = {
|
||||||
topBar: {
|
title: {
|
||||||
title: {
|
text: '日记详情'
|
||||||
text: '日记详情'
|
|
||||||
},
|
|
||||||
rightButtons: [{
|
|
||||||
id: 'navButtonMore',
|
|
||||||
icon: Icon.navButtonMore,
|
|
||||||
|
|
||||||
color: Color.primary // android
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!passProps.expired) {
|
||||||
|
topBar.rightButtons = [{
|
||||||
|
id: 'navButtonMore',
|
||||||
|
icon: Icon.navButtonMore,
|
||||||
|
|
||||||
|
color: Color.primary // android
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
topBar
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
navigationButtonPressed({buttonId}) {
|
navigationButtonPressed({buttonId}) {
|
||||||
if(this.state.editable) {
|
if(this.state.editable || this.state.diary.user_id == this.state.selfInfo.id) {
|
||||||
this.onDiaryAction(this.state.diary);
|
let componentId = this.props.componentId;
|
||||||
|
DiaryAction.action(componentId, this.state.diary, {
|
||||||
|
onDelete: () => {
|
||||||
|
Navigation.pop(componentId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ActionSheet.showActionSheetWithOptions({
|
ActionSheet.showActionSheetWithOptions({
|
||||||
|
@ -90,7 +100,9 @@ export default class DiaryDetailPage extends Component {
|
||||||
}).done();
|
}).done();
|
||||||
|
|
||||||
this.diaryListener = DeviceEventEmitter.addListener(Event.updateDiarys, (param) => {
|
this.diaryListener = DeviceEventEmitter.addListener(Event.updateDiarys, (param) => {
|
||||||
this.refreshDiary();
|
if(param != 'del') {
|
||||||
|
this.refreshDiary();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.commentListener = DeviceEventEmitter.addListener(Event.updateComments, (param) => {
|
this.commentListener = DeviceEventEmitter.addListener(Event.updateComments, (param) => {
|
||||||
|
@ -131,6 +143,15 @@ export default class DiaryDetailPage extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
if(!this.state.selfInfo || !this.state.diary) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isMine = false;
|
||||||
|
if(this.state.selfInfo.id == this.state.diary.user_id) {
|
||||||
|
isMine = true;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={localStyle.wrap}>
|
<View style={localStyle.wrap}>
|
||||||
<ScrollView ref={(r)=>this.scroll = r}
|
<ScrollView ref={(r)=>this.scroll = r}
|
||||||
|
@ -144,16 +165,16 @@ export default class DiaryDetailPage extends Component {
|
||||||
>
|
>
|
||||||
|
|
||||||
<DiaryFull ref={(r) => this.diaryFull = r}
|
<DiaryFull ref={(r) => this.diaryFull = r}
|
||||||
|
{...this.props}
|
||||||
diary={this.state.diary}
|
diary={this.state.diary}
|
||||||
refreshData={() => this.state.diary}
|
refreshData={() => this.state.diary}
|
||||||
editable={this.state.editable}
|
editable={this.state.editable || isMine}
|
||||||
{...this.props}
|
|
||||||
></DiaryFull>
|
></DiaryFull>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
{
|
{
|
||||||
this.state.selfInfo && this.state.diary ? (
|
!this.state.expired ? (
|
||||||
<CommentInput ref={(r) => this.commentInput = r}
|
<CommentInput ref={(r) => this.commentInput = r}
|
||||||
diary={this.state.diary}
|
diary={this.state.diary}
|
||||||
selfInfo={this.state.selfInfo}
|
selfInfo={this.state.selfInfo}
|
||||||
|
|
70
src/page/FeedbackPage.js
Normal file
70
src/page/FeedbackPage.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
TextInput
|
||||||
|
} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
import {Button} from "react-native-elements";
|
||||||
|
|
||||||
|
import Color from '../style/color';
|
||||||
|
import Api from '../util/api';
|
||||||
|
import Msg from '../util/msg';
|
||||||
|
|
||||||
|
|
||||||
|
export default class FeedbackPage extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
content: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static options(passProps) {
|
||||||
|
return {
|
||||||
|
topBar: {
|
||||||
|
title: {
|
||||||
|
text: '意见反馈'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
send() {
|
||||||
|
Api.feedback(this.state.content)
|
||||||
|
.then(() => {
|
||||||
|
Msg.showMsg('感谢反馈 :)');
|
||||||
|
Navigation.pop(this.props.componentId);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
Msg.showMsg('反馈失败');
|
||||||
|
})
|
||||||
|
.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{flex: 1, backgroundColor: Color.spaceBackground}}>
|
||||||
|
<TextInput
|
||||||
|
style={{padding: 10, height: 240, margin: 10, backgroundColor: '#fff', textAlignVertical:'top'}}
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
selectionColor={Color.light}
|
||||||
|
autoCorrect={false}
|
||||||
|
|
||||||
|
multiline={true}
|
||||||
|
maxLength={1000}
|
||||||
|
|
||||||
|
value={this.state.content}
|
||||||
|
onChangeText={(text) => this.setState({content: text})}
|
||||||
|
/>
|
||||||
|
<Button borderRadius={999} title={'发送'} backgroundColor={Color.primary}
|
||||||
|
onPress={this.send.bind(this)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,7 +49,6 @@ export default class FollowPage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {StyleSheet, Text, View, ScrollView} from 'react-native';
|
import {StyleSheet, Text, View, DeviceEventEmitter} from 'react-native';
|
||||||
import {Navigation} from 'react-native-navigation';
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
||||||
import Color from '../style/color';
|
import Color from '../style/color';
|
||||||
import {Icon} from '../style/icon';
|
import {Icon} from '../style/icon';
|
||||||
|
import Event from '../util/event';
|
||||||
import NotebookDiaryList from '../component/notebook/notebookDiaryList';
|
import NotebookDiaryList from '../component/notebook/notebookDiaryList';
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,10 +47,21 @@ export default class NotebookDetailPage extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.diaryListener = DeviceEventEmitter.addListener(Event.updateDiarys, (param) => {
|
||||||
|
this.diaryList.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.diaryListener.remove();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1}}>
|
||||||
<NotebookDiaryList notebook={this.props.notebook}
|
<NotebookDiaryList ref={(r) => this.diaryList = r}
|
||||||
|
notebook={this.props.notebook}
|
||||||
{...this.props}>
|
{...this.props}>
|
||||||
</NotebookDiaryList>
|
</NotebookDiaryList>
|
||||||
</View>
|
</View>
|
||||||
|
|
208
src/page/PasswordPage.js
Normal file
208
src/page/PasswordPage.js
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
Alert,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
TouchableOpacity,
|
||||||
|
Keyboard
|
||||||
|
} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
||||||
|
import Color from '../style/color';
|
||||||
|
import Api from '../util/api'
|
||||||
|
import TokenManager from '../util/token';
|
||||||
|
import Event from '../util/event';
|
||||||
|
import Msg from '../util/msg';
|
||||||
|
|
||||||
|
import BottomNav from '../nav/bottomNav';
|
||||||
|
import PasswordInput from "../component/passwordInput";
|
||||||
|
|
||||||
|
|
||||||
|
export default class PasswordPage extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
title: '',
|
||||||
|
oldPassword: null,
|
||||||
|
step: 1,
|
||||||
|
|
||||||
|
password: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
TokenManager.getLoginPassword()
|
||||||
|
.then(pwd => {
|
||||||
|
if(this.props.type == 'setting') {
|
||||||
|
if(this.props.operation == 'setnew') {
|
||||||
|
this.setState({
|
||||||
|
title: '请输入新密码'
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if(this.props.operation == 'cancel'){
|
||||||
|
this.setState({
|
||||||
|
title: '请输入密码',
|
||||||
|
oldPassword: pwd
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(this.props.type == 'login') {
|
||||||
|
this.setState({
|
||||||
|
oldPassword: pwd
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_onEnd(password) {
|
||||||
|
if(this.props.type == 'setting') {
|
||||||
|
if(this.props.operation == 'setnew') {
|
||||||
|
this._setting(password);
|
||||||
|
|
||||||
|
} else if(this.props.operation == 'cancel') {
|
||||||
|
this._clearPassword(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(this.props.type == 'login') {
|
||||||
|
this._login(password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setting(password) {
|
||||||
|
if (this.state.step == 1) {
|
||||||
|
if(!password.match(/^\d+$/)) {
|
||||||
|
Alert.alert('提示', '只能设置数字密码');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
title: '请再次输入密码',
|
||||||
|
password: password,
|
||||||
|
step: 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refs.input.clear();
|
||||||
|
|
||||||
|
} else if (this.state.step == 2) {
|
||||||
|
if(this.state.password !== password) {
|
||||||
|
Alert.alert('设置失败', '两次输入的密码不相同,请重新输入');
|
||||||
|
this.refs.input.clear();
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
title: '请输入新密码',
|
||||||
|
password: null,
|
||||||
|
step: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
TokenManager.setLoginPassword(password)
|
||||||
|
.then(() => {
|
||||||
|
Keyboard.dismiss();
|
||||||
|
Msg.showMsg('密码已设置');
|
||||||
|
|
||||||
|
DeviceEventEmitter.emit(Event.passwordUpdated);
|
||||||
|
Navigation.pop(this.props.componentId);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
Alert.alert('错误', '设置密码失败:' + e.message);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_login(password) {
|
||||||
|
if(!this.state.oldPassword) {
|
||||||
|
Alert.alert('错误', '密码加载失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.state.oldPassword === password) {
|
||||||
|
Navigation.setRoot(BottomNav.config());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Alert.alert('失败', '密码错误');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refs.input.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_clearPassword(password) {
|
||||||
|
if(!this.state.oldPassword) {
|
||||||
|
Alert.alert('错误', '密码加载失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.state.oldPassword !== password) {
|
||||||
|
Alert.alert('提示', '密码不正确');
|
||||||
|
this.refs.input.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenManager.setLoginPassword('')
|
||||||
|
.then(() => {
|
||||||
|
Keyboard.dismiss();
|
||||||
|
Msg.showMsg('密码已清除');
|
||||||
|
|
||||||
|
DeviceEventEmitter.emit(Event.passwordUpdated);
|
||||||
|
Navigation.pop(this.props.componentId);
|
||||||
|
|
||||||
|
}).catch(() => {
|
||||||
|
Alert.alert('错误', '清除密码失败');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
toLogin() {
|
||||||
|
Navigation.setRoot({
|
||||||
|
root: {
|
||||||
|
stack: {
|
||||||
|
children: [{
|
||||||
|
component: {
|
||||||
|
name: 'Timepill',
|
||||||
|
options: {
|
||||||
|
topBar: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide top bar for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{flex: 1, backgroundColor: '#EFEFF4'}}>
|
||||||
|
<View style={{flex: 1, alignItems: 'center', marginTop: 60}}>
|
||||||
|
<Text style={{fontSize: 24}}>{this.state.title}</Text>
|
||||||
|
<PasswordInput ref='input' style={{marginTop: 50}} maxLength={4} onEnd={this._onEnd.bind(this)}/>
|
||||||
|
{
|
||||||
|
this.props.type == 'setting' && this.props.operation != 'cancel'
|
||||||
|
? (
|
||||||
|
<Text style={{marginTop: 50, fontSize: 11, color: Color.inactiveText}}>提示: 从后台切切换前台时不需要输入密码</Text>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.props.type == 'setting' ? null : (
|
||||||
|
<View style={{flex: 1, alignItems: 'center', paddingTop: 22}}>
|
||||||
|
<TouchableOpacity onPress={this.toLogin}>
|
||||||
|
<Text style={{fontSize: 14, color: Color.primary, padding: 10}}>
|
||||||
|
忘记密码?通过登录重设
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
272
src/page/SettingPage.js
Normal file
272
src/page/SettingPage.js
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
Switch,
|
||||||
|
Alert,
|
||||||
|
Linking,
|
||||||
|
TouchableOpacity,
|
||||||
|
DeviceEventEmitter
|
||||||
|
} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
|
import Api from '../util/api';
|
||||||
|
import TokenManager from '../util/token';
|
||||||
|
import Color from '../style/color';
|
||||||
|
|
||||||
|
|
||||||
|
export default class SettingPage extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
hasPassword: false,
|
||||||
|
hasUpdateNews: false,
|
||||||
|
|
||||||
|
settings: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static options(passProps) {
|
||||||
|
return {
|
||||||
|
topBar: {
|
||||||
|
title: {
|
||||||
|
text: '设置'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.refreshPasswordState();
|
||||||
|
this.passwordListener = DeviceEventEmitter.addListener('passwordUpdated', this.refreshPasswordState.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.passwordListener.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshPasswordState() {
|
||||||
|
TokenManager.getLoginPassword()
|
||||||
|
.then((pwd) => this.setState({
|
||||||
|
hasPassword: pwd != null && pwd.length > 0
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
changePassword = () => {
|
||||||
|
let titleText = '';
|
||||||
|
if(!this.state.hasPassword) {
|
||||||
|
titleText = '设置启动密码';
|
||||||
|
} else {
|
||||||
|
titleText = '取消启动密码';
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigation.push(this.props.componentId, {
|
||||||
|
component: {
|
||||||
|
name: 'Password',
|
||||||
|
options: {
|
||||||
|
topBar: {
|
||||||
|
title: {
|
||||||
|
text: titleText
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
passProps: {
|
||||||
|
type: 'setting',
|
||||||
|
operation: !this.state.hasPassword ? 'setnew' : 'cancel'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
changePush = (val) => {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpTo(pageName) {
|
||||||
|
Navigation.push(this.props.componentId, {
|
||||||
|
component: {
|
||||||
|
name: pageName,
|
||||||
|
options: {
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
Alert.alert('提示','确认退出登录?',[
|
||||||
|
{text: '退出', style: 'destructive', onPress: () => {
|
||||||
|
Api.logout();
|
||||||
|
Navigation.setRoot({
|
||||||
|
root: {
|
||||||
|
stack: {
|
||||||
|
children: [{
|
||||||
|
component: {
|
||||||
|
name: 'Timepill',
|
||||||
|
options: {
|
||||||
|
topBar: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide top bar for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}},
|
||||||
|
{text: '取消', onPress: () => {}}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={localStyle.wrap}>
|
||||||
|
<View style={localStyle.group}>
|
||||||
|
<TouchableOpacity style={localStyle.item} onPress={() => this.jumpTo('UserInfoEdit')}>
|
||||||
|
<Text style={localStyle.title}>修改个人信息</Text>
|
||||||
|
<Ionicons name="ios-arrow-forward" style={localStyle.arrow} size={18} color='#0076FF'/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={localStyle.line} />
|
||||||
|
|
||||||
|
<View style={localStyle.item}>
|
||||||
|
<Text style={localStyle.title}>启动密码</Text>
|
||||||
|
<Switch value={this.state.hasPassword}
|
||||||
|
trackColor={Api.IS_ANDROID ? Color.textSelect : null}
|
||||||
|
thumbColor={Api.IS_ANDROID && this.state.hasPassword ? Color.light : null}
|
||||||
|
onValueChange={this.changePassword} />
|
||||||
|
</View>
|
||||||
|
<View style={localStyle.line} />
|
||||||
|
|
||||||
|
<View style={localStyle.item}>
|
||||||
|
<Text style={localStyle.title}>提醒推送</Text>
|
||||||
|
<Switch value={this.state.settings['pushMessage']}
|
||||||
|
trackColor={Api.IS_ANDROID ? Color.textSelect : null}
|
||||||
|
thumbColor={Api.IS_ANDROID && this.state.settings['pushMessage'] ? Color.light : null}
|
||||||
|
onValueChange={this.changePush} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={localStyle.group}>
|
||||||
|
{
|
||||||
|
Api.IS_IOS ? (
|
||||||
|
<View>
|
||||||
|
<TouchableOpacity style={localStyle.item}
|
||||||
|
onPress={() =>
|
||||||
|
Linking.openURL("https://itunes.apple.com/us/app/jiao-nang-ri-ji/id1142102323?l=zh&ls=1&mt=8")}
|
||||||
|
>
|
||||||
|
<Text style={localStyle.title}>去 App Store 评价</Text>
|
||||||
|
<Ionicons name="ios-arrow-forward" style={localStyle.arrow} size={18}/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={localStyle.line} />
|
||||||
|
</View>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
<TouchableOpacity style={localStyle.item}
|
||||||
|
onPress={() => this.jumpTo('Feedback')}>
|
||||||
|
<Text style={localStyle.title}>意见反馈</Text>
|
||||||
|
<Ionicons name="ios-arrow-forward" style={localStyle.arrow} size={18}/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={localStyle.line} />
|
||||||
|
|
||||||
|
<TouchableOpacity style={localStyle.item}
|
||||||
|
onPress={() => this.jumpTo('About')}>
|
||||||
|
<Text style={localStyle.title}>关于</Text>
|
||||||
|
{
|
||||||
|
this.state.hasUpdateNews
|
||||||
|
? (
|
||||||
|
<View style={localStyle.badge}>
|
||||||
|
<Text style={localStyle.badgeText}>1</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
<Ionicons name="ios-arrow-forward" style={localStyle.arrow} size={18}/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={[localStyle.group, { marginTop: 45 }]}>
|
||||||
|
<TouchableOpacity style={localStyle.item}
|
||||||
|
onPress={this.logout.bind(this)}
|
||||||
|
>
|
||||||
|
<Text style={localStyle.button}>退出登录</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStyle = StyleSheet.create({
|
||||||
|
wrap: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#EFEFF4'
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
marginTop: 30,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderColor: '#c8c7cc'
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingHorizontal: 15,
|
||||||
|
height: 45
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#222',
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
marginLeft: 15,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderColor: '#c8c7cc'
|
||||||
|
},
|
||||||
|
arrow: {
|
||||||
|
paddingTop: 1,
|
||||||
|
color: Color.inactiveText
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
flex: 1,
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#d9534f',
|
||||||
|
fontSize: 16
|
||||||
|
},
|
||||||
|
badge: {
|
||||||
|
backgroundColor: 'red',
|
||||||
|
paddingHorizontal:8,
|
||||||
|
paddingVertical: 2,
|
||||||
|
borderRadius: 12,
|
||||||
|
marginRight: 10
|
||||||
|
},
|
||||||
|
badgeText: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'Arial'
|
||||||
|
}
|
||||||
|
});
|
187
src/page/UserInfoEditPage.js
Normal file
187
src/page/UserInfoEditPage.js
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
Image,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
Keyboard
|
||||||
|
} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
|
import Color from '../style/color';
|
||||||
|
import Token from '../util/token'
|
||||||
|
import Api from '../util/api';
|
||||||
|
import Event from '../util/event';
|
||||||
|
import Msg from '../util/msg';
|
||||||
|
|
||||||
|
import Loading from '../component/loading'
|
||||||
|
import ImageAction from '../component/image/imageAction'
|
||||||
|
|
||||||
|
|
||||||
|
export default class UserInfoEditPage extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
user: null,
|
||||||
|
uploading: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.loadUser();
|
||||||
|
this.userInfoListener = DeviceEventEmitter.addListener(Event.userInfoUpdated, this.loadUser.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.userInfoListener.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadUser() {
|
||||||
|
Api.getSelfInfoByStore()
|
||||||
|
.then(user => {
|
||||||
|
this.setState({user});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
editIcon() {
|
||||||
|
ImageAction.action({
|
||||||
|
width: 640,
|
||||||
|
height: 640,
|
||||||
|
cropping: true
|
||||||
|
|
||||||
|
}, -1, 640 * 640, (e, imageUri) => {
|
||||||
|
|
||||||
|
if(e) {
|
||||||
|
Msg.showMsg('操作失败:' + e.message);
|
||||||
|
} else {
|
||||||
|
this.uploadIcon(imageUri);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadIcon(uri) {
|
||||||
|
this.setState({uploading: true});
|
||||||
|
Api.updateUserIcon(uri)
|
||||||
|
.then(async user => {
|
||||||
|
await Token.setUserInfo(user);
|
||||||
|
this.loadUser();
|
||||||
|
|
||||||
|
Msg.showMsg('头像保存成功');
|
||||||
|
DeviceEventEmitter.emit(Event.userInfoUpdated);
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
Msg.showMsg('头像更新失败:' + e.message);
|
||||||
|
})
|
||||||
|
.done(() => {
|
||||||
|
this.setState({uploading: false});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpTo(pageName) {
|
||||||
|
Navigation.push(this.props.componentId, {
|
||||||
|
component: {
|
||||||
|
name: pageName,
|
||||||
|
options: {
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
passProps: {
|
||||||
|
user: this.state.user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{flex: 1, backgroundColor: '#EFEFF4'}}>
|
||||||
|
<Loading visible={this.state.uploading}></Loading>
|
||||||
|
{
|
||||||
|
this.state.user ? (
|
||||||
|
<View style={localStyle.group}>
|
||||||
|
<TouchableOpacity style={localStyle.item} onPress={this.editIcon.bind(this)}>
|
||||||
|
<Text style={localStyle.title}>头像</Text>
|
||||||
|
<View style={localStyle.right}>
|
||||||
|
<Image source={{uri: this.state.user.iconUrl}} style={{width: 28, height: 28, borderRadius: 14}} />
|
||||||
|
<Ionicons name="ios-arrow-forward" style={localStyle.arrow} size={18}/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={localStyle.line} />
|
||||||
|
|
||||||
|
<TouchableOpacity style={localStyle.item} onPress={() => this.jumpTo('UserNameEdit')}>
|
||||||
|
<Text style={localStyle.title}>名字</Text>
|
||||||
|
<View style={localStyle.right}>
|
||||||
|
<Text style={localStyle.value}>{this.state.user.name}</Text>
|
||||||
|
<Ionicons name="ios-arrow-forward" style={localStyle.arrow} size={18}/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={localStyle.line} />
|
||||||
|
|
||||||
|
<TouchableOpacity style={localStyle.item} onPress={() => this.jumpTo('UserIntroEdit')}>
|
||||||
|
<Text style={localStyle.title}>个人简介</Text>
|
||||||
|
<Ionicons name="ios-arrow-forward" style={localStyle.arrow} size={18}/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStyle = StyleSheet.create({
|
||||||
|
group: {
|
||||||
|
marginTop: 30,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderColor: '#c8c7cc'
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingHorizontal: 15,
|
||||||
|
height: 45
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#222'
|
||||||
|
},
|
||||||
|
line: {
|
||||||
|
marginLeft: 15,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderColor: '#c8c7cc'
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
flexDirection:'row',
|
||||||
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
arrow: {
|
||||||
|
paddingTop: 1,
|
||||||
|
color: Color.inactiveText,
|
||||||
|
paddingLeft: 15
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: Color.inactiveText
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
flex: 1,
|
||||||
|
textAlign: 'center',
|
||||||
|
color: '#d9534f',
|
||||||
|
fontSize: 16
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
126
src/page/UserIntroEditPage.js
Normal file
126
src/page/UserIntroEditPage.js
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
Alert,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
Keyboard
|
||||||
|
} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
||||||
|
import Color from '../style/color';
|
||||||
|
import {Icon} from '../style/icon';
|
||||||
|
import Msg from '../util/msg';
|
||||||
|
import Api from '../util/api';
|
||||||
|
import Token from '../util/token';
|
||||||
|
import Event from '../util/event';
|
||||||
|
|
||||||
|
|
||||||
|
export default class EditIntroPage extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
Navigation.events().bindComponent(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
intro: props.user.intro
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static options(passProps) {
|
||||||
|
return {
|
||||||
|
topBar: {
|
||||||
|
title: {
|
||||||
|
text: '修改简介'
|
||||||
|
},
|
||||||
|
rightButtons: [{
|
||||||
|
id: 'save',
|
||||||
|
icon: Icon.navButtonSave
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.refs.input.focus();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationButtonPressed({buttonId}) {
|
||||||
|
this.saveUserIntro();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveUserIntro() {
|
||||||
|
const len = this.state.intro.length;
|
||||||
|
if(len === 0) {
|
||||||
|
Alert.alert('提示', '简介不能为空');
|
||||||
|
return;
|
||||||
|
} else if (len > 500) {
|
||||||
|
Alert.alert('提示', '简介不能超过500个字');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Api.updateUserInfo(this.props.user.name, this.state.intro)
|
||||||
|
.then(async user => {
|
||||||
|
Keyboard.dismiss();
|
||||||
|
Msg.showMsg('修改成功');
|
||||||
|
|
||||||
|
await Token.setUserInfo(user);
|
||||||
|
DeviceEventEmitter.emit(Event.userInfoUpdated);
|
||||||
|
|
||||||
|
Navigation.pop(this.props.componentId);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
Msg.showMsg('修改失败');
|
||||||
|
})
|
||||||
|
.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{flex: 1, backgroundColor: '#EFEFF4'}}>
|
||||||
|
<View style={localStyle.group}>
|
||||||
|
<TextInput ref='input'
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
style={localStyle.textInput}
|
||||||
|
selectionColor={Color.primary}
|
||||||
|
|
||||||
|
value={this.state.intro}
|
||||||
|
onChangeText={(text) => this.setState({intro: text})}
|
||||||
|
multiline={true}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const localStyle = StyleSheet.create({
|
||||||
|
group: {
|
||||||
|
marginTop: 30,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderColor: '#c8c7cc'
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
flexGrow: 1,
|
||||||
|
fontSize: 16,
|
||||||
|
margin: 15,
|
||||||
|
color: Color.text,
|
||||||
|
height: 200,
|
||||||
|
textAlignVertical: 'top'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
137
src/page/UserNameEditPage.js
Normal file
137
src/page/UserNameEditPage.js
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
Alert,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
Keyboard
|
||||||
|
} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
||||||
|
import Color from '../style/color';
|
||||||
|
import {Icon} from '../style/icon';
|
||||||
|
import Msg from '../util/msg';
|
||||||
|
import Api from '../util/api';
|
||||||
|
import Token from '../util/token';
|
||||||
|
import Event from '../util/event';
|
||||||
|
|
||||||
|
|
||||||
|
export default class UserNameEditPage extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
Navigation.events().bindComponent(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
name: props.user.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static options(passProps) {
|
||||||
|
return {
|
||||||
|
topBar: {
|
||||||
|
title: {
|
||||||
|
text: '修改名字'
|
||||||
|
},
|
||||||
|
rightButtons: [{
|
||||||
|
id: 'save',
|
||||||
|
icon: Icon.navButtonSave
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.refs.input.focus();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationButtonPressed({buttonId}) {
|
||||||
|
this.saveUserName();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveUserName() {
|
||||||
|
const len = this.state.name.length;
|
||||||
|
if (len === 0) {
|
||||||
|
Alert.alert('提示', '名字不能为空');
|
||||||
|
return;
|
||||||
|
} else if (len > 10) {
|
||||||
|
Alert.alert('提示', '名字不能超过10个字');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Api.updateUserInfo(this.state.name, this.props.user.intro)
|
||||||
|
.then(async user => {
|
||||||
|
Keyboard.dismiss();
|
||||||
|
Msg.showMsg('修改成功');
|
||||||
|
|
||||||
|
await Token.setUserInfo(user);
|
||||||
|
DeviceEventEmitter.emit(Event.userInfoUpdated);
|
||||||
|
|
||||||
|
Navigation.pop(this.props.componentId);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
Msg.showMsg('修改失败');
|
||||||
|
})
|
||||||
|
.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{flex: 1, backgroundColor: '#EFEFF4'}}>
|
||||||
|
<View style={localStyle.group}>
|
||||||
|
<View style={localStyle.item}>
|
||||||
|
<Text style={localStyle.title}>名字</Text>
|
||||||
|
<TextInput ref='input'
|
||||||
|
style={localStyle.textInput}
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
selectionColor={Color.primary}
|
||||||
|
|
||||||
|
value={this.state.name}
|
||||||
|
onChangeText={(text) => this.setState({name: text})}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStyle = StyleSheet.create({
|
||||||
|
group: {
|
||||||
|
marginTop: 30,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderColor: '#c8c7cc'
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingHorizontal: 15,
|
||||||
|
height: 45
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#222'
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
flex: 1,
|
||||||
|
fontSize: 16,
|
||||||
|
marginLeft: 15,
|
||||||
|
padding: 0,
|
||||||
|
height: 24,
|
||||||
|
color: Color.content
|
||||||
|
}
|
||||||
|
});
|
|
@ -9,7 +9,7 @@ import {
|
||||||
import {Navigation} from 'react-native-navigation';
|
import {Navigation} from 'react-native-navigation';
|
||||||
|
|
||||||
import Api from '../util/api';
|
import Api from '../util/api';
|
||||||
import {Icon} from '../style/icon'
|
import {Icon} from '../style/icon';
|
||||||
import Event from "../util/event";
|
import Event from "../util/event";
|
||||||
import Color from '../style/color';
|
import Color from '../style/color';
|
||||||
|
|
||||||
|
@ -101,6 +101,22 @@ export default class UserPage extends Component {
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
Alert.alert('取消关注失败');
|
Alert.alert('取消关注失败');
|
||||||
}).done();
|
}).done();
|
||||||
|
|
||||||
|
} else if(buttonId == 'setting') {
|
||||||
|
Navigation.push(this.props.componentId, {
|
||||||
|
component: {
|
||||||
|
name: 'Setting',
|
||||||
|
options: {
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,11 +146,16 @@ export default class UserPage extends Component {
|
||||||
this.diaryListener = DeviceEventEmitter.addListener(Event.updateDiarys, (param) => {
|
this.diaryListener = DeviceEventEmitter.addListener(Event.updateDiarys, (param) => {
|
||||||
this.diaryList.refresh();
|
this.diaryList.refresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.userInfoListener = DeviceEventEmitter.addListener(Event.userInfoUpdated, (param) => {
|
||||||
|
this.userIntro.refresh();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.notebookListener.remove();
|
this.notebookListener.remove();
|
||||||
this.diaryListener.remove();
|
this.diaryListener.remove();
|
||||||
|
this.userInfoListener.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderLabel = props => ({route}) => {
|
_renderLabel = props => ({route}) => {
|
||||||
|
@ -166,6 +187,7 @@ export default class UserPage extends Component {
|
||||||
|
|
||||||
_renderScene = SceneMap({
|
_renderScene = SceneMap({
|
||||||
userIntro: () => <UserIntro
|
userIntro: () => <UserIntro
|
||||||
|
ref={(r) => this.userIntro = r}
|
||||||
user={this.user}
|
user={this.user}
|
||||||
/>,
|
/>,
|
||||||
diary: () => <DiaryList
|
diary: () => <DiaryList
|
||||||
|
|
|
@ -23,7 +23,6 @@ import {Icon} from '../style/icon';
|
||||||
import Color from '../style/color';
|
import Color from '../style/color';
|
||||||
import Api from '../util/api';
|
import Api from '../util/api';
|
||||||
import Msg from '../util/msg';
|
import Msg from '../util/msg';
|
||||||
import Token from '../util/token'
|
|
||||||
import Event from "../util/event";
|
import Event from "../util/event";
|
||||||
|
|
||||||
import NotebookLine from '../component/notebook/notebookLine';
|
import NotebookLine from '../component/notebook/notebookLine';
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
export default {
|
export default {
|
||||||
|
About: require("./AboutPage.js").default,
|
||||||
DiaryDetail: require("./DiaryDetailPage.js").default,
|
DiaryDetail: require("./DiaryDetailPage.js").default,
|
||||||
Empty: require("./EmptyPage.js").default,
|
Empty: require("./EmptyPage.js").default,
|
||||||
|
Feedback: require("./FeedbackPage.js").default,
|
||||||
Follow: require("./FollowPage.js").default,
|
Follow: require("./FollowPage.js").default,
|
||||||
FollowUser: require("./FollowUserPage.js").default,
|
FollowUser: require("./FollowUserPage.js").default,
|
||||||
Home: require("./HomePage.js").default,
|
Home: require("./HomePage.js").default,
|
||||||
|
@ -8,7 +10,12 @@ NotebookDetail: require("./NotebookDetailPage.js").default,
|
||||||
NotebookEdit: require("./NotebookEditPage.js").default,
|
NotebookEdit: require("./NotebookEditPage.js").default,
|
||||||
NotificationHistory: require("./NotificationHistoryPage.js").default,
|
NotificationHistory: require("./NotificationHistoryPage.js").default,
|
||||||
Notification: require("./NotificationPage.js").default,
|
Notification: require("./NotificationPage.js").default,
|
||||||
|
Password: require("./PasswordPage.js").default,
|
||||||
Photo: require("./PhotoPage.js").default,
|
Photo: require("./PhotoPage.js").default,
|
||||||
|
Setting: require("./SettingPage.js").default,
|
||||||
|
UserInfoEdit: require("./UserInfoEditPage.js").default,
|
||||||
|
UserIntroEdit: require("./UserIntroEditPage.js").default,
|
||||||
|
UserNameEdit: require("./UserNameEditPage.js").default,
|
||||||
User: require("./UserPage.js").default,
|
User: require("./UserPage.js").default,
|
||||||
Write: require("./WritePage.js").default
|
Write: require("./WritePage.js").default
|
||||||
}
|
}
|
11
src/updateInfo.js
Normal file
11
src/updateInfo.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export default {
|
||||||
|
version: 5,
|
||||||
|
date: '4月9日',
|
||||||
|
info: `
|
||||||
|
1.增加草稿本
|
||||||
|
2.修复桌面图标提示点不掉的问题
|
||||||
|
3.优化话题UI
|
||||||
|
4.优化 iPhone X 兼容
|
||||||
|
5.设置页增加关注用户入口
|
||||||
|
6.点击 Tab 图标回到顶部,再次点击刷新列表
|
||||||
|
`}
|
|
@ -18,6 +18,7 @@ const IS_IPHONEX = isIphoneX();
|
||||||
|
|
||||||
|
|
||||||
const baseUrl = 'http://open.timepill.net/api';
|
const baseUrl = 'http://open.timepill.net/api';
|
||||||
|
const v2Url = 'http://v2.timepill.net/api';
|
||||||
|
|
||||||
|
|
||||||
async function login(username, password) {
|
async function login(username, password) {
|
||||||
|
@ -42,6 +43,12 @@ async function login(username, password) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function logout() {
|
||||||
|
TokenManager.setUserToken('');
|
||||||
|
TokenManager.setUserInfo(false);
|
||||||
|
TokenManager.setLoginPassword('');
|
||||||
|
}
|
||||||
|
|
||||||
async function getSelfInfo() {
|
async function getSelfInfo() {
|
||||||
return call('GET', '/users/my');
|
return call('GET', '/users/my');
|
||||||
}
|
}
|
||||||
|
@ -54,6 +61,20 @@ async function getUserInfo(id) {
|
||||||
return call('GET', '/users/' + id)
|
return call('GET', '/users/' + id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateUserIcon(photoUri) {
|
||||||
|
return upload('POST', '/users/icon', {
|
||||||
|
icon: {uri: photoUri, name: 'image.jpg', type: 'image/jpg'}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateUserInfo(name, intro) {
|
||||||
|
return call('PUT', '/users', {
|
||||||
|
name: name,
|
||||||
|
intro: intro
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function getTodayDiaries(page = 1, page_size = 20, first_id = '') {
|
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}`)
|
return call('GET', '/diaries/today?page=' + page + '&page_size=' + page_size + `&first_id=${first_id}`)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
|
@ -216,6 +237,10 @@ async function report(user_id, diary_id) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function feedback(content) {
|
||||||
|
return callV2('POST', '/feedback', {content});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function upload(method, api, body) {
|
async function upload(method, api, body) {
|
||||||
let token = await TokenManager.getUserToken();
|
let token = await TokenManager.getUserToken();
|
||||||
|
@ -245,9 +270,8 @@ async function upload(method, api, body) {
|
||||||
, 60000);
|
, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function call(method, api, body, _timeout = 10000) {
|
async function call(method, api, body = null, _timeout = 10000) {
|
||||||
let token = await TokenManager.getUserToken();
|
let token = await TokenManager.getUserToken();
|
||||||
|
|
||||||
return timeout(fetch(baseUrl + api, {
|
return timeout(fetch(baseUrl + api, {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -268,6 +292,31 @@ async function call(method, api, body, _timeout = 10000) {
|
||||||
, _timeout);
|
, _timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function callV2(method, api, body = null, _timeout = 10000) {
|
||||||
|
let token = await TokenManager.getToken();
|
||||||
|
return timeout(fetch(v2Url + api, {
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
'Authorization': token,
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-TP-OS': OS,
|
||||||
|
'X-TP-OS-Version': OS_VERSION,
|
||||||
|
'X-TP-Version': VERSION,
|
||||||
|
'X-Device-ID': DEVICE_ID,
|
||||||
|
},
|
||||||
|
body: body ? JSON.stringify(body) : null
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.then(checkStatus)
|
||||||
|
.then(parseJSON)
|
||||||
|
.catch(handleCatch)
|
||||||
|
|
||||||
|
,_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
async function checkStatus(response) {
|
async function checkStatus(response) {
|
||||||
if (response.status >= 200 && response.status < 300) {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
return response;
|
return response;
|
||||||
|
@ -332,8 +381,12 @@ export default {
|
||||||
IS_IPHONEX,
|
IS_IPHONEX,
|
||||||
|
|
||||||
login,
|
login,
|
||||||
|
logout,
|
||||||
getSelfInfoByStore,
|
getSelfInfoByStore,
|
||||||
getUserInfo,
|
getUserInfo,
|
||||||
|
|
||||||
|
updateUserIcon,
|
||||||
|
updateUserInfo,
|
||||||
|
|
||||||
getTodayDiaries,
|
getTodayDiaries,
|
||||||
getFollowDiaries,
|
getFollowDiaries,
|
||||||
|
@ -367,5 +420,6 @@ export default {
|
||||||
addDiary,
|
addDiary,
|
||||||
updateDiary,
|
updateDiary,
|
||||||
|
|
||||||
report
|
report,
|
||||||
|
feedback
|
||||||
}
|
}
|
|
@ -4,6 +4,8 @@ export default {
|
||||||
updateDiarys: 'updateDiarys',
|
updateDiarys: 'updateDiarys',
|
||||||
updateComments: 'updateComments',
|
updateComments: 'updateComments',
|
||||||
|
|
||||||
commentPressed: 'commentPressed'
|
commentPressed: 'commentPressed',
|
||||||
|
passwordUpdated: 'passwordUpdated',
|
||||||
|
updateNewsRead: 'updateNewsRead',
|
||||||
|
userInfoUpdated: 'userInfoUpdated'
|
||||||
}
|
}
|
Loading…
Reference in a new issue