mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Mobile: Made tag UI a dialog
This commit is contained in:
parent
d6f7893c56
commit
ca3946689a
@ -30,21 +30,21 @@ class ModalDialog extends React.Component {
|
|||||||
borderColor:theme.dividerColor,
|
borderColor:theme.dividerColor,
|
||||||
margin: 20,
|
margin: 20,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
|
borderRadius: 5,
|
||||||
},
|
},
|
||||||
modalContentWrapper2: {
|
modalContentWrapper2: {
|
||||||
paddingTop: 10,
|
|
||||||
flex:1,
|
flex:1,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: theme.dividerColor,
|
borderBottomColor: theme.dividerColor,
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
buttonRow: {
|
buttonRow: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderTopColor: theme.dividerColor,
|
borderTopColor: theme.dividerColor,
|
||||||
paddingTop: 10,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,21 +54,22 @@ class ModalDialog extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const ContentComponent = this.props.ContentComponent;
|
const ContentComponent = this.props.ContentComponent;
|
||||||
|
const buttonBarEnabled = this.props.buttonBarEnabled !== false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={this.styles().modalWrapper}>
|
<View style={this.styles().modalWrapper}>
|
||||||
<Modal transparent={true} visible={true} onRequestClose={() => { }} >
|
<Modal transparent={true} visible={true} onRequestClose={() => { }} >
|
||||||
<View style={this.styles().modalContentWrapper}>
|
<View elevation={10} style={this.styles().modalContentWrapper}>
|
||||||
<Text style={this.styles().title}>Title</Text>
|
<Text style={this.styles().title}>{this.props.title}</Text>
|
||||||
<View style={this.styles().modalContentWrapper2}>
|
<View style={this.styles().modalContentWrapper2}>
|
||||||
{ContentComponent}
|
{ContentComponent}
|
||||||
</View>
|
</View>
|
||||||
<View style={this.styles().buttonRow}>
|
<View style={this.styles().buttonRow}>
|
||||||
<View style={{flex:1}}>
|
<View style={{flex:1}}>
|
||||||
<Button title={_('OK')} onPress={() => {}}></Button>
|
<Button disabled={!buttonBarEnabled} title={_('OK')} onPress={this.props.onOkPress}></Button>
|
||||||
</View>
|
</View>
|
||||||
<View style={{flex:1, marginLeft: 5}}>
|
<View style={{flex:1, marginLeft: 5}}>
|
||||||
<Button title={_('Cancel')} onPress={() => {}}></Button>
|
<Button disabled={!buttonBarEnabled} title={_('Cancel')} onPress={this.props.onCancelPress}></Button>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -12,18 +12,12 @@ const { Database } = require('lib/database.js');
|
|||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
const { ReportService } = require('lib/services/report.js');
|
const { ReportService } = require('lib/services/report.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { BaseScreenComponent } = require('lib/components/base-screen.js');
|
|
||||||
const { globalStyle, themeStyle } = require('lib/components/global-style.js');
|
const { globalStyle, themeStyle } = require('lib/components/global-style.js');
|
||||||
const Icon = require('react-native-vector-icons/Ionicons').default;
|
const Icon = require('react-native-vector-icons/Ionicons').default;
|
||||||
|
const ModalDialog = require('lib/components/ModalDialog');
|
||||||
|
const naturalCompare = require('string-natural-compare');
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
class NoteTagsDialogComponent extends React.Component {
|
||||||
body: {
|
|
||||||
flex: 1,
|
|
||||||
margin: globalStyle.margin,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class NoteTagsScreenComponent extends BaseScreenComponent {
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -94,15 +88,11 @@ class NoteTagsScreenComponent extends BaseScreenComponent {
|
|||||||
this.setState({ savingTags: false });
|
this.setState({ savingTags: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.dispatch({
|
if (this.props.onCloseRequested) this.props.onCloseRequested();
|
||||||
type: 'NAV_BACK',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cancelButton_press = () => {
|
this.cancelButton_press = () => {
|
||||||
this.props.dispatch({
|
if (this.props.onCloseRequested) this.props.onCloseRequested();
|
||||||
type: 'NAV_BACK',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +112,11 @@ class NoteTagsScreenComponent extends BaseScreenComponent {
|
|||||||
selected: tagIds.indexOf(tag.id) >= 0,
|
selected: tagIds.indexOf(tag.id) >= 0,
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
tagListData.sort((a, b) => {
|
||||||
|
return naturalCompare.caseInsensitive(a.title, b.title);
|
||||||
|
//return a.title.toLowerCase() < b.title.toLowerCase() ? -1 : +1;
|
||||||
|
});
|
||||||
|
|
||||||
this.setState({ tagListData: tagListData });
|
this.setState({ tagListData: tagListData });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,8 +146,8 @@ class NoteTagsScreenComponent extends BaseScreenComponent {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingLeft: theme.marginLeft,
|
paddingLeft: theme.marginLeft,
|
||||||
paddingRight: theme.marginRight,
|
paddingRight: theme.marginRight,
|
||||||
borderTopWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderTopColor: theme.dividerColor
|
borderBottomColor: theme.dividerColor
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -163,32 +158,32 @@ class NoteTagsScreenComponent extends BaseScreenComponent {
|
|||||||
render() {
|
render() {
|
||||||
const theme = themeStyle(this.props.theme);
|
const theme = themeStyle(this.props.theme);
|
||||||
|
|
||||||
return (
|
const dialogContent = (
|
||||||
<View style={this.rootStyle(this.props.theme).root}>
|
<View style={{flex:1}}>
|
||||||
<ScreenHeader title={_('Note tags')} showSideMenuButton={false} showSearchButton={false} showContextMenuButton={false}/>
|
<View style={this.styles().newTagBox}>
|
||||||
|
<Text>{_('New tags:')}</Text><TextInput value={this.state.newTags} onChangeText={value => { this.setState({ newTags: value }) }} style={{flex:1}}/>
|
||||||
|
</View>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.state.tagListData}
|
data={this.state.tagListData}
|
||||||
renderItem={this.renderTag}
|
renderItem={this.renderTag}
|
||||||
keyExtractor={this.tagKeyExtractor}
|
keyExtractor={this.tagKeyExtractor}
|
||||||
/>
|
/>
|
||||||
<View style={this.styles().newTagBox}>
|
|
||||||
<Text>{_('Or type tags:')}</Text><TextInput value={this.state.newTags} onChangeText={value => { this.setState({ newTags: value }) }} style={{flex:1}}/>
|
|
||||||
</View>
|
|
||||||
<View style={theme.buttonRow}>
|
|
||||||
<View style={{flex:1}}>
|
|
||||||
<Button disabled={this.state.savingTags} title={_('OK')} onPress={this.okButton_press}></Button>
|
|
||||||
</View>
|
|
||||||
<View style={{flex:1, marginLeft: 5}}>
|
|
||||||
<Button disabled={this.state.savingTags} title={_('Cancel')} onPress={this.cancelButton_press}></Button>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return <ModalDialog
|
||||||
|
theme={this.props.theme}
|
||||||
|
ContentComponent={dialogContent}
|
||||||
|
title={_('Type new tags or select from list')}
|
||||||
|
onOkPress={this.okButton_press}
|
||||||
|
onCancelPress={this.cancelButton_press}
|
||||||
|
buttonBarEnabled={!this.state.savingTags}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NoteTagsScreen = connect(
|
const NoteTagsDialog = connect(
|
||||||
(state) => {
|
(state) => {
|
||||||
return {
|
return {
|
||||||
theme: state.settings.theme,
|
theme: state.settings.theme,
|
||||||
@ -196,6 +191,6 @@ const NoteTagsScreen = connect(
|
|||||||
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)(NoteTagsScreenComponent)
|
)(NoteTagsDialogComponent)
|
||||||
|
|
||||||
module.exports = { NoteTagsScreen };
|
module.exports = NoteTagsDialog;
|
@ -15,6 +15,7 @@ const Icon = require('react-native-vector-icons/Ionicons').default;
|
|||||||
const { fileExtension, basename, safeFileExtension } = require('lib/path-utils.js');
|
const { fileExtension, basename, safeFileExtension } = require('lib/path-utils.js');
|
||||||
const mimeUtils = require('lib/mime-utils.js').mime;
|
const mimeUtils = require('lib/mime-utils.js').mime;
|
||||||
const { ScreenHeader } = require('lib/components/screen-header.js');
|
const { ScreenHeader } = require('lib/components/screen-header.js');
|
||||||
|
const NoteTagsDialog = require('lib/components/screens/NoteTagsDialog');
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
const { Checkbox } = require('lib/components/checkbox.js');
|
const { Checkbox } = require('lib/components/checkbox.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
@ -51,7 +52,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
isLoading: true,
|
isLoading: true,
|
||||||
titleTextInputHeight: 20,
|
titleTextInputHeight: 20,
|
||||||
alarmDialogShown: false,
|
alarmDialogShown: false,
|
||||||
heightBumpView:0
|
heightBumpView:0,
|
||||||
|
noteTagDialogShown: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// iOS doesn't support multiline text fields properly so disable it
|
// iOS doesn't support multiline text fields properly so disable it
|
||||||
@ -101,6 +103,10 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.noteTagDialog_closeRequested = () => {
|
||||||
|
this.setState({ noteTagDialogShown: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
styles() {
|
styles() {
|
||||||
@ -360,11 +366,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
tags_onPress() {
|
tags_onPress() {
|
||||||
if (!this.state.note || !this.state.note.id) return;
|
if (!this.state.note || !this.state.note.id) return;
|
||||||
|
|
||||||
this.props.dispatch({
|
this.setState({ noteTagDialogShown: true });
|
||||||
type: 'NAV_GO',
|
|
||||||
routeName: 'NoteTags',
|
|
||||||
noteId: this.state.note.id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setAlarm_onPress() {
|
setAlarm_onPress() {
|
||||||
@ -547,6 +549,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const noteTagDialog = !this.state.noteTagDialogShown ? null : <NoteTagsDialog onCloseRequested={this.noteTagDialog_closeRequested}/>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={this.rootStyle(this.props.theme).root}>
|
<View style={this.rootStyle(this.props.theme).root}>
|
||||||
<ScreenHeader
|
<ScreenHeader
|
||||||
@ -584,6 +588,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
|
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
|
||||||
|
{ noteTagDialog }
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class FsDriverRN extends FsDriverBase {
|
|||||||
|
|
||||||
// same as rm -rf
|
// same as rm -rf
|
||||||
async remove(path) {
|
async remove(path) {
|
||||||
throw new Error('Not implemented');
|
return await this.unlink(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeBinaryFile(path, content) {
|
writeBinaryFile(path, content) {
|
||||||
|
5
ReactNativeClient/package-lock.json
generated
5
ReactNativeClient/package-lock.json
generated
@ -6533,6 +6533,11 @@
|
|||||||
"strip-ansi": "3.0.1"
|
"strip-ansi": "3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"string-natural-compare": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-2.0.2.tgz",
|
||||||
|
"integrity": "sha1-xc5OJ4q10SZa5vxVQ1rre3b8sAE="
|
||||||
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
"react-redux": "4.4.8",
|
"react-redux": "4.4.8",
|
||||||
"redux": "3.6.0",
|
"redux": "3.6.0",
|
||||||
"stream": "0.0.2",
|
"stream": "0.0.2",
|
||||||
|
"string-natural-compare": "^2.0.2",
|
||||||
"timers": "^0.1.1",
|
"timers": "^0.1.1",
|
||||||
"url-parse": "^1.2.0",
|
"url-parse": "^1.2.0",
|
||||||
"uuid": "^3.0.1",
|
"uuid": "^3.0.1",
|
||||||
|
@ -32,7 +32,6 @@ const { ConfigScreen } = require('lib/components/screens/config.js');
|
|||||||
const { FolderScreen } = require('lib/components/screens/folder.js');
|
const { FolderScreen } = require('lib/components/screens/folder.js');
|
||||||
const { LogScreen } = require('lib/components/screens/log.js');
|
const { LogScreen } = require('lib/components/screens/log.js');
|
||||||
const { StatusScreen } = require('lib/components/screens/status.js');
|
const { StatusScreen } = require('lib/components/screens/status.js');
|
||||||
const { NoteTagsScreen } = require('lib/components/screens/note-tags.js');
|
|
||||||
const { WelcomeScreen } = require('lib/components/screens/welcome.js');
|
const { WelcomeScreen } = require('lib/components/screens/welcome.js');
|
||||||
const { SearchScreen } = require('lib/components/screens/search.js');
|
const { SearchScreen } = require('lib/components/screens/search.js');
|
||||||
const { OneDriveLoginScreen } = require('lib/components/screens/onedrive-login.js');
|
const { OneDriveLoginScreen } = require('lib/components/screens/onedrive-login.js');
|
||||||
@ -129,7 +128,7 @@ const generalMiddleware = store => next => async (action) => {
|
|||||||
let navHistory = [];
|
let navHistory = [];
|
||||||
|
|
||||||
function historyCanGoBackTo(route, nextRoute) {
|
function historyCanGoBackTo(route, nextRoute) {
|
||||||
if (route.routeName === 'Note' && nextRoute.routeName !== 'NoteTags') return false;
|
if (route.routeName === 'Note') return false;
|
||||||
if (route.routeName === 'Folder') return false;
|
if (route.routeName === 'Folder') return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -565,7 +564,6 @@ class AppComponent extends React.Component {
|
|||||||
Status: { screen: StatusScreen },
|
Status: { screen: StatusScreen },
|
||||||
Search: { screen: SearchScreen },
|
Search: { screen: SearchScreen },
|
||||||
Config: { screen: ConfigScreen },
|
Config: { screen: ConfigScreen },
|
||||||
NoteTags: { screen: NoteTagsScreen },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user