mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Refactor to move state changes to browser process
This commit is contained in:
parent
cc277018b7
commit
dbf51382c8
@ -235,6 +235,10 @@ class Application extends BaseApplication {
|
||||
return Object.assign({}, this.commandMetadata_);
|
||||
}
|
||||
|
||||
hasGui() {
|
||||
return this.gui() && !this.gui().isDummy();
|
||||
}
|
||||
|
||||
findCommandByName(name) {
|
||||
if (this.commands_[name]) return this.commands_[name];
|
||||
|
||||
|
@ -5,10 +5,9 @@ const path = require('path')
|
||||
|
||||
class ElectronAppWrapper {
|
||||
|
||||
constructor(electronApp, app, store) {
|
||||
this.app_ = app;
|
||||
constructor(electronApp) {
|
||||
this.electronApp_ = electronApp;
|
||||
this.store_ = store;
|
||||
//this.store_ = store;
|
||||
this.win_ = null;
|
||||
}
|
||||
|
||||
@ -24,19 +23,23 @@ class ElectronAppWrapper {
|
||||
return this.logger_;
|
||||
}
|
||||
|
||||
store() {
|
||||
return this.store_;
|
||||
window() {
|
||||
return this.win_;
|
||||
}
|
||||
|
||||
dispatch(action) {
|
||||
return this.store().dispatch(action);
|
||||
}
|
||||
// store() {
|
||||
// return this.store_;
|
||||
// }
|
||||
|
||||
windowContentSize() {
|
||||
if (!this.win_) return { width: 0, height: 0 };
|
||||
const s = this.win_.getContentSize();
|
||||
return { width: s[0], height: s[1] };
|
||||
}
|
||||
// dispatch(action) {
|
||||
// return this.store().dispatch(action);
|
||||
// }
|
||||
|
||||
// windowContentSize() {
|
||||
// if (!this.win_) return { width: 0, height: 0 };
|
||||
// const s = this.win_.getContentSize();
|
||||
// return { width: s[0], height: s[1] };
|
||||
// }
|
||||
|
||||
createWindow() {
|
||||
this.win_ = new BrowserWindow({width: 800, height: 600})
|
||||
@ -54,16 +57,16 @@ class ElectronAppWrapper {
|
||||
})
|
||||
|
||||
this.win_.on('resize', () => {
|
||||
this.dispatch({
|
||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
||||
size: this.windowContentSize(),
|
||||
});
|
||||
// this.dispatch({
|
||||
// type: 'WINDOW_CONTENT_SIZE_SET',
|
||||
// size: this.windowContentSize(),
|
||||
// });
|
||||
});
|
||||
|
||||
this.dispatch({
|
||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
||||
size: this.windowContentSize(),
|
||||
});
|
||||
// this.dispatch({
|
||||
// type: 'WINDOW_CONTENT_SIZE_SET',
|
||||
// size: this.windowContentSize(),
|
||||
// });
|
||||
}
|
||||
|
||||
async waitForElectronAppReady() {
|
||||
|
@ -17,14 +17,12 @@ const { ElectronAppWrapper } = require('./ElectronAppWrapper');
|
||||
|
||||
class Application extends BaseApplication {
|
||||
|
||||
constructor(electronApp) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.electronApp_ = electronApp;
|
||||
}
|
||||
|
||||
gui() {
|
||||
return this.gui_;
|
||||
hasGui() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async start(argv) {
|
||||
@ -32,11 +30,11 @@ class Application extends BaseApplication {
|
||||
|
||||
this.initRedux();
|
||||
|
||||
this.gui_ = new ElectronAppWrapper(this.electronApp_, this, this.store());
|
||||
//this.gui_ = new ElectronAppWrapper(this.electronApp_, this, this.store());
|
||||
|
||||
try {
|
||||
this.gui_.setLogger(this.logger());
|
||||
await this.gui().start();
|
||||
// this.gui_.setLogger(this.logger());
|
||||
// await this.gui().start();
|
||||
|
||||
// Since the settings need to be loaded before the store is created, it will never
|
||||
// receive the SETTINGS_UPDATE_ALL even, which mean state.settings will not be
|
||||
@ -57,7 +55,7 @@ class Application extends BaseApplication {
|
||||
id: Setting.value('activeFolderId'),
|
||||
});
|
||||
} catch (error) {
|
||||
await this.gui_.exit();
|
||||
//await this.gui_.exit();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -67,7 +65,8 @@ class Application extends BaseApplication {
|
||||
let application_ = null;
|
||||
|
||||
function app() {
|
||||
if (!application_) throw new Error('Application has not been initialized');
|
||||
//if (!application_) throw new Error('Application has not been initialized');
|
||||
if (!application_) application_ = new Application();
|
||||
return application_;
|
||||
}
|
||||
|
||||
|
36
ElectronClient/app/bridge.js
Normal file
36
ElectronClient/app/bridge.js
Normal file
@ -0,0 +1,36 @@
|
||||
class Bridge {
|
||||
|
||||
constructor(electronWrapper) {
|
||||
this.electronWrapper_ = electronWrapper;
|
||||
}
|
||||
|
||||
processArgv() {
|
||||
return process.argv;
|
||||
}
|
||||
|
||||
window() {
|
||||
return this.electronWrapper_.window();
|
||||
}
|
||||
|
||||
windowContentSize() {
|
||||
if (!this.window()) return { width: 0, height: 0 };
|
||||
const s = this.window().getContentSize();
|
||||
return { width: s[0], height: s[1] };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let bridge_ = null;
|
||||
|
||||
function initBridge(wrapper) {
|
||||
if (bridge_) throw new Error('Bridge already initialized');
|
||||
bridge_ = new Bridge(wrapper);
|
||||
return bridge_;
|
||||
}
|
||||
|
||||
function bridge() {
|
||||
if (!bridge_) throw new Error('Bridge not initialized');
|
||||
return bridge_;
|
||||
}
|
||||
|
||||
module.exports = { bridge, initBridge }
|
@ -1,3 +1,5 @@
|
||||
const React = require('react');
|
||||
|
||||
class ItemList extends React.Component {
|
||||
|
||||
constructor() {
|
||||
@ -6,34 +8,32 @@ class ItemList extends React.Component {
|
||||
this.scrollTop_ = 0;
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
updateStateItemIndexes(props) {
|
||||
if (typeof props === 'undefined') props = this.props;
|
||||
|
||||
const topItemIndex = Math.floor(this.scrollTop_ / props.itemHeight);
|
||||
const visibleItemCount = Math.ceil(props.style.height / props.itemHeight);
|
||||
|
||||
let bottomItemIndex = topItemIndex + visibleItemCount;
|
||||
if (bottomItemIndex >= props.items.length) bottomItemIndex = props.items.length - 1;
|
||||
|
||||
this.setState({
|
||||
topItemIndex: this.topItemIndex(),
|
||||
bottomItemIndex: this.bottomItemIndex(),
|
||||
topItemIndex: topItemIndex,
|
||||
bottomItemIndex: bottomItemIndex,
|
||||
});
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.updateStateItemIndexes();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps) {
|
||||
this.updateStateItemIndexes(newProps);
|
||||
}
|
||||
|
||||
onScroll(scrollTop) {
|
||||
this.scrollTop_ = scrollTop;
|
||||
|
||||
this.setState({
|
||||
topItemIndex: this.topItemIndex(),
|
||||
bottomItemIndex: this.bottomItemIndex(),
|
||||
});
|
||||
}
|
||||
|
||||
topItemIndex() {
|
||||
return Math.floor(this.scrollTop_ / this.props.itemHeight);
|
||||
}
|
||||
|
||||
visibleItemCount() {
|
||||
return Math.ceil(this.props.style.height / this.props.itemHeight);
|
||||
}
|
||||
|
||||
bottomItemIndex() {
|
||||
let r = this.topItemIndex() + this.visibleItemCount();
|
||||
if (r >= this.props.items.length) r = this.props.items.length - 1;
|
||||
return r;
|
||||
this.updateStateItemIndexes();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -1,4 +1,6 @@
|
||||
const { ItemList } = require('./ItemList.min.js');
|
||||
const React = require('react');
|
||||
const { connect } = require('react-redux');
|
||||
|
||||
class NoteListComponent extends React.Component {
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
//const { BaseModel } = require('lib/base-model.js');
|
||||
|
||||
const React = require('react');
|
||||
const { connect } = require('react-redux');
|
||||
|
||||
class NoteTextComponent extends React.Component {
|
||||
|
||||
componentWillMount() {
|
||||
|
@ -3,13 +3,47 @@ const { render } = require('react-dom');
|
||||
const { createStore } = require('redux');
|
||||
const { connect, Provider } = require('react-redux');
|
||||
|
||||
const { NoteList } = require('./gui/NoteList.min.js');
|
||||
const { NoteText } = require('./gui/NoteText.min.js');
|
||||
const { NoteList } = require('./NoteList.min.js');
|
||||
const { NoteText } = require('./NoteText.min.js');
|
||||
|
||||
const { app } = require('electron').remote.require('./app');
|
||||
const { app } = require('../app');
|
||||
|
||||
const { bridge } = require('electron').remote.require('./bridge');
|
||||
|
||||
//const { app } = require('electron').remote.require('./app');
|
||||
|
||||
async function initialize(dispatch) {
|
||||
bridge().window().on('resize', function() {
|
||||
store.dispatch({
|
||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
||||
size: bridge().windowContentSize(),
|
||||
});
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
||||
size: bridge().windowContentSize(),
|
||||
});
|
||||
}
|
||||
|
||||
class ReactRootComponent extends React.Component {
|
||||
|
||||
async componentDidMount() {
|
||||
if (this.props.appState == 'starting') {
|
||||
this.props.dispatch({
|
||||
type: 'SET_APP_STATE',
|
||||
state: 'initializing',
|
||||
});
|
||||
|
||||
await initialize(this.props.dispatch);
|
||||
|
||||
this.props.dispatch({
|
||||
type: 'SET_APP_STATE',
|
||||
state: 'ready',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const style = {
|
||||
width: this.props.size.width,
|
||||
@ -33,7 +67,7 @@ class ReactRootComponent extends React.Component {
|
||||
return (
|
||||
<div style={style}>
|
||||
<NoteList itemHeight={40} style={noteListStyle}></NoteList>
|
||||
<NoteText style={noteTextStyle}></NoteText>
|
||||
{/*<NoteText style={noteTextStyle}></NoteText>*/}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -43,6 +77,7 @@ class ReactRootComponent extends React.Component {
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
size: state.windowContentSize,
|
||||
appState: state.appState,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="react-root"></div>
|
||||
<script src="gui/Root.min.js"></script>
|
||||
<!-- <script src="gui/Root.min.js"></script> -->
|
||||
<script src="main-html.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
40
ElectronClient/app/main-html.js
Normal file
40
ElectronClient/app/main-html.js
Normal file
@ -0,0 +1,40 @@
|
||||
// Make it possible to require("/lib/...") without specifying full path
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
const { app } = require('./app.js');
|
||||
const { Folder } = require('lib/models/folder.js');
|
||||
const { Resource } = require('lib/models/resource.js');
|
||||
const { BaseItem } = require('lib/models/base-item.js');
|
||||
const { Note } = require('lib/models/note.js');
|
||||
const { Tag } = require('lib/models/tag.js');
|
||||
const { NoteTag } = require('lib/models/note-tag.js');
|
||||
const { Setting } = require('lib/models/setting.js');
|
||||
const { Logger } = require('lib/logger.js');
|
||||
const { FsDriverNode } = require('lib/fs-driver-node.js');
|
||||
const { shimInit } = require('lib/shim-init-node.js');
|
||||
|
||||
const { bridge } = require('electron').remote.require('./bridge');
|
||||
|
||||
const fsDriver = new FsDriverNode();
|
||||
Logger.fsDriver_ = fsDriver;
|
||||
Resource.fsDriver_ = fsDriver;
|
||||
|
||||
// That's not good, but it's to avoid circular dependency issues
|
||||
// in the BaseItem class.
|
||||
BaseItem.loadClass('Note', Note);
|
||||
BaseItem.loadClass('Folder', Folder);
|
||||
BaseItem.loadClass('Resource', Resource);
|
||||
BaseItem.loadClass('Tag', Tag);
|
||||
BaseItem.loadClass('NoteTag', NoteTag);
|
||||
|
||||
Setting.setConstant('appId', 'net.cozic.joplin-desktop');
|
||||
Setting.setConstant('appType', 'desktop');
|
||||
|
||||
shimInit();
|
||||
|
||||
app().start(bridge().processArgv()).then(() => {
|
||||
require('./gui/Root.min.js');
|
||||
}).catch((error) => {
|
||||
console.error('Fatal error:');
|
||||
console.error(error);
|
||||
});
|
@ -2,43 +2,61 @@
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
const electronApp = require('electron').app;
|
||||
const { initApp } = require('./app.js');
|
||||
const { Folder } = require('lib/models/folder.js');
|
||||
const { Resource } = require('lib/models/resource.js');
|
||||
const { BaseItem } = require('lib/models/base-item.js');
|
||||
const { Note } = require('lib/models/note.js');
|
||||
const { Tag } = require('lib/models/tag.js');
|
||||
const { NoteTag } = require('lib/models/note-tag.js');
|
||||
const { Setting } = require('lib/models/setting.js');
|
||||
const { Logger } = require('lib/logger.js');
|
||||
const { FsDriverNode } = require('lib/fs-driver-node.js');
|
||||
const { shimInit } = require('lib/shim-init-node.js');
|
||||
const { ElectronAppWrapper } = require('./ElectronAppWrapper');
|
||||
const { initBridge } = require('./bridge');
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
const fsDriver = new FsDriverNode();
|
||||
Logger.fsDriver_ = fsDriver;
|
||||
Resource.fsDriver_ = fsDriver;
|
||||
const wrapper = new ElectronAppWrapper(electronApp);
|
||||
|
||||
// That's not good, but it's to avoid circular dependency issues
|
||||
// in the BaseItem class.
|
||||
BaseItem.loadClass('Note', Note);
|
||||
BaseItem.loadClass('Folder', Folder);
|
||||
BaseItem.loadClass('Resource', Resource);
|
||||
BaseItem.loadClass('Tag', Tag);
|
||||
BaseItem.loadClass('NoteTag', NoteTag);
|
||||
initBridge(wrapper);
|
||||
|
||||
Setting.setConstant('appId', 'net.cozic.joplin-desktop');
|
||||
Setting.setConstant('appType', 'desktop');
|
||||
|
||||
shimInit();
|
||||
|
||||
const app = initApp(electronApp);
|
||||
|
||||
app.start(process.argv).catch((error) => {
|
||||
console.error('Fatal error:');
|
||||
wrapper.start().catch((error) => {
|
||||
console.error('Electron App fatal error:');
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
// const electronApp = require('electron').app;
|
||||
// const { initApp } = require('./app.js');
|
||||
// const { Folder } = require('lib/models/folder.js');
|
||||
// const { Resource } = require('lib/models/resource.js');
|
||||
// const { BaseItem } = require('lib/models/base-item.js');
|
||||
// const { Note } = require('lib/models/note.js');
|
||||
// const { Tag } = require('lib/models/tag.js');
|
||||
// const { NoteTag } = require('lib/models/note-tag.js');
|
||||
// const { Setting } = require('lib/models/setting.js');
|
||||
// const { Logger } = require('lib/logger.js');
|
||||
// const { FsDriverNode } = require('lib/fs-driver-node.js');
|
||||
// const { shimInit } = require('lib/shim-init-node.js');
|
||||
|
||||
// process.on('unhandledRejection', (reason, p) => {
|
||||
// console.error('Unhandled promise rejection', p, 'reason:', reason);
|
||||
// process.exit(1);
|
||||
// });
|
||||
|
||||
// const fsDriver = new FsDriverNode();
|
||||
// Logger.fsDriver_ = fsDriver;
|
||||
// Resource.fsDriver_ = fsDriver;
|
||||
|
||||
// // That's not good, but it's to avoid circular dependency issues
|
||||
// // in the BaseItem class.
|
||||
// BaseItem.loadClass('Note', Note);
|
||||
// BaseItem.loadClass('Folder', Folder);
|
||||
// BaseItem.loadClass('Resource', Resource);
|
||||
// BaseItem.loadClass('Tag', Tag);
|
||||
// BaseItem.loadClass('NoteTag', NoteTag);
|
||||
|
||||
// Setting.setConstant('appId', 'net.cozic.joplin-desktop');
|
||||
// Setting.setConstant('appType', 'desktop');
|
||||
|
||||
// shimInit();
|
||||
|
||||
// const app = initApp(electronApp);
|
||||
|
||||
// app.start(process.argv).catch((error) => {
|
||||
// console.error('Fatal error:');
|
||||
// console.error(error);
|
||||
// });
|
@ -192,6 +192,10 @@ class BaseApplication {
|
||||
return o.join(', ');
|
||||
}
|
||||
|
||||
hasGui() {
|
||||
return false;
|
||||
}
|
||||
|
||||
generalMiddleware() {
|
||||
const middleware = store => next => async (action) => {
|
||||
this.logger().debug('Reducer action', this.reducerActionToString(action));
|
||||
@ -213,7 +217,7 @@ class BaseApplication {
|
||||
await this.refreshNotes(BaseModel.TYPE_SEARCH, action.id);
|
||||
}
|
||||
|
||||
if (this.gui() && action.type == 'SETTINGS_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTINGS_UPDATE_ALL') {
|
||||
if (this.hasGui() && action.type == 'SETTINGS_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTINGS_UPDATE_ALL') {
|
||||
reg.setupRecurrentSync();
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,12 @@ shim.fs = null;
|
||||
shim.FileApiDriverLocal = null;
|
||||
shim.readLocalFileBase64 = () => { throw new Error('Not implemented'); }
|
||||
shim.uploadBlob = () => { throw new Error('Not implemented'); }
|
||||
shim.setInterval = setInterval;
|
||||
shim.clearInterval = clearInterval;
|
||||
shim.setInterval = function(fn, interval) {
|
||||
return setInterval(fn, interval);
|
||||
}
|
||||
shim.clearInterval = function(id) {
|
||||
return clearInterval(id);
|
||||
}
|
||||
shim.detectAndSetLocale = null;
|
||||
|
||||
module.exports = { shim };
|
Loading…
Reference in New Issue
Block a user