You've already forked joplin
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:
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -30,6 +30,6 @@ const reduxSharedMiddleware = async function(store, next, action) {
|
||||
items: await Tag.allWithNotes(),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = reduxSharedMiddleware;
|
||||
module.exports = reduxSharedMiddleware;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user