You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Mobile: Also do multi-selection from search page
This commit is contained in:
		| @@ -100,7 +100,7 @@ class NoteItemComponent extends Component { | ||||
| 		if (!this.props.note) return; | ||||
|  | ||||
| 		this.props.dispatch({ | ||||
| 			type: 'NOTE_SELECTION_START', | ||||
| 			type: this.props.noteSelectionEnabled ? 'NOTE_SELECTION_TOGGLE' : 'NOTE_SELECTION_START', | ||||
| 			id: this.props.note.id, | ||||
| 		}); | ||||
| 	} | ||||
| @@ -126,21 +126,23 @@ class NoteItemComponent extends Component { | ||||
|  | ||||
| 		const listItemStyle = isTodo ? this.styles().listItemWithCheckbox : this.styles().listItem; | ||||
| 		const listItemTextStyle = isTodo ? this.styles().listItemTextWithCheckbox : this.styles().listItemText; | ||||
| 		const rootStyle = isTodo && checkboxChecked ? {opacity: 0.4} : {}; | ||||
| 		const opacityStyle = isTodo && checkboxChecked ? {opacity: 0.4} : {}; | ||||
| 		const isSelected = this.props.noteSelectionEnabled && this.props.selectedNoteIds.indexOf(note.id) >= 0; | ||||
|  | ||||
| 		const selectionWrapperStyle = isSelected ? this.styles().selectionWrapperSelected : this.styles().selectionWrapper; | ||||
|  | ||||
| 		return ( | ||||
| 			<TouchableOpacity onPress={() => this.onPress()} style={rootStyle} onLongPress={() => this.onLongPress()}> | ||||
| 			<TouchableOpacity onPress={() => this.onPress()} onLongPress={() => this.onLongPress()}> | ||||
| 				<View style={ selectionWrapperStyle }> | ||||
| 					<View style={ listItemStyle }> | ||||
| 						<Checkbox | ||||
| 							style={checkboxStyle} | ||||
| 							checked={checkboxChecked} | ||||
| 							onChange={(checked) => this.todoCheckbox_change(checked)} | ||||
| 						/> | ||||
| 						<Text style={listItemTextStyle}>{note.title}</Text> | ||||
| 					<View style={ opacityStyle }> | ||||
| 						<View style={ listItemStyle }> | ||||
| 							<Checkbox | ||||
| 								style={checkboxStyle} | ||||
| 								checked={checkboxChecked} | ||||
| 								onChange={(checked) => this.todoCheckbox_change(checked)} | ||||
| 							/> | ||||
| 							<Text style={listItemTextStyle}>{note.title}</Text> | ||||
| 						</View> | ||||
| 					</View> | ||||
| 				</View> | ||||
| 			</TouchableOpacity> | ||||
|   | ||||
| @@ -9,6 +9,7 @@ const { Menu, MenuOptions, MenuOption, MenuTrigger } = require('react-native-pop | ||||
| const { _ } = require('lib/locale.js'); | ||||
| const { Setting } = require('lib/models/setting.js'); | ||||
| const { Note } = require('lib/models/note.js'); | ||||
| const { Folder } = require('lib/models/folder.js'); | ||||
| const { FileApi } = require('lib/file-api.js'); | ||||
| const { FileApiDriverOneDrive } = require('lib/file-api-driver-onedrive.js'); | ||||
| const { reg } = require('lib/registry.js'); | ||||
| @@ -162,7 +163,6 @@ class ScreenHeaderComponent extends Component { | ||||
| 	async deleteButton_press() { | ||||
| 		// Dialog needs to be displayed as a child of the parent component, otherwise | ||||
| 		// it won't be visible within the header component. | ||||
| 		if (!this.props.parentComponent) throw new Error('parentComponent not set'); | ||||
| 		const ok = await dialogs.confirm(this.props.parentComponent, _('Delete these notes?')); | ||||
| 		if (!ok) return; | ||||
|  | ||||
| @@ -368,9 +368,29 @@ class ScreenHeaderComponent extends Component { | ||||
| 							color: theme.color, | ||||
| 							fontSize: theme.fontSize, | ||||
| 						}} | ||||
| 						onValueChange={(itemValue, itemIndex) => { | ||||
| 							if (!folderPickerOptions.onValueChange) return; | ||||
| 							folderPickerOptions.onValueChange(itemValue, itemIndex); | ||||
| 						onValueChange={async (folderId, itemIndex) => { | ||||
| 							// If onValueChange is specified, use this as a callback, otherwise do the default | ||||
| 							// which is to take the selectedNoteIds from the state and move them to the | ||||
| 							// chosen folder. | ||||
|  | ||||
| 							if (folderPickerOptions.onValueChange) { | ||||
| 								folderPickerOptions.onValueChange(folderId, itemIndex); | ||||
| 								return; | ||||
| 							} | ||||
|  | ||||
| 							if (!folderId) return; | ||||
| 							const noteIds = this.props.selectedNoteIds; | ||||
| 							if (!noteIds.length) return; | ||||
|  | ||||
| 							const folder = await Folder.load(folderId); | ||||
|  | ||||
| 							const ok = noteIds.length > 1 ? await dialogs.confirm(this.props.parentComponent, _('Move %d notes to notebook "%s"?', noteIds.length, folder.title)) : true; | ||||
| 							if (!ok) return; | ||||
|  | ||||
| 							this.props.dispatch({ type: 'NOTE_SELECTION_END' }); | ||||
| 							for (let i = 0; i < noteIds.length; i++) { | ||||
| 								await Note.moveToFolder(noteIds[i], folderId); | ||||
| 							} | ||||
| 						}} | ||||
| 					/> | ||||
| 				); | ||||
|   | ||||
| @@ -143,6 +143,7 @@ class NotesScreenComponent extends BaseScreenComponent { | ||||
| 		let title = parent ? parent.title : null; | ||||
| 		const addFolderNoteButtons = this.props.selectedFolderId && this.props.selectedFolderId != Folder.conflictFolderId(); | ||||
| 		const thisComp = this; | ||||
| 		const actionButtonComp = this.props.noteSelectionEnabled ? null : <ActionButton addFolderNoteButtons={addFolderNoteButtons} parentFolderId={this.props.selectedFolderId}></ActionButton> | ||||
|  | ||||
| 		return ( | ||||
| 			<View style={rootStyle}> | ||||
| @@ -153,25 +154,10 @@ class NotesScreenComponent extends BaseScreenComponent { | ||||
| 					folderPickerOptions={{ | ||||
| 						enabled: this.props.noteSelectionEnabled, | ||||
| 						mustSelect: true, | ||||
| 						onValueChange: async (folderId, itemIndex) => { | ||||
| 							if (!folderId) return; | ||||
| 							const noteIds = this.props.selectedNoteIds; | ||||
| 							if (!noteIds.length) return; | ||||
|  | ||||
| 							const folder = await Folder.load(folderId); | ||||
|  | ||||
| 							const ok = await dialogs.confirm(this, _('Move %d note(s) to notebook "%s"?', noteIds.length, folder.title)); | ||||
| 							if (!ok) return; | ||||
|  | ||||
| 							this.props.dispatch({ type: 'NOTE_SELECTION_END' }); | ||||
| 							for (let i = 0; i < noteIds.length; i++) { | ||||
| 								await Note.moveToFolder(noteIds[i], folderId); | ||||
| 							} | ||||
| 						}, | ||||
| 					}} | ||||
| 				/> | ||||
| 				<NoteList style={{flex: 1}}/> | ||||
| 				<ActionButton addFolderNoteButtons={addFolderNoteButtons} parentFolderId={this.props.selectedFolderId}></ActionButton> | ||||
| 				{ actionButtonComp } | ||||
| 				<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/> | ||||
| 			</View> | ||||
| 		); | ||||
|   | ||||
| @@ -8,6 +8,8 @@ const { Note } = require('lib/models/note.js'); | ||||
| const { NoteItem } = require('lib/components/note-item.js'); | ||||
| const { BaseScreenComponent } = require('lib/components/base-screen.js'); | ||||
| const { themeStyle } = require('lib/components/global-style.js'); | ||||
| const { dialogs } = require('lib/dialogs.js'); | ||||
| const DialogBox = require('react-native-dialogbox').default; | ||||
|  | ||||
| class SearchScreenComponent extends BaseScreenComponent { | ||||
| 	 | ||||
| @@ -139,9 +141,18 @@ class SearchScreenComponent extends BaseScreenComponent { | ||||
| 			rootStyle.flex = 0.001; // This is a bit of a hack but it seems to work fine - it makes the component invisible but without unmounting it | ||||
| 		} | ||||
|  | ||||
| 		const thisComponent = this; | ||||
|  | ||||
| 		return ( | ||||
| 			<View style={rootStyle}> | ||||
| 				<ScreenHeader title={_('Search')}/> | ||||
| 				<ScreenHeader | ||||
| 					title={_('Search')} | ||||
| 					parentComponent={thisComponent} | ||||
| 					folderPickerOptions={{ | ||||
| 						enabled: this.props.noteSelectionEnabled, | ||||
| 						mustSelect: true, | ||||
| 					}} | ||||
| 				/> | ||||
| 				<View style={this.styles().body}> | ||||
| 					<View style={this.styles().searchContainer}> | ||||
| 						<TextInput | ||||
| @@ -163,6 +174,7 @@ class SearchScreenComponent extends BaseScreenComponent { | ||||
| 						renderItem={(event) => <NoteItem note={event.item}/>} | ||||
| 					/> | ||||
| 				</View> | ||||
| 				<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/> | ||||
| 			</View> | ||||
| 		); | ||||
| 	} | ||||
| @@ -174,6 +186,7 @@ const SearchScreen = connect( | ||||
| 		return { | ||||
| 			query: state.searchQuery, | ||||
| 			theme: state.settings.theme, | ||||
| 			noteSelectionEnabled: state.noteSelectionEnabled, | ||||
| 		}; | ||||
| 	} | ||||
| )(SearchScreenComponent) | ||||
|   | ||||
| @@ -8,7 +8,8 @@ const { Keyboard } = require('react-native'); | ||||
| let dialogs = {}; | ||||
|  | ||||
| dialogs.confirm = (parentComponent, message) => { | ||||
| 	if (!'dialogbox' in parentComponent) throw new Error('A "dialogbox" component must be defined on the parent component!'); | ||||
| 	if (!parentComponent) throw new Error('parentComponent is required'); | ||||
| 	if (!('dialogbox' in parentComponent)) throw new Error('A "dialogbox" component must be defined on the parent component!'); | ||||
|  | ||||
| 	return new Promise((resolve, reject) => { | ||||
| 		Keyboard.dismiss(); | ||||
| @@ -33,7 +34,8 @@ dialogs.confirm = (parentComponent, message) => { | ||||
| }; | ||||
|  | ||||
| dialogs.pop = (parentComponent, message, buttons) => { | ||||
| 	if (!'dialogbox' in parentComponent) throw new Error('A "dialogbox" component must be defined on the parent component!'); | ||||
| 	if (!parentComponent) throw new Error('parentComponent is required'); | ||||
| 	if (!('dialogbox' in parentComponent)) throw new Error('A "dialogbox" component must be defined on the parent component!'); | ||||
|  | ||||
| 	return new Promise((resolve, reject) => { | ||||
| 		Keyboard.dismiss(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user