diff --git a/ReactNativeClient/lib/components/item-list.js b/ReactNativeClient/lib/components/item-list.js
index 2438ebce7..ddf72501d 100644
--- a/ReactNativeClient/lib/components/item-list.js
+++ b/ReactNativeClient/lib/components/item-list.js
@@ -7,6 +7,7 @@ import { Checkbox } from 'lib/components/checkbox.js';
import { NoteItem } from 'lib/components/note-item.js';
import { reg } from 'lib/registry.js';
import { Note } from 'lib/models/note.js';
+import { Setting } from 'lib/models/setting.js';
import { time } from 'lib/time-utils.js';
import { globalStyle } from 'lib/components/global-style.js';
@@ -33,15 +34,35 @@ class ItemListComponent extends Component {
};
}
+ filterNotes(notes) {
+ const todoFilter = Setting.value('todoFilter');
+ if (todoFilter == 'all') return notes;
+
+ const now = time.unixMs();
+ const maxInterval = 1000 * 60 * 60 * 24 * 2;
+ const notRecentTime = now - maxInterval;
+
+ let output = [];
+ for (let i = 0; i < notes.length; i++) {
+ const note = notes[i];
+ if (note.is_todo) {
+ if (todoFilter == 'recent' && note.updated_time < notRecentTime) continue;
+ if (todoFilter == 'nonCompleted' && !!note.todo_completed) continue;
+ }
+ output.push(note);
+ }
+ return output;
+ }
+
componentWillMount() {
- const newDataSource = this.state.dataSource.cloneWithRows(this.props.items);
+ const newDataSource = this.state.dataSource.cloneWithRows(this.filterNotes(this.props.items));
this.state = { dataSource: newDataSource };
}
componentWillReceiveProps(newProps) {
// https://stackoverflow.com/questions/38186114/react-native-redux-and-listview
this.setState({
- dataSource: this.state.dataSource.cloneWithRows(newProps.items),
+ dataSource: this.state.dataSource.cloneWithRows(this.filterNotes(newProps.items)),
});
}
@@ -49,7 +70,6 @@ class ItemListComponent extends Component {
let note = await Note.load(itemId);
await Note.save({ id: note.id, todo_completed: checked ? time.unixMs() : 0 });
reg.scheduleSync();
-
}
listView_itemLongPress(itemId) {}
diff --git a/ReactNativeClient/lib/components/note-item.js b/ReactNativeClient/lib/components/note-item.js
index 6961448d0..dabae2987 100644
--- a/ReactNativeClient/lib/components/note-item.js
+++ b/ReactNativeClient/lib/components/note-item.js
@@ -9,7 +9,7 @@ import { Note } from 'lib/models/note.js';
import { time } from 'lib/time-utils.js';
import { globalStyle } from 'lib/components/global-style.js';
-const styleObject = {
+let styles = {
listItem: {
flexDirection: 'row',
height: 40,
@@ -24,7 +24,10 @@ const styleObject = {
},
};
-const styles = StyleSheet.create(styleObject);
+styles.listItemFadded = Object.assign({}, styles.listItem);
+styles.listItemFadded.opacity = 0.4;
+
+styles = StyleSheet.create(styles);
class NoteItemComponent extends Component {
@@ -45,9 +48,11 @@ class NoteItemComponent extends Component {
const checkboxStyle = !Number(note.is_todo) ? { display: 'none' } : { color: globalStyle.color };
const checkboxChecked = !!Number(note.todo_completed);
+ const listItemStyle = !!Number(note.is_todo) && checkboxChecked ? styles.listItemFadded : styles.listItem;
+
return (
onPress ? onPress(note) : this.noteItem_press(note.id)} onLongPress={() => onLongPress(note)} underlayColor="#0066FF">
-
+
{ onCheckboxChange(note, checked) }}/>{note.title}
diff --git a/ReactNativeClient/lib/components/screen-header.js b/ReactNativeClient/lib/components/screen-header.js
index d12abb744..d15efb6c7 100644
--- a/ReactNativeClient/lib/components/screen-header.js
+++ b/ReactNativeClient/lib/components/screen-header.js
@@ -144,6 +144,13 @@ class ScreenHeaderComponent extends Component {
});
}
+ config_press() {
+ this.props.dispatch({
+ type: 'Navigation/NAVIGATE',
+ routeName: 'Config',
+ });
+ }
+
render() {
function sideMenuButton(styles, onPress) {
@@ -213,6 +220,15 @@ class ScreenHeaderComponent extends Component {
{_('Status')}
);
+ if (menuOptionComponents.length) {
+ menuOptionComponents.push();
+ }
+
+ menuOptionComponents.push(
+ this.config_press()} key={'menuOption_' + key++} style={styles.contextMenuItem}>
+ {_('Configuration')}
+ );
+
const createTitleComponent = () => {
const p = this.props.titlePicker;
if (p) {
diff --git a/ReactNativeClient/lib/components/screens/config.js b/ReactNativeClient/lib/components/screens/config.js
new file mode 100644
index 000000000..f6eb1c84d
--- /dev/null
+++ b/ReactNativeClient/lib/components/screens/config.js
@@ -0,0 +1,114 @@
+import React, { Component } from 'react';
+import { View, StyleSheet, Picker, Text, Button } from 'react-native';
+import { connect } from 'react-redux'
+import { ScreenHeader } from 'lib/components/screen-header.js';
+import { _ } from 'lib/locale.js';
+import { BaseScreenComponent } from 'lib/components/base-screen.js';
+import { globalStyle } from 'lib/components/global-style.js';
+import { Setting } from 'lib/models/setting.js';
+
+let styles = {
+ body: {}
+}
+
+styles = StyleSheet.create(styles);
+
+class ConfigScreenComponent extends BaseScreenComponent {
+
+ static navigationOptions(options) {
+ return { header: null };
+ }
+
+ constructor() {
+ super();
+ this.state = {
+ values: {},
+ };
+ }
+
+ componentWillMount() {
+ const settings = Setting.publicSettings(Setting.value('appType'));
+
+ let values = {};
+ for (let key in settings) {
+ if (!settings.hasOwnProperty(key)) continue;
+ values[key] = settings[key].value;
+ }
+
+ this.setState({ values: values });
+ }
+
+ settingToComponent(key, setting) {
+ let output = null;
+
+ const updateSettingValue = (key, value) => {
+ let values = this.state.values;
+ values[key] = value;
+ this.setState({ values: values });
+ }
+
+ const value = this.state.values[key];
+
+ if (setting.type == 'enum') {
+ let items = [];
+ const settingOptions = setting.options();
+ for (let k in settingOptions) {
+ if (!settingOptions.hasOwnProperty(k)) continue;
+ items.push();
+ }
+
+ return (
+
+ {setting.label()}
+ updateSettingValue(key, itemValue)} >
+ { items }
+
+
+ );
+ } else {
+ //throw new Error('Unsupported setting type: ' + setting.type);
+ }
+
+ return output;
+ }
+
+ saveButton_press() {
+ const values = this.state.values;
+ for (let key in values) {
+ if (!values.hasOwnProperty(key)) continue;
+ Setting.setValue(key, values[key]);
+ }
+ Setting.saveAll();
+ }
+
+ render() {
+ const settings = Setting.publicSettings(Setting.value('appType'));
+
+ let settingComps = [];
+ for (let key in settings) {
+ if (!settings.hasOwnProperty(key)) continue;
+ const comp = this.settingToComponent(key, settings[key]);
+ if (!comp) continue;
+ settingComps.push(comp);
+ }
+
+ return (
+
+
+
+ { settingComps }
+
+
+ );
+ }
+
+}
+
+const ConfigScreen = connect(
+ (state) => {
+ return {};
+ }
+)(ConfigScreenComponent)
+
+export { ConfigScreen };
\ No newline at end of file
diff --git a/ReactNativeClient/lib/components/screens/search.js b/ReactNativeClient/lib/components/screens/search.js
index 5773b7789..e193b319c 100644
--- a/ReactNativeClient/lib/components/screens/search.js
+++ b/ReactNativeClient/lib/components/screens/search.js
@@ -90,8 +90,16 @@ class SearchScreenComponent extends BaseScreenComponent {
let notes = []
if (query) {
+ let p = query.split(' ');
+ let temp = [];
+ for (let i = 0; i < p.length; i++) {
+ let t = p[i].trim();
+ if (!t) continue;
+ temp.push(t);
+ }
+
notes = await Note.previews(null, {
- anywherePattern: '*' + query + '*',
+ anywherePattern: '*' + temp.join('*') + '*',
});
}
@@ -112,6 +120,7 @@ class SearchScreenComponent extends BaseScreenComponent {
{ this.searchTextInput_submit() }}
onChangeText={(text) => this.searchTextInput_changeText(text) }
diff --git a/ReactNativeClient/lib/models/setting.js b/ReactNativeClient/lib/models/setting.js
index 3704e0fc8..4ee15529a 100644
--- a/ReactNativeClient/lib/models/setting.js
+++ b/ReactNativeClient/lib/models/setting.js
@@ -1,5 +1,6 @@
import { BaseModel } from 'lib/base-model.js';
import { Database } from 'lib/database.js';
+import { _ } from 'lib/locale.js';
class Setting extends BaseModel {
@@ -120,6 +121,9 @@ class Setting extends BaseModel {
for (let i = 0; i < this.cache_.length; i++) {
let s = Object.assign({}, this.cache_[i]);
delete s.public;
+ delete s.appTypes;
+ delete s.label;
+ delete s.options;
queries.push(Database.insertQuery(this.tableName(), s));
}
@@ -141,17 +145,37 @@ class Setting extends BaseModel {
this.updateTimeoutId_ = null;
}
+ static publicSettings(appType) {
+ if (!appType) throw new Error('appType is required');
+
+ let output = {};
+ for (let key in Setting.defaults_) {
+ if (!Setting.defaults_.hasOwnProperty(key)) continue;
+ let s = Object.assign({}, Setting.defaults_[key]);
+ if (!s.public) continue;
+ if (s.appTypes && s.appTypes.indexOf(appType) < 0) continue;
+ s.value = this.value(key);
+ output[key] = s;
+ }
+ return output;
+ }
+
}
Setting.defaults_ = {
'activeFolderId': { value: '', type: 'string', public: false },
'sync.onedrive.auth': { value: '', type: 'string', public: false },
- 'sync.filesystem.path': { value: '', type: 'string', public: true },
- 'sync.target': { value: 'onedrive', type: 'string', public: true },
+ 'sync.filesystem.path': { value: '', type: 'string', public: true, appTypes: ['cli'] },
+ 'sync.target': { value: 'onedrive', type: 'string', public: true, label: () => _('Synchronisation target') },
'sync.context': { value: '', type: 'string', public: false },
- 'editor': { value: '', type: 'string', public: true },
+ 'editor': { value: '', type: 'string', public: true, appTypes: ['cli'] },
'locale': { value: 'en_GB', type: 'string', public: true },
- 'aliases': { value: '', type: 'string', public: true },
+ //'aliases': { value: '', type: 'string', public: true },
+ 'todoFilter': { value: 'all', type: 'enum', public: true, appTypes: ['mobile'], label: () => _('Todo filter'), options: () => ({
+ all: _('Show all'),
+ recent: _('Non-completed and recently completed ones'),
+ nonCompleted: _('Non-completed ones only'),
+ })},
};
// Contains constants that are set by the application and
diff --git a/ReactNativeClient/root.js b/ReactNativeClient/root.js
index b8033ea8a..75939aa0f 100644
--- a/ReactNativeClient/root.js
+++ b/ReactNativeClient/root.js
@@ -20,6 +20,7 @@ import { ItemList } from 'lib/components/item-list.js'
import { NotesScreen } from 'lib/components/screens/notes.js'
import { NotesScreenUtils } from 'lib/components/screens/notes-utils.js'
import { NoteScreen } from 'lib/components/screens/note.js'
+import { ConfigScreen } from 'lib/components/screens/config.js'
import { FolderScreen } from 'lib/components/screens/folder.js'
import { FoldersScreen } from 'lib/components/screens/folders.js'
import { LogScreen } from 'lib/components/screens/log.js'
@@ -409,6 +410,11 @@ async function initialize(dispatch, backButtonHandler) {
let folderId = Setting.value('activeFolderId');
let folder = await Folder.load(folderId);
+ // dispatch({
+ // type: 'Navigation/NAVIGATE',
+ // routeName: 'Config',
+ // });
+
if (folder) {
await NotesScreenUtils.openNoteList(folderId);
} else {
@@ -490,6 +496,7 @@ class AppComponent extends React.Component {
Log: { screen: LogScreen },
Status: { screen: StatusScreen },
Search: { screen: SearchScreen },
+ Config: { screen: ConfigScreen },
};
return (