You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-09-16 08:56:40 +02:00
handle todos
This commit is contained in:
@@ -15,12 +15,23 @@ const styles = StyleSheet.create({
|
|||||||
|
|
||||||
class ActionButtonComponent extends React.Component {
|
class ActionButtonComponent extends React.Component {
|
||||||
|
|
||||||
|
newTodo_press() {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'Navigation/NAVIGATE',
|
||||||
|
routeName: 'Note',
|
||||||
|
noteId: null,
|
||||||
|
folderId: this.props.parentFolderId,
|
||||||
|
itemType: 'todo',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
newNote_press() {
|
newNote_press() {
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'Navigation/NAVIGATE',
|
type: 'Navigation/NAVIGATE',
|
||||||
routeName: 'Note',
|
routeName: 'Note',
|
||||||
noteId: null,
|
noteId: null,
|
||||||
folderId: this.props.parentFolderId,
|
folderId: this.props.parentFolderId,
|
||||||
|
itemType: 'note',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,12 +46,19 @@ class ActionButtonComponent extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ReactNativeActionButton buttonColor="rgba(231,76,60,1)">
|
<ReactNativeActionButton buttonColor="rgba(231,76,60,1)">
|
||||||
|
|
||||||
|
<ReactNativeActionButton.Item buttonColor='#9b59b6' title="New todo" onPress={() => { this.newTodo_press() }}>
|
||||||
|
<Icon name="md-checkbox-outline" style={styles.actionButtonIcon} />
|
||||||
|
</ReactNativeActionButton.Item>
|
||||||
|
|
||||||
<ReactNativeActionButton.Item buttonColor='#9b59b6' title="New note" onPress={() => { this.newNote_press() }}>
|
<ReactNativeActionButton.Item buttonColor='#9b59b6' title="New note" onPress={() => { this.newNote_press() }}>
|
||||||
<Icon name="md-document" style={styles.actionButtonIcon} />
|
<Icon name="md-document" style={styles.actionButtonIcon} />
|
||||||
</ReactNativeActionButton.Item>
|
</ReactNativeActionButton.Item>
|
||||||
|
|
||||||
<ReactNativeActionButton.Item buttonColor='#3498db' title="New folder" onPress={() => { this.newFolder_press() }}>
|
<ReactNativeActionButton.Item buttonColor='#3498db' title="New folder" onPress={() => { this.newFolder_press() }}>
|
||||||
<Icon name="md-folder" style={styles.actionButtonIcon} />
|
<Icon name="md-folder" style={styles.actionButtonIcon} />
|
||||||
</ReactNativeActionButton.Item>
|
</ReactNativeActionButton.Item>
|
||||||
|
|
||||||
</ReactNativeActionButton>
|
</ReactNativeActionButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,36 +1,44 @@
|
|||||||
// https://hellokoding.com/todo-app-with-react-native/
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
import { StyleSheet, TouchableHighlight } from 'react-native';
|
||||||
|
import Icon from 'react-native-vector-icons/Ionicons';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
checkboxIcon: {
|
||||||
|
fontSize: 20,
|
||||||
|
height: 22,
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
class Checkbox extends Component {
|
class Checkbox extends Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
data: this.props.data
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
constructor() {
|
||||||
let iconName = 'check-box'; //this.state.data.completed ? 'check-box' : 'check-box-outline-blank';
|
super();
|
||||||
let color = this.props.color || '#000';
|
this.state = {
|
||||||
|
checked: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.state = { checked: this.props.checked };
|
||||||
|
}
|
||||||
|
|
||||||
|
onPress = () => {
|
||||||
|
let newChecked = !this.state.checked;
|
||||||
|
this.setState({ checked: newChecked });
|
||||||
|
if (this.props.onChange) this.props.onChange(newChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const iconName = this.state.checked ? 'md-checkbox-outline' : 'md-square-outline';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableHighlight onPress={this.onPress} style={{justifyContent: 'center', alignItems: 'center'}}>
|
||||||
|
<Icon name={iconName} style={styles.checkboxIcon}/>
|
||||||
|
</TouchableHighlight>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<Icon.Button
|
|
||||||
data={this.state.data}
|
|
||||||
name={iconName}
|
|
||||||
backgroundColor='rgba(0,0,0,0)'
|
|
||||||
color={color}
|
|
||||||
underlayColor='rgba(0,0,0,0)'
|
|
||||||
size={20}
|
|
||||||
iconStyle={{marginLeft: -10, marginRight: 0}}
|
|
||||||
activeOpacity={1}
|
|
||||||
borderRadius={5}
|
|
||||||
onPress={this.props.onCheckboxPressed}
|
|
||||||
>
|
|
||||||
</Icon.Button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Checkbox }
|
export { Checkbox };
|
@@ -2,8 +2,10 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { ListView, Text, TouchableHighlight, Switch, View } from 'react-native';
|
import { ListView, Text, TouchableHighlight, Switch, View } from 'react-native';
|
||||||
import { Log } from 'src/log.js';
|
import { Log } from 'src/log.js';
|
||||||
import Checkbox from 'react-native-checkbox';
|
|
||||||
import { _ } from 'src/locale.js';
|
import { _ } from 'src/locale.js';
|
||||||
|
import { Checkbox } from 'src/components/checkbox.js';
|
||||||
|
import { NoteFolderService } from 'src/services/note-folder-service.js';
|
||||||
|
import { Note } from 'src/models/note.js';
|
||||||
|
|
||||||
class ItemListComponent extends Component {
|
class ItemListComponent extends Component {
|
||||||
|
|
||||||
@@ -31,6 +33,14 @@ class ItemListComponent extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
todoCheckbox_change(itemId, checked) {
|
||||||
|
Note.load(itemId).then((oldNote) => {
|
||||||
|
let newNote = Object.assign({}, oldNote);
|
||||||
|
newNote.todo_completed = checked;
|
||||||
|
return NoteFolderService.save('note', newNote, oldNote);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
listView_itemPress = (itemId) => {}
|
listView_itemPress = (itemId) => {}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -41,10 +51,11 @@ class ItemListComponent extends Component {
|
|||||||
let onLongPress = () => {
|
let onLongPress = () => {
|
||||||
this.listView_itemLongPress(item.id);
|
this.listView_itemLongPress(item.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableHighlight onPress={onPress} onLongPress={onLongPress}>
|
<TouchableHighlight onPress={onPress} onLongPress={onLongPress}>
|
||||||
<View>
|
<View style={{flexDirection: 'row'}}>
|
||||||
<Text>{item.title} [{item.id}]</Text>
|
{ !!Number(item.is_todo) && <Checkbox checked={!!Number(item.todo_completed)} onChange={(checked) => { this.todoCheckbox_change(item.id, checked) }}/> }<Text>{item.title} [{item.id}]</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
);
|
);
|
||||||
|
@@ -5,6 +5,7 @@ import { Log } from 'src/log.js'
|
|||||||
import { Note } from 'src/models/note.js'
|
import { Note } from 'src/models/note.js'
|
||||||
import { Registry } from 'src/registry.js'
|
import { Registry } from 'src/registry.js'
|
||||||
import { ScreenHeader } from 'src/components/screen-header.js';
|
import { ScreenHeader } from 'src/components/screen-header.js';
|
||||||
|
import { Checkbox } from 'src/components/checkbox.js'
|
||||||
import { NoteFolderService } from 'src/services/note-folder-service.js';
|
import { NoteFolderService } from 'src/services/note-folder-service.js';
|
||||||
|
|
||||||
class NoteScreenComponent extends React.Component {
|
class NoteScreenComponent extends React.Component {
|
||||||
@@ -21,7 +22,9 @@ class NoteScreenComponent extends React.Component {
|
|||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
if (!this.props.noteId) {
|
if (!this.props.noteId) {
|
||||||
this.setState({ note: Note.new(this.props.folderId) });
|
let note = this.props.itemType == 'todo' ? Note.newTodo(this.props.folderId) : Note.new(this.props.folderId);
|
||||||
|
Log.info(note);
|
||||||
|
this.setState({ note: note });
|
||||||
} else {
|
} else {
|
||||||
Note.load(this.props.noteId).then((note) => {
|
Note.load(this.props.noteId).then((note) => {
|
||||||
this.originalNote = Object.assign({}, note);
|
this.originalNote = Object.assign({}, note);
|
||||||
@@ -54,11 +57,26 @@ class NoteScreenComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const note = this.state.note;
|
||||||
|
const isTodo = !!Number(note.is_todo);
|
||||||
|
let todoComponents = null;
|
||||||
|
|
||||||
|
if (note.is_todo) {
|
||||||
|
todoComponents = (
|
||||||
|
<View>
|
||||||
|
<Button title="test" onPress={this.saveNoteButton_press} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1}}>
|
||||||
<ScreenHeader navState={this.props.navigation.state} />
|
<ScreenHeader navState={this.props.navigation.state} />
|
||||||
<TextInput value={this.state.note.title} onChangeText={this.title_changeText} />
|
<View style={{ flexDirection: 'row' }}>
|
||||||
<TextInput style={{flex: 1, textAlignVertical: 'top'}} multiline={true} value={this.state.note.body} onChangeText={this.body_changeText} />
|
{ isTodo && <Checkbox checked={!!Number(note.todo_completed)} /> }<TextInput style={{flex:1}} value={note.title} onChangeText={this.title_changeText} />
|
||||||
|
</View>
|
||||||
|
<TextInput style={{flex: 1, textAlignVertical: 'top'}} multiline={true} value={note.body} onChangeText={this.body_changeText} />
|
||||||
|
{ todoComponents }
|
||||||
<Button title="Save note" onPress={this.saveNoteButton_press} />
|
<Button title="Save note" onPress={this.saveNoteButton_press} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@@ -71,6 +89,7 @@ const NoteScreen = connect(
|
|||||||
return {
|
return {
|
||||||
noteId: state.selectedNoteId,
|
noteId: state.selectedNoteId,
|
||||||
folderId: state.selectedFolderId,
|
folderId: state.selectedFolderId,
|
||||||
|
itemType: state.selectedItemType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)(NoteScreenComponent)
|
)(NoteScreenComponent)
|
||||||
|
@@ -26,8 +26,14 @@ class Note extends BaseModel {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static newTodo(parentId = '') {
|
||||||
|
let output = this.new(parentId);
|
||||||
|
output.is_todo = true;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
static previews(parentId) {
|
static previews(parentId) {
|
||||||
return this.db().selectAll('SELECT id, title, body, parent_id, updated_time FROM notes WHERE parent_id = ?', [parentId]).then((r) => {
|
return this.db().selectAll('SELECT id, title, body, is_todo, todo_completed, parent_id, updated_time FROM notes WHERE parent_id = ?', [parentId]).then((r) => {
|
||||||
let output = [];
|
let output = [];
|
||||||
for (let i = 0; i < r.rows.length; i++) {
|
for (let i = 0; i < r.rows.length; i++) {
|
||||||
output.push(r.rows.item(i));
|
output.push(r.rows.item(i));
|
||||||
|
@@ -30,6 +30,7 @@ let defaultState = {
|
|||||||
notes: [],
|
notes: [],
|
||||||
folders: [],
|
folders: [],
|
||||||
selectedNoteId: null,
|
selectedNoteId: null,
|
||||||
|
selectedItemType: 'note',
|
||||||
selectedFolderId: null,
|
selectedFolderId: null,
|
||||||
user: { email: 'laurent@cozic.net', session: null },
|
user: { email: 'laurent@cozic.net', session: null },
|
||||||
showSideMenu: false,
|
showSideMenu: false,
|
||||||
@@ -62,6 +63,10 @@ const reducer = (state = defaultState, action) => {
|
|||||||
newState.selectedFolderId = action.folderId;
|
newState.selectedFolderId = action.folderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('itemType' in action) {
|
||||||
|
newState.selectedItemType = action.itemType;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentRouteName == action.routeName) {
|
if (currentRouteName == action.routeName) {
|
||||||
// If the current screen is already the requested screen, don't do anything
|
// If the current screen is already the requested screen, don't do anything
|
||||||
} else {
|
} else {
|
||||||
@@ -84,6 +89,8 @@ const reducer = (state = defaultState, action) => {
|
|||||||
// update it within the note array if it already exists.
|
// update it within the note array if it already exists.
|
||||||
case 'NOTES_UPDATE_ONE':
|
case 'NOTES_UPDATE_ONE':
|
||||||
|
|
||||||
|
Log.info('NOITTEOJTNEONTOE', action.note);
|
||||||
|
|
||||||
let newNotes = state.notes.splice(0);
|
let newNotes = state.notes.splice(0);
|
||||||
var found = false;
|
var found = false;
|
||||||
for (let i = 0; i < newNotes.length; i++) {
|
for (let i = 0; i < newNotes.length; i++) {
|
||||||
|
@@ -36,6 +36,17 @@ class NoteFolderService extends BaseService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static setField(type, itemId, fieldName, fieldValue, oldValue = undefined) {
|
||||||
|
// // TODO: not really consistent as the promise will return 'null' while
|
||||||
|
// // this.save will return the note or folder. Currently not used, and maybe not needed.
|
||||||
|
// if (oldValue !== undefined && fieldValue === oldValue) return Promise.resolve();
|
||||||
|
|
||||||
|
// let item = { id: itemId };
|
||||||
|
// item[fieldName] = fieldValue;
|
||||||
|
// let oldItem = { id: itemId };
|
||||||
|
// return this.save(type, item, oldItem);
|
||||||
|
// }
|
||||||
|
|
||||||
static openNoteList(folderId) {
|
static openNoteList(folderId) {
|
||||||
return Note.previews(folderId).then((notes) => {
|
return Note.previews(folderId).then((notes) => {
|
||||||
this.dispatch({
|
this.dispatch({
|
||||||
|
Reference in New Issue
Block a user