Files
notesnook/apps/mobile/src/components/Container/index.js

305 lines
7.8 KiB
JavaScript
Raw Normal View History

2020-04-18 13:39:45 +05:00
import React, {useEffect, useState} from 'react';
import {
2020-01-18 01:04:33 +05:00
Keyboard,
KeyboardAvoidingView,
Platform,
SafeAreaView,
2020-01-18 01:04:33 +05:00
Text,
TouchableOpacity,
View,
} from 'react-native';
import * as Animatable from 'react-native-animatable';
2020-02-11 20:07:36 +05:00
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
2020-04-18 13:39:45 +05:00
import {br, opacity, pv, SIZE, WEIGHT} from '../../common/common';
import {useTracked} from '../../provider';
import {ACTIONS} from '../../provider/actions';
import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/eventManager';
import {eScrollEvent, eClearSearch} from '../../services/events';
import {db, getElevation, ToastEvent, DDS, selection} from '../../utils/utils';
import {Header} from '../header';
import {Search} from '../SearchInput';
2020-01-25 23:47:17 +05:00
import SelectionHeader from '../SelectionHeader';
2020-04-18 13:39:45 +05:00
import {inputRef} from '../../utils/refs';
import {useSafeArea} from 'react-native-safe-area-context';
2020-03-14 13:54:16 +05:00
2020-04-18 13:39:45 +05:00
const AnimatedKeyboardAvoidingView = Animatable.createAnimatableComponent(
KeyboardAvoidingView,
);
2020-01-20 16:24:01 +05:00
const AnimatedTouchableOpacity = Animatable.createAnimatableComponent(
TouchableOpacity,
);
export const Container = ({
children,
bottomButtonOnPress,
bottomButtonText,
2020-01-13 17:34:29 +05:00
noBottomButton = false,
2020-01-25 23:47:17 +05:00
data = [],
2020-01-27 00:25:19 +05:00
heading,
canGoBack = true,
menu,
customIcon,
verticalMenu = false,
preventDefaultMargins,
navigation = null,
isLoginNavigator,
placeholder = '',
2020-01-27 13:04:25 +05:00
noSearch = false,
noSelectionHeader = false,
2020-02-07 00:26:44 +05:00
headerColor = null,
2020-02-07 00:53:59 +05:00
type = null,
}) => {
// State
2020-01-17 21:26:01 +05:00
const [state, dispatch] = useTracked();
2020-04-18 13:39:45 +05:00
const {colors, selectionMode, searchResults, loading} = state;
2020-01-25 23:47:17 +05:00
const [text, setText] = useState('');
const [hideHeader, setHideHeader] = useState(false);
const [buttonHide, setButtonHide] = useState(false);
2020-04-16 13:57:51 +05:00
const insets = useSafeArea();
2020-01-25 23:47:17 +05:00
let offsetY = 0;
let countUp = 1;
let countDown = 0;
let searchResult = [];
const onScroll = y => {
if (searchResults.length > 0) return;
2020-01-27 13:04:25 +05:00
if (y < 30) {
countUp = 1;
countDown = 0;
setHideHeader(false);
}
2020-01-25 23:47:17 +05:00
if (y > offsetY) {
if (y - offsetY < 150 || countDown > 0) return;
countDown = 1;
countUp = 0;
setHideHeader(true);
} else {
2020-01-27 13:04:25 +05:00
if (offsetY - y < 50 || countUp > 0) return;
2020-01-25 23:47:17 +05:00
countDown = 0;
countUp = 1;
setHideHeader(false);
}
offsetY = y;
};
const onChangeText = value => {
2020-02-07 00:53:59 +05:00
setText(value);
2020-01-25 23:47:17 +05:00
};
const onSubmitEditing = async () => {
if (!text || text.length < 1) {
2020-03-03 11:26:12 +05:00
ToastEvent.show('Please enter a search keyword');
2020-01-25 23:47:17 +05:00
clearSearch();
2020-03-09 15:30:40 +05:00
return;
}
if (!type) return;
searchResult = await db.lookup[type](
data[0].data ? db.notes.all : data,
text,
);
if (!searchResult || searchResult.length === 0) {
ToastEvent.show('No search results found for ' + text, 'error');
2020-03-09 15:30:40 +05:00
return;
} else {
dispatch({
type: ACTIONS.SEARCH_RESULTS,
results: {
type,
results: searchResult,
keyword: text,
},
});
2020-01-25 23:47:17 +05:00
}
};
const onBlur = () => {
if (text && text.length < 1) {
clearSearch();
}
};
const onFocus = () => {
//setSearch(false);
};
const clearSearch = () => {
searchResult = null;
setText(null);
inputRef.current?.setNativeProps({
text: '',
});
2020-03-09 15:30:40 +05:00
dispatch({
type: ACTIONS.SEARCH_RESULTS,
results: {
results: [],
type: null,
keyword: null,
},
});
2020-01-25 23:47:17 +05:00
};
useEffect(() => {
eSubscribeEvent(eClearSearch, clearSearch);
Keyboard.addListener('keyboardDidShow', () => {
2020-01-20 16:24:01 +05:00
setTimeout(() => {
2020-03-15 09:39:14 +05:00
if (DDS.isTab) return;
2020-01-20 16:24:01 +05:00
setButtonHide(true);
}, 300);
});
Keyboard.addListener('keyboardDidHide', () => {
setTimeout(() => {
2020-03-15 09:39:14 +05:00
if (DDS.isTab) return;
setButtonHide(false);
2020-03-15 09:38:23 +05:00
}, 0);
});
return () => {
eUnSubscribeEvent(eClearSearch, clearSearch);
Keyboard.removeListener('keyboardDidShow', () => {
2020-01-20 16:24:01 +05:00
setTimeout(() => {
2020-03-15 09:39:14 +05:00
if (DDS.isTab) return;
2020-01-20 16:24:01 +05:00
setButtonHide(true);
}, 300);
});
Keyboard.removeListener('keyboardDidHide', () => {
setTimeout(() => {
2020-03-15 09:39:14 +05:00
if (DDS.isTab) return;
setButtonHide(false);
2020-03-15 09:38:23 +05:00
}, 0);
});
};
}, []);
2020-01-25 23:47:17 +05:00
useEffect(() => {
2020-03-18 11:58:56 +05:00
selection.data = data;
selection.type = type;
2020-01-25 23:47:17 +05:00
eSubscribeEvent(eScrollEvent, onScroll);
return () => {
eUnSubscribeEvent(eScrollEvent, onScroll);
};
});
// Render
return (
2020-04-16 13:57:51 +05:00
<AnimatedKeyboardAvoidingView
transition="backgroundColor"
duration={300}
style={{
height: '100%',
2020-01-24 22:52:34 +05:00
backgroundColor: colors.bg,
2020-04-18 13:39:45 +05:00
paddingTop: insets.top,
2020-04-16 13:57:51 +05:00
}}
behavior="padding"
2020-04-18 13:39:45 +05:00
enabled={Platform.OS === 'ios' ? true : false}>
2020-04-16 13:57:51 +05:00
{noSelectionHeader ? null : <SelectionHeader items={data} />}
<View
style={{
2020-04-16 13:57:51 +05:00
position: selectionMode ? 'relative' : 'absolute',
backgroundColor: colors.bg,
zIndex: 999,
display: selectionMode ? 'none' : 'flex',
width: '100%',
}}>
2020-04-16 13:57:51 +05:00
<Header
menu={menu}
hide={hideHeader}
verticalMenu={verticalMenu}
showSearch={() => {
setHideHeader(false);
countUp = 0;
countDown = 0;
}}
headerColor={headerColor}
navigation={navigation}
colors={colors}
isLoginNavigator={isLoginNavigator}
preventDefaultMargins={preventDefaultMargins}
heading={heading}
canGoBack={canGoBack}
customIcon={customIcon}
/>
2020-01-25 23:47:17 +05:00
2020-04-16 13:57:51 +05:00
{data[0] && !noSearch ? (
<Search
clear={() => setText('')}
2020-01-26 22:15:08 +05:00
hide={hideHeader}
2020-04-16 13:57:51 +05:00
onChangeText={onChangeText}
2020-02-07 00:26:44 +05:00
headerColor={headerColor}
2020-04-16 13:57:51 +05:00
onSubmitEditing={onSubmitEditing}
placeholder={placeholder}
onBlur={onBlur}
onFocus={onFocus}
clearSearch={clearSearch}
value={text}
2020-01-26 22:15:08 +05:00
/>
2020-04-16 13:57:51 +05:00
) : null}
</View>
2020-01-26 22:15:08 +05:00
2020-04-16 13:57:51 +05:00
{children}
2020-01-25 23:47:17 +05:00
2020-04-16 13:57:51 +05:00
{noBottomButton ? null : (
<Animatable.View
transition={['translateY', 'opacity']}
useNativeDriver={true}
duration={300}
style={{
width: '100%',
opacity: buttonHide ? 0 : 1,
position: 'absolute',
paddingHorizontal: 12,
zIndex: 10,
2020-04-18 13:39:45 +05:00
bottom: Platform.OS === 'ios' ? insets.bottom : 15,
2020-04-16 13:57:51 +05:00
transform: [
{
translateY: buttonHide ? 200 : 0,
},
],
}}>
<AnimatedTouchableOpacity
onPress={bottomButtonOnPress}
activeOpacity={opacity}
style={{
2020-04-16 13:57:51 +05:00
...getElevation(5),
2020-01-22 02:50:25 +05:00
width: '100%',
2020-04-16 13:57:51 +05:00
alignSelf: 'center',
borderRadius: br,
backgroundColor: headerColor ? headerColor : colors.accent,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 0,
}}>
2020-04-16 13:57:51 +05:00
<View
style={{
2020-04-16 13:57:51 +05:00
justifyContent: 'flex-start',
2020-01-22 02:50:25 +05:00
alignItems: 'center',
2020-04-16 13:57:51 +05:00
flexDirection: 'row',
width: '100%',
padding: pv,
paddingVertical: pv + 5,
}}>
2020-04-16 13:57:51 +05:00
<Icon name="plus" color="white" size={SIZE.xl} />
<Text
style={{
2020-04-16 13:57:51 +05:00
fontSize: SIZE.md,
color: 'white',
fontFamily: WEIGHT.regular,
textAlignVertical: 'center',
}}>
2020-04-16 13:57:51 +05:00
{' ' + bottomButtonText}
</Text>
</View>
</AnimatedTouchableOpacity>
</Animatable.View>
)}
</AnimatedKeyboardAvoidingView>
);
};
export default Container;