mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Mobile: Also do multi-selection from search page
This commit is contained in:
parent
acc4eb5d28
commit
d8b19f7d08
@ -100,7 +100,7 @@ class NoteItemComponent extends Component {
|
|||||||
if (!this.props.note) return;
|
if (!this.props.note) return;
|
||||||
|
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'NOTE_SELECTION_START',
|
type: this.props.noteSelectionEnabled ? 'NOTE_SELECTION_TOGGLE' : 'NOTE_SELECTION_START',
|
||||||
id: this.props.note.id,
|
id: this.props.note.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -126,21 +126,23 @@ class NoteItemComponent extends Component {
|
|||||||
|
|
||||||
const listItemStyle = isTodo ? this.styles().listItemWithCheckbox : this.styles().listItem;
|
const listItemStyle = isTodo ? this.styles().listItemWithCheckbox : this.styles().listItem;
|
||||||
const listItemTextStyle = isTodo ? this.styles().listItemTextWithCheckbox : this.styles().listItemText;
|
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 isSelected = this.props.noteSelectionEnabled && this.props.selectedNoteIds.indexOf(note.id) >= 0;
|
||||||
|
|
||||||
const selectionWrapperStyle = isSelected ? this.styles().selectionWrapperSelected : this.styles().selectionWrapper;
|
const selectionWrapperStyle = isSelected ? this.styles().selectionWrapperSelected : this.styles().selectionWrapper;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={() => this.onPress()} style={rootStyle} onLongPress={() => this.onLongPress()}>
|
<TouchableOpacity onPress={() => this.onPress()} onLongPress={() => this.onLongPress()}>
|
||||||
<View style={ selectionWrapperStyle }>
|
<View style={ selectionWrapperStyle }>
|
||||||
<View style={ listItemStyle }>
|
<View style={ opacityStyle }>
|
||||||
<Checkbox
|
<View style={ listItemStyle }>
|
||||||
style={checkboxStyle}
|
<Checkbox
|
||||||
checked={checkboxChecked}
|
style={checkboxStyle}
|
||||||
onChange={(checked) => this.todoCheckbox_change(checked)}
|
checked={checkboxChecked}
|
||||||
/>
|
onChange={(checked) => this.todoCheckbox_change(checked)}
|
||||||
<Text style={listItemTextStyle}>{note.title}</Text>
|
/>
|
||||||
|
<Text style={listItemTextStyle}>{note.title}</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -9,6 +9,7 @@ const { Menu, MenuOptions, MenuOption, MenuTrigger } = require('react-native-pop
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { Setting } = require('lib/models/setting.js');
|
const { Setting } = require('lib/models/setting.js');
|
||||||
const { Note } = require('lib/models/note.js');
|
const { Note } = require('lib/models/note.js');
|
||||||
|
const { Folder } = require('lib/models/folder.js');
|
||||||
const { FileApi } = require('lib/file-api.js');
|
const { FileApi } = require('lib/file-api.js');
|
||||||
const { FileApiDriverOneDrive } = require('lib/file-api-driver-onedrive.js');
|
const { FileApiDriverOneDrive } = require('lib/file-api-driver-onedrive.js');
|
||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
@ -162,7 +163,6 @@ class ScreenHeaderComponent extends Component {
|
|||||||
async deleteButton_press() {
|
async deleteButton_press() {
|
||||||
// Dialog needs to be displayed as a child of the parent component, otherwise
|
// Dialog needs to be displayed as a child of the parent component, otherwise
|
||||||
// it won't be visible within the header component.
|
// 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?'));
|
const ok = await dialogs.confirm(this.props.parentComponent, _('Delete these notes?'));
|
||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
|
|
||||||
@ -368,9 +368,29 @@ class ScreenHeaderComponent extends Component {
|
|||||||
color: theme.color,
|
color: theme.color,
|
||||||
fontSize: theme.fontSize,
|
fontSize: theme.fontSize,
|
||||||
}}
|
}}
|
||||||
onValueChange={(itemValue, itemIndex) => {
|
onValueChange={async (folderId, itemIndex) => {
|
||||||
if (!folderPickerOptions.onValueChange) return;
|
// If onValueChange is specified, use this as a callback, otherwise do the default
|
||||||
folderPickerOptions.onValueChange(itemValue, itemIndex);
|
// 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;
|
let title = parent ? parent.title : null;
|
||||||
const addFolderNoteButtons = this.props.selectedFolderId && this.props.selectedFolderId != Folder.conflictFolderId();
|
const addFolderNoteButtons = this.props.selectedFolderId && this.props.selectedFolderId != Folder.conflictFolderId();
|
||||||
const thisComp = this;
|
const thisComp = this;
|
||||||
|
const actionButtonComp = this.props.noteSelectionEnabled ? null : <ActionButton addFolderNoteButtons={addFolderNoteButtons} parentFolderId={this.props.selectedFolderId}></ActionButton>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={rootStyle}>
|
<View style={rootStyle}>
|
||||||
@ -153,25 +154,10 @@ class NotesScreenComponent extends BaseScreenComponent {
|
|||||||
folderPickerOptions={{
|
folderPickerOptions={{
|
||||||
enabled: this.props.noteSelectionEnabled,
|
enabled: this.props.noteSelectionEnabled,
|
||||||
mustSelect: true,
|
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}}/>
|
<NoteList style={{flex: 1}}/>
|
||||||
<ActionButton addFolderNoteButtons={addFolderNoteButtons} parentFolderId={this.props.selectedFolderId}></ActionButton>
|
{ actionButtonComp }
|
||||||
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
|
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -8,6 +8,8 @@ const { Note } = require('lib/models/note.js');
|
|||||||
const { NoteItem } = require('lib/components/note-item.js');
|
const { NoteItem } = require('lib/components/note-item.js');
|
||||||
const { BaseScreenComponent } = require('lib/components/base-screen.js');
|
const { BaseScreenComponent } = require('lib/components/base-screen.js');
|
||||||
const { themeStyle } = require('lib/components/global-style.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 {
|
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
|
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 (
|
return (
|
||||||
<View style={rootStyle}>
|
<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().body}>
|
||||||
<View style={this.styles().searchContainer}>
|
<View style={this.styles().searchContainer}>
|
||||||
<TextInput
|
<TextInput
|
||||||
@ -163,6 +174,7 @@ class SearchScreenComponent extends BaseScreenComponent {
|
|||||||
renderItem={(event) => <NoteItem note={event.item}/>}
|
renderItem={(event) => <NoteItem note={event.item}/>}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -174,6 +186,7 @@ const SearchScreen = connect(
|
|||||||
return {
|
return {
|
||||||
query: state.searchQuery,
|
query: state.searchQuery,
|
||||||
theme: state.settings.theme,
|
theme: state.settings.theme,
|
||||||
|
noteSelectionEnabled: state.noteSelectionEnabled,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)(SearchScreenComponent)
|
)(SearchScreenComponent)
|
||||||
|
@ -8,7 +8,8 @@ const { Keyboard } = require('react-native');
|
|||||||
let dialogs = {};
|
let dialogs = {};
|
||||||
|
|
||||||
dialogs.confirm = (parentComponent, message) => {
|
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) => {
|
return new Promise((resolve, reject) => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
@ -33,7 +34,8 @@ dialogs.confirm = (parentComponent, message) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
dialogs.pop = (parentComponent, message, buttons) => {
|
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) => {
|
return new Promise((resolve, reject) => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
|
Loading…
Reference in New Issue
Block a user