mirror of
https://github.com/timepill/timepill-app.git
synced 2025-04-30 09:59:31 +08:00
1. 日记本“新增”按钮
2. 创建日记本页面(未完成) 3. 试用react-native-datepicker,用于选择日记本过期时间 - ios下月份显示英文,暂时没有配置项可以显示数字 - 安卓下界面良好
This commit is contained in:
parent
912cf0cabb
commit
0a7175a277
8 changed files with 333 additions and 1 deletions
|
@ -5,4 +5,14 @@
|
|||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
<style name="SpinnerDatePickerDialog" parent="android:Theme.Material.Light.Dialog">
|
||||
<item name="android:datePickerStyle">@style/MyDatePicker</item>
|
||||
<item name="android:colorAccent">#2196f3</item>
|
||||
<item name="android:colorControlNormal">#2196f3</item>
|
||||
</style>
|
||||
|
||||
<style name="MyDatePicker" parent="android:Widget.Material.DatePicker">
|
||||
<item name="android:datePickerMode">spinner</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -10821,6 +10821,14 @@
|
|||
"resolved": "http://registry.npm.taobao.org/react-native-actionsheet-api/download/react-native-actionsheet-api-1.0.4.tgz",
|
||||
"integrity": "sha1-AGJeOeRdy8KnERKB/xUDl+5ZUbI="
|
||||
},
|
||||
"react-native-datepicker": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npm.taobao.org/react-native-datepicker/download/react-native-datepicker-1.7.2.tgz",
|
||||
"integrity": "sha1-WNCCJZGgrJsyq6CCZQIioO4pZp0=",
|
||||
"requires": {
|
||||
"moment": "^2.22.0"
|
||||
}
|
||||
},
|
||||
"react-native-device-info": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npm.taobao.org/react-native-device-info/download/react-native-device-info-1.6.1.tgz",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"react": "16.8.3",
|
||||
"react-native": "0.59.5",
|
||||
"react-native-actionsheet-api": "^1.0.4",
|
||||
"react-native-datepicker": "^1.7.2",
|
||||
"react-native-device-info": "^1.6.1",
|
||||
"react-native-elements": "^0.19.0",
|
||||
"react-native-iphone-x-helper": "^1.0.2",
|
||||
|
|
82
src/component/dateInput.js
Normal file
82
src/component/dateInput.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
import React, {Component} from 'react';
|
||||
import {StyleSheet, Text, View, InteractionManager} from 'react-native';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
import DatePicker from 'react-native-datepicker'
|
||||
|
||||
|
||||
function now() {
|
||||
const d = new Date();
|
||||
const localTime = d.getTime();
|
||||
const localOffset = d.getTimezoneOffset() * 60000;
|
||||
const utc = localTime + localOffset;
|
||||
const offset = 8; //东 8 区
|
||||
const beijingTime = utc + (3600000 * offset);
|
||||
|
||||
return new Date(beijingTime);
|
||||
}
|
||||
|
||||
export default class DateInput extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.updateDate();
|
||||
this.state = {
|
||||
date: this.formatDate(this.nowDate)
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
this.updateDate();
|
||||
});
|
||||
}
|
||||
|
||||
updateDate() {
|
||||
this.nowDate = now();
|
||||
let nowMSec = this.nowDate.getTime();
|
||||
|
||||
let minExpiredMSec = 7 * 24 * 3600000; // at least 7 days to expire
|
||||
let minExpiredDate = new Date(nowMSec + minExpiredMSec);
|
||||
this.minDate = this.formatDate(minExpiredDate);
|
||||
|
||||
let maxExpiredMSec = 3650 * 24 * 3600000; // at most 10 years to expire
|
||||
let maxExpireDate = new Date(nowMSec + maxExpiredMSec);
|
||||
this.maxDate = this.formatDate(maxExpireDate);
|
||||
}
|
||||
|
||||
formatDate(date) {
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1;
|
||||
let day = date.getDate();
|
||||
|
||||
return year + '-' + month + '-' + day;
|
||||
}
|
||||
|
||||
getDate() {
|
||||
return this.state.date;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DatePicker mode="date" format="YYYY-MM-DD" showIcon={false}
|
||||
style={this.props.style}
|
||||
customStyles={this.props.customStyles}
|
||||
|
||||
confirmBtnText="确认"
|
||||
cancelBtnText="取消"
|
||||
|
||||
placeholder="过期日期"
|
||||
minDate={this.minDate}
|
||||
maxDate={this.maxDate}
|
||||
date={this.state.date}
|
||||
|
||||
onDateChange={(date) => {
|
||||
this.setState({date: date})
|
||||
}}
|
||||
|
||||
androidMode={'spinner'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
44
src/component/notebook/notebookAdd.js
Normal file
44
src/component/notebook/notebookAdd.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import React, {Component} from 'react';
|
||||
import {View, StyleSheet, Text, TouchableOpacity} from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
|
||||
import Color from '../../style/color'
|
||||
|
||||
|
||||
export default class NotebookAdd extends Component {
|
||||
|
||||
_defaultOnPress() {
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TouchableOpacity activeOpacity={0.7} onPress={
|
||||
this.props.onPress ? this.props.onPress : this._defaultOnPress.bind(this)
|
||||
}>
|
||||
<View style={localStyle.box}>
|
||||
<Ionicons name="md-add" size={48} color={Color.inactiveText} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const localStyle = StyleSheet.create({
|
||||
box: {
|
||||
flex: 1,
|
||||
width: 140,
|
||||
shadowColor: '#444',
|
||||
shadowOpacity: 0.1,
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 0
|
||||
},
|
||||
elevation: 1,
|
||||
backgroundColor: "#eee",
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
margin: 3,
|
||||
marginBottom: 15
|
||||
}
|
||||
});
|
|
@ -12,6 +12,7 @@ import {Navigation} from 'react-native-navigation';
|
|||
|
||||
import Api from '../../util/api';
|
||||
import Notebook from './notebook'
|
||||
import NotebookAdd from './notebookAdd'
|
||||
|
||||
|
||||
export default class NotebookList extends Component {
|
||||
|
@ -59,6 +60,17 @@ export default class NotebookList extends Component {
|
|||
return groups;
|
||||
}
|
||||
|
||||
_onAddPress() {
|
||||
Navigation.push(this.props.componentId, {
|
||||
component: {
|
||||
name: 'NotebookAdd',
|
||||
passProps: {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_onNotebookPress(notebook) {
|
||||
Navigation.push(this.props.componentId, {
|
||||
component: {
|
||||
|
@ -85,6 +97,10 @@ export default class NotebookList extends Component {
|
|||
let user = this.state.user;
|
||||
(user ? Api.getUserNotebooks(user.id) : Api.getSelfNotebooks())
|
||||
.then(notebooks => {
|
||||
if(!user) {
|
||||
notebooks.unshift({id: 'new'});
|
||||
}
|
||||
|
||||
let groups = this.createGroup(notebooks, this.itemsPerRow);
|
||||
this.setState({
|
||||
notebooks: groups
|
||||
|
@ -95,6 +111,16 @@ export default class NotebookList extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
_renderAdd() {
|
||||
return (<NotebookAdd key='new'
|
||||
onPress={() => this._onAddPress()}>
|
||||
</NotebookAdd>);
|
||||
}
|
||||
|
||||
_renderPlaceHolder() {
|
||||
return <View key="placeholder" style={{width: 140}} />;
|
||||
}
|
||||
|
||||
_renderItem(notebook) {
|
||||
return notebook ? (
|
||||
<TouchableOpacity key={notebook.id} activeOpacity={0.7}
|
||||
|
@ -113,11 +139,18 @@ export default class NotebookList extends Component {
|
|||
data={this.state.notebooks}
|
||||
|
||||
keyExtractor={(item, index) => {
|
||||
return item[0].id.toString()
|
||||
return item[0].id.toString();
|
||||
}}
|
||||
|
||||
renderItem={({item}) => {
|
||||
let row = item.map((notebook) => {
|
||||
if(!notebook) {
|
||||
return this._renderPlaceHolder();
|
||||
|
||||
} else if(notebook.id == 'new') {
|
||||
return this._renderAdd();
|
||||
}
|
||||
|
||||
return this._renderItem(notebook);
|
||||
});
|
||||
|
||||
|
|
153
src/page/NotebookAddPage.js
Normal file
153
src/page/NotebookAddPage.js
Normal file
|
@ -0,0 +1,153 @@
|
|||
import React, {Component} from 'react';
|
||||
import {StyleSheet, Text, View, ScrollView, Switch, TextInput, TouchableOpacity} from 'react-native';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import Color from '../style/color';
|
||||
import {Icon} from '../style/icon';
|
||||
import Api from '../util/api';
|
||||
|
||||
import DateInput from '../component/dateInput'
|
||||
|
||||
|
||||
export default class NotebookAddPage extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
Navigation.events().bindComponent(this);
|
||||
|
||||
this.state = {
|
||||
notebook: props.notebook,
|
||||
|
||||
subject: '',
|
||||
isPublic: false,
|
||||
dateString: ''
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
navigationButtonPressed({buttonId}) {
|
||||
console.log('date string:', this.dateInput.getDate());
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={localStyle.wrap}>
|
||||
|
||||
<View style={localStyle.group}>
|
||||
<View style={localStyle.item}>
|
||||
<TextInput style={localStyle.subject}
|
||||
underlineColorAndroid='transparent'
|
||||
selectionColor={Color.primary}
|
||||
autoCorrect={false}
|
||||
|
||||
placeholder="主题"
|
||||
value={this.state.subject}
|
||||
|
||||
onChangeText={(text) => this.setState({subject: text})}
|
||||
/>
|
||||
</View>
|
||||
<View style={localStyle.line} />
|
||||
|
||||
<View>
|
||||
<View style={localStyle.item}>
|
||||
<DateInput ref={(r) => {this.dateInput = r}}
|
||||
style={localStyle.datePickerStyle}
|
||||
customStyles={customDatePickerStyle}>
|
||||
</DateInput>
|
||||
</View>
|
||||
</View>
|
||||
<View style={localStyle.line} />
|
||||
|
||||
<View style={localStyle.item}>
|
||||
<Text style={localStyle.title}>公开日记本</Text>
|
||||
<Switch value={this.state.isPublic}
|
||||
onValueChange={(v) => this.setState({isPublic: v})}
|
||||
trackColor={Api.IS_ANDROID ? Color.textSelect : null}
|
||||
thumbColor={Api.IS_ANDROID && this.state.isPublic ? Color.light : null}
|
||||
/>
|
||||
</View>
|
||||
</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
|
||||
},
|
||||
subject: {
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
height: '100%',
|
||||
padding: 0
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
color: '#222'
|
||||
},
|
||||
line: {
|
||||
marginLeft: 15,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#c8c7cc'
|
||||
},
|
||||
datePickerStyle: {
|
||||
flex: 1,
|
||||
padding: 0,
|
||||
height: '100%',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
const customDatePickerStyle = StyleSheet.create({
|
||||
dateInput: {
|
||||
height: 45,
|
||||
alignItems: 'flex-start',
|
||||
borderWidth: 0
|
||||
},
|
||||
placeholderText: {
|
||||
fontSize: 16
|
||||
},
|
||||
dateText: {
|
||||
fontSize: 16
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -3,6 +3,7 @@ DiaryDetail: require("./DiaryDetailPage.js").default,
|
|||
Follow: require("./FollowPage.js").default,
|
||||
FollowUser: require("./FollowUserPage.js").default,
|
||||
Home: require("./HomePage.js").default,
|
||||
NotebookAdd: require("./NotebookAddPage.js").default,
|
||||
NotebookDetail: require("./NotebookDetailPage.js").default,
|
||||
NotificationHistory: require("./NotificationHistoryPage.js").default,
|
||||
Notification: require("./NotificationPage.js").default,
|
||||
|
|
Loading…
Reference in a new issue