You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Chore: Mobile: Search screen: Use stronger types, try to prevent multiple concurrent attempts to update the result list (#11075)
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| import * as React from 'react'; | ||||
| import { connect } from 'react-redux'; | ||||
| import NotesScreen from './screens/Notes'; | ||||
| const { SearchScreen } = require('./screens/search.js'); | ||||
| import SearchScreen from './screens/search'; | ||||
| import { Component } from 'react'; | ||||
| import { KeyboardAvoidingView, Keyboard, Platform, View, KeyboardEvent, Dimensions, EmitterSubscription } from 'react-native'; | ||||
| import { AppState } from '../utils/types'; | ||||
| @@ -116,7 +116,7 @@ class AppNavComponent extends Component<Props, State> { | ||||
| 				style={style} | ||||
| 			> | ||||
| 				<NotesScreen visible={notesScreenVisible} /> | ||||
| 				{searchScreenLoaded && <SearchScreen visible={searchScreenVisible} navigation={{ state: route }} />} | ||||
| 				{searchScreenLoaded && <SearchScreen visible={searchScreenVisible} />} | ||||
| 				{!notesScreenVisible && !searchScreenVisible && <Screen navigation={{ state: route }} themeId={this.props.themeId} dispatch={this.props.dispatch} />} | ||||
| 				<View style={{ height: this.state.autoCompletionBarExtraHeight }} /> | ||||
| 			</KeyboardAvoidingView> | ||||
|   | ||||
| @@ -1,37 +1,53 @@ | ||||
| const React = require('react'); | ||||
| import * as React from 'react'; | ||||
|  | ||||
| import { StyleSheet, View, TextInput, FlatList, TouchableHighlight } from 'react-native'; | ||||
| const { connect } = require('react-redux'); | ||||
| import { connect } from 'react-redux'; | ||||
| import ScreenHeader from '../ScreenHeader'; | ||||
| const Icon = require('react-native-vector-icons/Ionicons').default; | ||||
| import { _ } from '@joplin/lib/locale'; | ||||
| import Note from '@joplin/lib/models/Note'; | ||||
| import NoteItem from '../NoteItem'; | ||||
| const { BaseScreenComponent } = require('../base-screen'); | ||||
| import { BaseScreenComponent } from '../base-screen'; | ||||
| import { themeStyle } from '../global-style'; | ||||
| const DialogBox = require('react-native-dialogbox').default; | ||||
| import SearchEngineUtils from '@joplin/lib/services/search/SearchEngineUtils'; | ||||
| import SearchEngine from '@joplin/lib/services/search/SearchEngine'; | ||||
| import { AppState } from '../../utils/types'; | ||||
| import { NoteEntity } from '@joplin/lib/services/database/types'; | ||||
| import AsyncActionQueue from '@joplin/lib/AsyncActionQueue'; | ||||
| import { Dispatch } from 'redux'; | ||||
|  | ||||
| class SearchScreenComponent extends BaseScreenComponent { | ||||
| interface Props { | ||||
| 	themeId: number; | ||||
| 	query: string; | ||||
| 	visible: boolean; | ||||
| 	dispatch: Dispatch; | ||||
|  | ||||
| 	noteSelectionEnabled: boolean; | ||||
| 	ftsEnabled: number; | ||||
| } | ||||
|  | ||||
| interface State { | ||||
| 	query: string; | ||||
| 	notes: NoteEntity[]; | ||||
| } | ||||
|  | ||||
| class SearchScreenComponent extends BaseScreenComponent<Props, State> { | ||||
| 	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code from before rule was applied. | ||||
| 	public dialogbox: any; | ||||
|  | ||||
| 	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 	private state: any = null; | ||||
| 	private isMounted_ = false; | ||||
| 	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 	private styles_: any = {}; | ||||
| 	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 	private scheduleSearchTimer_: any = null; | ||||
| 	private styles_: Record<string, any> = {}; | ||||
| 	private searchActionQueue_ = new AsyncActionQueue(200); | ||||
|  | ||||
| 	public static navigationOptions() { | ||||
| 		// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 		return { header: null } as any; | ||||
| 	} | ||||
|  | ||||
| 	public constructor() { | ||||
| 		super(); | ||||
| 	public constructor(props: Props) { | ||||
| 		super(props); | ||||
| 		this.state = { | ||||
| 			query: '', | ||||
| 			notes: [], | ||||
| @@ -44,8 +60,7 @@ class SearchScreenComponent extends BaseScreenComponent { | ||||
| 		if (this.styles_[this.props.themeId]) return this.styles_[this.props.themeId]; | ||||
| 		this.styles_ = {}; | ||||
|  | ||||
| 		// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 		const styles: any = { | ||||
| 		const styleSheet = StyleSheet.create({ | ||||
| 			body: { | ||||
| 				flex: 1, | ||||
| 			}, | ||||
| @@ -55,21 +70,22 @@ class SearchScreenComponent extends BaseScreenComponent { | ||||
| 				borderWidth: 1, | ||||
| 				borderColor: theme.dividerColor, | ||||
| 			}, | ||||
| 		}; | ||||
|  | ||||
| 		styles.searchTextInput = { ...theme.lineInput }; | ||||
| 		styles.searchTextInput.paddingLeft = theme.marginLeft; | ||||
| 		styles.searchTextInput.flex = 1; | ||||
| 		styles.searchTextInput.backgroundColor = theme.backgroundColor; | ||||
| 		styles.searchTextInput.color = theme.color; | ||||
|  | ||||
| 		styles.clearIcon = { ...theme.icon }; | ||||
| 		styles.clearIcon.color = theme.colorFaded; | ||||
| 		styles.clearIcon.paddingRight = theme.marginRight; | ||||
| 		styles.clearIcon.backgroundColor = theme.backgroundColor; | ||||
|  | ||||
| 		this.styles_[this.props.themeId] = StyleSheet.create(styles); | ||||
| 		return this.styles_[this.props.themeId]; | ||||
| 			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, | ||||
| 			}, | ||||
| 		}); | ||||
| 		this.styles_[this.props.themeId] = styleSheet; | ||||
| 		return styleSheet; | ||||
| 	} | ||||
|  | ||||
| 	public componentDidMount() { | ||||
| @@ -98,7 +114,7 @@ class SearchScreenComponent extends BaseScreenComponent { | ||||
| 		let notes: NoteEntity[] = []; | ||||
|  | ||||
| 		if (query) { | ||||
| 			if (this.props.settings['db.ftsEnabled']) { | ||||
| 			if (this.props.ftsEnabled) { | ||||
| 				const r = await SearchEngineUtils.notesForQuery(query, true, { appendWildCards: true }); | ||||
| 				notes = r.notes; | ||||
| 			} else { | ||||
| @@ -130,12 +146,11 @@ class SearchScreenComponent extends BaseScreenComponent { | ||||
| 	} | ||||
|  | ||||
| 	public scheduleSearch() { | ||||
| 		if (this.scheduleSearchTimer_) clearTimeout(this.scheduleSearchTimer_); | ||||
| 		this.searchActionQueue_.push(() => this.refreshSearch(this.state.query)); | ||||
| 	} | ||||
|  | ||||
| 		this.scheduleSearchTimer_ = setTimeout(() => { | ||||
| 			this.scheduleSearchTimer_ = null; | ||||
| 			void this.refreshSearch(this.state.query); | ||||
| 		}, 200); | ||||
| 	public onComponentWillUnmount() { | ||||
| 		void this.searchActionQueue_.reset(); | ||||
| 	} | ||||
|  | ||||
| 	private searchTextInput_changeText(text: string) { | ||||
| @@ -215,7 +230,8 @@ const SearchScreen = connect((state: AppState) => { | ||||
| 		themeId: state.settings.theme, | ||||
| 		settings: state.settings, | ||||
| 		noteSelectionEnabled: state.noteSelectionEnabled, | ||||
| 		ftsEnabled: state.settings['db.ftsEnabled'], | ||||
| 	}; | ||||
| })(SearchScreenComponent); | ||||
|  | ||||
| module.exports = { SearchScreen }; | ||||
| export default SearchScreen; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user