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:
parent
576cb345bb
commit
6673baee91
@ -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');
|
||||
|
||||
|
@ -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) {}
|
||||
|
@ -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;
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
);
|
||||
|
35
ReactNativeClient/lib/event-dispatcher.js
Normal file
35
ReactNativeClient/lib/event-dispatcher.js
Normal 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 };
|
@ -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;
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user