2024-09-24 16:12:02 +02:00
|
|
|
import * as React from 'react';
|
|
|
|
|
|
|
|
import { StyleSheet, View, TextInput } from 'react-native';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import ScreenHeader from '../../ScreenHeader';
|
|
|
|
import { _ } from '@joplin/lib/locale';
|
|
|
|
import { ThemeStyle, themeStyle } from '../../global-style';
|
|
|
|
import { AppState } from '../../../utils/types';
|
|
|
|
import { Dispatch } from 'redux';
|
|
|
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
import IconButton from '../../IconButton';
|
|
|
|
import SearchResults from './SearchResults';
|
2024-09-27 16:23:31 +02:00
|
|
|
import AccessibleView from '../../accessibility/AccessibleView';
|
2024-11-23 18:47:46 +02:00
|
|
|
import { ComplexTerm } from '@joplin/lib/services/search/SearchEngine';
|
2024-09-24 16:12:02 +02:00
|
|
|
|
|
|
|
interface Props {
|
|
|
|
themeId: number;
|
|
|
|
query: string;
|
|
|
|
visible: boolean;
|
|
|
|
dispatch: Dispatch;
|
|
|
|
|
|
|
|
noteSelectionEnabled: boolean;
|
|
|
|
ftsEnabled: number;
|
|
|
|
}
|
|
|
|
|
2024-09-27 16:23:31 +02:00
|
|
|
const useStyles = (theme: ThemeStyle, visible: boolean) => {
|
2024-09-24 16:12:02 +02:00
|
|
|
return useMemo(() => {
|
|
|
|
return StyleSheet.create({
|
|
|
|
body: {
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
searchContainer: {
|
|
|
|
flexDirection: 'row',
|
|
|
|
alignItems: 'center',
|
|
|
|
borderWidth: 1,
|
|
|
|
borderColor: theme.dividerColor,
|
|
|
|
},
|
|
|
|
searchTextInput: {
|
|
|
|
...theme.lineInput,
|
|
|
|
paddingLeft: theme.marginLeft,
|
|
|
|
flex: 1,
|
|
|
|
backgroundColor: theme.backgroundColor,
|
|
|
|
color: theme.color,
|
|
|
|
},
|
|
|
|
clearIcon: {
|
|
|
|
...theme.icon,
|
|
|
|
color: theme.colorFaded,
|
|
|
|
paddingRight: theme.marginRight,
|
|
|
|
backgroundColor: theme.backgroundColor,
|
|
|
|
},
|
2024-09-27 16:23:31 +02:00
|
|
|
rootStyle: visible ? theme.rootStyle : theme.hiddenRootStyle,
|
2024-09-24 16:12:02 +02:00
|
|
|
});
|
2024-09-27 16:23:31 +02:00
|
|
|
}, [theme, visible]);
|
2024-09-24 16:12:02 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const SearchScreenComponent: React.FC<Props> = props => {
|
|
|
|
const theme = themeStyle(props.themeId);
|
2024-09-27 16:23:31 +02:00
|
|
|
const styles = useStyles(theme, props.visible);
|
2024-09-24 16:12:02 +02:00
|
|
|
|
|
|
|
const [query, setQuery] = useState(props.query);
|
|
|
|
|
|
|
|
const globalQueryRef = useRef(props.query);
|
|
|
|
globalQueryRef.current = props.query;
|
|
|
|
useEffect(() => {
|
|
|
|
if (globalQueryRef.current !== query) {
|
|
|
|
props.dispatch({
|
|
|
|
type: 'SEARCH_QUERY',
|
|
|
|
query,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, [props.dispatch, query]);
|
|
|
|
|
|
|
|
const clearButton_press = useCallback(() => {
|
|
|
|
setQuery('');
|
|
|
|
}, []);
|
|
|
|
|
2024-11-23 18:47:46 +02:00
|
|
|
const onHighlightedWordsChange = useCallback((words: (ComplexTerm | string)[]) => {
|
2024-09-24 16:12:02 +02:00
|
|
|
props.dispatch({
|
|
|
|
type: 'SET_HIGHLIGHTED',
|
|
|
|
words,
|
|
|
|
});
|
|
|
|
}, [props.dispatch]);
|
|
|
|
|
|
|
|
return (
|
2024-09-27 16:23:31 +02:00
|
|
|
<AccessibleView style={styles.rootStyle} inert={!props.visible}>
|
2024-09-24 16:12:02 +02:00
|
|
|
<ScreenHeader
|
|
|
|
title={_('Search')}
|
|
|
|
folderPickerOptions={{
|
2024-11-16 23:07:34 +02:00
|
|
|
visible: props.noteSelectionEnabled,
|
2024-09-24 16:12:02 +02:00
|
|
|
mustSelect: true,
|
|
|
|
}}
|
|
|
|
showSideMenuButton={false}
|
|
|
|
showSearchButton={false}
|
|
|
|
/>
|
|
|
|
<View style={styles.body}>
|
|
|
|
<View style={styles.searchContainer}>
|
|
|
|
<TextInput
|
|
|
|
style={styles.searchTextInput}
|
|
|
|
autoFocus={props.visible}
|
|
|
|
underlineColorAndroid="#ffffff00"
|
|
|
|
onChangeText={setQuery}
|
|
|
|
value={query}
|
|
|
|
selectionColor={theme.textSelectionColor}
|
|
|
|
keyboardAppearance={theme.keyboardAppearance}
|
|
|
|
/>
|
|
|
|
<IconButton
|
|
|
|
themeId={props.themeId}
|
|
|
|
iconStyle={styles.clearIcon}
|
|
|
|
iconName='ionicon close-circle'
|
|
|
|
onPress={clearButton_press}
|
|
|
|
description={_('Clear')}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
|
|
|
|
<SearchResults
|
|
|
|
query={query}
|
|
|
|
ftsEnabled={props.ftsEnabled}
|
|
|
|
onHighlightedWordsChange={onHighlightedWordsChange}
|
|
|
|
/>
|
|
|
|
</View>
|
2024-09-27 16:23:31 +02:00
|
|
|
</AccessibleView>
|
2024-09-24 16:12:02 +02:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const SearchScreen = connect((state: AppState) => {
|
|
|
|
return {
|
|
|
|
query: state.searchQuery,
|
|
|
|
themeId: state.settings.theme,
|
|
|
|
settings: state.settings,
|
|
|
|
noteSelectionEnabled: state.noteSelectionEnabled,
|
|
|
|
ftsEnabled: state.settings['db.ftsEnabled'],
|
|
|
|
};
|
|
|
|
})(SearchScreenComponent);
|
|
|
|
|
|
|
|
export default SearchScreen;
|