mirror of
https://github.com/timepill/timepill-app.git
synced 2025-04-30 09:59:31 +08:00
1. 写日记页面选择日记本模态框
2. 关注/被关注用户删除
This commit is contained in:
parent
3d44a3aaf5
commit
d862735d6f
6 changed files with 282 additions and 12 deletions
|
@ -1,5 +1,6 @@
|
||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {StyleSheet, Text, View, InteractionManager, FlatList} from 'react-native';
|
import {StyleSheet, Text, View, InteractionManager, FlatList, Alert} from 'react-native';
|
||||||
|
import {Navigation} from 'react-native-navigation';
|
||||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
import Touchable from '../touchable';
|
import Touchable from '../touchable';
|
||||||
|
@ -35,6 +36,41 @@ export default class FollowUserList extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onItemPress(user) {
|
||||||
|
Navigation.push(this.props.componentId, {
|
||||||
|
component: {
|
||||||
|
name: 'User',
|
||||||
|
options: {
|
||||||
|
bottomTabs: {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
// hide bottom tab for android
|
||||||
|
drawBehind: true,
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
passProps: {
|
||||||
|
user: user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDeletePress(user) {
|
||||||
|
Alert.alert('提示', '确定删除关注?', [
|
||||||
|
{text: '删除', style: 'destructive', onPress: () => {
|
||||||
|
this.props.onDeletePress(user.id)
|
||||||
|
.done(() => {
|
||||||
|
let filterUsers = this.state.users.filter((it) => it.id !== user.id);
|
||||||
|
this.setState({
|
||||||
|
users: filterUsers
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}},
|
||||||
|
{text: '取消', onPress: () => {}}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
if (this.state.refreshing) {
|
if (this.state.refreshing) {
|
||||||
return;
|
return;
|
||||||
|
@ -119,11 +155,11 @@ export default class FollowUserList extends Component {
|
||||||
|
|
||||||
renderItem={({item}) => {
|
renderItem={({item}) => {
|
||||||
return (
|
return (
|
||||||
<Touchable key={item.id} onPress={() => {}}>
|
<Touchable key={item.id} onPress={() => this._onItemPress(item)}>
|
||||||
<View style={localStyle.box}>
|
<View style={localStyle.box}>
|
||||||
<UserIcon iconUrl={item.iconUrl}></UserIcon>
|
<UserIcon iconUrl={item.iconUrl}></UserIcon>
|
||||||
<Text style={localStyle.userName}>{item.name}</Text>
|
<Text style={localStyle.userName}>{item.name}</Text>
|
||||||
<Touchable onPress={() => {}}>
|
<Touchable onPress={() => this._onDeletePress(item)}>
|
||||||
<Ionicons name="md-close" size={20}
|
<Ionicons name="md-close" size={20}
|
||||||
style={localStyle.removeIcon}
|
style={localStyle.removeIcon}
|
||||||
color={Color.inactiveText} />
|
color={Color.inactiveText} />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {View, StyleSheet, Text, Image, ImageBackground, TouchableOpacity} from 'react-native';
|
import {View, StyleSheet, Text, Image, ImageBackground} from 'react-native';
|
||||||
|
|
||||||
import Api from '../../util/api';
|
import Api from '../../util/api';
|
||||||
import Color from '../../style/color'
|
import Color from '../../style/color'
|
||||||
|
|
92
src/component/notebook/notebookLine.js
Normal file
92
src/component/notebook/notebookLine.js
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
Alert,
|
||||||
|
InteractionManager,
|
||||||
|
TouchableOpacity
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
import Api from '../../util/api';
|
||||||
|
import Notebook from './notebook'
|
||||||
|
|
||||||
|
|
||||||
|
export default class NotebookLine extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
notebooks: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
InteractionManager.runAfterInteractions(() => {
|
||||||
|
this.load();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
load() {
|
||||||
|
Api.getSelfNotebooks()
|
||||||
|
.then(notebooks => {
|
||||||
|
if(!notebooks || !notebooks.filter) {
|
||||||
|
notebooks = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const unExpiredBooks = notebooks.filter(it => !it.isExpired);
|
||||||
|
if(unExpiredBooks.length === 0) {
|
||||||
|
Alert.alert('提示', '没有可用日记本,无法写日记', [
|
||||||
|
{text: '取消', onPress: () => {}},
|
||||||
|
{text: '创建一个', onPress: () => {}}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
notebooks: unExpiredBooks
|
||||||
|
});
|
||||||
|
|
||||||
|
}).done(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ScrollView horizontal={true}
|
||||||
|
contentContainerStyle={localStyle.container}
|
||||||
|
|
||||||
|
keyboardDismissMode='on-drag'
|
||||||
|
keyboardShouldPersistTaps='always'
|
||||||
|
|
||||||
|
snapToAlignment='start'
|
||||||
|
snapToInterval={300}
|
||||||
|
|
||||||
|
decelerationRate={0}
|
||||||
|
showsHorizontalScrollIndicator={true}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
this.state.notebooks.map((notebook) => {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity key={notebook.id} activeOpacity={0.7}
|
||||||
|
onPress={this.props.onNotebookPress}>
|
||||||
|
|
||||||
|
<Notebook key={notebook.id} style={{paddingRight: 10}}
|
||||||
|
notebook={notebook} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStyle = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
padding: 10,
|
||||||
|
paddingRight: 0,
|
||||||
|
paddingBottom:0
|
||||||
|
}
|
||||||
|
});
|
|
@ -14,7 +14,7 @@ import FollowingUserData from '../dataLoader/followingUserData'
|
||||||
import FollowedByUserData from '../dataLoader/followedByUserData'
|
import FollowedByUserData from '../dataLoader/followedByUserData'
|
||||||
|
|
||||||
|
|
||||||
export default class FollowPage extends Component {
|
export default class FollowUserPage extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -70,9 +70,17 @@ export default class FollowPage extends Component {
|
||||||
_renderScene = SceneMap({
|
_renderScene = SceneMap({
|
||||||
following: () => <FollowUserList
|
following: () => <FollowUserList
|
||||||
listType={'followingUser'} dataSource={new FollowingUserData()}
|
listType={'followingUser'} dataSource={new FollowingUserData()}
|
||||||
|
onDeletePress={async (id) => {
|
||||||
|
return Api.deleteFollow(id);
|
||||||
|
}}
|
||||||
|
{...this.props}
|
||||||
/>,
|
/>,
|
||||||
followedBy: () => <FollowUserList
|
followedBy: () => <FollowUserList
|
||||||
listType={'followedByUser'} dataSource={new FollowedByUserData()}
|
listType={'followedByUser'} dataSource={new FollowedByUserData()}
|
||||||
|
onDeletePress={async (id) => {
|
||||||
|
return Api.deleteFollowBy(id);
|
||||||
|
}}
|
||||||
|
{...this.props}
|
||||||
/>
|
/>
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {Platform, StyleSheet, Text, View, ScrollView, TextInput, TouchableOpacity} from 'react-native';
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
ScrollView,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
Modal,
|
||||||
|
Animated,
|
||||||
|
Easing,
|
||||||
|
TouchableWithoutFeedback
|
||||||
|
} from 'react-native';
|
||||||
import {Navigation} from 'react-native-navigation';
|
import {Navigation} from 'react-native-navigation';
|
||||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
|
@ -7,6 +18,8 @@ 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 NotebookLine from '../component/notebook/notebookLine'
|
||||||
|
|
||||||
|
|
||||||
export default class WritePage extends Component {
|
export default class WritePage extends Component {
|
||||||
|
|
||||||
|
@ -15,7 +28,11 @@ export default class WritePage extends Component {
|
||||||
Navigation.events().bindComponent(this);
|
Navigation.events().bindComponent(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
content: ''
|
content: '',
|
||||||
|
|
||||||
|
modalVisible: false,
|
||||||
|
fadeAnimOpacity: new Animated.Value(0),
|
||||||
|
fadeAnimHeight: new Animated.Value(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +61,40 @@ export default class WritePage extends Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openModal() {
|
||||||
|
this.setState({modalVisible: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeModal(showKeyboard = true) {
|
||||||
|
this.contentInput.blur();
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.timing(
|
||||||
|
this.state.fadeAnimOpacity,
|
||||||
|
{
|
||||||
|
toValue: 0,
|
||||||
|
duration: 350,
|
||||||
|
easing: Easing.out(Easing.cubic)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Animated.timing(
|
||||||
|
this.state.fadeAnimHeight,
|
||||||
|
{
|
||||||
|
toValue: 0,
|
||||||
|
duration: 350,
|
||||||
|
easing: Easing.out(Easing.cubic)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]).start(({finished}) => {
|
||||||
|
this.setState({modalVisible: false});
|
||||||
|
if(!finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(showKeyboard) {
|
||||||
|
setTimeout(() => this.contentInput.focus(), 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ScrollView style={localStyle.container}
|
<ScrollView style={localStyle.container}
|
||||||
|
@ -68,7 +119,7 @@ export default class WritePage extends Component {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View style={localStyle.bottomBar}>
|
<View style={localStyle.bottomBar}>
|
||||||
<TouchableOpacity onPress={() => {}}>
|
<TouchableOpacity onPress={this.openModal.bind(this)}>
|
||||||
<View style={localStyle.notebookButton}>
|
<View style={localStyle.notebookButton}>
|
||||||
<Ionicons name='ios-bookmarks-outline' size={16}
|
<Ionicons name='ios-bookmarks-outline' size={16}
|
||||||
color={Color.text} style={{marginTop: 2, marginRight: 6}} />
|
color={Color.text} style={{marginTop: 2, marginRight: 6}} />
|
||||||
|
@ -88,9 +139,63 @@ export default class WritePage extends Component {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{this.renderModal()}
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderModal() {
|
||||||
|
return (
|
||||||
|
<Modal animationType='none' transparent={true}
|
||||||
|
visible={this.state.modalVisible}
|
||||||
|
onShow={() => {
|
||||||
|
Animated.parallel([
|
||||||
|
Animated.timing(
|
||||||
|
this.state.fadeAnimOpacity,
|
||||||
|
{
|
||||||
|
toValue: 0.4,
|
||||||
|
duration: 350,
|
||||||
|
easing: Easing.out(Easing.cubic)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Animated.timing(
|
||||||
|
this.state.fadeAnimHeight,
|
||||||
|
{
|
||||||
|
toValue: Api.IS_IOS
|
||||||
|
? (Api.IS_IPHONEX ? 280 : 250)
|
||||||
|
: 260,
|
||||||
|
duration: 350,
|
||||||
|
easing: Easing.out(Easing.cubic)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]).start();
|
||||||
|
}}
|
||||||
|
onRequestClose={() => {}}
|
||||||
|
>
|
||||||
|
<View style={{flex: 1}}>
|
||||||
|
<TouchableWithoutFeedback onPress={this.closeModal.bind(this)} style={{flex: 1}}>
|
||||||
|
<Animated.View style={{ flex: 1, backgroundColor: "black", opacity: this.state.fadeAnimOpacity }} />
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
|
||||||
|
<Animated.View style={{height: this.state.fadeAnimHeight, backgroundColor: '#fff'}}>
|
||||||
|
<View style={localStyle.modalBanner}>
|
||||||
|
<TouchableOpacity onPress={() => {}} style={localStyle.modalButton}>
|
||||||
|
<Text style={localStyle.modalButtonText}>新添</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Text style={{padding: 10, color: Color.text}}>选择日记本</Text>
|
||||||
|
<TouchableOpacity onPress={this.closeModal.bind(this)} style={localStyle.modalButton}>
|
||||||
|
<Text style={localStyle.modalButtonText}>取消</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<NotebookLine onNotebookPress={() => {}}></NotebookLine>
|
||||||
|
|
||||||
|
</Animated.View>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const localStyle = StyleSheet.create({
|
const localStyle = StyleSheet.create({
|
||||||
|
@ -138,5 +243,22 @@ const localStyle = StyleSheet.create({
|
||||||
height: 40,
|
height: 40,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
|
||||||
|
modalBanner: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
borderTopColor: '#e2e2e2',
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderBottomColor: '#e2e2e2',
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth
|
||||||
|
},
|
||||||
|
modalButton: {
|
||||||
|
paddingHorizontal: 15,
|
||||||
|
paddingVertical: 10
|
||||||
|
},
|
||||||
|
modalButtonText: {
|
||||||
|
color: Color.light,
|
||||||
|
fontSize: 15,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,6 +6,7 @@ import TokenManager from './token'
|
||||||
|
|
||||||
|
|
||||||
const IS_ANDROID = Platform.OS === 'android';
|
const IS_ANDROID = Platform.OS === 'android';
|
||||||
|
const IS_IOS = Platform.OS === 'ios';
|
||||||
const DEVICE_WINDOW = Dimensions.get('window')
|
const DEVICE_WINDOW = Dimensions.get('window')
|
||||||
|
|
||||||
const OS = DeviceInfo.getSystemName();
|
const OS = DeviceInfo.getSystemName();
|
||||||
|
@ -45,6 +46,14 @@ async function getSelfInfo() {
|
||||||
return call('GET', '/users/my');
|
return call('GET', '/users/my');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getSelfInfoByStore() {
|
||||||
|
return await TokenManager.getUserInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUserInfo(id) {
|
||||||
|
return call('GET', '/users/' + id)
|
||||||
|
}
|
||||||
|
|
||||||
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) => {
|
||||||
|
@ -99,12 +108,12 @@ async function getRelationReverseUsers(page, page_size) {
|
||||||
return call('GET', `/relation/reverse?page=${page}&page_size=${page_size}`);
|
return call('GET', `/relation/reverse?page=${page}&page_size=${page_size}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSelfInfoByStore() {
|
async function deleteFollow(user_id) {
|
||||||
return await TokenManager.getUserInfo();
|
return call('DELETE', '/relation/' + user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserInfo(id) {
|
async function deleteFollowBy(user_id) {
|
||||||
return call('GET', '/users/' + id)
|
return call('DELETE', '/relation/reverse/' + user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMessagesHistory() {
|
async function getMessagesHistory() {
|
||||||
|
@ -191,6 +200,7 @@ function handleCatch(err) {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
IS_ANDROID,
|
IS_ANDROID,
|
||||||
|
IS_IOS,
|
||||||
DEVICE_WINDOW,
|
DEVICE_WINDOW,
|
||||||
OS,
|
OS,
|
||||||
OS_VERSION,
|
OS_VERSION,
|
||||||
|
@ -214,6 +224,8 @@ export default {
|
||||||
|
|
||||||
getRelationUsers,
|
getRelationUsers,
|
||||||
getRelationReverseUsers,
|
getRelationReverseUsers,
|
||||||
|
deleteFollow,
|
||||||
|
deleteFollowBy,
|
||||||
|
|
||||||
getMessagesHistory
|
getMessagesHistory
|
||||||
}
|
}
|
Loading…
Reference in a new issue