1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Sync in background for RN

This commit is contained in:
Laurent Cozic 2017-07-16 22:17:22 +01:00
parent 576cb345bb
commit 6673baee91
8 changed files with 138 additions and 31 deletions

View File

@ -5,11 +5,6 @@ import { _ } from 'lib/locale.js';
class AppNavComponent extends Component {
constructor() {
super();
this.screenCache_ = [];
}
render() {
if (!this.props.route) throw new Error('Route must not be null');

View File

@ -4,6 +4,7 @@ import { ListView, Text, TouchableHighlight, Switch, View } from 'react-native';
import { Log } from 'lib/log.js';
import { _ } from 'lib/locale.js';
import { Checkbox } from 'lib/components/checkbox.js';
import { reg } from 'lib/registry.js';
import { Note } from 'lib/models/note.js';
import { time } from 'lib/time-utils.js';
@ -36,6 +37,8 @@ class ItemListComponent extends Component {
async todoCheckbox_change(itemId, checked) {
let note = await Note.load(itemId);
await Note.save({ id: note.id, todo_completed: checked ? time.unixMs() : 0 });
reg.scheduleSync();
}
listView_itemLongPress(itemId) {}

View File

@ -6,6 +6,7 @@ import { ActionButton } from 'lib/components/action-button.js';
import { Folder } from 'lib/models/folder.js'
import { BaseModel } from 'lib/base-model.js'
import { ScreenHeader } from 'lib/components/screen-header.js';
import { reg } from 'lib/registry.js';
import { NotesScreenUtils } from 'lib/components/screens/notes-utils.js'
import { BaseScreenComponent } from 'lib/components/base-screen.js';
import { dialogs } from 'lib/dialogs.js';
@ -69,6 +70,8 @@ class FolderScreenComponent extends BaseScreenComponent {
duplicateCheck: true,
reservedTitleCheck: true,
});
reg.scheduleSync();
} catch (error) {
dialogs.error(this, _('The folder could not be saved: %s', error.message));
return;

View File

@ -12,6 +12,7 @@ import { time } from 'lib/time-utils.js';
import { Checkbox } from 'lib/components/checkbox.js'
import { _ } from 'lib/locale.js';
import marked from 'lib/marked.js';
import { reg } from 'lib/registry.js';
import { BaseScreenComponent } from 'lib/components/base-screen.js';
import { dialogs } from 'lib/dialogs.js';
import { NotesScreenUtils } from 'lib/components/screens/notes-utils.js'
@ -38,7 +39,9 @@ class NoteScreenComponent extends BaseScreenComponent {
showNoteMetadata: false,
folder: null,
lastSavedNote: null,
}
};
this.saveButtonHasBeenShown_ = false;
this.backHandler = () => {
if (!this.state.note.id) {
@ -112,11 +115,9 @@ class NoteScreenComponent extends BaseScreenComponent {
}
noteComponent_change(propName, propValue) {
this.setState((prevState, props) => {
let note = Object.assign({}, prevState.note);
note[propName] = propValue;
return { note: note }
});
let note = Object.assign({}, this.state.note);
note[propName] = propValue;
this.setState({ note: note });
}
async refreshNoteMetadata(force = null) {
@ -155,6 +156,8 @@ class NoteScreenComponent extends BaseScreenComponent {
});
if (isNew) Note.updateGeolocation(note.id);
this.refreshNoteMetadata();
reg.scheduleSync();
}
async deleteNote_onPress() {
@ -168,6 +171,8 @@ class NoteScreenComponent extends BaseScreenComponent {
await Note.delete(note.id);
await NotesScreenUtils.openNoteList(folderId);
reg.scheduleSync();
}
attachFile_onPress() {
@ -200,6 +205,8 @@ class NoteScreenComponent extends BaseScreenComponent {
lastSavedNote: Object.assign({}, note),
note: note,
});
reg.scheduleSync();
} else {
note[name] = value;
this.setState({ note: note });
@ -207,7 +214,8 @@ class NoteScreenComponent extends BaseScreenComponent {
}
async todoCheckbox_change(checked) {
return this.saveOneProperty('todo_completed', checked ? time.unixMs() : 0);
await this.saveOneProperty('todo_completed', checked ? time.unixMs() : 0);
reg.scheduleSync();
}
render() {
@ -307,9 +315,11 @@ class NoteScreenComponent extends BaseScreenComponent {
const actionButtonComp = renderActionButton();
let showSaveButton = this.state.mode == 'edit';
let showSaveButton = this.state.mode == 'edit' || this.isModified() || this.saveButtonHasBeenShown_;
let saveButtonDisabled = !this.isModified();
if (showSaveButton) this.saveButtonHasBeenShown_ = true;
return (
<View style={this.styles().screen}>
<ScreenHeader
@ -328,6 +338,8 @@ class NoteScreenComponent extends BaseScreenComponent {
note: note,
folder: folder,
});
reg.scheduleSync();
}
}}
navState={this.props.navigation.state}

View File

@ -40,7 +40,7 @@ const styles = StyleSheet.create({
paddingRight: 20,
paddingTop: 14,
paddingBottom: 14,
marginBottom: 5 ,
marginBottom: 5,
},
folderButtonText: {
color: "#ffffff",
@ -65,24 +65,30 @@ class SideMenuContentComponent extends Component {
NotesScreenUtils.openNoteList(folder.id);
}
async synchronizer_progress(report) {
const sync = await reg.synchronizer();
let lines = sync.reportToLines(report);
this.setState({ syncReportText: lines.join("\n") });
}
synchronizer_complete() {
FoldersScreenUtils.refreshFolders();
}
async componentWillMount() {
reg.dispatcher().on('synchronizer_progress', this.synchronizer_progress.bind(this));
reg.dispatcher().on('synchronizer_complete', this.synchronizer_complete.bind(this));
}
componentWillUnmount() {
reg.dispatcher().off('synchronizer_progress', this.synchronizer_progress.bind(this));
reg.dispatcher().off('synchronizer_complete', this.synchronizer_complete.bind(this));
}
async synchronize_press() {
if (reg.oneDriveApi().auth()) {
const sync = await reg.synchronizer()
let options = {
onProgress: (report) => {
let lines = sync.reportToLines(report);
this.setState({ syncReportText: lines.join("\n") });
},
};
try {
sync.start(options).then(async () => {
await FoldersScreenUtils.refreshFolders();
});
} catch (error) {
Log.error(error);
}
sync.start();
} else {
this.props.dispatch({ type: 'SIDE_MENU_CLOSE' });
@ -102,7 +108,7 @@ class SideMenuContentComponent extends Component {
items.push(
<TouchableOpacity key={f.id} onPress={() => { this.folder_press(f) }}>
<View style={styles.folderButton}>
<Text style={styles.folderButtonText}>{title}</Text>
<Text numberOfLines={1} style={styles.folderButtonText}>{title}</Text>
</View>
</TouchableOpacity>
);

View File

@ -0,0 +1,35 @@
class EventDispatcher {
constructor() {
this.listeners_ = [];
}
dispatch(eventName, event = null) {
if (!this.listeners_[eventName]) return;
let ls = this.listeners_[eventName];
for (let i = 0; i < ls.length; i++) {
ls[i](event);
}
}
on(eventName, callback) {
if (!this.listeners_[eventName]) this.listeners_[eventName] = [];
this.listeners_[eventName].push(callback);
}
off(eventName, callback) {
if (!this.listeners_[eventName]) return;
let ls = this.listeners_[eventName];
for (let i = 0; i < ls.length; i++) {
if (ls[i] === callback) {
ls.splice(i, 1);
return;
}
}
}
}
export { EventDispatcher };

View File

@ -5,9 +5,16 @@ import { parameters } from 'lib/parameters.js';
import { FileApi } from 'lib/file-api.js';
import { Synchronizer } from 'lib/synchronizer.js';
import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js';
import { EventDispatcher } from 'lib/event-dispatcher.js';
const reg = {};
reg.dispatcher = () => {
if (this.dispatcher_) return this.dispatcher_;
this.dispatcher_ = new EventDispatcher();
return this.dispatcher_;
}
reg.logger = () => {
if (!reg.logger_) {
console.warn('Calling logger before it is initialized');
@ -70,9 +77,37 @@ reg.synchronizer = async () => {
let fileApi = await reg.fileApi();
reg.synchronizer_ = new Synchronizer(reg.db(), fileApi, Setting.value('appType'));
reg.synchronizer_.setLogger(reg.logger());
reg.synchronizer_.on('progress', (report) => {
reg.dispatcher().dispatch('synchronizer_progress', report);
});
reg.synchronizer_.on('complete', () => {
reg.dispatcher().dispatch('synchronizer_complete');
});
return reg.synchronizer_;
}
reg.scheduleSync = async () => {
if (reg.scheduleSyncId_) return;
reg.logger().info('Scheduling sync operation...');
reg.scheduleSyncId_ = setTimeout(async () => {
reg.scheduleSyncId_ = null;
reg.logger().info('Doing scheduled sync');
if (!reg.oneDriveApi().auth()) {
reg.logger().info('Synchronizer is missing credentials - manual sync required to authenticate.');
return;
}
const sync = await reg.synchronizer();
sync.start();
}, 1000 * 10);
}
reg.setDb = (v) => {
reg.db_ = v;
}

View File

@ -7,6 +7,7 @@ import { sprintf } from 'sprintf-js';
import { time } from 'lib/time-utils.js';
import { Logger } from 'lib/logger.js'
import { _ } from 'lib/locale.js';
import { EventDispatcher } from 'lib/event-dispatcher.js';
import moment from 'moment';
class Synchronizer {
@ -23,6 +24,16 @@ class Synchronizer {
this.onProgress_ = function(s) {};
this.progressReport_ = {};
this.dispatcher_ = new EventDispatcher();
}
on(eventName, callback) {
return this.dispatcher_.on(eventName, callback);
}
off(eventName, callback) {
return this.dispatcher_.off(eventName, callback);
}
state() {
@ -55,6 +66,7 @@ class Synchronizer {
if (report.deleteRemote) lines.push(_('Deleted remote items: %d.', report.deleteRemote));
if (report.state) lines.push(_('State: %s.', report.state.replace(/_/g, ' ')));
if (report.errors && report.errors.length) lines.push(_('Last error: %s (stacktrace in log).', report.errors[report.errors.length-1].message));
if (report.completedTime) lines.push(_('Completed: %s', time.unixMsToLocalDateTime(report.completedTime)));
return lines;
}
@ -88,6 +100,8 @@ class Synchronizer {
this.progressReport_[action]++;
this.progressReport_.state = this.state();
this.onProgress_(this.progressReport_);
this.dispatcher_.dispatch('progress', this.progressReport_);
}
async logSyncSummary(report) {
@ -143,7 +157,7 @@ class Synchronizer {
const syncTargetId = this.api().driver().syncTargetId();
if (this.state() != 'idle') {
this.logger().warn('Synchronization is already in progress. State: ' + this.state());
this.logger().info('Synchronization is already in progress. State: ' + this.state());
return;
}
@ -430,10 +444,14 @@ class Synchronizer {
this.logSyncOperation('finished', null, null, 'Synchronization finished [' + synchronizationId + ']');
this.progressReport_.completedTime = time.unixMs();
await this.logSyncSummary(this.progressReport_);
this.onProgress_ = function(s) {};
this.progressReport_ = {};
this.dispatcher_.dispatch('complete');
}
}