This commit is contained in:
ammarahm-ed
2020-01-11 23:05:39 +05:00
parent ea94048294
commit 9e24f2b40e
2 changed files with 233 additions and 144 deletions

View File

@@ -1,13 +1,16 @@
import React, {useState} from 'react'; import React, {Component} from 'react';
import { import {
View, View,
TouchableOpacity, TouchableOpacity,
Dimensions, Dimensions,
ScrollView, ScrollView,
Modal, Modal,
KeyboardAvoidingView,
Platform,
} from 'react-native'; } from 'react-native';
import PropTypes from 'prop-types';
import {styles} from './styles'; import {styles} from './styles';
let scrollViewRef;
const deviceHeight = Dimensions.get('window').height; const deviceHeight = Dimensions.get('window').height;
const getElevation = elevation => { const getElevation = elevation => {
@@ -20,173 +23,213 @@ const getElevation = elevation => {
}; };
}; };
const ActionSheet = ({ export default class ActionSheet extends Component {
ref, constructor(props) {
children = <View />, super(props);
animated = true, this.state = {
animationType = 'fade', modalVisible: false,
closeOnPressBack = true, scrollable: false,
gestureEnabled = true, layoutHasCalled: false,
bounceOnOpen = true, };
bounceOffset = 20, this.customComponentHeight;
springOffset = 50, this.prevScroll;
elevation = 5, this.scrollAnimationEndValue;
initialOffsetFromBottom = 0.6, this.hasBounced;
indicatorColor = 'gray', this.scrollViewRef;
customStyles = {backgroundColor: 'white'},
overlayColor = 'rgba(0,0,0,0.3)',
onClose = () => {},
onOpen = () => {},
}) => {
const [modalVisible, setModalVisible] = useState(false);
const [scrollable, setScrollable] = useState(false);
const [layoutHasCalled, setLayoutHasCalled] = useState(false);
ActionSheet.customComponentHeight;
ActionSheet.prevScroll;
ActionSheet.scrollAnimationEndValue;
ActionSheet.hasBounced;
const _setModalVisible = () => {
if (!modalVisible) {
setModalVisible(true);
if (gestureEnabled) {
setScrollable(true);
} }
_setModalVisible = () => {
if (!this.state.modalVisible) {
this.setState({
modalVisible: true,
scrollable: this.props.gestureEnabled,
});
} else { } else {
_hideModal(); this._hideModal();
} }
}; };
const _hideModal = () => { _hideModal = () => {
_scrollTo(0); this._scrollTo(0);
setTimeout(() => { setTimeout(() => {
setLayoutHasCalled(false); this.setState(
setModalVisible(false); {
ActionSheet.customComponentHeight = null; modalVisible: false,
ActionSheet.prevScroll = null; layoutHasCalled: false,
ActionSheet.scrollAnimationEndValue = null; },
ActionSheet.hasBounced = null; () => {
if (typeof onClose === 'function') onClose(); if (typeof this.props.onClose === 'function') this.props.onClose();
},
);
}, 150); }, 150);
}; };
const _showModal = event => { _showModal = event => {
if (layoutHasCalled) { let {gestureEnabled, bounceOffset, initialOffsetFromBottom} = this.props;
let addFactor = deviceHeight * 0.1;
let height = event.nativeEvent.layout.height;
console.log('layout called again');
if (this.state.layoutHasCalled) {
let diff;
if (height > this.customComponentHeight) {
diff = height - this.customComponentHeight;
this._scrollTo(this.prevScroll + diff);
console.log(this.prevScroll);
this.customComponentHeight = height;
} else {
diff = this.customComponentHeight - height;
this._scrollTo(this.prevScroll - diff);
this.customComponentHeight = height;
}
return; return;
} else { } else {
ActionSheet.customComponentHeight = event.nativeEvent.layout.height; this.customComponentHeight = height;
let addFactor = deviceHeight * 0.1;
_scrollTo( this._scrollTo(
gestureEnabled gestureEnabled
? ActionSheet.customComponentHeight * initialOffsetFromBottom + ? this.customComponentHeight * initialOffsetFromBottom +
addFactor + addFactor +
bounceOffset bounceOffset
: ActionSheet.customComponentHeight + bounceOffset, : this.customComponentHeight + bounceOffset,
); );
this.setState({
setLayoutHasCalled(true); layoutHasCalled: true,
});
} }
}; };
const _onScrollBeginDrag = event => { _onScrollBeginDrag = event => {
let verticalOffset = event.nativeEvent.contentOffset.y; let verticalOffset = event.nativeEvent.contentOffset.y;
ActionSheet.prevScroll = verticalOffset;
this.prevScroll = verticalOffset;
}; };
const _onScrollEndDrag = event => { _onScrollEndDrag = event => {
let {springOffset} = this.props;
let verticalOffset = event.nativeEvent.contentOffset.y; let verticalOffset = event.nativeEvent.contentOffset.y;
if (ActionSheet.prevScroll < verticalOffset) { if (this.prevScroll < verticalOffset) {
if (verticalOffset - ActionSheet.prevScroll > springOffset * 0.75) { if (verticalOffset - this.prevScroll > springOffset * 0.75) {
let addFactor = deviceHeight * 0.1; let addFactor = deviceHeight * 0.1;
_scrollTo(ActionSheet.customComponentHeight + addFactor); this._scrollTo(this.customComponentHeight + addFactor);
} else { } else {
_scrollTo(ActionSheet.prevScroll); this._scrollTo(this.prevScroll);
} }
} else { } else {
if (ActionSheet.prevScroll - verticalOffset > springOffset) { if (this.prevScroll - verticalOffset > springOffset) {
_hideModal(); this._hideModal();
} else { } else {
_scrollTo(ActionSheet.prevScroll); this._scrollTo(this.prevScroll);
} }
} }
}; };
const _scrollTo = (y, bouncing) => { _scrollTo = (y, bouncing) => {
let {bounceOffset, bounceOnOpen} = this.props;
this.hasBounced = false;
if (!bouncing && bounceOnOpen) { if (!bouncing && bounceOnOpen) {
ActionSheet.scrollAnimationEndValue = y + bounceOffset; this.scrollAnimationEndValue = y + bounceOffset;
} else { } else {
ActionSheet.scrollAnimationEndValue = y; this.scrollAnimationEndValue = y;
} }
ActionSheet.hasBounced = false;
scrollViewRef.scrollTo({ this.scrollViewRef.scrollTo({
x: 0, x: 0,
y: ActionSheet.scrollAnimationEndValue, y: this.scrollAnimationEndValue,
animated: true, animated: true,
}); });
}; };
const _onTouchMove = () => { _onTouchMove = () => {
setScrollable(false); this._hideModal();
this.setState({
scrollable: false,
});
}; };
const _onTouchStart = () => { _onTouchStart = () => {
setScrollable(false); this._hideModal();
this.setState({
scrollable: false,
});
}; };
const _onTouchEnd = () => { _onTouchEnd = () => {
if (gestureEnabled) { if (this.props.gestureEnabled) {
setScrollable(true); this.setState({
scrollable: true,
});
} }
}; };
const _onScrollEndAnimation = () => { _onScrollEndAnimation = event => {
if (!ActionSheet.hasBounced) { this.prevScroll = event.nativeEvent.contentOffset.y;
_scrollTo(ActionSheet.scrollAnimationEndValue - bounceOffset, true);
ActionSheet.hasBounced = true; let {bounceOffset, bounceOnOpen} = this.props;
if (!this.hasBounced && bounceOnOpen) {
this._scrollTo(this.scrollAnimationEndValue - bounceOffset, true);
this.hasBounced = true;
} }
}; };
render() {
let {scrollable, modalVisible} = this.state;
let {
animationType,
animated,
onOpen,
closeOnPressBack,
overlayColor,
bounceOnOpen,
gestureEnabled,
elevation,
indicatorColor,
children,
customStyles,
} = this.props;
return ( return (
<Modal <Modal
ref={ref}
visible={modalVisible} visible={modalVisible}
animationType={animationType} animationType={animationType}
animated={animated} animated={animated}
onShow={() => onOpen} onShow={() => onOpen}
onRequestClose={() => { onRequestClose={() => {
if (closeOnPressBack) _hideModal(); if (closeOnPressBack) this._hideModal();
}} }}
transparent={true}> transparent={true}>
<View style={[styles.parentContainer, {backgroundColor: overlayColor}]}> <View style={[styles.parentContainer, {backgroundColor: overlayColor}]}>
<KeyboardAvoidingView
style={{
width: '100%',
}}
enabled={Platform.OS === 'ios' ? true : false}
behavior="position">
<ScrollView <ScrollView
bounces={false} bounces={false}
ref={ref => (scrollViewRef = ref)} ref={ref => (this.scrollViewRef = ref)}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
scrollEnabled={scrollable} scrollEnabled={scrollable}
onScrollBeginDrag={_onScrollBeginDrag} onScrollBeginDrag={this._onScrollBeginDrag}
onScrollEndDrag={_onScrollEndDrag} onScrollEndDrag={this._onScrollEndDrag}
onMomentumScrollEnd={() => { onMomentumScrollEnd={this._onScrollEndAnimation}
if (bounceOnOpen) { onScrollAnimationEnd={this._onScrollEndAnimation}
_onScrollEndAnimation(); onTouchEnd={this._onTouchEnd}
}
}}
onScrollAnimationEnd={_onScrollEndAnimation}
onTouchEnd={_onTouchEnd}
overScrollMode="always" overScrollMode="always"
style={[styles.scrollview]}> style={[styles.scrollview]}>
<View <View
onTouchMove={_onTouchMove} onTouchMove={this._onTouchMove}
onTouchStart={_onTouchStart} onTouchStart={this._onTouchStart}
onTouchEnd={_onTouchEnd} onTouchEnd={this._onTouchEnd}
style={{ style={{
height: deviceHeight * 1.1, height: deviceHeight * 1.1,
width: '100%', width: '100%',
}}> }}>
<TouchableOpacity <TouchableOpacity
onPress={_hideModal} onPress={this._hideModal}
onLongPress={_hideModal} onLongPress={this._hideModal}
style={{ style={{
height: deviceHeight, height: deviceHeight,
width: '100%', width: '100%',
@@ -194,7 +237,7 @@ const ActionSheet = ({
/> />
</View> </View>
<View <View
onLayout={_showModal} onLayout={this._showModal}
style={[ style={[
styles.container, styles.container,
customStyles, customStyles,
@@ -202,16 +245,54 @@ const ActionSheet = ({
]}> ]}>
{gestureEnabled ? ( {gestureEnabled ? (
<View <View
style={[styles.indicator, {backgroundColor: indicatorColor}]} style={[
styles.indicator,
{backgroundColor: indicatorColor},
]}
/> />
) : null} ) : null}
{children} {children}
</View> </View>
</ScrollView> </ScrollView>
</KeyboardAvoidingView>
</View> </View>
</Modal> </Modal>
); );
}; }
}
export default ActionSheet; ActionSheet.defaultProps = {
children: <View />,
animated: true,
animationType: 'fade',
closeOnPressBack: true,
gestureEnabled: true,
bounceOnOpen: true,
bounceOffset: 20,
springOffset: 50,
elevation: 5,
initialOffsetFromBottom: 0.6,
indicatorColor: 'gray',
customStyles: {},
overlayColor: 'rgba(0,0,0,0.3)',
onClose: () => {},
onOpen: () => {},
};
ActionSheet.propTypes = {
children: PropTypes.node,
animated: PropTypes.bool,
animationType: PropTypes.oneOf(['none', 'slide', 'fade']),
closeOnPressBack: PropTypes.bool,
gestureEnabled: PropTypes.bool,
bounceOnOpen: PropTypes.bool,
bounceOffset: PropTypes.number,
springOffset: PropTypes.number,
elevation: PropTypes.number,
initialOffsetFromBottom: PropTypes.number,
indicatorColor: PropTypes.string,
customStyles: PropTypes.object,
overlayColor: PropTypes.string,
onClose: PropTypes.func,
onOpen: PropTypes.func,
};

View File

@@ -1,4 +1,4 @@
import React, {useState} from 'react'; import React, {useState, useEffect} from 'react';
import { import {
View, View,
Text, Text,
@@ -28,7 +28,7 @@ const h = Dimensions.get('window').height;
let tagsInputRef; let tagsInputRef;
export const ActionSheetComponent = ({ export const ActionSheetComponent = ({
close = () => {}, close = () => {},
item = {}, item,
setWillRefresh = value => {}, setWillRefresh = value => {},
hasColors = false, hasColors = false,
hasTags = false, hasTags = false,
@@ -39,6 +39,10 @@ export const ActionSheetComponent = ({
const [focused, setFocused] = useState(false); const [focused, setFocused] = useState(false);
const [note, setNote] = useState(item ? item : {}); const [note, setNote] = useState(item ? item : {});
useEffect(() => {
setNote({...item});
}, [item]);
let tagToAdd = null; let tagToAdd = null;
let backPressCount = 0; let backPressCount = 0;
@@ -257,6 +261,10 @@ export const ActionSheetComponent = ({
return ( return (
<View <View
onLayout={() => {
console.log(item);
setNote({...item});
}}
style={{ style={{
paddingBottom: 15, paddingBottom: 15,
backgroundColor: colors.bg, backgroundColor: colors.bg,