1
0
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:
Laurent Cozic 2018-03-17 23:00:01 +00:00
parent d6f7893c56
commit ca3946689a
7 changed files with 55 additions and 50 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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>
); );
} }

View File

@ -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) {

View File

@ -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",

View File

@ -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",

View File

@ -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 (