mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-22 22:49:45 +01:00
improve search ui & ux
This commit is contained in:
@@ -5,11 +5,11 @@ import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
|||||||
import {useTracked} from '../../provider';
|
import {useTracked} from '../../provider';
|
||||||
import {getElevation} from '../../utils';
|
import {getElevation} from '../../utils';
|
||||||
import {PressableButton} from '../PressableButton';
|
import {PressableButton} from '../PressableButton';
|
||||||
import {pv, SIZE, WEIGHT} from "../../utils/SizeUtils";
|
import {normalize, pv, SIZE, WEIGHT} from '../../utils/SizeUtils';
|
||||||
import {DDS} from "../../services/DeviceDetection";
|
import {DDS} from '../../services/DeviceDetection';
|
||||||
|
|
||||||
export const ContainerBottomButton = ({title, onPress, color}) => {
|
export const ContainerBottomButton = ({title, onPress, color}) => {
|
||||||
const [state,] = useTracked();
|
const [state] = useTracked();
|
||||||
const {colors} = state;
|
const {colors} = state;
|
||||||
const [buttonHide, setButtonHide] = useState(false);
|
const [buttonHide, setButtonHide] = useState(false);
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
@@ -17,12 +17,12 @@ export const ContainerBottomButton = ({title, onPress, color}) => {
|
|||||||
const onKeyboardHide = () => {
|
const onKeyboardHide = () => {
|
||||||
if (DDS.isTab) return;
|
if (DDS.isTab) return;
|
||||||
setButtonHide(false);
|
setButtonHide(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const onKeyboardShow = () => {
|
const onKeyboardShow = () => {
|
||||||
if (DDS.isTab) return;
|
if (DDS.isTab) return;
|
||||||
setButtonHide(true);
|
setButtonHide(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Keyboard.addListener('keyboardDidShow', onKeyboardShow);
|
Keyboard.addListener('keyboardDidShow', onKeyboardShow);
|
||||||
@@ -64,7 +64,7 @@ export const ContainerBottomButton = ({title, onPress, color}) => {
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
padding: pv,
|
padding: pv,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
paddingVertical: pv + 5,
|
height: normalize(60),
|
||||||
}}>
|
}}>
|
||||||
<Icon
|
<Icon
|
||||||
name={title === 'Clear all trash' ? 'delete' : 'plus'}
|
name={title === 'Clear all trash' ? 'delete' : 'plus'}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
import React from 'react';
|
import React, {useEffect} from 'react';
|
||||||
import {useTracked} from '../../provider';
|
import {useTracked} from '../../provider';
|
||||||
import {SIZE} from "../../utils/SizeUtils";
|
import {SIZE} from '../../utils/SizeUtils';
|
||||||
import {DDS} from "../../services/DeviceDetection";
|
import {DDS} from '../../services/DeviceDetection';
|
||||||
import {ActionIcon} from "../ActionIcon";
|
import {ActionIcon} from '../ActionIcon';
|
||||||
import NavigationService from "../../services/Navigation";
|
import NavigationService from '../../services/Navigation';
|
||||||
|
import {eSendEvent} from '../../services/EventManager';
|
||||||
|
import {eClearSearch} from '../../utils/Events';
|
||||||
|
import {BackHandler} from 'react-native';
|
||||||
|
|
||||||
export const HeaderLeftMenu = () => {
|
export const HeaderLeftMenu = () => {
|
||||||
const [state,] = useTracked();
|
const [state] = useTracked();
|
||||||
const {colors, headerMenuState} = state;
|
const {colors, headerMenuState, searchResults} = state;
|
||||||
|
|
||||||
const onLeftButtonPress = () => {
|
const onLeftButtonPress = () => {
|
||||||
|
if (searchResults.results.length > 0) {
|
||||||
|
eSendEvent(eClearSearch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (headerMenuState) {
|
if (headerMenuState) {
|
||||||
NavigationService.openDrawer();
|
NavigationService.openDrawer();
|
||||||
return;
|
return;
|
||||||
@@ -17,6 +24,26 @@ export const HeaderLeftMenu = () => {
|
|||||||
NavigationService.goBack();
|
NavigationService.goBack();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onBackPress = () => {
|
||||||
|
if (searchResults.results.length > 0) {
|
||||||
|
eSendEvent(eClearSearch);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchResults.results.length > 0) {
|
||||||
|
BackHandler.addEventListener('hardwareBackPress', onBackPress);
|
||||||
|
} else {
|
||||||
|
BackHandler.removeEventListener('hardwareBackPress', onBackPress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
BackHandler.removeEventListener('hardwareBackPress', onBackPress);
|
||||||
|
};
|
||||||
|
}, [searchResults.results]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!DDS.isTab ? (
|
{!DDS.isTab ? (
|
||||||
@@ -32,7 +59,11 @@ export const HeaderLeftMenu = () => {
|
|||||||
marginRight: 25,
|
marginRight: 25,
|
||||||
}}
|
}}
|
||||||
onPress={onLeftButtonPress}
|
onPress={onLeftButtonPress}
|
||||||
name={!headerMenuState ? 'arrow-left' : 'menu'}
|
name={
|
||||||
|
!headerMenuState || searchResults.results.length > 0
|
||||||
|
? 'arrow-left'
|
||||||
|
: 'menu'
|
||||||
|
}
|
||||||
size={SIZE.xxxl}
|
size={SIZE.xxxl}
|
||||||
color={colors.pri}
|
color={colors.pri}
|
||||||
iconStyle={{
|
iconStyle={{
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ import {selection} from '../../utils';
|
|||||||
import Animated, {Easing} from 'react-native-reanimated';
|
import Animated, {Easing} from 'react-native-reanimated';
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import {TextInput, Text} from 'react-native';
|
import {TextInput, Text} from 'react-native';
|
||||||
import {br, SIZE, WEIGHT} from '../../utils/SizeUtils';
|
import {br, normalize, SIZE, WEIGHT} from '../../utils/SizeUtils';
|
||||||
import {db} from '../../utils/DB';
|
import {db} from '../../utils/DB';
|
||||||
import {DDS} from '../../services/DeviceDetection';
|
import {DDS} from '../../services/DeviceDetection';
|
||||||
|
import {ActionIcon} from '../ActionIcon';
|
||||||
const {Value, timing, block} = Animated;
|
const {Value, timing, block} = Animated;
|
||||||
|
|
||||||
let searchResult = [];
|
let searchResult = [];
|
||||||
@@ -54,6 +55,8 @@ const animation = (margin, opacity, border) => {
|
|||||||
}, 200);
|
}, 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let timeout = null;
|
||||||
|
|
||||||
export const Search = (props) => {
|
export const Search = (props) => {
|
||||||
const [state, dispatch] = useTracked();
|
const [state, dispatch] = useTracked();
|
||||||
const {colors, searchResults} = state;
|
const {colors, searchResults} = state;
|
||||||
@@ -142,6 +145,15 @@ export const Search = (props) => {
|
|||||||
keyword: null,
|
keyword: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
dispatch({
|
||||||
|
type: Actions.SEARCH_RESULTS,
|
||||||
|
results: {
|
||||||
|
results: [],
|
||||||
|
type: null,
|
||||||
|
keyword: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -152,15 +164,22 @@ export const Search = (props) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!text || text.length === 0) {
|
||||||
|
clearSearch();
|
||||||
|
}
|
||||||
|
}, [text]);
|
||||||
|
|
||||||
const onChangeText = (value) => {
|
const onChangeText = (value) => {
|
||||||
setText(value);
|
setText(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmitEditing = async () => {
|
const onSubmitEditing = async () => {
|
||||||
if (!text || text.length < 1) {
|
if (!text || text.length < 1) {
|
||||||
ToastEvent.show('Please enter a search keyword');
|
|
||||||
clearSearch();
|
clearSearch();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let type = searchState.type;
|
let type = searchState.type;
|
||||||
if (!type) return;
|
if (!type) return;
|
||||||
|
|
||||||
@@ -208,25 +227,40 @@ export const Search = (props) => {
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingLeft: 12,
|
|
||||||
width: '100%',
|
width: '100%',
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
borderRadius: br,
|
borderRadius: br,
|
||||||
height: '90%',
|
height: normalize(55),
|
||||||
backgroundColor: focus
|
backgroundColor: focus
|
||||||
? searchState.color
|
? searchState.color
|
||||||
? searchState.color
|
? searchState.color
|
||||||
: colors.shade
|
: colors.shade
|
||||||
: colors.nav,
|
: colors.nav,
|
||||||
}}>
|
}}>
|
||||||
|
<ActionIcon
|
||||||
|
customStyle={{
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
}}
|
||||||
|
name="magnify"
|
||||||
|
color={
|
||||||
|
focus
|
||||||
|
? searchState.color
|
||||||
|
? searchState.color
|
||||||
|
: colors.accent
|
||||||
|
: colors.icon
|
||||||
|
}
|
||||||
|
size={SIZE.xxl}
|
||||||
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
style={{
|
style={{
|
||||||
fontFamily: WEIGHT.regular,
|
fontFamily: WEIGHT.regular,
|
||||||
color: colors.pri,
|
color: colors.pri,
|
||||||
maxWidth: '85%',
|
fontSize: SIZE.md,
|
||||||
width: '85%',
|
flexGrow: 1,
|
||||||
fontSize: SIZE.sm,
|
flex: 1,
|
||||||
|
flexWrap: 'wrap',
|
||||||
}}
|
}}
|
||||||
onChangeText={onChangeText}
|
onChangeText={onChangeText}
|
||||||
onSubmitEditing={onSubmitEditing}
|
onSubmitEditing={onSubmitEditing}
|
||||||
@@ -242,17 +276,13 @@ export const Search = (props) => {
|
|||||||
placeholder={searchState.placeholder}
|
placeholder={searchState.placeholder}
|
||||||
placeholderTextColor={colors.icon}
|
placeholderTextColor={colors.icon}
|
||||||
/>
|
/>
|
||||||
<Icon
|
<ActionIcon
|
||||||
style={{paddingRight: DDS.isTab ? 12 : 12}}
|
customStyle={{
|
||||||
onPress={onSubmitEditing}
|
width: 50,
|
||||||
name="magnify"
|
height: 50,
|
||||||
color={
|
}}
|
||||||
focus
|
name="tune"
|
||||||
? searchState.color
|
color={colors.icon}
|
||||||
? searchState.color
|
|
||||||
: colors.accent
|
|
||||||
: colors.icon
|
|
||||||
}
|
|
||||||
size={SIZE.xxl}
|
size={SIZE.xxl}
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|||||||
@@ -13,7 +13,12 @@ import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
|
|||||||
import {useTracked} from '../../provider';
|
import {useTracked} from '../../provider';
|
||||||
import {Actions} from '../../provider/Actions';
|
import {Actions} from '../../provider/Actions';
|
||||||
import {eSendEvent, ToastEvent} from '../../services/EventManager';
|
import {eSendEvent, ToastEvent} from '../../services/EventManager';
|
||||||
import {eClearSearch, eOpenJumpToDialog, eOpenLoginDialog, eScrollEvent} from '../../utils/Events';
|
import {
|
||||||
|
eClearSearch,
|
||||||
|
eOpenJumpToDialog,
|
||||||
|
eOpenLoginDialog,
|
||||||
|
eScrollEvent,
|
||||||
|
} from '../../utils/Events';
|
||||||
import {PressableButton} from '../PressableButton';
|
import {PressableButton} from '../PressableButton';
|
||||||
import {COLORS_NOTE} from '../../utils/Colors';
|
import {COLORS_NOTE} from '../../utils/Colors';
|
||||||
import {SIZE, WEIGHT} from '../../utils/SizeUtils';
|
import {SIZE, WEIGHT} from '../../utils/SizeUtils';
|
||||||
@@ -35,7 +40,7 @@ const SimpleList = ({
|
|||||||
refreshCallback,
|
refreshCallback,
|
||||||
sortMenuButton,
|
sortMenuButton,
|
||||||
scrollRef,
|
scrollRef,
|
||||||
jumpToDialog
|
jumpToDialog,
|
||||||
}) => {
|
}) => {
|
||||||
const [state, dispatch] = useTracked();
|
const [state, dispatch] = useTracked();
|
||||||
const {colors, selectionMode, messageBoardState} = state;
|
const {colors, selectionMode, messageBoardState} = state;
|
||||||
@@ -59,7 +64,7 @@ const SimpleList = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadData();
|
loadData();
|
||||||
}, [listData]);
|
}, [listData, searchResults.results]);
|
||||||
|
|
||||||
const loadData = () => {
|
const loadData = () => {
|
||||||
let mainData =
|
let mainData =
|
||||||
@@ -96,7 +101,7 @@ const SimpleList = ({
|
|||||||
color: colors.accent,
|
color: colors.accent,
|
||||||
height: 30,
|
height: 30,
|
||||||
minWidth: 60,
|
minWidth: 60,
|
||||||
textAlignVertical:"bottom"
|
textAlignVertical: 'bottom',
|
||||||
},
|
},
|
||||||
]}>
|
]}>
|
||||||
{item.title}
|
{item.title}
|
||||||
@@ -367,14 +372,7 @@ const MessageCard = ({data}) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ListHeaderComponent = ({type, data}) => {
|
const ListHeaderComponent = ({type, data}) => {
|
||||||
const [state] = useTracked();
|
return <MessageCard type={type} data={data} />;
|
||||||
const searchResults = {...state.searchResults};
|
|
||||||
|
|
||||||
return searchResults.type === type && searchResults.results.length > 0 ? (
|
|
||||||
<SearchHeader />
|
|
||||||
) : (
|
|
||||||
<MessageCard type={type} data={data} />
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|||||||
Reference in New Issue
Block a user