add hideable search

This commit is contained in:
ammarahm-ed
2019-12-06 18:13:15 +05:00
parent 4cc7331852
commit a369704fc7
10 changed files with 422 additions and 160 deletions

View File

@@ -39,12 +39,13 @@ const NoteItem = props => {
<View
style={{
marginHorizontal: w * 0.05,
marginVertical: h * 0.015,
paddingVertical: pv,
borderRadius: br,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
padding: pv,
paddingHorizontal: ph,
width: Platform.isPad ? '95%' : '90%',
alignSelf: 'center',
borderBottomWidth: 1,
@@ -68,7 +69,8 @@ const NoteItem = props => {
});
}}
style={{
width: '95%',
paddingLeft: ph,
width: '100%',
}}>
<>
<Text
@@ -140,6 +142,7 @@ const NoteItem = props => {
justifyContent: 'center',
minHeight: 70,
alignItems: 'center',
paddingRight: ph,
}}>
<Menu
style={{

View File

@@ -39,7 +39,7 @@ export const NotebookItem = ({
marginHorizontal: '5%',
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0',
paddingVertical: pv + 5,
paddingVertical: pv,
}}>
<View
style={{

View File

@@ -27,7 +27,7 @@ import NoteItem from '../NoteItem';
import NavigationService from '../../services/NavigationService';
import {storage} from '../../../App';
export const RecentList = ({update}) => {
export const RecentList = ({update, onScroll, margin}) => {
const [colors, setColors] = useState(COLOR_SCHEME);
const [notes, setNotes] = useState([]);
const fetchNotes = async () => {
@@ -45,9 +45,21 @@ export const RecentList = ({update}) => {
<>
<FlatList
data={notes}
onScroll={event => {
y = event.nativeEvent.contentOffset.y;
onScroll(y);
}}
style={{
height: '100%',
width: '100%',
}}
ListHeaderComponent={
<View
style={{
marginTop: margin,
}}
/>
}
ListFooterComponent={
<View
style={{

View File

@@ -12,62 +12,82 @@ import {
} from '../../common/common';
import Icon from 'react-native-vector-icons/Ionicons';
import {getElevation} from '../../utils/utils';
import * as Animatable from 'react-native-animatable';
export const Search = props => {
const [colors, setColors] = useState(COLOR_SCHEME);
const [focus, setFocus] = useState(false);
const inputRef = createRef();
return (
<View
<Animatable.View
onLayout={e => {
props.sendHeight(e.nativeEvent.layout.height);
}}
transition="opacity"
duration={300}
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: Platform.isPad ? '95%' : '90%',
alignSelf: 'center',
borderRadius: br,
borderWidth: 1.5,
paddingHorizontal: ph,
paddingVertical: Platform.OS == 'ios' ? pv - 3 : pv - 8,
marginBottom: 10,
borderColor: focus ? colors.navbg : '#f0f0f0',
opacity: props.hide ? 0 : 1,
}}>
<TextInput
ref={inputRef}
<Animatable.View
transition="height"
duration={400}
style={{
fontFamily: WEIGHT.regular,
maxWidth: '90%',
width: '90%',
fontSize: SIZE.md,
}}
onChangeText={props.onChangeText}
onSubmitEditing={props.onSubmitEditing}
onFocus={() => {
setFocus(true);
props.onFocus;
}}
onBlur={() => {
setFocus(false);
props.onBlur;
}}
numberOfLines={1}
placeholder={props.placeholder}
placeholderTextColor={colors.icon}
/>
<Icon
style={{paddingRight: Platform.isPad ? '1.25%' : '2.5%'}}
onPress={() => {
props.value.length > 0 ? props.clearSearch() : null;
inputRef.current.setNativeProps({
text: '',
});
}}
name={
props.value && props.value.length > 0 ? 'ios-close' : 'ios-search'
}
color={focus ? colors.accent : colors.icon}
size={SIZE.xl}
/>
</View>
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: Platform.isPad ? '95%' : '90%',
alignSelf: 'center',
borderRadius: br,
borderWidth: props.hide ? 0 : 1.5,
paddingHorizontal: ph,
backgroundColor: colors.bg,
paddingVertical: props.hide
? 0
: Platform.OS == 'ios'
? pv - 3
: pv - 8,
marginBottom: props.hide ? 0 : 10,
borderColor: focus ? colors.navbg : '#f0f0f0',
height: props.hide ? 0 : 55,
}}>
<TextInput
ref={inputRef}
style={{
fontFamily: WEIGHT.regular,
maxWidth: '90%',
width: '90%',
fontSize: SIZE.md,
}}
onChangeText={props.onChangeText}
onSubmitEditing={props.onSubmitEditing}
onFocus={() => {
setFocus(true);
props.onFocus;
}}
onBlur={() => {
setFocus(false);
props.onBlur;
}}
numberOfLines={1}
placeholder={props.placeholder}
placeholderTextColor={colors.icon}
/>
<Icon
style={{paddingRight: Platform.isPad ? '1.25%' : '2.5%'}}
onPress={() => {
props.value.length > 0 ? props.clearSearch() : null;
inputRef.current.setNativeProps({
text: '',
});
}}
name={
props.value && props.value.length > 0 ? 'ios-close' : 'ios-search'
}
color={focus ? colors.accent : colors.icon}
size={SIZE.xl}
/>
</Animatable.View>
</Animatable.View>
);
};

View File

@@ -1,42 +1,86 @@
import React from 'react';
import React, {useEffect, useState} from 'react';
import {View, TouchableOpacity, Platform, Text} from 'react-native';
import Icon from 'react-native-vector-icons/Feather';
import {SIZE, WEIGHT} from '../../common/common';
import {h} from '../../utils/utils';
import * as Animatable from 'react-native-animatable';
export const Header = ({heading, colors, canGoBack = true}) => {
export const Header = ({
heading,
colors,
canGoBack = true,
hide,
showSearch,
sendHeight = e => {},
}) => {
return (
<View
<Animatable.View
onLayout={e => {
if (sendHeight) {
sendHeight(e.nativeEvent.layout.height);
}
}}
transition="height"
duration={300}
style={{
height: hide ? 50 : 50,
flexDirection: 'row',
justifyContent: 'flex-start',
zIndex: 10,
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: Platform.isPad ? '2.5%' : '5%',
marginTop: Platform.OS == 'ios' ? h * 0.02 : h * 0.04,
marginBottom: h * 0.04,
paddingTop: Platform.OS == 'ios' ? h * 0.02 : h * 0.06,
marginBottom: h * 0.06,
}}>
{canGoBack ? (
<View
style={{
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
}}>
{canGoBack ? (
<TouchableOpacity
style={{
justifyContent: 'center',
alignItems: 'center',
paddingRight: 15,
}}>
<Icon name={'chevron-left'} size={SIZE.xl} />
</TouchableOpacity>
) : (
undefined
)}
<Animatable.Text
transition="fontSize"
duration={300}
style={{
fontSize: hide ? SIZE.xl : SIZE.xxl,
color: colors.pri,
fontFamily: WEIGHT.bold,
}}>
{heading}
</Animatable.Text>
</View>
<Animatable.View
transition="opacity"
duration={500}
style={{
opacity: hide ? 1 : 0,
}}>
<TouchableOpacity
onPress={() => showSearch()}
style={{
justifyContent: 'center',
alignItems: 'center',
paddingRight: 15,
alignItems: 'flex-end',
height: 40,
width: 60,
paddingRight: 0,
marginTop: 7,
}}>
<Icon name={'chevron-left'} size={SIZE.xl} />
<Icon name={'search'} size={SIZE.xl} />
</TouchableOpacity>
) : (
undefined
)}
<Text
style={{
fontSize: SIZE.xxl,
color: colors.pri,
fontFamily: WEIGHT.bold,
}}>
{heading}
</Text>
</View>
</Animatable.View>
</Animatable.View>
);
};

View File

@@ -80,34 +80,29 @@ export const AccountSettings = ({navigation}) => {
</Text>
</View>
<FlatList
data={['Subscription Status', 'Space Used', 'E-to-E Encryption']}
ListHeaderComponent={
<TouchableOpacity
activeOpacity={opacity}
style={{
borderRadius: 5,
width: '90%',
marginHorizontal: '5%',
paddingHorizontal: ph,
borderWidth: 1,
borderColor: '#f0f0f0',
paddingVertical: pv + 5,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 10,
backgroundColor: colors.bg,
}}>
<Text
style={{
fontSize: SIZE.md,
fontFamily: WEIGHT.regular,
color: colors.pri,
}}>
Backup notes
</Text>
</TouchableOpacity>
}
data={[
{
name: 'Backup Notes',
icon: 'database',
},
{
name: 'My Devices',
icon: 'tablet',
},
{
name: 'Vault',
icon: 'shield',
},
{
name: 'My Subscription',
icon: 'credit-card',
},
{
name: 'Change Password',
icon: 'key',
},
]}
renderItem={({item, index}) => (
<TouchableOpacity
activeOpacity={opacity}
@@ -126,15 +121,10 @@ export const AccountSettings = ({navigation}) => {
style={{
fontSize: SIZE.md,
fontFamily: WEIGHT.regular,
textAlignVertical: 'center',
}}>
{item}
</Text>
<Text
style={{
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
}}>
100/90
<Icon name={item.icon} size={SIZE.md} />
{' '} {item.name}
</Text>
</TouchableOpacity>
)}

View File

@@ -32,12 +32,34 @@ import {AddNotebookDialog} from '../../components/AddNotebookDialog';
import {NotebookItem} from '../../components/NotebookItem';
import {Search} from '../../components/SearchInput';
import {storage} from '../../../App';
import {Header} from '../../components/header';
export const Folders = ({navigation}) => {
const [colors, setColors] = useState(COLOR_SCHEME);
const [addNotebook, setAddNotebook] = useState(false);
const [notebooks, setNotebooks] = useState([]);
const [hideHeader, setHideHeader] = useState(false);
const [margin, setMargin] = useState(150);
const params = navigation.state.params;
let offsetY = 0;
let countUp = 0;
let countDown = 0;
let headerHeight = 0;
let searchHeight = 0;
const setMarginTop = () => {
if (margin !== 150) return;
if (headerHeight == 0 || searchHeight == 0) {
let toAdd = h * 0.06;
setTimeout(() => {
if (margin > headerHeight + searchHeight + toAdd) return;
setMargin(headerHeight + searchHeight + toAdd);
headerHeight = 0;
searchHeight = 0;
}, 10);
}
};
useEffect(() => {
setNotebooks(storage.getNotebooks());
@@ -64,36 +86,59 @@ export const Folders = ({navigation}) => {
}}>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: '5%',
marginTop: Platform.OS == 'ios' ? h * 0.02 : h * 0.04,
marginBottom: h * 0.04,
position: 'absolute',
backgroundColor: colors.bg,
zIndex: 10,
width: '100%',
}}>
<Text
style={{
fontSize: SIZE.xxl,
color: colors.pri,
fontFamily: WEIGHT.bold,
}}>
{params.title}
</Text>
<Icon
style={{
marginTop: 10,
<Header
sendHeight={height => (headerHeight = height)}
hide={hideHeader}
showSearch={() => {
setHideHeader(false);
countUp = 0;
countDown = 0;
}}
name="more-vertical"
color={colors.icon}
size={SIZE.xxl}
colors={colors}
heading={params.title}
canGoBack={false}
/>
<Search
sendHeight={height => {
searchHeight = height;
setMarginTop();
}}
placeholder="Search your notebook"
hide={hideHeader}
/>
</View>
<Search placeholder="Search in notebooks" />
<FlatList
style={{
width: '100%',
}}
onScroll={event => {
y = event.nativeEvent.contentOffset.y;
if (y > offsetY) {
if (y - offsetY < 150 || countDown > 0) return;
countDown = 1;
countUp = 0;
setHideHeader(true);
} else {
if (offsetY - y < 150 || countUp > 0) return;
countDown = 0;
countUp = 1;
setHideHeader(false);
}
offsetY = y;
}}
ListHeaderComponent={
<View
style={{
marginTop: margin,
}}
/>
}
data={notebooks}
keyExtractor={(item, index) => item.dateCreated.toString()}
renderItem={({item, index}) => (

View File

@@ -12,13 +12,14 @@ import {COLOR_SCHEME, opacity, pv, br, SIZE, WEIGHT} from '../../common/common';
import {styles} from './styles';
import {Search} from '../../components/SearchInput';
import {RecentList} from '../../components/Recents';
import {w} from '../../utils/utils';
import {w, h} from '../../utils/utils';
import {Header} from '../../components/header';
import {NavigationEvents} from 'react-navigation';
import {NotesList} from '../../components/NotesList';
import {storage} from '../../../App';
import Icon from 'react-native-vector-icons/Feather';
import NavigationService from '../../services/NavigationService';
import {ScrollView} from 'react-native-gesture-handler';
export const Home = ({navigation}) => {
const [loading, setLoading] = useState(true);
const [colors, setColors] = useState(COLOR_SCHEME);
@@ -26,6 +27,14 @@ export const Home = ({navigation}) => {
const [text, setText] = useState('');
const [searchResults, setSearchResults] = useState([]);
const [update, setUpdate] = useState(0);
const [hideHeader, setHideHeader] = useState(false);
const [margin, setMargin] = useState(150);
let offsetY = 0;
let countUp = 0;
let countDown = 0;
let headerHeight = 0;
let searchHeight = 0;
useEffect(() => {
setTimeout(() => {
setLoading(false);
@@ -62,6 +71,20 @@ export const Home = ({navigation}) => {
setHidden(false);
};
const setMarginTop = () => {
if (margin !== 150) return;
if (headerHeight == 0 || searchHeight == 0) {
let toAdd = h * 0.06;
setTimeout(() => {
if (margin > headerHeight + searchHeight + toAdd) return;
setMargin(headerHeight + searchHeight + toAdd);
headerHeight = 0;
searchHeight = 0;
}, 10);
}
};
return Platform.isPad ? (
<SafeAreaView style={[styles.container]}>
<KeyboardAvoidingView>
@@ -103,28 +126,66 @@ export const Home = ({navigation}) => {
setUpdate(update + 1);
}}
/>
<View
style={{
position: 'absolute',
backgroundColor: colors.bg,
zIndex: 10,
width: '100%',
}}>
<Header
sendHeight={height => {
headerHeight = height;
setMarginTop();
}}
hide={hideHeader}
showSearch={() => {
setHideHeader(false);
countUp = 0;
countDown = 0;
}}
colors={colors}
heading="Home"
canGoBack={false}
customIcon="menu"
/>
<Header
colors={colors}
heading="Home"
canGoBack={false}
customIcon="menu"
/>
<Search
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
placeholder="Search your notes"
onBlur={onBlur}
onFocus={onFocus}
clearSearch={clearSearch}
value={text}
/>
<Search
sendHeight={height => {
searchHeight = height;
setMarginTop();
}}
hide={hideHeader}
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
placeholder="Search your notes"
onBlur={onBlur}
onFocus={onFocus}
clearSearch={clearSearch}
value={text}
/>
</View>
{hidden ? (
<NotesList searchResults={searchResults} keyword={text} />
) : (
<RecentList update={update} />
<RecentList
onScroll={y => {
if (y > offsetY) {
if (y - offsetY < 150 || countDown > 0) return;
countDown = 1;
countUp = 0;
setHideHeader(true);
} else {
if (offsetY - y < 150 || countUp > 0) return;
countDown = 0;
countUp = 1;
setHideHeader(false);
}
offsetY = y;
}}
margin={margin}
update={update}
/>
)}
<TouchableOpacity
onPress={() => {

View File

@@ -36,6 +36,27 @@ const h = Dimensions.get('window').height;
export const Notebook = ({navigation}) => {
const [colors, setColors] = useState(COLOR_SCHEME);
const params = navigation.state.params;
const [hideHeader, setHideHeader] = useState(false);
const [margin, setMargin] = useState(150);
let offsetY = 0;
let countUp = 0;
let countDown = 0;
let headerHeight = 0;
let searchHeight = 0;
const setMarginTop = () => {
if (margin !== 150) return;
if (headerHeight == 0 || searchHeight == 0) {
let toAdd = h * 0.06;
setTimeout(() => {
if (margin > headerHeight + searchHeight + toAdd) return;
setMargin(headerHeight + searchHeight + toAdd);
headerHeight = 0;
searchHeight = 0;
}, 10);
}
};
return (
<SafeAreaView
style={{
@@ -45,13 +66,56 @@ export const Notebook = ({navigation}) => {
style={{
height: '100%',
}}>
<Header colors={colors} heading={params.title} canGoBack={false} />
<Search />
<View
style={{
position: 'absolute',
backgroundColor: colors.bg,
zIndex: 10,
width: '100%',
}}>
<Header
sendHeight={height => (headerHeight = height)}
hide={hideHeader}
showSearch={() => {
setHideHeader(false);
countUp = 0;
countDown = 0;
}}
colors={colors}
heading={params.title}
canGoBack={false}
/>
<Search
sendHeight={height => {
searchHeight = height;
setMarginTop();
}}
placeholder="Search your notebook"
hide={hideHeader}
/>
</View>
<FlatList
style={{
width: '100%',
}}
data={params.notebook.topics}
onScroll={event => {
y = event.nativeEvent.contentOffset.y;
if (y > offsetY) {
if (y - offsetY < 150 || countDown > 0) return;
countDown = 1;
countUp = 0;
setHideHeader(true);
} else {
if (offsetY - y < 150 || countUp > 0) return;
countDown = 0;
countUp = 1;
setHideHeader(false);
}
offsetY = y;
}}
ListHeaderComponent={
<>
{params.hideMore ? null : (
@@ -63,6 +127,7 @@ export const Notebook = ({navigation}) => {
style={{
borderWidth: 1,
borderRadius: 5,
marginTop: margin,
width: '90%',
marginHorizontal: '5%',
paddingHorizontal: ph,

View File

@@ -37,7 +37,24 @@ export const Settings = ({navigation}) => {
<Header colors={colors} heading="Settings" canGoBack={false} />
<FlatList
data={['Sync', 'Dark Mode', 'Sunset to Sunrise']}
data={[
{
name: 'Sync',
icon: 'refresh-ccw',
switch: true,
},
{
name: 'Dark Mode',
icon: 'moon',
switch: true,
},
{
name: 'Sunset to Sunrise',
icon: null,
switch: true,
step: true,
},
]}
ListHeaderComponent={
<View>
<TouchableOpacity
@@ -75,7 +92,7 @@ export const Settings = ({navigation}) => {
activeOpacity={opacity}
style={{
borderBottomWidth: 1,
width: '90%',
width: item.step ? '85%' : '90%',
marginHorizontal: '5%',
borderBottomColor: '#f0f0f0',
paddingVertical: pv + 5,
@@ -83,15 +100,20 @@ export const Settings = ({navigation}) => {
paddingHorizontal: ph,
justifyContent: 'space-between',
alignItems: 'center',
marginLeft: item.step ? '10%' : '5%',
}}>
<Text
style={{
fontSize: SIZE.md,
fontSize: item.step ? SIZE.sm : SIZE.md,
fontFamily: WEIGHT.regular,
textAlignVertical: 'center',
}}>
{item}
<Icon name={item.icon} size={SIZE.md} />
{' '} {item.name}
</Text>
<Icon size={SIZE.lg} color={colors.icon} name="toggle-left" />
{item.switch ? (
<Icon name="toggle-right" size={item.step ? SIZE.sm : SIZE.md} />
) : null}
</TouchableOpacity>
)}
/>