1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-29 22:48:10 +02:00

First pass at linting lib dir

This commit is contained in:
Laurent Cozic
2019-07-29 15:43:53 +02:00
parent 64b7bc3d62
commit 86dc72b204
170 changed files with 4140 additions and 3119 deletions

View File

@@ -1,9 +1,8 @@
const React = require('react');
const { TouchableOpacity, TouchableWithoutFeedback , Dimensions, Text, Modal, View } = require('react-native');
const { TouchableOpacity, TouchableWithoutFeedback, Dimensions, Text, Modal, View } = require('react-native');
const { ItemList } = require('lib/components/ItemList.js');
class Dropdown extends React.Component {
constructor() {
super();
@@ -21,7 +20,7 @@ class Dropdown extends React.Component {
// https://stackoverflow.com/questions/30096038/react-native-getting-the-position-of-an-element
this.headerRef_.measure((fx, fy, width, height, px, py) => {
this.setState({
headerSize: { x: px, y: py, width: width, height: height }
headerSize: { x: px, y: py, width: width, height: height },
});
});
}
@@ -51,7 +50,7 @@ class Dropdown extends React.Component {
});
const itemWrapperStyle = Object.assign({}, this.props.itemWrapperStyle ? this.props.itemWrapperStyle : {}, {
flex:1,
flex: 1,
justifyContent: 'center',
height: itemHeight,
paddingLeft: 20,
@@ -74,9 +73,7 @@ class Dropdown extends React.Component {
marginRight: 10,
});
const itemStyle = Object.assign({}, this.props.itemStyle ? this.props.itemStyle : {}, {
});
const itemStyle = Object.assign({}, this.props.itemStyle ? this.props.itemStyle : {}, {});
let headerLabel = '...';
for (let i = 0; i < items.length; i++) {
@@ -91,34 +88,61 @@ class Dropdown extends React.Component {
const closeList = () => {
this.setState({ listVisible: false });
}
};
const itemRenderer= (item) => {
const itemRenderer = item => {
return (
<TouchableOpacity style={itemWrapperStyle} key={item.value} onPress={() => { closeList(); if (this.props.onValueChange) this.props.onValueChange(item.value); }}>
<Text ellipsizeMode="tail" numberOfLines={1} style={itemStyle} key={item.value}>{item.label}</Text>
<TouchableOpacity
style={itemWrapperStyle}
key={item.value}
onPress={() => {
closeList();
if (this.props.onValueChange) this.props.onValueChange(item.value);
}}
>
<Text ellipsizeMode="tail" numberOfLines={1} style={itemStyle} key={item.value}>
{item.label}
</Text>
</TouchableOpacity>
);
}
};
return (
<View style={{flex: 1, flexDirection: 'column' }}>
<TouchableOpacity style={headerWrapperStyle} ref={(ref) => this.headerRef_ = ref} onPress={() => {
this.updateHeaderCoordinates();
this.setState({ listVisible: true });
}}>
<Text ellipsizeMode="tail" numberOfLines={1} style={headerStyle}>{headerLabel}</Text>
<View style={{ flex: 1, flexDirection: 'column' }}>
<TouchableOpacity
style={headerWrapperStyle}
ref={ref => (this.headerRef_ = ref)}
onPress={() => {
this.updateHeaderCoordinates();
this.setState({ listVisible: true });
}}
>
<Text ellipsizeMode="tail" numberOfLines={1} style={headerStyle}>
{headerLabel}
</Text>
<Text style={headerArrowStyle}>{'▼'}</Text>
</TouchableOpacity>
<Modal transparent={true} visible={this.state.listVisible} onRequestClose={() => { closeList(); }} >
<TouchableWithoutFeedback onPressOut={() => { closeList() }}>
<View style={{flex:1}}>
<Modal
transparent={true}
visible={this.state.listVisible}
onRequestClose={() => {
closeList();
}}
>
<TouchableWithoutFeedback
onPressOut={() => {
closeList();
}}
>
<View style={{ flex: 1 }}>
<View style={wrapperStyle}>
<ItemList
style={itemListStyle}
items={this.props.items}
itemHeight={itemHeight}
itemRenderer={(item) => { return itemRenderer(item) }}
itemRenderer={item => {
return itemRenderer(item);
}}
/>
</View>
</View>
@@ -129,4 +153,4 @@ class Dropdown extends React.Component {
}
}
module.exports = { Dropdown };
module.exports = { Dropdown };

View File

@@ -2,7 +2,6 @@ const React = require('react');
const { Text, TouchableHighlight, View, StyleSheet, ScrollView } = require('react-native');
class ItemList extends React.Component {
constructor() {
super();
@@ -77,8 +76,8 @@ class ItemList extends React.Component {
const items = this.props.items;
const blankItem = function(key, height) {
return <View key={key} style={{height:height}}></View>
}
return <View key={key} style={{ height: height }}></View>;
};
itemComps = [blankItem('top', this.state.topItemIndex * this.props.itemHeight)];
@@ -93,11 +92,20 @@ class ItemList extends React.Component {
}
return (
<ScrollView scrollEventThrottle={500} onLayout={(event) => { this.onLayout(event); }} style={style} onScroll={ (event) => { this.onScroll(event) }}>
{ itemComps }
<ScrollView
scrollEventThrottle={500}
onLayout={event => {
this.onLayout(event);
}}
style={style}
onScroll={event => {
this.onScroll(event);
}}
>
{itemComps}
</ScrollView>
);
}
}
module.exports = { ItemList };
module.exports = { ItemList };

View File

@@ -4,7 +4,6 @@ const { themeStyle } = require('lib/components/global-style.js');
const { _ } = require('lib/locale');
class ModalDialog extends React.Component {
constructor() {
super();
this.styles_ = {};
@@ -23,17 +22,17 @@ class ModalDialog extends React.Component {
justifyContent: 'center',
},
modalContentWrapper: {
flex:1,
flex: 1,
flexDirection: 'column',
backgroundColor: theme.backgroundColor,
borderWidth: 1,
borderColor:theme.dividerColor,
borderColor: theme.dividerColor,
margin: 20,
padding: 10,
borderRadius: 5,
},
modalContentWrapper2: {
flex:1,
flex: 1,
},
title: Object.assign({}, theme.normalText, {
borderBottomWidth: 1,
@@ -59,17 +58,15 @@ class ModalDialog extends React.Component {
return (
<View style={this.styles().modalWrapper}>
<Modal transparent={true} visible={true} onRequestClose={() => { }} >
<Modal transparent={true} visible={true} onRequestClose={() => {}}>
<View elevation={10} style={this.styles().modalContentWrapper}>
<Text style={this.styles().title}>{this.props.title}</Text>
<View style={this.styles().modalContentWrapper2}>
{ContentComponent}
</View>
<View style={this.styles().modalContentWrapper2}>{ContentComponent}</View>
<View style={this.styles().buttonRow}>
<View style={{flex:1}}>
<View style={{ flex: 1 }}>
<Button disabled={!buttonBarEnabled} title={_('OK')} onPress={this.props.onOkPress}></Button>
</View>
<View style={{flex:1, marginLeft: 5}}>
<View style={{ flex: 1, marginLeft: 5 }}>
<Button disabled={!buttonBarEnabled} title={_('Cancel')} onPress={this.props.onCancelPress}></Button>
</View>
</View>
@@ -80,4 +77,4 @@ class ModalDialog extends React.Component {
}
}
module.exports = ModalDialog;
module.exports = ModalDialog;

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { StyleSheet, Text } = require('react-native');
const Icon = require('react-native-vector-icons/Ionicons').default;
const ReactNativeActionButton = require('react-native-action-button').default;
@@ -14,11 +15,10 @@ const styles = StyleSheet.create({
},
itemText: {
// fontSize: 14, // Cannot currently set fontsize since the bow surrounding the label has a fixed size
}
},
});
class ActionButtonComponent extends React.Component {
constructor() {
super();
this.state = {
@@ -59,14 +59,18 @@ class ActionButtonComponent extends React.Component {
if (this.props.folders.length) {
buttons.push({
title: _('New to-do'),
onPress: () => { this.newTodo_press() },
onPress: () => {
this.newTodo_press();
},
color: '#9b59b6',
icon: 'md-checkbox-outline',
});
buttons.push({
title: _('New note'),
onPress: () => { this.newNote_press() },
onPress: () => {
this.newNote_press();
},
color: '#9b59b6',
icon: 'md-document',
});
@@ -86,41 +90,41 @@ class ActionButtonComponent extends React.Component {
}
if (!buttonComps.length && !this.props.mainButton) {
return <ReactNativeActionButton style={{ display: 'none' }}/>
return <ReactNativeActionButton style={{ display: 'none' }} />;
}
let mainButton = this.props.mainButton ? this.props.mainButton : {};
let mainIcon = mainButton.icon ? <Icon name={mainButton.icon} style={styles.actionButtonIcon} /> : <Icon name="md-add" style={styles.actionButtonIcon} />
let mainIcon = mainButton.icon ? <Icon name={mainButton.icon} style={styles.actionButtonIcon} /> : <Icon name="md-add" style={styles.actionButtonIcon} />;
if (this.props.multiStates) {
if (!this.props.buttons || !this.props.buttons.length) throw new Error('Multi-state button requires at least one state');
if (this.state.buttonIndex < 0 || this.state.buttonIndex >= this.props.buttons.length) throw new Error('Button index out of bounds: ' + this.state.buttonIndex + '/' + this.props.buttons.length);
let button = this.props.buttons[this.state.buttonIndex];
let mainIcon = <Icon name={button.icon} style={styles.actionButtonIcon} />
let mainIcon = <Icon name={button.icon} style={styles.actionButtonIcon} />;
return (
<ReactNativeActionButton
icon={mainIcon}
buttonColor="rgba(231,76,60,1)"
onPress={() => { button.onPress() }}
onPress={() => {
button.onPress();
}}
/>
);
} else {
return (
<ReactNativeActionButton textStyle={styles.itemText} icon={mainIcon} buttonColor="rgba(231,76,60,1)" onPress={ function() { } }>
{ buttonComps }
<ReactNativeActionButton textStyle={styles.itemText} icon={mainIcon} buttonColor="rgba(231,76,60,1)" onPress={function() {}}>
{buttonComps}
</ReactNativeActionButton>
);
}
}
}
const ActionButton = connect(
(state) => {
return {
folders: state.folders,
locale: state.settings.locale,
};
}
)(ActionButtonComponent)
const ActionButton = connect(state => {
return {
folders: state.folders,
locale: state.settings.locale,
};
})(ActionButtonComponent);
module.exports = { ActionButton };
module.exports = { ActionButton };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { connect } = require('react-redux');
const { NotesScreen } = require('lib/components/screens/notes.js');
const { SearchScreen } = require('lib/components/screens/search.js');
@@ -7,13 +8,12 @@ const { _ } = require('lib/locale.js');
const { themeStyle } = require('lib/components/global-style.js');
class AppNavComponent extends Component {
constructor() {
super();
this.previousRouteName_ = null;
this.state = {
autoCompletionBarExtraHeight: 0, // Extra padding for the auto completion bar at the top of the keyboard
}
};
}
UNSAFE_componentWillMount() {
@@ -30,12 +30,12 @@ class AppNavComponent extends Component {
this.keyboardDidHideListener = null;
}
keyboardDidShow () {
this.setState({ autoCompletionBarExtraHeight: 30 })
keyboardDidShow() {
this.setState({ autoCompletionBarExtraHeight: 30 });
}
keyboardDidHide () {
this.setState({ autoCompletionBarExtraHeight:0 })
keyboardDidHide() {
this.setState({ autoCompletionBarExtraHeight: 0 });
}
render() {
@@ -66,27 +66,24 @@ class AppNavComponent extends Component {
const theme = themeStyle(this.props.theme);
const style = { flex: 1, backgroundColor: theme.backgroundColor }
const style = { flex: 1, backgroundColor: theme.backgroundColor };
return (
<KeyboardAvoidingView behavior={ Platform.OS === 'ios' ? "padding" : null } style={style}>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : null} style={style}>
<NotesScreen visible={notesScreenVisible} navigation={{ state: route }} />
{ searchScreenLoaded && <SearchScreen visible={searchScreenVisible} navigation={{ state: route }} /> }
{ (!notesScreenVisible && !searchScreenVisible) && <Screen navigation={{ state: route }} /> }
{searchScreenLoaded && <SearchScreen visible={searchScreenVisible} navigation={{ state: route }} />}
{!notesScreenVisible && !searchScreenVisible && <Screen navigation={{ state: route }} />}
<View style={{ height: this.state.autoCompletionBarExtraHeight }} />
</KeyboardAvoidingView>
);
}
}
const AppNav = connect(
(state) => {
return {
route: state.route,
theme: state.settings.theme,
};
}
)(AppNavComponent)
const AppNav = connect(state => {
return {
route: state.route,
theme: state.settings.theme,
};
})(AppNavComponent);
module.exports = { AppNav };
module.exports = { AppNav };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { StyleSheet } = require('react-native');
const { globalStyle, themeStyle } = require('lib/components/global-style.js');
@@ -14,7 +15,6 @@ const styles_ = StyleSheet.create(styleObject_);
let rootStyles_ = {};
class BaseScreenComponent extends React.Component {
styles() {
return styles_;
}
@@ -34,7 +34,6 @@ class BaseScreenComponent extends React.Component {
});
return rootStyles_[themeId];
}
}
module.exports = { BaseScreenComponent };
module.exports = { BaseScreenComponent };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { StyleSheet, View, TouchableHighlight } = require('react-native');
const Icon = require('react-native-vector-icons/Ionicons').default;
@@ -11,12 +12,11 @@ const styles = {
};
class Checkbox extends Component {
constructor() {
super();
this.state = {
checked: false,
}
};
}
UNSAFE_componentWillMount() {
@@ -55,17 +55,16 @@ class Checkbox extends Component {
alignItems: 'center',
};
if (style && style.display === 'none') return <View/>
if (style && style.display === 'none') return <View />;
//if (style.display) thStyle.display = style.display;
return (
<TouchableHighlight onPress={() => this.onPress()} style={thStyle}>
<Icon name={iconName} style={checkboxIconStyle}/>
<Icon name={iconName} style={checkboxIconStyle} />
</TouchableHighlight>
);
}
}
module.exports = { Checkbox };
module.exports = { Checkbox };

View File

@@ -6,25 +6,25 @@ const globalStyle = {
margin: 15, // No text and no interactive component should be within this margin
itemMarginTop: 10,
itemMarginBottom: 10,
backgroundColor: "#ffffff",
color: "#555555", // For regular text
colorError: "red",
colorWarn: "#9A5B00",
colorFaded: "#777777", // For less important text
backgroundColor: '#ffffff',
color: '#555555', // For regular text
colorError: 'red',
colorWarn: '#9A5B00',
colorFaded: '#777777', // For less important text
fontSizeSmaller: 14,
dividerColor: "#dddddd",
strongDividerColor: "#aaaaaa",
dividerColor: '#dddddd',
strongDividerColor: '#aaaaaa',
selectedColor: '#e5e5e5',
headerBackgroundColor: '#F0F0F0',
disabledOpacity: 0.2,
colorUrl: '#7B81FF',
textSelectionColor: "#0096FF",
textSelectionColor: '#0096FF',
raisedBackgroundColor: "#0080EF",
raisedColor: "#003363",
raisedHighlightedColor: "#ffffff",
raisedBackgroundColor: '#0080EF',
raisedColor: '#003363',
raisedHighlightedColor: '#ffffff',
warningBackgroundColor: "#FFD08D",
warningBackgroundColor: '#FFD08D',
// For WebView - must correspond to the properties above
htmlFontSize: '16px',
@@ -118,9 +118,9 @@ function themeStyle(theme) {
output.textSelectionColor = '#00AEFF';
output.headerBackgroundColor = '#2D3136';
output.raisedBackgroundColor = "#0F2051";
output.raisedColor = "#788BC3";
output.raisedHighlightedColor = "#ffffff";
output.raisedBackgroundColor = '#0F2051';
output.raisedColor = '#788BC3';
output.raisedHighlightedColor = '#ffffff';
output.htmlColor = 'rgb(220,220,220)';
output.htmlBackgroundColor = 'rgb(29,32,36)';
@@ -140,4 +140,4 @@ function themeStyle(theme) {
return addExtraStyles(themeCache_[theme]);
}
module.exports = { globalStyle, themeStyle };
module.exports = { globalStyle, themeStyle };

View File

@@ -1,6 +1,7 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { Platform, View } = require('react-native');
const { WebView } = require('react-native-webview');
const { WebView } = require('react-native-webview');
const { themeStyle } = require('lib/components/global-style.js');
const Resource = require('lib/models/Resource.js');
const Setting = require('lib/models/Setting.js');
@@ -10,13 +11,12 @@ const MdToHtml = require('lib/renderers/MdToHtml.js');
const shared = require('lib/components/shared/note-screen-shared.js');
class NoteBodyViewer extends Component {
constructor() {
super();
this.state = {
resources: {},
webViewLoaded: false,
}
};
this.isMounted_ = false;
}
@@ -47,12 +47,11 @@ class NoteBodyViewer extends Component {
}
shouldComponentUpdate(nextProps, nextState) {
const safeGetNoteProp = (props, propName) => {
if (!props) return null;
if (!props.note) return null;
return props.note[propName];
}
};
// To address https://github.com/laurent22/joplin/issues/433
// If a checkbox in a note is ticked, the body changes, which normally would trigger a re-render
@@ -63,7 +62,7 @@ class NoteBodyViewer extends Component {
// will not be displayed immediately.
const currentNoteId = safeGetNoteProp(this.props, 'id');
const nextNoteId = safeGetNoteProp(nextProps, 'id');
if (currentNoteId !== nextNoteId || nextState.webViewLoaded !== this.state.webViewLoaded) return true;
// If the length of the body has changed, then it's something other than a checkbox that has changed,
@@ -98,7 +97,7 @@ class NoteBodyViewer extends Component {
},
paddingBottom: '3.8em', // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text)
highlightedKeywords: this.props.highlightedKeywords,
resources: this.props.noteResources,//await shared.attachedResources(bodyToRender),
resources: this.props.noteResources, //await shared.attachedResources(bodyToRender),
codeTheme: theme.codeThemeCss,
postMessageSyntax: 'window.ReactNativeWebView.postMessage',
};
@@ -120,19 +119,22 @@ class NoteBodyViewer extends Component {
}, 10);
`);
html = `
html =
`
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
` + html + `
` +
html +
`
</body>
</html>
`;
let webViewStyle = {'backgroundColor': this.props.webViewStyle.backgroundColor}
let webViewStyle = { backgroundColor: this.props.webViewStyle.backgroundColor };
// On iOS, the onLoadEnd() event is never fired so always
// display the webview (don't do the little trick
// to avoid the white flash).
@@ -183,8 +185,8 @@ class NoteBodyViewer extends Component {
mixedContentMode="always"
allowFileAccess={true}
onLoadEnd={() => this.onLoadEnd()}
onError={() => reg.logger().error('WebView error') }
onMessage={(event) => {
onError={() => reg.logger().error('WebView error')}
onMessage={event => {
// Since RN 58 (or 59) messages are now escaped twice???
let msg = unescape(unescape(event.nativeEvent.data));
@@ -196,7 +198,7 @@ class NoteBodyViewer extends Component {
} else if (msg.indexOf('markForDownload:') === 0) {
msg = msg.split(':');
const resourceId = msg[1];
if (this.props.onMarkForDownload) this.props.onMarkForDownload({ resourceId: resourceId });
if (this.props.onMarkForDownload) this.props.onMarkForDownload({ resourceId: resourceId });
} else {
this.props.onJoplinLinkClick(msg);
}
@@ -205,7 +207,6 @@ class NoteBodyViewer extends Component {
</View>
);
}
}
module.exports = { NoteBodyViewer };
module.exports = { NoteBodyViewer };

View File

@@ -1,6 +1,7 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { connect } = require('react-redux');
const { ListView, Text, TouchableOpacity , View, StyleSheet } = require('react-native');
const { ListView, Text, TouchableOpacity, View, StyleSheet } = require('react-native');
const { _ } = require('lib/locale.js');
const { Checkbox } = require('lib/components/checkbox.js');
const { reg } = require('lib/registry.js');
@@ -9,7 +10,6 @@ const { time } = require('lib/time-utils.js');
const { globalStyle, themeStyle } = require('lib/components/global-style.js');
class NoteItemComponent extends Component {
constructor() {
super();
this.styles_ = {};
@@ -68,19 +68,19 @@ class NoteItemComponent extends Component {
return this.styles_[this.props.theme];
}
async todoCheckbox_change(checked) {
async todoCheckbox_change(checked) {
if (!this.props.note) return;
const newNote = {
id: this.props.note.id,
todo_completed: checked ? time.unixMs() : 0,
}
};
await Note.save(newNote);
}
onPress() {
if (!this.props.note) return;
if (!!this.props.note.encryption_applied) return;
if (this.props.note.encryption_applied) return;
if (this.props.noteSelectionEnabled) {
this.props.dispatch({
@@ -126,21 +126,17 @@ class NoteItemComponent extends Component {
const listItemStyle = isTodo ? this.styles().listItemWithCheckbox : this.styles().listItem;
const listItemTextStyle = isTodo ? this.styles().listItemTextWithCheckbox : this.styles().listItemText;
const opacityStyle = 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()} onLongPress={() => this.onLongPress() } activeOpacity={0.5}>
<View style={ selectionWrapperStyle }>
<View style={ opacityStyle }>
<View style={ listItemStyle }>
<Checkbox
style={checkboxStyle}
checked={checkboxChecked}
onChange={(checked) => this.todoCheckbox_change(checked)}
/>
<TouchableOpacity onPress={() => this.onPress()} onLongPress={() => this.onLongPress()} activeOpacity={0.5}>
<View style={selectionWrapperStyle}>
<View style={opacityStyle}>
<View style={listItemStyle}>
<Checkbox style={checkboxStyle} checked={checkboxChecked} onChange={checked => this.todoCheckbox_change(checked)} />
<Text style={listItemTextStyle}>{Note.displayTitle(note)}</Text>
</View>
</View>
@@ -148,17 +144,14 @@ class NoteItemComponent extends Component {
</TouchableOpacity>
);
}
}
const NoteItem = connect(
(state) => {
return {
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
selectedNoteIds: state.selectedNoteIds,
};
}
)(NoteItemComponent)
const NoteItem = connect(state => {
return {
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
selectedNoteIds: state.selectedNoteIds,
};
})(NoteItemComponent);
module.exports = { NoteItem };
module.exports = { NoteItem };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { connect } = require('react-redux');
const { ListView, Text, TouchableHighlight, Switch, View, StyleSheet } = require('react-native');
const { _ } = require('lib/locale.js');
@@ -11,11 +12,12 @@ const { time } = require('lib/time-utils.js');
const { themeStyle } = require('lib/components/global-style.js');
class NoteListComponent extends Component {
constructor() {
super();
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => { return r1 !== r2; }
rowHasChanged: (r1, r2) => {
return r1 !== r2;
},
});
this.state = {
dataSource: ds,
@@ -91,30 +93,28 @@ class NoteListComponent extends Component {
if (this.state.dataSource.getRowCount()) {
return (
<ListView
ref={(ref) => this.rootRef_ = ref}
ref={ref => (this.rootRef_ = ref)}
dataSource={this.state.dataSource}
renderRow={(note) => {
return <NoteItem note={note}/>
renderRow={note => {
return <NoteItem note={note} />;
}}
enableEmptySections={true}
/>
);
} else {
const noItemMessage = _('There are currently no notes. Create one by clicking on the (+) button.');
return <Text style={this.styles().noItemMessage} >{noItemMessage}</Text>;
return <Text style={this.styles().noItemMessage}>{noItemMessage}</Text>;
}
}
}
const NoteList = connect(
(state) => {
return {
items: state.notes,
notesSource: state.notesSource,
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
};
}
)(NoteListComponent)
const NoteList = connect(state => {
return {
items: state.notes,
notesSource: state.notesSource,
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
};
})(NoteListComponent);
module.exports = { NoteList };
module.exports = { NoteList };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { connect } = require('react-redux');
const { Platform, View, Text, Button, StyleSheet, TouchableOpacity, Image, ScrollView, Dimensions } = require('react-native');
const Icon = require('react-native-vector-icons/Ionicons').default;
@@ -27,7 +28,6 @@ const DialogBox = require('react-native-dialogbox').default;
const PADDING_V = 10;
class ScreenHeaderComponent extends React.PureComponent {
constructor() {
super();
this.styles_ = {};
@@ -52,7 +52,7 @@ class ScreenHeaderComponent extends React.PureComponent {
divider: {
borderBottomWidth: 1,
borderColor: theme.dividerColor,
backgroundColor: "#0000ff"
backgroundColor: '#0000ff',
},
sideMenuButton: {
flex: 1,
@@ -132,7 +132,7 @@ class ScreenHeaderComponent extends React.PureComponent {
paddingBottom: 15,
},
warningBox: {
backgroundColor: "#ff9900",
backgroundColor: '#ff9900',
flexDirection: 'row',
padding: theme.marginLeft,
},
@@ -160,9 +160,9 @@ class ScreenHeaderComponent extends React.PureComponent {
async backButton_press() {
if (this.props.noteSelectionEnabled) {
this.props.dispatch({ type: 'NOTE_SELECTION_END' });
} else {
} else {
await BackButtonService.back();
}
}
}
searchButton_press() {
@@ -181,7 +181,7 @@ class ScreenHeaderComponent extends React.PureComponent {
}
menu_select(value) {
if (typeof(value) == 'function') {
if (typeof value == 'function') {
value();
}
}
@@ -199,12 +199,11 @@ class ScreenHeaderComponent extends React.PureComponent {
}
render() {
function sideMenuButton(styles, onPress) {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.sideMenuButton}>
<Icon name='md-menu' style={styles.topIcon} />
<Icon name="md-menu" style={styles.topIcon} />
</View>
</TouchableOpacity>
);
@@ -214,7 +213,7 @@ class ScreenHeaderComponent extends React.PureComponent {
return (
<TouchableOpacity onPress={onPress} disabled={disabled}>
<View style={disabled ? styles.backButtonDisabled : styles.backButton}>
<Icon name='md-arrow-back' style={styles.topIcon} />
<Icon name="md-arrow-back" style={styles.topIcon} />
</View>
</TouchableOpacity>
);
@@ -223,13 +222,11 @@ class ScreenHeaderComponent extends React.PureComponent {
function saveButton(styles, onPress, disabled, show) {
if (!show) return null;
const icon = disabled ? <Icon name='md-checkmark' style={styles.savedButtonIcon} /> : <Image style={styles.saveButtonIcon} source={require('./SaveIcon.png')} />;
const icon = disabled ? <Icon name="md-checkmark" style={styles.savedButtonIcon} /> : <Image style={styles.saveButtonIcon} source={require('./SaveIcon.png')} />;
return (
<TouchableOpacity onPress={onPress} disabled={disabled} style={{ padding:0 }}>
<View style={disabled ? styles.saveButtonDisabled : styles.saveButton}>
{ icon }
</View>
<TouchableOpacity onPress={onPress} disabled={disabled} style={{ padding: 0 }}>
<View style={disabled ? styles.saveButtonDisabled : styles.saveButton}>{icon}</View>
</TouchableOpacity>
);
}
@@ -238,7 +235,7 @@ class ScreenHeaderComponent extends React.PureComponent {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.iconButton}>
<Icon name='md-search' style={styles.topIcon} />
<Icon name="md-search" style={styles.topIcon} />
</View>
</TouchableOpacity>
);
@@ -248,7 +245,7 @@ class ScreenHeaderComponent extends React.PureComponent {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.iconButton}>
<Icon name='md-trash' style={styles.topIcon} />
<Icon name="md-trash" style={styles.topIcon} />
</View>
</TouchableOpacity>
);
@@ -258,7 +255,7 @@ class ScreenHeaderComponent extends React.PureComponent {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.iconButton}>
<Icon name='md-funnel' style={styles.topIcon} />
<Icon name="md-funnel" style={styles.topIcon} />
</View>
</TouchableOpacity>
);
@@ -272,23 +269,25 @@ class ScreenHeaderComponent extends React.PureComponent {
let o = this.props.menuOptions[i];
if (o.isDivider) {
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider}/>);
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider} />);
} else {
menuOptionComponents.push(
<MenuOption value={o.onPress} key={'menuOption_' + key++} style={this.styles().contextMenuItem}>
<Text style={this.styles().contextMenuItemText}>{o.title}</Text>
</MenuOption>);
</MenuOption>
);
}
}
if (menuOptionComponents.length) {
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider}/>);
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider} />);
}
} else {
menuOptionComponents.push(
<MenuOption value={() => this.deleteButton_press()} key={'menuOption_delete'} style={this.styles().contextMenuItem}>
<Text style={this.styles().contextMenuItemText}>{_('Delete')}</Text>
</MenuOption>);
</MenuOption>
);
}
const createTitleComponent = () => {
@@ -297,7 +296,6 @@ class ScreenHeaderComponent extends React.PureComponent {
const folderPickerOptions = this.props.folderPickerOptions;
if (folderPickerOptions && folderPickerOptions.enabled) {
const addFolderChildren = (folders, pickerItems, indent) => {
folders.sort((a, b) => {
const aTitle = a && a.title ? a.title : '';
@@ -312,23 +310,23 @@ class ScreenHeaderComponent extends React.PureComponent {
}
return pickerItems;
}
};
const titlePickerItems = (mustSelect) => {
const titlePickerItems = mustSelect => {
const folders = this.props.folders.filter(f => f.id !== Folder.conflictFolderId());
let output = [];
if (mustSelect) output.push({ label: _('Move to notebook...'), value: null });
const folderTree = Folder.buildTree(folders);
output = addFolderChildren(folderTree, output, 0);
return output;
}
};
return (
<Dropdown
items={titlePickerItems(!!folderPickerOptions.mustSelect)}
itemHeight={35}
labelTransform="trim"
selectedValue={('selectedFolderId' in folderPickerOptions) ? folderPickerOptions.selectedFolderId : null}
selectedValue={'selectedFolderId' in folderPickerOptions ? folderPickerOptions.selectedFolderId : null}
itemListStyle={{
backgroundColor: theme.backgroundColor,
}}
@@ -368,13 +366,13 @@ class ScreenHeaderComponent extends React.PureComponent {
);
} else {
let title = 'title' in this.props && this.props.title !== null ? this.props.title : '';
return <Text style={this.styles().titleText}>{title}</Text>
return <Text style={this.styles().titleText}>{title}</Text>;
}
}
};
const warningComp = this.props.showMissingMasterKeyMessage ? (
<TouchableOpacity style={this.styles().warningBox} onPress={() => this.warningBox_press()} activeOpacity={0.8}>
<Text style={{flex:1}}>{_('Press to set the decryption password.')}</Text>
<Text style={{ flex: 1 }}>{_('Press to set the decryption password.')}</Text>
</TouchableOpacity>
) : null;
@@ -384,7 +382,7 @@ class ScreenHeaderComponent extends React.PureComponent {
const showBackButton = !!this.props.noteSelectionEnabled || this.props.showBackButton !== false;
let backButtonDisabled = !this.props.historyCanGoBack;
if (!!this.props.noteSelectionEnabled) backButtonDisabled = false;
if (this.props.noteSelectionEnabled) backButtonDisabled = false;
const titleComp = createTitleComponent();
const sideMenuComp = !showSideMenuButton ? null : sideMenuButton(this.styles(), () => this.sideMenuButton_press());
@@ -395,59 +393,66 @@ class ScreenHeaderComponent extends React.PureComponent {
const windowHeight = Dimensions.get('window').height - 50;
const contextMenuStyle = { paddingTop: PADDING_V, paddingBottom: PADDING_V };
// HACK: if this button is removed during selection mode, the header layout is broken, so for now just make it 1 pixel large (normally it should be hidden)
if (!!this.props.noteSelectionEnabled) contextMenuStyle.width = 1;
const menuComp = !menuOptionComponents.length || !showContextMenuButton ? null : (
<Menu onSelect={(value) => this.menu_select(value)} style={this.styles().contextMenu}>
<MenuTrigger style={contextMenuStyle}>
<Icon name='md-more' style={this.styles().contextMenuTrigger} />
</MenuTrigger>
<MenuOptions>
<ScrollView style={{ maxHeight: windowHeight }}>
{ menuOptionComponents }
</ScrollView>
</MenuOptions>
</Menu>
);
// HACK: if this button is removed during selection mode, the header layout is broken, so for now just make it 1 pixel large (normally it should be hidden)
if (this.props.noteSelectionEnabled) contextMenuStyle.width = 1;
const menuComp =
!menuOptionComponents.length || !showContextMenuButton ? null : (
<Menu onSelect={value => this.menu_select(value)} style={this.styles().contextMenu}>
<MenuTrigger style={contextMenuStyle}>
<Icon name="md-more" style={this.styles().contextMenuTrigger} />
</MenuTrigger>
<MenuOptions>
<ScrollView style={{ maxHeight: windowHeight }}>{menuOptionComponents}</ScrollView>
</MenuOptions>
</Menu>
);
return (
<View style={this.styles().container} >
<View style={{flexDirection:'row', alignItems: 'center'}}>
{ sideMenuComp }
{ backButtonComp }
{ saveButton(this.styles(), () => { if (this.props.onSaveButtonPress) this.props.onSaveButtonPress() }, this.props.saveButtonDisabled === true, this.props.showSaveButton === true) }
{ titleComp }
{ searchButtonComp }
{ deleteButtonComp }
{ sortButtonComp }
{ menuComp }
<View style={this.styles().container}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
{sideMenuComp}
{backButtonComp}
{saveButton(
this.styles(),
() => {
if (this.props.onSaveButtonPress) this.props.onSaveButtonPress();
},
this.props.saveButtonDisabled === true,
this.props.showSaveButton === true
)}
{titleComp}
{searchButtonComp}
{deleteButtonComp}
{sortButtonComp}
{menuComp}
</View>
{ warningComp }
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
{warningComp}
<DialogBox
ref={dialogbox => {
this.dialogbox = dialogbox;
}}
/>
</View>
);
}
}
ScreenHeaderComponent.defaultProps = {
menuOptions: [],
};
const ScreenHeader = connect(
(state) => {
return {
historyCanGoBack: state.historyCanGoBack,
locale: state.settings.locale,
folders: state.folders,
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
selectedNoteIds: state.selectedNoteIds,
showMissingMasterKeyMessage: state.notLoadedMasterKeys.length && state.masterKeys.length,
};
}
)(ScreenHeaderComponent)
const ScreenHeader = connect(state => {
return {
historyCanGoBack: state.historyCanGoBack,
locale: state.settings.locale,
folders: state.folders,
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
selectedNoteIds: state.selectedNoteIds,
showMissingMasterKeyMessage: state.notLoadedMasterKeys.length && state.masterKeys.length,
};
})(ScreenHeaderComponent);
module.exports = { ScreenHeader };
module.exports = { ScreenHeader };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { ListView, StyleSheet, View, Text, Button, FlatList, TouchableOpacity, TextInput } = require('react-native');
const Setting = require('lib/models/Setting.js');
const { connect } = require('react-redux');
@@ -18,7 +19,6 @@ const ModalDialog = require('lib/components/ModalDialog');
const naturalCompare = require('string-natural-compare');
class NoteTagsDialogComponent extends React.Component {
constructor() {
super();
this.styles_ = {};
@@ -30,21 +30,21 @@ class NoteTagsDialogComponent extends React.Component {
savingTags: false,
};
const noteHasTag = (tagId) => {
const noteHasTag = tagId => {
for (let i = 0; i < this.state.tagListData.length; i++) {
if (this.state.tagListData[i].id === tagId) return this.state.tagListData[i].selected;
}
return false;
}
};
const newTagTitles = () => {
return this.state.newTags
.split(',')
.map(t => t.trim().toLowerCase())
.filter(t => !!t);
}
};
this.tag_press = (tagId) => {
this.tag_press = tagId => {
const newData = this.state.tagListData.slice();
for (let i = 0; i < newData.length; i++) {
const t = newData[i];
@@ -57,19 +57,20 @@ class NoteTagsDialogComponent extends React.Component {
}
this.setState({ tagListData: newData });
}
};
this.renderTag = (data) => {
this.renderTag = data => {
const tag = data.item;
const iconName = noteHasTag(tag.id) ? 'md-checkbox-outline' : 'md-square-outline';
return (
<TouchableOpacity key={tag.id} onPress={() => this.tag_press(tag.id)} style={this.styles().tag}>
<View style={this.styles().tagIconText}>
<Icon name={iconName} style={this.styles().tagCheckbox}/><Text style={this.styles().tagText}>{tag.title}</Text>
<Icon name={iconName} style={this.styles().tagCheckbox} />
<Text style={this.styles().tagText}>{tag.title}</Text>
</View>
</TouchableOpacity>
);
}
};
this.tagKeyExtractor = (tag, index) => tag.id;
@@ -89,11 +90,11 @@ class NoteTagsDialogComponent extends React.Component {
}
if (this.props.onCloseRequested) this.props.onCloseRequested();
}
};
this.cancelButton_press = () => {
if (this.props.onCloseRequested) this.props.onCloseRequested();
}
};
}
UNSAFE_componentWillMount() {
@@ -106,11 +107,13 @@ class NoteTagsDialogComponent extends React.Component {
const tags = await Tag.tagsByNoteId(noteId);
const tagIds = tags.map(t => t.id);
const tagListData = this.props.tags.map(tag => { return {
id: tag.id,
title: tag.title,
selected: tagIds.indexOf(tag.id) >= 0,
}});
const tagListData = this.props.tags.map(tag => {
return {
id: tag.id,
title: tag.title,
selected: tagIds.indexOf(tag.id) >= 0,
};
});
tagListData.sort((a, b) => {
return naturalCompare.caseInsensitive(a.title, b.title);
@@ -143,12 +146,12 @@ class NoteTagsDialogComponent extends React.Component {
color: theme.color,
},
newTagBox: {
flexDirection:'row',
flexDirection: 'row',
alignItems: 'center',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
borderBottomWidth: 1,
borderBottomColor: theme.dividerColor
borderBottomColor: theme.dividerColor,
},
newTagBoxLabel: Object.assign({}, theme.normalText, { marginRight: 8 }),
newTagBoxInput: Object.assign({}, theme.lineInput, { flex: 1 }),
@@ -157,43 +160,37 @@ class NoteTagsDialogComponent extends React.Component {
this.styles_[themeId] = StyleSheet.create(styles);
return this.styles_[themeId];
}
render() {
const theme = themeStyle(this.props.theme);
const dialogContent = (
<View style={{flex:1}}>
<View style={{ flex: 1 }}>
<View style={this.styles().newTagBox}>
<Text style={this.styles().newTagBoxLabel}>{_('New tags:')}</Text><TextInput selectionColor={theme.textSelectionColor} value={this.state.newTags} onChangeText={value => { this.setState({ newTags: value }) }} style={this.styles().newTagBoxInput}/>
<Text style={this.styles().newTagBoxLabel}>{_('New tags:')}</Text>
<TextInput
selectionColor={theme.textSelectionColor}
value={this.state.newTags}
onChangeText={value => {
this.setState({ newTags: value });
}}
style={this.styles().newTagBoxInput}
/>
</View>
<FlatList
data={this.state.tagListData}
renderItem={this.renderTag}
keyExtractor={this.tagKeyExtractor}
/>
<FlatList data={this.state.tagListData} renderItem={this.renderTag} keyExtractor={this.tagKeyExtractor} />
</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}
/>
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 NoteTagsDialog = connect(
(state) => {
return {
theme: state.settings.theme,
tags: state.tags,
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
};
}
)(NoteTagsDialogComponent)
const NoteTagsDialog = connect(state => {
return {
theme: state.settings.theme,
tags: state.tags,
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
};
})(NoteTagsDialogComponent);
module.exports = NoteTagsDialog;
module.exports = NoteTagsDialog;

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { View, Button, Text, TextInput, TouchableOpacity, StyleSheet, ScrollView } = require('react-native');
const { connect } = require('react-redux');
const { ScreenHeader } = require('lib/components/screen-header.js');
@@ -10,17 +11,12 @@ const Shared = require('lib/components/shared/dropbox-login-shared');
const { themeStyle } = require('lib/components/global-style.js');
class DropboxLoginScreenComponent extends BaseScreenComponent {
constructor() {
super();
this.styles_ = {};
this.shared_ = new Shared(
this,
(msg) => dialogs.info(this, msg),
(msg) => dialogs.error(this, msg)
);
this.shared_ = new Shared(this, msg => dialogs.info(this, msg), msg => dialogs.error(this, msg));
}
UNSAFE_componentWillMount() {
@@ -40,7 +36,7 @@ class DropboxLoginScreenComponent extends BaseScreenComponent {
},
stepText: Object.assign({}, theme.normalText, { marginBottom: theme.margin }),
urlText: Object.assign({}, theme.urlText, { marginBottom: theme.margin }),
}
};
this.styles_[themeId] = StyleSheet.create(styles);
return this.styles_[themeId];
@@ -51,8 +47,8 @@ class DropboxLoginScreenComponent extends BaseScreenComponent {
return (
<View style={this.styles().screen}>
<ScreenHeader title={_('Login with Dropbox')}/>
<ScreenHeader title={_('Login with Dropbox')} />
<ScrollView style={this.styles().container}>
<Text style={this.styles().stepText}>{_('To allow Joplin to synchronise with Dropbox, please follow the steps below:')}</Text>
<Text style={this.styles().stepText}>{_('Step 1: Open this URL in your browser to authorise the application:')}</Text>
@@ -62,25 +58,28 @@ class DropboxLoginScreenComponent extends BaseScreenComponent {
</TouchableOpacity>
</View>
<Text style={this.styles().stepText}>{_('Step 2: Enter the code provided by Dropbox:')}</Text>
<TextInput placeholder={_('Enter code here')} placeholderTextColor={theme.colorFaded} selectionColor={theme.textSelectionColor} value={this.state.authCode} onChangeText={this.shared_.authCodeInput_change} style={theme.lineInput}/>
<View style={{height:10}}></View>
<Button disabled={this.state.checkingAuthToken} title={_("Submit")} onPress={this.shared_.submit_click}></Button>
<TextInput placeholder={_('Enter code here')} placeholderTextColor={theme.colorFaded} selectionColor={theme.textSelectionColor} value={this.state.authCode} onChangeText={this.shared_.authCodeInput_change} style={theme.lineInput} />
<View style={{ height: 10 }}></View>
<Button disabled={this.state.checkingAuthToken} title={_('Submit')} onPress={this.shared_.submit_click}></Button>
{/* Add this extra padding to make sure the view is scrollable when the keyboard is visible on small screens (iPhone SE) */}
<View style={{ height: 200 }}></View>
</ScrollView>
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
<DialogBox
ref={dialogbox => {
this.dialogbox = dialogbox;
}}
/>
</View>
);
}
}
const DropboxLoginScreen = connect((state) => {
const DropboxLoginScreen = connect(state => {
return {
theme: state.settings.theme,
};
})(DropboxLoginScreenComponent)
})(DropboxLoginScreenComponent);
module.exports = { DropboxLoginScreen };
module.exports = { DropboxLoginScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { TextInput, TouchableOpacity, Linking, View, Switch, StyleSheet, Text, Button, ScrollView, Platform } = require('react-native');
const EncryptionService = require('lib/services/EncryptionService');
const { connect } = require('react-redux');
@@ -14,7 +15,6 @@ const { dialogs } = require('lib/dialogs.js');
const DialogBox = require('react-native-dialogbox').default;
class EncryptionConfigScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -88,7 +88,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
flex: 1,
padding: theme.margin,
},
}
};
this.styles_[themeId] = StyleSheet.create(styles);
return this.styles_[themeId];
@@ -99,28 +99,28 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
const onSaveClick = () => {
return shared.onSavePasswordClick(this, mk);
}
};
const onPasswordChange = (text) => {
const onPasswordChange = text => {
return shared.onPasswordChange(this, mk, text);
}
};
const password = this.state.passwords[mk.id] ? this.state.passwords[mk.id] : '';
const passwordOk = this.state.passwordChecks[mk.id] === true ? '✔' : '❌';
const active = this.props.activeMasterKeyId === mk.id ? '✔' : '';
const inputStyle = {flex:1, marginRight: 10, color: theme.color};
const inputStyle = { flex: 1, marginRight: 10, color: theme.color };
inputStyle.borderBottomWidth = 1;
inputStyle.borderBottomColor = theme.strongDividerColor;
return (
<View key={mk.id}>
<Text style={this.styles().titleText}>{_('Master Key %s', mk.id.substr(0,6))}</Text>
<Text style={this.styles().titleText}>{_('Master Key %s', mk.id.substr(0, 6))}</Text>
<Text style={this.styles().normalText}>{_('Created: %s', time.formatMsToLocal(mk.created_time))}</Text>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex:0, fontSize: theme.fontSize, marginRight: 10, color: theme.color}}>{_('Password:')}</Text>
<TextInput selectionColor={theme.textSelectionColor} secureTextEntry={true} value={password} onChangeText={(text) => onPasswordChange(text)} style={inputStyle}></TextInput>
<Text style={{fontSize: theme.fontSize, marginRight: 10, color: theme.color}}>{passwordOk}</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={{ flex: 0, fontSize: theme.fontSize, marginRight: 10, color: theme.color }}>{_('Password:')}</Text>
<TextInput selectionColor={theme.textSelectionColor} secureTextEntry={true} value={password} onChangeText={text => onPasswordChange(text)} style={inputStyle}></TextInput>
<Text style={{ fontSize: theme.fontSize, marginRight: 10, color: theme.color }}>{passwordOk}</Text>
<Button title={_('Save')} onPress={() => onSaveClick()}></Button>
</View>
</View>
@@ -139,18 +139,36 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
} catch (error) {
await dialogs.error(this, error.message);
}
}
};
return (
<View style={{flex:1, borderColor: theme.dividerColor, borderWidth: 1, padding: 10, marginTop: 10, marginBottom: 10}}>
<Text style={{fontSize: theme.fontSize, color: theme.color}}>{_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.')}</Text>
<TextInput selectionColor={theme.textSelectionColor} style={{margin: 10, color: theme.color, borderWidth: 1, borderColor: theme.dividerColor }} secureTextEntry={true} value={this.state.passwordPromptAnswer} onChangeText={(text) => { this.setState({ passwordPromptAnswer: text }) }}></TextInput>
<View style={{flexDirection: 'row'}}>
<View style={{flex:1 , marginRight:10}} >
<Button title={_('Enable')} onPress={() => { onEnableClick() }}></Button>
<View style={{ flex: 1, borderColor: theme.dividerColor, borderWidth: 1, padding: 10, marginTop: 10, marginBottom: 10 }}>
<Text style={{ fontSize: theme.fontSize, color: theme.color }}>{_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.')}</Text>
<TextInput
selectionColor={theme.textSelectionColor}
style={{ margin: 10, color: theme.color, borderWidth: 1, borderColor: theme.dividerColor }}
secureTextEntry={true}
value={this.state.passwordPromptAnswer}
onChangeText={text => {
this.setState({ passwordPromptAnswer: text });
}}
></TextInput>
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1, marginRight: 10 }}>
<Button
title={_('Enable')}
onPress={() => {
onEnableClick();
}}
></Button>
</View>
<View style={{flex:1}} >
<Button title={_('Cancel')} onPress={() => { this.setState({ passwordPromptShow: false}) }}></Button>
<View style={{ flex: 1 }}>
<Button
title={_('Cancel')}
onPress={() => {
this.setState({ passwordPromptShow: false });
}}
></Button>
</View>
</View>
</View>
@@ -168,7 +186,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
for (let i = 0; i < masterKeys.length; i++) {
const mk = masterKeys[i];
mkComps.push(this.renderMasterKey(i+1, mk));
mkComps.push(this.renderMasterKey(i + 1, mk));
const idx = nonExistingMasterKeyIds.indexOf(mk.id);
if (idx >= 0) nonExistingMasterKeyIds.splice(idx, 1);
@@ -199,30 +217,45 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
const rows = [];
for (let i = 0; i < nonExistingMasterKeyIds.length; i++) {
const id = nonExistingMasterKeyIds[i];
rows.push(<Text style={this.styles().normalText} key={id}>{id}</Text>);
rows.push(
<Text style={this.styles().normalText} key={id}>
{id}
</Text>
);
}
nonExistingMasterKeySection = (
<View>
<Text style={this.styles().titleText}>{_('Missing Master Keys')}</Text>
<Text style={this.styles().normalText}>{_('The master keys with these IDs are used to encrypt some of your items, however the application does not currently have access to them. It is likely they will eventually be downloaded via synchronisation.')}</Text>
<View style={{marginTop: 10}}>{rows}</View>
<View style={{ marginTop: 10 }}>{rows}</View>
</View>
);
}
const passwordPromptComp = this.state.passwordPromptShow ? this.passwordPromptComponent() : null;
const toggleButton = !this.state.passwordPromptShow ? <View style={{marginTop: 10}}><Button title={this.props.encryptionEnabled ? _('Disable encryption') : _('Enable encryption')} onPress={() => onToggleButtonClick()}></Button></View> : null;
const toggleButton = !this.state.passwordPromptShow ? (
<View style={{ marginTop: 10 }}>
<Button title={this.props.encryptionEnabled ? _('Disable encryption') : _('Enable encryption')} onPress={() => onToggleButtonClick()}></Button>
</View>
) : null;
return (
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader title={_('Encryption Config')}/>
<ScreenHeader title={_('Encryption Config')} />
<ScrollView style={this.styles().container}>
{<View style={{backgroundColor: theme.warningBackgroundColor, paddingTop: 5, paddingBottom: 5, paddingLeft: 10, paddingRight: 10 }}>
<Text>{_('For more information about End-To-End Encryption (E2EE) and advices on how to enable it please check the documentation:')}</Text>
<TouchableOpacity onPress={() => { Linking.openURL('https://joplinapp.org/e2ee/') }}><Text>https://joplinapp.org/e2ee/</Text></TouchableOpacity>
</View>}
{
<View style={{ backgroundColor: theme.warningBackgroundColor, paddingTop: 5, paddingBottom: 5, paddingLeft: 10, paddingRight: 10 }}>
<Text>{_('For more information about End-To-End Encryption (E2EE) and advices on how to enable it please check the documentation:')}</Text>
<TouchableOpacity
onPress={() => {
Linking.openURL('https://joplinapp.org/e2ee/');
}}
>
<Text>https://joplinapp.org/e2ee/</Text>
</TouchableOpacity>
</View>
}
<Text style={this.styles().titleText}>{_('Status')}</Text>
<Text style={this.styles().normalText}>{_('Encryption is: %s', this.props.encryptionEnabled ? _('Enabled') : _('Disabled'))}</Text>
@@ -231,26 +264,27 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
{passwordPromptComp}
{mkComps}
{nonExistingMasterKeySection}
<View style={{flex:1, height: 20}}></View>
<View style={{ flex: 1, height: 20 }}></View>
</ScrollView>
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
<DialogBox
ref={dialogbox => {
this.dialogbox = dialogbox;
}}
/>
</View>
);
}
}
const EncryptionConfigScreen = connect(
(state) => {
return {
theme: state.settings.theme,
masterKeys: state.masterKeys,
passwords: state.settings['encryption.passwordCache'],
encryptionEnabled: state.settings['encryption.enabled'],
activeMasterKeyId: state.settings['encryption.activeMasterKeyId'],
notLoadedMasterKeys: state.notLoadedMasterKeys,
};
}
)(EncryptionConfigScreenComponent)
const EncryptionConfigScreen = connect(state => {
return {
theme: state.settings.theme,
masterKeys: state.masterKeys,
passwords: state.settings['encryption.passwordCache'],
encryptionEnabled: state.settings['encryption.enabled'],
activeMasterKeyId: state.settings['encryption.activeMasterKeyId'],
notLoadedMasterKeys: state.notLoadedMasterKeys,
};
})(EncryptionConfigScreenComponent);
module.exports = { EncryptionConfigScreen };
module.exports = { EncryptionConfigScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { View, Button, TextInput, StyleSheet } = require('react-native');
const { connect } = require('react-redux');
const { ActionButton } = require('lib/components/action-button.js');
@@ -12,7 +13,6 @@ const { themeStyle } = require('lib/components/global-style.js');
const { _ } = require('lib/locale.js');
class FolderScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -52,7 +52,7 @@ class FolderScreenComponent extends BaseScreenComponent {
lastSavedFolder: Object.assign({}, folder),
});
} else {
Folder.load(this.props.folderId).then((folder) => {
Folder.load(this.props.folderId).then(folder => {
this.setState({
folder: folder,
lastSavedFolder: Object.assign({}, folder),
@@ -72,7 +72,7 @@ class FolderScreenComponent extends BaseScreenComponent {
this.setState((prevState, props) => {
let folder = Object.assign({}, prevState.folder);
folder[propName] = propValue;
return { folder: folder }
return { folder: folder };
});
}
@@ -108,29 +108,23 @@ class FolderScreenComponent extends BaseScreenComponent {
return (
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader
title={_('Edit notebook')}
showSaveButton={true}
saveButtonDisabled={saveButtonDisabled}
onSaveButtonPress={() => this.saveFolderButton_press()}
showSideMenuButton={false}
showSearchButton={false}
<ScreenHeader title={_('Edit notebook')} showSaveButton={true} saveButtonDisabled={saveButtonDisabled} onSaveButtonPress={() => this.saveFolderButton_press()} showSideMenuButton={false} showSearchButton={false} />
<TextInput placeholder={_('Enter notebook title')} underlineColorAndroid={theme.strongDividerColor} selectionColor={theme.textSelectionColor} style={this.styles().textInput} autoFocus={true} value={this.state.folder.title} onChangeText={text => this.title_changeText(text)} />
<dialogs.DialogBox
ref={dialogbox => {
this.dialogbox = dialogbox;
}}
/>
<TextInput placeholder={_('Enter notebook title')} underlineColorAndroid={theme.strongDividerColor} selectionColor={theme.textSelectionColor} style={this.styles().textInput} autoFocus={true} value={this.state.folder.title} onChangeText={(text) => this.title_changeText(text)} />
<dialogs.DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
</View>
);
}
}
const FolderScreen = connect(
(state) => {
return {
folderId: state.selectedFolderId,
theme: state.settings.theme,
};
}
)(FolderScreenComponent)
const FolderScreen = connect(state => {
return {
folderId: state.selectedFolderId,
theme: state.settings.theme,
};
})(FolderScreenComponent);
module.exports = { FolderScreen };
module.exports = { FolderScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { ListView, View, Text, Button, StyleSheet, Platform } = require('react-native');
const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
@@ -10,7 +11,6 @@ const { BaseScreenComponent } = require('lib/components/base-screen.js');
const { _ } = require('lib/locale.js');
class LogScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -18,7 +18,9 @@ class LogScreenComponent extends BaseScreenComponent {
constructor() {
super();
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => { return r1 !== r2; }
rowHasChanged: (r1, r2) => {
return r1 !== r2;
},
});
this.state = {
dataSource: ds,
@@ -38,16 +40,17 @@ class LogScreenComponent extends BaseScreenComponent {
flexDirection: 'row',
paddingLeft: 1,
paddingRight: 1,
paddingTop:0,
paddingBottom:0,
paddingTop: 0,
paddingBottom: 0,
},
rowText: {
fontSize: 10,
color: theme.color,
color: theme.color,
},
};
if (Platform.OS !== 'ios') { // Crashes on iOS with error "Unrecognized font family 'monospace'"
if (Platform.OS !== 'ios') {
// Crashes on iOS with error "Unrecognized font family 'monospace'"
styles.rowText.fontFamily = 'monospace';
}
@@ -69,12 +72,15 @@ class LogScreenComponent extends BaseScreenComponent {
if (showErrorsOnly === null) showErrorsOnly = this.state.showErrorsOnly;
let levels = [Logger.LEVEL_DEBUG, Logger.LEVEL_INFO, Logger.LEVEL_WARN, Logger.LEVEL_ERROR];
if (showErrorsOnly) levels = [Logger.LEVEL_WARN, Logger.LEVEL_ERROR]
if (showErrorsOnly) levels = [Logger.LEVEL_WARN, Logger.LEVEL_ERROR];
reg.logger().lastEntries(1000, { levels: levels }).then((entries) => {
const newDataSource = this.state.dataSource.cloneWithRows(entries);
this.setState({ dataSource: newDataSource });
});
reg
.logger()
.lastEntries(1000, { levels: levels })
.then(entries => {
const newDataSource = this.state.dataSource.cloneWithRows(entries);
this.setState({ dataSource: newDataSource });
});
}
toggleErrorsOnly() {
@@ -84,47 +90,50 @@ class LogScreenComponent extends BaseScreenComponent {
}
render() {
let renderRow = (item) => {
let renderRow = item => {
let textStyle = this.styles().rowText;
if (item.level == Logger.LEVEL_WARN) textStyle = this.styles().rowTextWarn;
if (item.level == Logger.LEVEL_ERROR) textStyle = this.styles().rowTextError;
return (
<View style={this.styles().row}>
<Text style={textStyle}>{time.formatMsToLocal(item.timestamp, 'MM-DDTHH:mm:ss') + ': ' + item.message}</Text>
</View>
);
}
};
// `enableEmptySections` is to fix this warning: https://github.com/FaridSafi/react-native-gifted-listview/issues/39
return (
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader title={_('Log')}/>
<ListView
dataSource={this.state.dataSource}
renderRow={renderRow}
enableEmptySections={true}
/>
<View style={{flexDirection: 'row'}}>
<View style={{flex:1, marginRight: 5 }}>
<Button title={_("Refresh")} onPress={() => { this.resfreshLogEntries(); }}/>
<ScreenHeader title={_('Log')} />
<ListView dataSource={this.state.dataSource} renderRow={renderRow} enableEmptySections={true} />
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1, marginRight: 5 }}>
<Button
title={_('Refresh')}
onPress={() => {
this.resfreshLogEntries();
}}
/>
</View>
<View style={{flex:1}}>
<Button title={this.state.showErrorsOnly ? _("Show all") : _("Errors only")} onPress={() => { this.toggleErrorsOnly(); }}/>
<View style={{ flex: 1 }}>
<Button
title={this.state.showErrorsOnly ? _('Show all') : _('Errors only')}
onPress={() => {
this.toggleErrorsOnly();
}}
/>
</View>
</View>
</View>
);
}
}
const LogScreen = connect(
(state) => {
return {
theme: state.settings.theme,
};
}
)(LogScreenComponent)
const LogScreen = connect(state => {
return {
theme: state.settings.theme,
};
})(LogScreenComponent);
module.exports = { LogScreen };
module.exports = { LogScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { AppState, View, Button, Text, StyleSheet } = require('react-native');
const { stateUtils } = require('lib/reducer.js');
const { connect } = require('react-redux');
@@ -18,7 +19,6 @@ const DialogBox = require('react-native-dialogbox').default;
const { BaseScreenComponent } = require('lib/components/base-screen.js');
class NotesScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -31,16 +31,16 @@ class NotesScreenComponent extends BaseScreenComponent {
let newProps = Object.assign({}, this.props);
newProps.notesSource = '';
await this.refreshNotes(newProps);
}
};
this.sortButton_press = async () => {
const buttons = [];
const sortNoteOptions = Setting.enumOptions('notes.sortOrder.field');
const makeCheckboxText = function(selected, sign, label) {
const s = sign === 'tick' ? '✓' : '⬤'
return (selected ? (s + ' ') : '') + label;
}
const s = sign === 'tick' ? '✓' : '⬤';
return (selected ? s + ' ' : '') + label;
};
for (let field in sortNoteOptions) {
if (!sortNoteOptions.hasOwnProperty(field)) continue;
@@ -69,7 +69,7 @@ class NotesScreenComponent extends BaseScreenComponent {
if (!r) return;
Setting.setValue(r.name, r.value);
}
};
}
styles() {
@@ -100,15 +100,11 @@ class NotesScreenComponent extends BaseScreenComponent {
AppState.removeEventListener('change', this.onAppStateChange_);
}
async componentDidUpdate(prevProps) {
if (prevProps.notesOrder !== this.props.notesOrder ||
prevProps.selectedFolderId != this.props.selectedFolderId ||
prevProps.selectedTagId != this.props.selectedTagId ||
prevProps.selectedSmartFilterId != this.props.selectedSmartFilterId ||
prevProps.notesParentType != this.props.notesParentType) {
await this.refreshNotes(this.props);
}
async componentDidUpdate(prevProps) {
if (prevProps.notesOrder !== this.props.notesOrder || prevProps.selectedFolderId != this.props.selectedFolderId || prevProps.selectedTagId != this.props.selectedTagId || prevProps.selectedSmartFilterId != this.props.selectedSmartFilterId || prevProps.notesParentType != this.props.notesParentType) {
await this.refreshNotes(this.props);
}
}
async refreshNotes(props = null) {
if (props === null) props = this.props;
@@ -147,18 +143,20 @@ class NotesScreenComponent extends BaseScreenComponent {
}
deleteFolder_onPress(folderId) {
dialogs.confirm(this, _('Delete notebook? All notes and sub-notebooks within this notebook will also be deleted.')).then((ok) => {
dialogs.confirm(this, _('Delete notebook? All notes and sub-notebooks within this notebook will also be deleted.')).then(ok => {
if (!ok) return;
Folder.delete(folderId).then(() => {
this.props.dispatch({
type: 'NAV_GO',
routeName: 'Notes',
smartFilterId: 'c3176726992c11e9ac940492261af972',
Folder.delete(folderId)
.then(() => {
this.props.dispatch({
type: 'NAV_GO',
routeName: 'Notes',
smartFilterId: 'c3176726992c11e9ac940492261af972',
});
})
.catch(error => {
alert(error.message);
});
}).catch((error) => {
alert(error.message);
});
});
}
@@ -206,7 +204,7 @@ class NotesScreenComponent extends BaseScreenComponent {
let rootStyle = {
flex: 1,
backgroundColor: theme.backgroundColor,
}
};
if (!this.props.visible) {
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
@@ -217,52 +215,46 @@ class NotesScreenComponent extends BaseScreenComponent {
<View style={rootStyle}>
<ScreenHeader title={title} showSideMenuButton={true} showBackButton={false} />
</View>
)
);
}
let title = parent ? parent.title : null;
const addFolderNoteButtons = this.props.selectedFolderId && this.props.selectedFolderId != Folder.conflictFolderId();
const thisComp = this;
const actionButtonComp = this.props.noteSelectionEnabled || !this.props.visible ? null : <ActionButton addFolderNoteButtons={addFolderNoteButtons} parentFolderId={this.props.selectedFolderId}></ActionButton>
const actionButtonComp = this.props.noteSelectionEnabled || !this.props.visible ? null : <ActionButton addFolderNoteButtons={addFolderNoteButtons} parentFolderId={this.props.selectedFolderId}></ActionButton>;
return (
<View style={rootStyle}>
<ScreenHeader
title={title}
showBackButton={false}
parentComponent={thisComp}
sortButton_press={this.sortButton_press}
folderPickerOptions={this.folderPickerOptions()}
showSearchButton={true}
showSideMenuButton={true}
<ScreenHeader title={title} showBackButton={false} parentComponent={thisComp} sortButton_press={this.sortButton_press} folderPickerOptions={this.folderPickerOptions()} showSearchButton={true} showSideMenuButton={true} />
<NoteList style={this.styles().noteList} />
{actionButtonComp}
<DialogBox
ref={dialogbox => {
this.dialogbox = dialogbox;
}}
/>
<NoteList style={this.styles().noteList}/>
{ actionButtonComp }
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
</View>
);
}
}
const NotesScreen = connect(
(state) => {
return {
folders: state.folders,
tags: state.tags,
selectedFolderId: state.selectedFolderId,
selectedNoteIds: state.selectedNoteIds,
selectedTagId: state.selectedTagId,
selectedSmartFilterId: state.selectedSmartFilterId,
notesParentType: state.notesParentType,
notes: state.notes,
notesSource: state.notesSource,
uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
showCompletedTodos: state.settings.showCompletedTodos,
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
notesOrder: stateUtils.notesOrder(state.settings),
};
}
)(NotesScreenComponent)
const NotesScreen = connect(state => {
return {
folders: state.folders,
tags: state.tags,
selectedFolderId: state.selectedFolderId,
selectedNoteIds: state.selectedNoteIds,
selectedTagId: state.selectedTagId,
selectedSmartFilterId: state.selectedSmartFilterId,
notesParentType: state.notesParentType,
notes: state.notes,
notesSource: state.notesSource,
uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
showCompletedTodos: state.settings.showCompletedTodos,
theme: state.settings.theme,
noteSelectionEnabled: state.noteSelectionEnabled,
notesOrder: stateUtils.notesOrder(state.settings),
};
})(NotesScreenComponent);
module.exports = { NotesScreen };

View File

@@ -1,7 +1,8 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { View } = require('react-native');
const { Button, Text } = require('react-native');
const { WebView } = require('react-native-webview');
const { WebView } = require('react-native-webview');
const { connect } = require('react-redux');
const Setting = require('lib/models/Setting.js');
const { ScreenHeader } = require('lib/components/screen-header.js');
@@ -11,7 +12,6 @@ const { BaseScreenComponent } = require('lib/components/base-screen.js');
const parseUri = require('lib/parseUri');
class OneDriveLoginScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -29,11 +29,17 @@ class OneDriveLoginScreenComponent extends BaseScreenComponent {
}
startUrl() {
return reg.syncTarget().api().authCodeUrl(this.redirectUrl());
return reg
.syncTarget()
.api()
.authCodeUrl(this.redirectUrl());
}
redirectUrl() {
return reg.syncTarget().api().nativeClientRedirectUrl();
return reg
.syncTarget()
.api()
.nativeClientRedirectUrl();
}
async webview_load(noIdeaWhatThisIs) {
@@ -44,10 +50,13 @@ class OneDriveLoginScreenComponent extends BaseScreenComponent {
const parsedUrl = parseUri(url);
if (!this.authCode_ && parsedUrl && parsedUrl.queryKey && parsedUrl.queryKey.code) {
this.authCode_ = parsedUrl.queryKey.code
this.authCode_ = parsedUrl.queryKey.code;
try {
await reg.syncTarget().api().execTokenRequest(this.authCode_, this.redirectUrl(), true);
await reg
.syncTarget()
.api()
.execTokenRequest(this.authCode_, this.redirectUrl(), true);
this.props.dispatch({ type: 'NAV_BACK' });
reg.scheduleSync(0);
} catch (error) {
@@ -83,27 +92,33 @@ class OneDriveLoginScreenComponent extends BaseScreenComponent {
render() {
const source = {
uri: this.state.webviewUrl,
}
};
return (
<View style={this.styles().screen}>
<ScreenHeader title={_('Login with OneDrive')}/>
<ScreenHeader title={_('Login with OneDrive')} />
<WebView
source={source}
onNavigationStateChange={(o) => { this.webview_load(o); }}
onError={() => { this.webview_error(); }}
onNavigationStateChange={o => {
this.webview_load(o);
}}
onError={() => {
this.webview_error();
}}
/>
<Button title={_("Refresh")} onPress={() => { this.retryButton_click(); }}></Button>
<Button
title={_('Refresh')}
onPress={() => {
this.retryButton_click();
}}
></Button>
</View>
);
}
}
const OneDriveLoginScreen = connect(
(state) => {
return {};
}
)(OneDriveLoginScreenComponent)
const OneDriveLoginScreen = connect(state => {
return {};
})(OneDriveLoginScreenComponent);
module.exports = { OneDriveLoginScreen };
module.exports = { OneDriveLoginScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { ListView, StyleSheet, View, TextInput, FlatList, TouchableHighlight } = require('react-native');
const { connect } = require('react-redux');
const { ScreenHeader } = require('lib/components/screen-header.js');
@@ -13,7 +14,6 @@ const SearchEngineUtils = require('lib/services/SearchEngineUtils');
const DialogBox = require('react-native-dialogbox').default;
class SearchScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -43,8 +43,8 @@ class SearchScreenComponent extends BaseScreenComponent {
alignItems: 'center',
borderWidth: 1,
borderColor: theme.dividerColor,
}
}
},
};
styles.searchTextInput = Object.assign({}, theme.lineInput);
styles.searchTextInput.paddingLeft = theme.marginLeft;
@@ -111,13 +111,12 @@ class SearchScreenComponent extends BaseScreenComponent {
query = query === null ? this.state.query.trim : query.trim();
let notes = []
let notes = [];
if (query) {
if (!!this.props.settings['db.ftsEnabled']) {
if (this.props.settings['db.ftsEnabled']) {
notes = await SearchEngineUtils.notesForQuery(query);
} else {
} else {
let p = query.split(' ');
let temp = [];
for (let i = 0; i < p.length; i++) {
@@ -149,7 +148,7 @@ class SearchScreenComponent extends BaseScreenComponent {
let rootStyle = {
flex: 1,
backgroundColor: theme.backgroundColor,
}
};
if (!this.props.visible) {
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
@@ -174,39 +173,38 @@ class SearchScreenComponent extends BaseScreenComponent {
<TextInput
style={this.styles().searchTextInput}
autoFocus={this.props.visible}
underlineColorAndroid="#ffffff00"
onSubmitEditing={() => { this.searchTextInput_submit() }}
onChangeText={(text) => this.searchTextInput_changeText(text) }
underlineColorAndroid="#ffffff00"
onSubmitEditing={() => {
this.searchTextInput_submit();
}}
onChangeText={text => this.searchTextInput_changeText(text)}
value={this.state.query}
selectionColor={theme.textSelectionColor}
/>
<TouchableHighlight onPress={() => this.clearButton_press() }>
<Icon name='md-close-circle' style={this.styles().clearIcon} />
<TouchableHighlight onPress={() => this.clearButton_press()}>
<Icon name="md-close-circle" style={this.styles().clearIcon} />
</TouchableHighlight>
</View>
<FlatList
data={this.state.notes}
keyExtractor={(item, index) => item.id}
renderItem={(event) => <NoteItem note={event.item}/>}
/>
<FlatList data={this.state.notes} keyExtractor={(item, index) => item.id} renderItem={event => <NoteItem note={event.item} />} />
</View>
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
<DialogBox
ref={dialogbox => {
this.dialogbox = dialogbox;
}}
/>
</View>
);
}
}
const SearchScreen = connect(
(state) => {
return {
query: state.searchQuery,
theme: state.settings.theme,
settings: state.settings,
noteSelectionEnabled: state.noteSelectionEnabled,
};
}
)(SearchScreenComponent)
const SearchScreen = connect(state => {
return {
query: state.searchQuery,
theme: state.settings.theme,
settings: state.settings,
noteSelectionEnabled: state.noteSelectionEnabled,
};
})(SearchScreenComponent);
module.exports = { SearchScreen };
module.exports = { SearchScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { ListView, StyleSheet, View, Text, Button, FlatList } = require('react-native');
const Setting = require('lib/models/Setting.js');
const { connect } = require('react-redux');
@@ -22,7 +23,6 @@ const styles = StyleSheet.create({
});
class StatusScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -82,7 +82,7 @@ class StatusScreenComponent extends BaseScreenComponent {
retryHandler = async () => {
await item.retryHandler();
this.resfreshScreen();
}
};
}
text = item.text;
} else {
@@ -95,55 +95,56 @@ class StatusScreenComponent extends BaseScreenComponent {
lines.push({ key: 'divider2_' + i, isDivider: true });
}
return (<FlatList
data={lines}
renderItem={({item}) => {
let style = Object.assign({}, baseStyle);
return (
<FlatList
data={lines}
renderItem={({ item }) => {
let style = Object.assign({}, baseStyle);
if (item.isSection === true) {
style.fontWeight = 'bold';
style.marginBottom = 5;
}
if (item.isSection === true) {
style.fontWeight = 'bold';
style.marginBottom = 5;
}
style.flex = 1;
style.flex = 1;
const retryButton = item.retryHandler ? <View style={{flex:0}}><Button title={_('Retry')} onPress={item.retryHandler}/></View> : null;
if (item.isDivider) {
return (<View style={{borderBottomWidth: 1, borderBottomColor: theme.dividerColor, marginTop: 20, marginBottom: 20}}/>);
} else {
return (
<View style={{flex:1, flexDirection:'row'}}>
<Text style={style}>{item.text}</Text>
{retryButton}
const retryButton = item.retryHandler ? (
<View style={{ flex: 0 }}>
<Button title={_('Retry')} onPress={item.retryHandler} />
</View>
);
}
}}
/>);
}
) : null;
if (item.isDivider) {
return <View style={{ borderBottomWidth: 1, borderBottomColor: theme.dividerColor, marginTop: 20, marginBottom: 20 }} />;
} else {
return (
<View style={{ flex: 1, flexDirection: 'row' }}>
<Text style={style}>{item.text}</Text>
{retryButton}
</View>
);
}
}}
/>
);
};
let body = renderBody(this.state.report);
return (
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader title={_('Status')}/>
<View style={styles.body}>
{ body }
</View>
<Button title={_("Refresh")} onPress={() => this.resfreshScreen()}/>
<ScreenHeader title={_('Status')} />
<View style={styles.body}>{body}</View>
<Button title={_('Refresh')} onPress={() => this.resfreshScreen()} />
</View>
);
}
}
const StatusScreen = connect(
(state) => {
return {
theme: state.settings.theme,
};
}
)(StatusScreenComponent)
const StatusScreen = connect(state => {
return {
theme: state.settings.theme,
};
})(StatusScreenComponent);
module.exports = { StatusScreen };
module.exports = { StatusScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { ListView, StyleSheet, View, TextInput, FlatList, TouchableHighlight } = require('react-native');
const { connect } = require('react-redux');
const { ScreenHeader } = require('lib/components/screen-header.js');
@@ -13,10 +14,9 @@ let styles = {
body: {
flex: 1,
},
}
};
class TagScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -53,22 +53,23 @@ class TagScreenComponent extends BaseScreenComponent {
return (
<View style={this.styles().screen}>
<ScreenHeader title={title} menuOptions={this.menuOptions()} />
<NoteList style={{flex: 1}}/>
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
<NoteList style={{ flex: 1 }} />
<DialogBox
ref={dialogbox => {
this.dialogbox = dialogbox;
}}
/>
</View>
);
}
}
const TagScreen = connect(
(state) => {
return {
tag: tag,
notes: state.notes,
notesSource: state.notesSource,
};
}
)(TagScreenComponent)
const TagScreen = connect(state => {
return {
tag: tag,
notes: state.notes,
notesSource: state.notesSource,
};
})(TagScreenComponent);
module.exports = { TagScreen };
module.exports = { TagScreen };

View File

@@ -1,4 +1,5 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { AppState, View, Button, Text, FlatList, StyleSheet, TouchableOpacity } = require('react-native');
const { stateUtils } = require('lib/reducer.js');
const { connect } = require('react-redux');
@@ -18,7 +19,6 @@ const DialogBox = require('react-native-dialogbox').default;
const { BaseScreenComponent } = require('lib/components/base-screen.js');
class TagsScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -74,8 +74,12 @@ class TagsScreenComponent extends BaseScreenComponent {
tagList_renderItem(event) {
const tag = event.item;
return (
<TouchableOpacity onPress={() => { this.tagItem_press({ id: tag.id }) }}>
<View style={ this.styles().listItem }>
<TouchableOpacity
onPress={() => {
this.tagItem_press({ id: tag.id });
}}
>
<View style={this.styles().listItem}>
<Text style={this.styles().listItemText}>{tag.title}</Text>
</View>
</TouchableOpacity>
@@ -100,31 +104,21 @@ class TagsScreenComponent extends BaseScreenComponent {
let rootStyle = {
flex: 1,
backgroundColor: theme.backgroundColor,
}
};
return (
<View style={rootStyle}>
<ScreenHeader
title={_('Tags')}
parentComponent={this}
showSearchButton={false}
/>
<FlatList style={{flex:1}}
data={this.state.tags}
renderItem={this.tagList_renderItem}
keyExtractor={this.tagList_keyExtractor}
/>
<ScreenHeader title={_('Tags')} parentComponent={this} showSearchButton={false} />
<FlatList style={{ flex: 1 }} data={this.state.tags} renderItem={this.tagList_renderItem} keyExtractor={this.tagList_keyExtractor} />
</View>
);
}
}
const TagsScreen = connect(
(state) => {
return {
theme: state.settings.theme,
};
}
)(TagsScreenComponent)
const TagsScreen = connect(state => {
return {
theme: state.settings.theme,
};
})(TagsScreenComponent);
module.exports = { TagsScreen };

View File

@@ -3,14 +3,14 @@ const SyncTargetRegistry = require('lib/SyncTargetRegistry');
const ObjectUtils = require('lib/ObjectUtils');
const { _ } = require('lib/locale.js');
const shared = {}
const shared = {};
shared.init = function(comp) {
if (!comp.state) comp.state = {};
comp.state.checkSyncConfigResult = null;
comp.state.settings = {};
comp.state.changedSettingKeys = [];
}
};
shared.checkSyncConfig = async function(comp, settings) {
const syncTargetId = settings['sync.target'];
@@ -19,7 +19,7 @@ shared.checkSyncConfig = async function(comp, settings) {
comp.setState({ checkSyncConfigResult: 'checking' });
const result = await SyncTargetClass.checkConfig(ObjectUtils.convertValuesToFunctions(options));
comp.setState({ checkSyncConfigResult: result });
}
};
shared.checkSyncConfigMessages = function(comp) {
const result = comp.state.checkSyncConfigResult;
@@ -35,7 +35,7 @@ shared.checkSyncConfigMessages = function(comp) {
}
return output;
}
};
shared.updateSettingValue = function(comp, key, value) {
const settings = Object.assign({}, comp.state.settings);
@@ -47,18 +47,18 @@ shared.updateSettingValue = function(comp, key, value) {
settings: settings,
changedSettingKeys: changedSettingKeys,
});
}
};
shared.saveSettings = function(comp) {
for (let key in comp.state.settings) {
if (!comp.state.settings.hasOwnProperty(key)) continue;
if (comp.state.changedSettingKeys.indexOf(key) < 0) continue;
console.info("Saving", key, comp.state.settings[key]);
console.info('Saving', key, comp.state.settings[key]);
Setting.setValue(key, comp.state.settings[key]);
}
comp.setState({ changedSettingKeys: [] });
}
};
shared.settingsToComponents = function(comp, device, settings) {
const keys = Setting.keys(true, device);
@@ -76,8 +76,8 @@ shared.settingsToComponents = function(comp, device, settings) {
settingComps.push(settingComp);
}
return settingComps
}
return settingComps;
};
shared.settingsToComponents2 = function(comp, device, settings) {
const keys = Setting.keys(true, device);
@@ -103,7 +103,7 @@ shared.settingsToComponents2 = function(comp, device, settings) {
sectionComps.push(sectionComp);
}
return sectionComps
}
return sectionComps;
};
module.exports = shared;
module.exports = shared;

View File

@@ -5,7 +5,6 @@ const { _ } = require('lib/locale.js');
const Setting = require('lib/models/Setting');
class Shared {
constructor(comp, showInfoMessageBox, showErrorMessageBox) {
this.comp_ = comp;
@@ -20,13 +19,13 @@ class Shared {
this.loginUrl_click = () => {
if (!this.comp_.state.loginUrl) return;
shim.openUrl(this.comp_.state.loginUrl);
}
};
this.authCodeInput_change = (event) => {
this.authCodeInput_change = event => {
this.comp_.setState({
authCode: typeof event === 'object' ? event.target.value : event
authCode: typeof event === 'object' ? event.target.value : event,
});
}
};
this.submit_click = async () => {
this.comp_.setState({ checkingAuthToken: true });
@@ -45,7 +44,7 @@ class Shared {
} finally {
this.comp_.setState({ checkingAuthToken: false });
}
}
};
}
syncTargetId() {
@@ -67,7 +66,6 @@ class Shared {
loginUrl: api.loginUrl(),
});
}
}
module.exports = Shared;
module.exports = Shared;

View File

@@ -18,15 +18,18 @@ shared.constructor = function(comp) {
comp.isMounted_ = false;
comp.refreshStatsIID_ = null;
}
};
shared.initState = function(comp, props) {
comp.setState({
masterKeys: props.masterKeys,
passwords: props.passwords ? props.passwords : {},
}, () => {
comp.checkPasswords();
});
comp.setState(
{
masterKeys: props.masterKeys,
passwords: props.passwords ? props.passwords : {},
},
() => {
comp.checkPasswords();
}
);
comp.refreshStats();
@@ -43,12 +46,12 @@ shared.initState = function(comp, props) {
}
comp.refreshStats();
}, 3000);
}
};
shared.refreshStats = async function(comp) {
const stats = await BaseItem.encryptedItemsStats();
comp.setState({ stats: stats });
}
};
shared.checkPasswords = async function(comp) {
const passwordChecks = Object.assign({}, comp.state.passwordChecks);
@@ -59,14 +62,14 @@ shared.checkPasswords = async function(comp) {
passwordChecks[mk.id] = ok;
}
comp.setState({ passwordChecks: passwordChecks });
}
};
shared.decryptedStatText = function(comp) {
const stats = comp.state.stats;
const doneCount = stats.encrypted !== null ? (stats.total - stats.encrypted) : '-';
const doneCount = stats.encrypted !== null ? stats.total - stats.encrypted : '-';
const totalCount = stats.total !== null ? stats.total : '-';
return _('Decrypted items: %s / %s', doneCount, totalCount);
}
};
shared.onSavePasswordClick = function(comp, mk) {
const password = comp.state.passwords[mk.id];
@@ -77,12 +80,12 @@ shared.onSavePasswordClick = function(comp, mk) {
}
comp.checkPasswords();
}
};
shared.onPasswordChange = function(comp, mk, password) {
const passwords = comp.state.passwords;
passwords[mk.id] = password;
comp.setState({ passwords: passwords });
}
};
module.exports = shared;
module.exports = shared;

View File

@@ -17,12 +17,16 @@ const saveNoteMutex_ = new Mutex();
shared.noteExists = async function(noteId) {
const existingNote = await Note.load(noteId);
return !!existingNote;
}
};
shared.saveNoteButton_press = async function(comp, folderId = null, options = null) {
options = Object.assign({}, {
autoTitle: true,
}, options);
options = Object.assign(
{},
{
autoTitle: true,
},
options
);
const releaseMutex = await saveNoteMutex_.acquire();
@@ -55,7 +59,7 @@ shared.saveNoteButton_press = async function(comp, folderId = null, options = nu
if (saveOptions.fields && saveOptions.fields.indexOf('title') < 0) saveOptions.fields.push('title');
}
const savedNote = ('fields' in saveOptions) && !saveOptions.fields.length ? Object.assign({}, note) : await Note.save(note, saveOptions);
const savedNote = 'fields' in saveOptions && !saveOptions.fields.length ? Object.assign({}, note) : await Note.save(note, saveOptions);
const stateNote = comp.state.note;
@@ -91,7 +95,7 @@ shared.saveNoteButton_press = async function(comp, folderId = null, options = nu
// await shared.refreshAttachedResources(comp, newState.note.body);
if (isNew) {
Note.updateGeolocation(note.id).then((geoNote) => {
Note.updateGeolocation(note.id).then(geoNote => {
const stateNote = comp.state.note;
if (!stateNote || !geoNote) return;
if (stateNote.id !== geoNote.id) return; // Another note has been loaded while geoloc was being retrieved
@@ -103,7 +107,7 @@ shared.saveNoteButton_press = async function(comp, folderId = null, options = nu
longitude: geoNote.longitude,
latitude: geoNote.latitude,
altitude: geoNote.altitude,
}
};
const modNote = Object.assign({}, stateNote, geoInfo);
const modLastSavedNote = Object.assign({}, comp.state.lastSavedNote, geoInfo);
@@ -122,7 +126,7 @@ shared.saveNoteButton_press = async function(comp, folderId = null, options = nu
}
releaseMutex();
}
};
shared.saveOneProperty = async function(comp, name, value) {
let note = Object.assign({}, comp.state.note);
@@ -145,25 +149,25 @@ shared.saveOneProperty = async function(comp, name, value) {
});
} else {
note[name] = value;
comp.setState({ note: note });
comp.setState({ note: note });
}
}
};
shared.noteComponent_change = function(comp, propName, propValue) {
let newState = {}
let newState = {};
let note = Object.assign({}, comp.state.note);
note[propName] = propValue;
newState.note = note;
comp.setState(newState);
}
};
let resourceCache_ = {};
shared.clearResourceCache = function() {
resourceCache_ = {};
}
};
shared.attachedResources = async function(noteBody) {
if (!noteBody) return {};
@@ -172,7 +176,7 @@ shared.attachedResources = async function(noteBody) {
const output = {};
for (let i = 0; i < resourceIds.length; i++) {
const id = resourceIds[i];
if (resourceCache_[id]) {
output[id] = resourceCache_[id];
} else {
@@ -190,14 +194,14 @@ shared.attachedResources = async function(noteBody) {
}
return output;
}
};
shared.isModified = function(comp) {
if (!comp.state.note || !comp.state.lastSavedNote) return false;
let diff = BaseModel.diffObjects(comp.state.lastSavedNote, comp.state.note);
delete diff.type_;
return !!Object.getOwnPropertyNames(diff).length;
}
};
shared.initState = async function(comp) {
let note = null;
@@ -226,13 +230,13 @@ shared.initState = async function(comp) {
}
comp.lastLoadedNoteId_ = note ? note.id : null;
}
};
shared.toggleIsTodo_onPress = function(comp) {
let newNote = Note.toggleIsTodo(comp.state.note);
let newState = { note: newNote };
comp.setState(newState);
}
};
shared.toggleCheckbox = function(ipcMessage, noteBody) {
let newBody = noteBody.split('\n');
@@ -264,24 +268,24 @@ shared.toggleCheckbox = function(ipcMessage, noteBody) {
if (!isCrossLine) {
line = line.replace(/- \[ \] /, '- [x] ');
} else {
} else {
line = line.replace(/- \[x\] /i, '- [ ] ');
}
newBody[lineIndex] = line;
return newBody.join('\n')
}
return newBody.join('\n');
};
shared.installResourceHandling = function(refreshResourceHandler) {
ResourceFetcher.instance().on('downloadComplete', refreshResourceHandler);
ResourceFetcher.instance().on('downloadStarted', refreshResourceHandler);
DecryptionWorker.instance().on('resourceDecrypted', refreshResourceHandler);
}
};
shared.uninstallResourceHandling = function(refreshResourceHandler) {
ResourceFetcher.instance().off('downloadComplete', refreshResourceHandler);
ResourceFetcher.instance().off('downloadStarted', refreshResourceHandler);
DecryptionWorker.instance().off('resourceDecrypted', refreshResourceHandler);
}
};
module.exports = shared;

View File

@@ -30,6 +30,6 @@ const reduxSharedMiddleware = async function(store, next, action) {
items: await Tag.allWithNotes(),
});
}
}
};
module.exports = reduxSharedMiddleware;
module.exports = reduxSharedMiddleware;

View File

@@ -49,11 +49,13 @@ function renderFoldersRecursive_(props, renderItem, items, parentId, depth, orde
shared.renderFolders = function(props, renderItem) {
return renderFoldersRecursive_(props, renderItem, [], '', 0, []);
}
};
shared.renderTags = function(props, renderItem) {
let tags = props.tags.slice();
tags.sort((a, b) => { return a.title < b.title ? -1 : +1; });
tags.sort((a, b) => {
return a.title < b.title ? -1 : +1;
});
let tagItems = [];
const order = [];
for (let i = 0; i < tags.length; i++) {
@@ -65,7 +67,7 @@ shared.renderTags = function(props, renderItem) {
items: tagItems,
order: order,
};
}
};
// shared.renderSearches = function(props, renderItem) {
// let searches = props.searches.slice();
@@ -88,7 +90,7 @@ shared.synchronize_press = async function(comp) {
const action = comp.props.syncStarted ? 'cancel' : 'start';
if (!await reg.syncTarget().isAuthenticated()) {
if (!(await reg.syncTarget().isAuthenticated())) {
if (reg.syncTarget().authRouteName()) {
comp.props.dispatch({
type: 'NAV_GO',
@@ -117,6 +119,6 @@ shared.synchronize_press = async function(comp) {
reg.scheduleSync(0);
return 'sync';
}
}
};
module.exports = shared;
module.exports = shared;

View File

@@ -1,5 +1,6 @@
const React = require('react'); const Component = React.Component;
const { TouchableOpacity , Button, Text, Image, StyleSheet, ScrollView, View, Alert } = require('react-native');
const React = require('react');
const Component = React.Component;
const { TouchableOpacity, Button, Text, Image, StyleSheet, ScrollView, View, Alert } = require('react-native');
const { connect } = require('react-redux');
const Icon = require('react-native-vector-icons/Ionicons').default;
const Tag = require('lib/models/Tag.js');
@@ -16,7 +17,6 @@ const shared = require('lib/components/shared/side-menu-shared.js');
const { ActionButton } = require('lib/components/action-button.js');
class SideMenuContentNoteComponent extends Component {
constructor() {
super();
@@ -32,7 +32,7 @@ class SideMenuContentNoteComponent extends Component {
let styles = {
menu: {
flex: 1,
backgroundColor: theme.backgroundColor
backgroundColor: theme.backgroundColor,
},
button: {
flex: 1,
@@ -57,7 +57,7 @@ class SideMenuContentNoteComponent extends Component {
}
renderDivider(key) {
return <View style={{ marginTop: 15, marginBottom: 15, flex: -1, borderBottomWidth: 1, borderBottomColor: globalStyle.dividerColor }} key={key}></View>
return <View style={{ marginTop: 15, marginBottom: 15, flex: -1, borderBottomWidth: 1, borderBottomColor: globalStyle.dividerColor }} key={key}></View>;
}
renderSideBarButton(key, title, iconName, onPressHandler) {
@@ -65,7 +65,7 @@ class SideMenuContentNoteComponent extends Component {
const content = (
<View key={key} style={onPressHandler ? this.styles().sideButton : this.styles().sideButtonDisabled}>
{ !iconName ? null : <Icon name={iconName} style={this.styles().sidebarIcon} /> }
{!iconName ? null : <Icon name={iconName} style={this.styles().sidebarIcon} />}
<Text style={this.styles().sideButtonText}>{title}</Text>
</View>
);
@@ -96,7 +96,7 @@ class SideMenuContentNoteComponent extends Component {
}
let style = {
flex:1,
flex: 1,
borderRightWidth: 1,
borderRightColor: globalStyle.dividerColor,
backgroundColor: theme.backgroundColor,
@@ -105,22 +105,20 @@ class SideMenuContentNoteComponent extends Component {
return (
<View style={style}>
<View style={{flex:1, opacity: this.props.opacity}}>
<View style={{ flex: 1, opacity: this.props.opacity }}>
<ScrollView scrollsToTop={false} style={this.styles().menu}>
{ items }
{items}
</ScrollView>
</View>
</View>
);
}
};
}
const SideMenuContentNote = connect(
(state) => {
return {
theme: state.settings.theme,
};
}
)(SideMenuContentNoteComponent)
const SideMenuContentNote = connect(state => {
return {
theme: state.settings.theme,
};
})(SideMenuContentNoteComponent);
module.exports = { SideMenuContentNote };
module.exports = { SideMenuContentNote };

View File

@@ -1,5 +1,6 @@
const React = require('react'); const Component = React.Component;
const { Easing, Animated, TouchableOpacity , Button, Text, Image, StyleSheet, ScrollView, View, Alert } = require('react-native');
const React = require('react');
const Component = React.Component;
const { Easing, Animated, TouchableOpacity, Button, Text, Image, StyleSheet, ScrollView, View, Alert } = require('react-native');
const { connect } = require('react-redux');
const Icon = require('react-native-vector-icons/Ionicons').default;
const Tag = require('lib/models/Tag.js');
@@ -16,7 +17,6 @@ const shared = require('lib/components/shared/side-menu-shared.js');
const { ActionButton } = require('lib/components/action-button.js');
class SideMenuContentComponent extends Component {
constructor() {
super();
this.state = {
@@ -47,7 +47,7 @@ class SideMenuContentComponent extends Component {
let styles = {
menu: {
flex: 1,
backgroundColor: theme.backgroundColor
backgroundColor: theme.backgroundColor,
},
button: {
flex: 1,
@@ -82,7 +82,7 @@ class SideMenuContentComponent extends Component {
styles.folderButtonSelected = Object.assign({}, styles.folderButton);
styles.folderButtonSelected.backgroundColor = theme.selectedColor;
styles.folderIcon = Object.assign({}, theme.icon);
styles.folderIcon.color = theme.colorFaded;//'#0072d5';
styles.folderIcon.color = theme.colorFaded; //'#0072d5';
styles.folderIcon.paddingTop = 3;
styles.sideButton = Object.assign({}, styles.button, { flex: 0 });
@@ -96,18 +96,20 @@ class SideMenuContentComponent extends Component {
componentDidUpdate(prevProps) {
if (this.props.syncStarted !== prevProps.syncStarted) {
if (this.props.syncStarted) {
this.syncIconAnimation = Animated.loop(Animated.timing(this.syncIconRotationValue, {
toValue: 1,
duration: 3000,
easing: Easing.linear,
}));
this.syncIconAnimation = Animated.loop(
Animated.timing(this.syncIconRotationValue, {
toValue: 1,
duration: 3000,
easing: Easing.linear,
})
);
this.syncIconAnimation.start();
} else {
if (this.syncIconAnimation) this.syncIconAnimation.stop();
this.syncIconAnimation = null;
}
}
}
}
folder_press(folder) {
@@ -127,7 +129,8 @@ class SideMenuContentComponent extends Component {
Alert.alert(
'',
_('Notebook: %s', folder.title), [
_('Notebook: %s', folder.title),
[
{
text: _('Rename'),
onPress: () => {
@@ -143,7 +146,7 @@ class SideMenuContentComponent extends Component {
routeName: 'Folder',
folderId: folder.id,
});
}
},
},
{
text: _('Delete'),
@@ -168,9 +171,10 @@ class SideMenuContentComponent extends Component {
text: _('Cancel'),
onPress: () => {},
style: 'cancel',
}
], {
cancelable: false
},
],
{
cancelable: false,
}
);
}
@@ -240,22 +244,38 @@ class SideMenuContentComponent extends Component {
let iconWrapper = null;
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'md-arrow-dropdown' : 'md-arrow-dropup';
const iconComp = <Icon name={iconName} style={this.styles().folderIcon} />
const iconComp = <Icon name={iconName} style={this.styles().folderIcon} />;
iconWrapper = !hasChildren ? null : (
<TouchableOpacity style={iconWrapperStyle} folderid={folder.id} onPress={() => { if (hasChildren) this.folder_togglePress(folder) }}>
{ iconComp }
<TouchableOpacity
style={iconWrapperStyle}
folderid={folder.id}
onPress={() => {
if (hasChildren) this.folder_togglePress(folder);
}}
>
{iconComp}
</TouchableOpacity>
);
return (
<View key={folder.id} style={{ flex: 1, flexDirection: 'row' }}>
<TouchableOpacity style={{ flex: 1 }} onPress={() => { this.folder_press(folder) }} onLongPress={() => { this.folder_longPress(folder) }}>
<TouchableOpacity
style={{ flex: 1 }}
onPress={() => {
this.folder_press(folder);
}}
onLongPress={() => {
this.folder_longPress(folder);
}}
>
<View style={folderButtonStyle}>
<Text numberOfLines={1} style={this.styles().folderButtonText}>{Folder.displayTitle(folder)}</Text>
<Text numberOfLines={1} style={this.styles().folderButtonText}>
{Folder.displayTitle(folder)}
</Text>
</View>
</TouchableOpacity>
{ iconWrapper }
{iconWrapper}
</View>
);
}
@@ -263,14 +283,10 @@ class SideMenuContentComponent extends Component {
renderSideBarButton(key, title, iconName, onPressHandler = null, selected = false) {
const theme = themeStyle(this.props.theme);
let icon = <Icon name={iconName} style={this.styles().sidebarIcon} />
let icon = <Icon name={iconName} style={this.styles().sidebarIcon} />;
if (key === 'synchronize_button') {
icon = (
<Animated.View style={{transform: [{rotate: this.syncIconRotation}]}}>
{icon}
</Animated.View>
);
icon = <Animated.View style={{ transform: [{ rotate: this.syncIconRotation }] }}>{icon}</Animated.View>;
}
const content = (
@@ -290,7 +306,7 @@ class SideMenuContentComponent extends Component {
}
makeDivider(key) {
return <View style={{ marginTop: 15, marginBottom: 15, flex: -1, borderBottomWidth: 1, borderBottomColor: globalStyle.dividerColor }} key={key}></View>
return <View style={{ marginTop: 15, marginBottom: 15, flex: -1, borderBottomWidth: 1, borderBottomColor: globalStyle.dividerColor }} key={key}></View>;
}
renderBottomPanel() {
@@ -309,7 +325,7 @@ class SideMenuContentComponent extends Component {
items.push(this.makeDivider('divider_2'));
let lines = Synchronizer.reportToLines(this.props.syncReport);
const syncReportText = lines.join("\n");
const syncReportText = lines.join('\n');
let decryptionReportText = '';
if (this.props.decryptionWorker && this.props.decryptionWorker.state !== 'idle' && this.props.decryptionWorker.itemCount) {
@@ -326,20 +342,16 @@ class SideMenuContentComponent extends Component {
if (resourceFetcherText) fullReport.push(resourceFetcherText);
if (decryptionReportText) fullReport.push(decryptionReportText);
items.push(this.renderSideBarButton(
'synchronize_button',
!this.props.syncStarted ? _('Synchronise') : _('Cancel'),
'md-sync',
this.synchronize_press
));
items.push(this.renderSideBarButton('synchronize_button', !this.props.syncStarted ? _('Synchronise') : _('Cancel'), 'md-sync', this.synchronize_press));
if (fullReport.length) items.push(<Text key='sync_report' style={this.styles().syncStatus}>{fullReport.join('\n')}</Text>);
if (fullReport.length)
items.push(
<Text key="sync_report" style={this.styles().syncStatus}>
{fullReport.join('\n')}
</Text>
);
return (
<View style={{ flex: 0, flexDirection: 'column', paddingBottom: theme.marginBottom }}>
{ items }
</View>
);
return <View style={{ flex: 0, flexDirection: 'column', paddingBottom: theme.marginBottom }}>{items}</View>;
}
render() {
@@ -349,7 +361,7 @@ class SideMenuContentComponent extends Component {
// HACK: inner height of ScrollView doesn't appear to be calculated correctly when
// using padding. So instead creating blank elements for padding bottom and top.
items.push(<View style={{ height: globalStyle.marginTop }} key='bottom_top_hack'/>);
items.push(<View style={{ height: globalStyle.marginTop }} key="bottom_top_hack" />);
items.push(this.renderSideBarButton('all_notes', _('All notes'), 'md-document', this.allNotesButton_press, this.props.notesParentType === 'SmartFilter'));
@@ -364,7 +376,7 @@ class SideMenuContentComponent extends Component {
}
let style = {
flex:1,
flex: 1,
borderRightWidth: 1,
borderRightColor: globalStyle.dividerColor,
backgroundColor: theme.backgroundColor,
@@ -372,35 +384,33 @@ class SideMenuContentComponent extends Component {
return (
<View style={style}>
<View style={{flex:1, opacity: this.props.opacity}}>
<View style={{ flex: 1, opacity: this.props.opacity }}>
<ScrollView scrollsToTop={false} style={this.styles().menu}>
{ items }
{items}
</ScrollView>
{ this.renderBottomPanel() }
{this.renderBottomPanel()}
</View>
</View>
);
}
};
}
const SideMenuContent = connect(
(state) => {
return {
folders: state.folders,
syncStarted: state.syncStarted,
syncReport: state.syncReport,
selectedFolderId: state.selectedFolderId,
selectedTagId: state.selectedTagId,
notesParentType: state.notesParentType,
locale: state.settings.locale,
theme: state.settings.theme,
// Don't do the opacity animation as it means re-rendering the list multiple times
// opacity: state.sideMenuOpenPercent,
collapsedFolderIds: state.collapsedFolderIds,
decryptionWorker: state.decryptionWorker,
resourceFetcher: state.resourceFetcher,
};
}
)(SideMenuContentComponent)
const SideMenuContent = connect(state => {
return {
folders: state.folders,
syncStarted: state.syncStarted,
syncReport: state.syncReport,
selectedFolderId: state.selectedFolderId,
selectedTagId: state.selectedTagId,
notesParentType: state.notesParentType,
locale: state.settings.locale,
theme: state.settings.theme,
// Don't do the opacity animation as it means re-rendering the list multiple times
// opacity: state.sideMenuOpenPercent,
collapsedFolderIds: state.collapsedFolderIds,
decryptionWorker: state.decryptionWorker,
resourceFetcher: state.resourceFetcher,
};
})(SideMenuContentComponent);
module.exports = { SideMenuContent };
module.exports = { SideMenuContent };

View File

@@ -1,15 +1,14 @@
const React = require('react'); const Component = React.Component;
const React = require('react');
const Component = React.Component;
const { connect } = require('react-redux');
const SideMenu_ = require('react-native-side-menu').default;
class SideMenuComponent extends SideMenu_ {};
class SideMenuComponent extends SideMenu_ {}
const MySideMenu = connect(
(state) => {
return {
isOpen: state.showSideMenu,
};
}
)(SideMenuComponent)
const MySideMenu = connect(state => {
return {
isOpen: state.showSideMenu,
};
})(SideMenuComponent);
module.exports = { SideMenu: MySideMenu };
module.exports = { SideMenu: MySideMenu };