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,84 +5,84 @@ import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import {useTracked} from '../../provider';
|
||||
import {getElevation} from '../../utils';
|
||||
import {PressableButton} from '../PressableButton';
|
||||
import {pv, SIZE, WEIGHT} from "../../utils/SizeUtils";
|
||||
import {DDS} from "../../services/DeviceDetection";
|
||||
import {normalize, pv, SIZE, WEIGHT} from '../../utils/SizeUtils';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
|
||||
export const ContainerBottomButton = ({title, onPress, color}) => {
|
||||
const [state,] = useTracked();
|
||||
const {colors} = state;
|
||||
const [buttonHide, setButtonHide] = useState(false);
|
||||
const insets = useSafeAreaInsets();
|
||||
const [state] = useTracked();
|
||||
const {colors} = state;
|
||||
const [buttonHide, setButtonHide] = useState(false);
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const onKeyboardHide = () => {
|
||||
if (DDS.isTab) return;
|
||||
setButtonHide(false);
|
||||
}
|
||||
const onKeyboardHide = () => {
|
||||
if (DDS.isTab) return;
|
||||
setButtonHide(false);
|
||||
};
|
||||
|
||||
const onKeyboardShow = () => {
|
||||
if (DDS.isTab) return;
|
||||
setButtonHide(true);
|
||||
}
|
||||
const onKeyboardShow = () => {
|
||||
if (DDS.isTab) return;
|
||||
setButtonHide(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
Keyboard.addListener('keyboardDidShow', onKeyboardShow);
|
||||
Keyboard.addListener('keyboardDidHide', onKeyboardHide);
|
||||
return () => {
|
||||
Keyboard.removeListener('keyboardDidShow', onKeyboardShow);
|
||||
Keyboard.removeListener('keyboardDidHide', onKeyboardHide);
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
Keyboard.addListener('keyboardDidShow', onKeyboardShow);
|
||||
Keyboard.addListener('keyboardDidHide', onKeyboardHide);
|
||||
return () => {
|
||||
Keyboard.removeListener('keyboardDidShow', onKeyboardShow);
|
||||
Keyboard.removeListener('keyboardDidHide', onKeyboardHide);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
width: '100%',
|
||||
opacity: buttonHide ? 0 : 1,
|
||||
position: 'absolute',
|
||||
paddingHorizontal: 12,
|
||||
bottom: Platform.OS === 'ios' ? insets.bottom - 10 : insets.bottom + 20,
|
||||
zIndex: 10,
|
||||
transform: [
|
||||
{
|
||||
translateY: buttonHide ? 200 : 0,
|
||||
},
|
||||
],
|
||||
}}>
|
||||
<PressableButton
|
||||
testID={'container_bottom_btn'}
|
||||
color={color || colors.accent}
|
||||
selectedColor={color || colors.accent}
|
||||
customStyle={{
|
||||
...getElevation(5),
|
||||
}}
|
||||
onPress={onPress}>
|
||||
<View
|
||||
style={{
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
padding: pv,
|
||||
borderRadius: 5,
|
||||
height: normalize(60),
|
||||
}}>
|
||||
<Icon
|
||||
name={title === 'Clear all trash' ? 'delete' : 'plus'}
|
||||
color="white"
|
||||
size={SIZE.xl}
|
||||
/>
|
||||
<Text
|
||||
testID="container_bottom_btn_text"
|
||||
style={{
|
||||
width: '100%',
|
||||
opacity: buttonHide ? 0 : 1,
|
||||
position: 'absolute',
|
||||
paddingHorizontal: 12,
|
||||
bottom: Platform.OS === 'ios' ? insets.bottom - 10 : insets.bottom + 20,
|
||||
zIndex: 10,
|
||||
transform: [
|
||||
{
|
||||
translateY: buttonHide ? 200 : 0,
|
||||
},
|
||||
],
|
||||
fontSize: SIZE.md,
|
||||
color: 'white',
|
||||
fontFamily: WEIGHT.regular,
|
||||
textAlignVertical: 'center',
|
||||
}}>
|
||||
<PressableButton
|
||||
testID={'container_bottom_btn'}
|
||||
color={color || colors.accent}
|
||||
selectedColor={color || colors.accent}
|
||||
customStyle={{
|
||||
...getElevation(5),
|
||||
}}
|
||||
onPress={onPress}>
|
||||
<View
|
||||
style={{
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
padding: pv,
|
||||
borderRadius: 5,
|
||||
paddingVertical: pv + 5,
|
||||
}}>
|
||||
<Icon
|
||||
name={title === 'Clear all trash' ? 'delete' : 'plus'}
|
||||
color="white"
|
||||
size={SIZE.xl}
|
||||
/>
|
||||
<Text
|
||||
testID="container_bottom_btn_text"
|
||||
style={{
|
||||
fontSize: SIZE.md,
|
||||
color: 'white',
|
||||
fontFamily: WEIGHT.regular,
|
||||
textAlignVertical: 'center',
|
||||
}}>
|
||||
{' ' + title}
|
||||
</Text>
|
||||
</View>
|
||||
</PressableButton>
|
||||
{' ' + title}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
</PressableButton>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,45 +1,76 @@
|
||||
import React from 'react';
|
||||
import React, {useEffect} from 'react';
|
||||
import {useTracked} from '../../provider';
|
||||
import {SIZE} from "../../utils/SizeUtils";
|
||||
import {DDS} from "../../services/DeviceDetection";
|
||||
import {ActionIcon} from "../ActionIcon";
|
||||
import NavigationService from "../../services/Navigation";
|
||||
import {SIZE} from '../../utils/SizeUtils';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
import {ActionIcon} from '../ActionIcon';
|
||||
import NavigationService from '../../services/Navigation';
|
||||
import {eSendEvent} from '../../services/EventManager';
|
||||
import {eClearSearch} from '../../utils/Events';
|
||||
import {BackHandler} from 'react-native';
|
||||
|
||||
export const HeaderLeftMenu = () => {
|
||||
const [state,] = useTracked();
|
||||
const {colors, headerMenuState} = state;
|
||||
const [state] = useTracked();
|
||||
const {colors, headerMenuState, searchResults} = state;
|
||||
|
||||
const onLeftButtonPress = () => {
|
||||
if (headerMenuState) {
|
||||
NavigationService.openDrawer();
|
||||
return;
|
||||
}
|
||||
NavigationService.goBack();
|
||||
const onLeftButtonPress = () => {
|
||||
if (searchResults.results.length > 0) {
|
||||
eSendEvent(eClearSearch);
|
||||
return;
|
||||
}
|
||||
if (headerMenuState) {
|
||||
NavigationService.openDrawer();
|
||||
return;
|
||||
}
|
||||
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 (
|
||||
<>
|
||||
{!DDS.isTab ? (
|
||||
<ActionIcon
|
||||
testID="left_menu_button"
|
||||
customStyle={{
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 40,
|
||||
width: 40,
|
||||
borderRadius: 100,
|
||||
marginLeft: -5,
|
||||
marginRight: 25,
|
||||
}}
|
||||
onPress={onLeftButtonPress}
|
||||
name={!headerMenuState ? 'arrow-left' : 'menu'}
|
||||
size={SIZE.xxxl}
|
||||
color={colors.pri}
|
||||
iconStyle={{
|
||||
marginLeft: !headerMenuState ? -5 : 0,
|
||||
}}
|
||||
/>
|
||||
) : undefined}
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{!DDS.isTab ? (
|
||||
<ActionIcon
|
||||
testID="left_menu_button"
|
||||
customStyle={{
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 40,
|
||||
width: 40,
|
||||
borderRadius: 100,
|
||||
marginLeft: -5,
|
||||
marginRight: 25,
|
||||
}}
|
||||
onPress={onLeftButtonPress}
|
||||
name={
|
||||
!headerMenuState || searchResults.results.length > 0
|
||||
? 'arrow-left'
|
||||
: 'menu'
|
||||
}
|
||||
size={SIZE.xxxl}
|
||||
color={colors.pri}
|
||||
iconStyle={{
|
||||
marginLeft: !headerMenuState ? -5 : 0,
|
||||
}}
|
||||
/>
|
||||
) : undefined}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -16,9 +16,10 @@ import {selection} from '../../utils';
|
||||
import Animated, {Easing} from 'react-native-reanimated';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
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 {DDS} from '../../services/DeviceDetection';
|
||||
import {ActionIcon} from '../ActionIcon';
|
||||
const {Value, timing, block} = Animated;
|
||||
|
||||
let searchResult = [];
|
||||
@@ -54,6 +55,8 @@ const animation = (margin, opacity, border) => {
|
||||
}, 200);
|
||||
};
|
||||
|
||||
let timeout = null;
|
||||
|
||||
export const Search = (props) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors, searchResults} = state;
|
||||
@@ -142,6 +145,15 @@ export const Search = (props) => {
|
||||
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) => {
|
||||
setText(value);
|
||||
};
|
||||
|
||||
const onSubmitEditing = async () => {
|
||||
if (!text || text.length < 1) {
|
||||
ToastEvent.show('Please enter a search keyword');
|
||||
clearSearch();
|
||||
return;
|
||||
}
|
||||
|
||||
let type = searchState.type;
|
||||
if (!type) return;
|
||||
|
||||
@@ -208,25 +227,40 @@ export const Search = (props) => {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 12,
|
||||
width: '100%',
|
||||
alignSelf: 'center',
|
||||
borderRadius: br,
|
||||
height: '90%',
|
||||
height: normalize(55),
|
||||
backgroundColor: focus
|
||||
? searchState.color
|
||||
? searchState.color
|
||||
: colors.shade
|
||||
: colors.nav,
|
||||
}}>
|
||||
<ActionIcon
|
||||
customStyle={{
|
||||
width: 50,
|
||||
height: 50,
|
||||
}}
|
||||
name="magnify"
|
||||
color={
|
||||
focus
|
||||
? searchState.color
|
||||
? searchState.color
|
||||
: colors.accent
|
||||
: colors.icon
|
||||
}
|
||||
size={SIZE.xxl}
|
||||
/>
|
||||
<TextInput
|
||||
ref={inputRef}
|
||||
style={{
|
||||
fontFamily: WEIGHT.regular,
|
||||
color: colors.pri,
|
||||
maxWidth: '85%',
|
||||
width: '85%',
|
||||
fontSize: SIZE.sm,
|
||||
fontSize: SIZE.md,
|
||||
flexGrow: 1,
|
||||
flex: 1,
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
onChangeText={onChangeText}
|
||||
onSubmitEditing={onSubmitEditing}
|
||||
@@ -242,17 +276,13 @@ export const Search = (props) => {
|
||||
placeholder={searchState.placeholder}
|
||||
placeholderTextColor={colors.icon}
|
||||
/>
|
||||
<Icon
|
||||
style={{paddingRight: DDS.isTab ? 12 : 12}}
|
||||
onPress={onSubmitEditing}
|
||||
name="magnify"
|
||||
color={
|
||||
focus
|
||||
? searchState.color
|
||||
? searchState.color
|
||||
: colors.accent
|
||||
: colors.icon
|
||||
}
|
||||
<ActionIcon
|
||||
customStyle={{
|
||||
width: 50,
|
||||
height: 50,
|
||||
}}
|
||||
name="tune"
|
||||
color={colors.icon}
|
||||
size={SIZE.xxl}
|
||||
/>
|
||||
</Animated.View>
|
||||
|
||||
@@ -13,7 +13,12 @@ import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
|
||||
import {useTracked} from '../../provider';
|
||||
import {Actions} from '../../provider/Actions';
|
||||
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 {COLORS_NOTE} from '../../utils/Colors';
|
||||
import {SIZE, WEIGHT} from '../../utils/SizeUtils';
|
||||
@@ -35,7 +40,7 @@ const SimpleList = ({
|
||||
refreshCallback,
|
||||
sortMenuButton,
|
||||
scrollRef,
|
||||
jumpToDialog
|
||||
jumpToDialog,
|
||||
}) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors, selectionMode, messageBoardState} = state;
|
||||
@@ -59,7 +64,7 @@ const SimpleList = ({
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, [listData]);
|
||||
}, [listData, searchResults.results]);
|
||||
|
||||
const loadData = () => {
|
||||
let mainData =
|
||||
@@ -85,18 +90,18 @@ const SimpleList = ({
|
||||
}}>
|
||||
<Text
|
||||
onPress={() => {
|
||||
console.log('clicekd');
|
||||
if (jumpToDialog) {
|
||||
eSendEvent(eOpenJumpToDialog);
|
||||
}
|
||||
console.log('clicekd');
|
||||
if (jumpToDialog) {
|
||||
eSendEvent(eOpenJumpToDialog);
|
||||
}
|
||||
}}
|
||||
style={[
|
||||
styles.sectionHeader,
|
||||
{
|
||||
color: colors.accent,
|
||||
height:30,
|
||||
minWidth:60,
|
||||
textAlignVertical:"bottom"
|
||||
height: 30,
|
||||
minWidth: 60,
|
||||
textAlignVertical: 'bottom',
|
||||
},
|
||||
]}>
|
||||
{item.title}
|
||||
@@ -367,14 +372,7 @@ const MessageCard = ({data}) => {
|
||||
};
|
||||
|
||||
const ListHeaderComponent = ({type, data}) => {
|
||||
const [state] = useTracked();
|
||||
const searchResults = {...state.searchResults};
|
||||
|
||||
return searchResults.type === type && searchResults.results.length > 0 ? (
|
||||
<SearchHeader />
|
||||
) : (
|
||||
<MessageCard type={type} data={data} />
|
||||
);
|
||||
return <MessageCard type={type} data={data} />;
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
Reference in New Issue
Block a user