Refactoring + mise en place store Redux
This commit is contained in:
parent
324c267f8a
commit
06c809a114
|
@ -2,30 +2,30 @@
|
|||
"items": [
|
||||
{
|
||||
"label": "Level 1",
|
||||
"icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png",
|
||||
"icon": "chromium-browser",
|
||||
"items": [
|
||||
{
|
||||
"label": "Level 2-1",
|
||||
"icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png",
|
||||
"icon": "chromium-browser",
|
||||
"items": [
|
||||
{
|
||||
"label": "Chromium Browser",
|
||||
"icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png",
|
||||
"icon": "chromium-browser",
|
||||
"exec": "/usr/bin/chromium-browser"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Level 2-2",
|
||||
"icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png",
|
||||
"icon": "chromium-browser",
|
||||
"items": [
|
||||
{
|
||||
"label": "Level 3-1",
|
||||
"icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png",
|
||||
"icon": "chromium-browser",
|
||||
"items": [
|
||||
{
|
||||
"label": "Chromium Browser",
|
||||
"icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png",
|
||||
"icon": "chromium-browser",
|
||||
"exec": "/usr/bin/chromium-browser"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
exports.mauncher = require('./launcher');
|
||||
exports.launcher = require('./launcher');
|
||||
exports.edit = require('./edit');
|
||||
|
|
|
@ -4,20 +4,48 @@ var LOAD_PROFILE = exports.LOAD_PROFILE = 'LOAD_PROFILE';
|
|||
var LOAD_PROFILE_SUCCESS = exports.LOAD_PROFILE_SUCCESS = 'LOAD_PROFILE_SUCCESS';
|
||||
var LOAD_PROFILE_FAILED = exports.LOAD_PROFILE_FAILED = 'LOAD_PROFILE_FAILED';
|
||||
|
||||
var RUN_APP = exports.RUN_APP = 'RUN_APP';
|
||||
var RUN_APP_SUCCESS = exports.RUN_APP_SUCCESS = 'RUN_APP_SUCCESS';
|
||||
var RUN_APP_FAILED = exports.RUN_APP_FAILED = 'RUN_APP_FAILED';
|
||||
|
||||
exports.loadProfile = function(profilePath) {
|
||||
|
||||
return function(dispatch, getState) {
|
||||
|
||||
dispatch({ type: LOAD_PROFILE });
|
||||
dispatch({ type: LOAD_PROFILE, profilePath: profilePath });
|
||||
|
||||
return Util.System.loadJSONFile(profilePath)
|
||||
.then(function(profile) {
|
||||
dispatch({ type: LOAD_PROFILE_SUCCESS, profile: profile });
|
||||
return profile;
|
||||
})
|
||||
.catch(function(err) {
|
||||
dispatch({ type: LOAD_PROFILE_FAILED, error: err });
|
||||
return err;
|
||||
})
|
||||
;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
exports.runApp = function(execPath) {
|
||||
|
||||
return function(dispatch, getState) {
|
||||
|
||||
dispatch({ type: RUN_APP, execPath: execPath });
|
||||
|
||||
return Util.System.runApp(execPath)
|
||||
.then(function() {
|
||||
dispatch({ type: RUN_APP_SUCCESS, execPath: execPath });
|
||||
return execPath;
|
||||
})
|
||||
.catch(function(err) {
|
||||
dispatch({ type: RUN_APP_FAILED, error: err });
|
||||
return err;
|
||||
})
|
||||
;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
|
50
js/app.jsx
50
js/app.jsx
|
@ -1,33 +1,23 @@
|
|||
var React = require('react');
|
||||
var minimist = require('minimist');
|
||||
var gui = global.window.require('nw.gui');
|
||||
var LauncherView = require('./components/launcher-view.jsx');
|
||||
var EditView = require('./components/edit-view.jsx');
|
||||
var LauncherView = require('./components/launcher/launcher-view.jsx');
|
||||
var EditView = require('./components/edit/edit-view.jsx');
|
||||
var Provider = require('react-redux').Provider;
|
||||
var stores = require('./stores');
|
||||
|
||||
// Internal constants
|
||||
var DEFAULT_PROFILE = './default-profile.json';
|
||||
var PROCESS_OPTS = minimist(gui.App.argv);
|
||||
var connect = require('react-redux').connect;
|
||||
var store = require('./store');
|
||||
|
||||
// Main component
|
||||
var App = React.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
profilePath: PROCESS_OPTS.profile,
|
||||
editMode: PROCESS_OPTS.edit || false
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var view = this.state.editMode ?
|
||||
<Provider store={stores.editStore}>
|
||||
{ function() { return <EditView profilePath={this.state.profilePath} />; }.bind(this) }
|
||||
var editMode = this.props.processOpts.edit || false;
|
||||
|
||||
var view = editMode ?
|
||||
<Provider store={store}>
|
||||
{ function() { return <EditView />; }.bind(this) }
|
||||
</Provider> :
|
||||
<Provider store={stores.launcherStore}>
|
||||
{ function() { return <LauncherView profilePath={this.state.profilePath ? this.state.profilePath : DEFAULT_PROFILE } />; }.bind(this) }
|
||||
<Provider store={store}>
|
||||
{ function() { return <LauncherView />; }.bind(this) }
|
||||
</Provider>
|
||||
;
|
||||
|
||||
|
@ -41,4 +31,20 @@ var App = React.createClass({
|
|||
|
||||
});
|
||||
|
||||
React.render(<App />, document.body);
|
||||
// Select props to inject from store state
|
||||
function select(state) {
|
||||
return {
|
||||
processOpts: state.processOpts
|
||||
}
|
||||
}
|
||||
|
||||
// Connect App to Redux store
|
||||
App = connect(select)(App);
|
||||
|
||||
React.render(
|
||||
<Provider store={store}>
|
||||
{ function() { return <App />; } }
|
||||
</Provider>
|
||||
,
|
||||
document.body
|
||||
);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var React = require('react');
|
||||
var Util = require('../util');
|
||||
var LazyLoad = require('./mixins/lazy-load');
|
||||
var Util = require('../../util');
|
||||
var LazyLoad = require('../mixins/lazy-load');
|
||||
var debug = Util.Debug('common:app-icon');
|
||||
|
||||
var LOADING_ICON = 'img/hourglass.svg';
|
||||
var DEFAULT_ICON = 'img/default-icon.svg';
|
||||
|
@ -50,7 +51,7 @@ module.exports = React.createClass({
|
|||
|
||||
var self = this;
|
||||
|
||||
console.log('Search icon %s:%s', iconPath, theme);
|
||||
debug('Search icon %s:%s', iconPath, theme);
|
||||
|
||||
Util.DesktopApps.findIcon(iconPath || DEFAULT_ICON, theme)
|
||||
.then(function(iconPath) {
|
||||
|
@ -60,9 +61,7 @@ module.exports = React.createClass({
|
|||
return iconPath;
|
||||
})
|
||||
.then(function(iconPath) {
|
||||
global.window.requestAnimationFrame(function() {
|
||||
self.setState({ icon: iconPath });
|
||||
});
|
||||
self.setState({ icon: iconPath });
|
||||
})
|
||||
;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
var React = require('react');
|
||||
var Util = require('../util');
|
||||
var AppIcon = require('./app-icon.jsx');
|
||||
var Util = require('../../util');
|
||||
var AppIcon = require('../common/app-icon.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
var React = require('react');
|
||||
var Util = require('../util');
|
||||
var Util = require('../../util');
|
||||
var DesktopAppItem = require('./desktop-app-item.jsx');
|
||||
var IconThemeSelector = require('./icon-theme-selector.jsx');
|
||||
var path = require('path');
|
|
@ -1,7 +1,7 @@
|
|||
var React = require('react');
|
||||
var connect = require('react-redux').connect;
|
||||
var DesktopAppList = require('./desktop-app-list.jsx');
|
||||
var actions = require('../actions');
|
||||
var actions = require('../../actions');
|
||||
|
||||
var EditView = React.createClass({
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
var React = require('react');
|
||||
var Util = require('../util');
|
||||
var Util = require('../../util');
|
||||
|
||||
module.exports = React.createClass({
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
var React = require('react');
|
||||
var AppIcon = require('../common/app-icon.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
|
||||
|
@ -19,7 +20,7 @@ module.exports = React.createClass({
|
|||
render: function() {
|
||||
return (
|
||||
<li className="app-item" onClick={this._onItemClick}>
|
||||
<img className="app-icon" src={this.props.item.icon} />
|
||||
<AppIcon icon={this.props.item.icon} theme={null} />
|
||||
<span className="app-label">{this.props.item.label}</span>
|
||||
</li>
|
||||
);
|
|
@ -1,17 +1,17 @@
|
|||
var React = require('react');
|
||||
var Util = require('../util');
|
||||
var CategoryHeader = require('./category-header.jsx');
|
||||
var AppList = require('./app-list.jsx');
|
||||
var AnimateMixin = require('./mixins/animate');
|
||||
var AnimateMixin = require('../mixins/animate');
|
||||
var actions = require('../../actions');
|
||||
var connect = require('react-redux').connect;
|
||||
var debug = require('../../util/debug')('launcher-view');
|
||||
|
||||
module.exports = React.createClass({
|
||||
var DEFAULT_PROFILE = './default-profile.json';
|
||||
|
||||
var LauncherView = React.createClass({
|
||||
|
||||
mixins: [AnimateMixin],
|
||||
|
||||
propTypes: {
|
||||
profilePath: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
currentItemPath: '',
|
||||
|
@ -20,20 +20,20 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
var profilePath = this.props.processOpts.profile || DEFAULT_PROFILE;
|
||||
this.props.dispatch(actions.launcher.loadProfile(profilePath));
|
||||
},
|
||||
|
||||
// Load profile on component mount
|
||||
Util.System.loadJSONFile(this.props.profilePath)
|
||||
.then(function(profile) {
|
||||
this.setState({ profile: profile, currentItem: profile, currentItemPath: '' });
|
||||
}.bind(this))
|
||||
;
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
if( nextProps.profile && !this.state.currentItem ) {
|
||||
this.setState({ currentItem: nextProps.profile });
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var currentItem = this.state.currentItem;
|
||||
var items = currentItem ? currentItem.items : [];
|
||||
var items = currentItem && currentItem.items ? currentItem.items : [];
|
||||
var currentItemPath = this.state.currentItemPath;
|
||||
|
||||
var header = currentItemPath !== '' ?
|
||||
|
@ -59,7 +59,7 @@ module.exports = React.createClass({
|
|||
onBackClick: function(itemPath) {
|
||||
|
||||
var parentPath = this._normalizeItemPath(itemPath).slice(0, -1);
|
||||
var parentItem = this._getItemByPath(parentPath);
|
||||
var parentItem = this._getItemByPath(parentPath, this.props.profile);
|
||||
|
||||
this.play(this.refs.appList, 'slide-out-right 250ms ease-in-out')
|
||||
.then(function() {
|
||||
|
@ -74,15 +74,16 @@ module.exports = React.createClass({
|
|||
|
||||
if(item.exec) {
|
||||
|
||||
console.info('Launching application "'+item.exec+'"...');
|
||||
evt.currentTarget.classList.add('pulse');
|
||||
debug('Launching application "'+item.exec+'"...');
|
||||
var el = evt.currentTarget;
|
||||
el.classList.add('pulse');
|
||||
|
||||
Util.System.runApp(item.exec)
|
||||
this.props.dispatch(actions.launcher.runApp(item.exec))
|
||||
.then(function() {
|
||||
evt.currentTarget.classList.remove('pulse');
|
||||
el.classList.remove('pulse');
|
||||
})
|
||||
.catch(function(err) {
|
||||
evt.currentTarget.classList.remove('pulse');
|
||||
.catch(function() {
|
||||
el.classList.remove('pulse');
|
||||
})
|
||||
;
|
||||
|
||||
|
@ -99,7 +100,6 @@ module.exports = React.createClass({
|
|||
|
||||
_getItemByPath: function(itemPath, rootItem) {
|
||||
|
||||
rootItem = rootItem || this.state.profile;
|
||||
itemPath = this._normalizeItemPath(itemPath);
|
||||
|
||||
var itemIndex = itemPath[0];
|
||||
|
@ -138,3 +138,14 @@ module.exports = React.createClass({
|
|||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
function select(state) {
|
||||
return {
|
||||
processOpts: state.processOpts,
|
||||
profile: state.profile
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
module.exports = connect(select)(LauncherView);
|
|
@ -0,0 +1,16 @@
|
|||
var redux = require('redux');
|
||||
var thunkMiddleware = require('redux-thunk');
|
||||
var loggerMiddleware = require('redux-logger');
|
||||
var reducers = require('./reducers');
|
||||
|
||||
var createStore = redux.applyMiddleware(
|
||||
thunkMiddleware
|
||||
)(redux.createStore);
|
||||
|
||||
var appReducer = redux.combineReducers({
|
||||
profile: reducers.profile,
|
||||
processOpts: reducers.processOpts,
|
||||
desktopApps: reducers.desktopApps
|
||||
});
|
||||
|
||||
module.exports = createStore(appReducer);
|
|
@ -0,0 +1,17 @@
|
|||
var actions = require('../../actions');
|
||||
|
||||
module.exports = function(oldProfile, action) {
|
||||
|
||||
var newProfile = oldProfile || null;
|
||||
|
||||
switch(action.type) {
|
||||
|
||||
case actions.launcher.LOAD_PROFILE_SUCCESS:
|
||||
newProfile = action.profile;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return newProfile;
|
||||
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
var redux = require('redux');
|
||||
var thunkMiddleware = require('redux-thunk');
|
||||
var loggerMiddleware = require('redux-logger');
|
||||
var reducers = require('./reducers');
|
||||
|
||||
var createStoreWithMiddleware = redux.applyMiddleware(
|
||||
thunkMiddleware
|
||||
)(redux.createStore);
|
||||
|
||||
var launcherReducers = redux.combineReducers({
|
||||
profile: reducers.profile,
|
||||
processOpts: reducers.processOpts
|
||||
});
|
||||
|
||||
var editReducers = redux.combineReducers({
|
||||
desktopApps: reducers.desktopApps,
|
||||
processOpts: reducers.processOpts
|
||||
});
|
||||
|
||||
exports.launcherStore = createStoreWithMiddleware(launcherReducers);
|
||||
exports.editStore = createStoreWithMiddleware(editReducers);
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = function(state, action) {
|
||||
return {};
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
var debug = require('debug');
|
||||
var util = require('util');
|
||||
|
||||
module.exports = function createLogger(namespace) {
|
||||
var logger = debug('pitaya:'+namespace);
|
||||
var console = global.window ? global.window.console : global.console;
|
||||
logger.log = function() {
|
||||
var str = util.format.apply(util, arguments);
|
||||
console.log(str);
|
||||
};
|
||||
return logger;
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
var path = require('path');
|
||||
var System = require('./system');
|
||||
var debug = require('debug')('pitaya:desktop-apps');
|
||||
var debug = require('./debug')('desktop-apps');
|
||||
var Cache = require('./cache');
|
||||
|
||||
// Constants
|
||||
var ICON_REALPATH_REGEX = /\..+$/;
|
||||
|
@ -69,6 +70,8 @@ exports.loadDesktopFile = function(filePath) {
|
|||
return System.loadINIFile(filePath);
|
||||
};
|
||||
|
||||
var iconCache = new Cache();
|
||||
|
||||
/**
|
||||
* Find the absolute path of a desktop icon
|
||||
*
|
||||
|
@ -77,6 +80,13 @@ exports.loadDesktopFile = function(filePath) {
|
|||
*/
|
||||
exports.findIcon = function(iconName, themeName, size, themeIgnore) {
|
||||
|
||||
var cachedIcon = iconCache.get([iconName, themeName, size]);
|
||||
|
||||
if(cachedIcon) {
|
||||
debug('Icon %s:%s:%s found in cache !', iconName, themeName, size);
|
||||
return Promise.resolve(cachedIcon);
|
||||
}
|
||||
|
||||
themeIgnore = themeIgnore || [];
|
||||
if(themeIgnore.indexOf(themeIgnore) !== -1) {
|
||||
debug('Theme %s already processed, ignoring...', themeName);
|
||||
|
@ -101,6 +111,7 @@ exports.findIcon = function(iconName, themeName, size, themeIgnore) {
|
|||
.then(exports._selectBestIcon)
|
||||
;
|
||||
})
|
||||
.then(_cacheIcon)
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -122,8 +133,15 @@ exports.findIcon = function(iconName, themeName, size, themeIgnore) {
|
|||
;
|
||||
|
||||
})
|
||||
.then(_cacheIcon)
|
||||
;
|
||||
|
||||
|
||||
function _cacheIcon(iconPath) {
|
||||
iconCache.set([iconName, themeName, size], iconPath);
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.findParentsThemeIcon = function(iconName, themeName, size, themeIgnore) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
exports.System = require('./system');
|
||||
exports.DesktopApps = require('./desktop-apps');
|
||||
exports.Cache = require('./cache');
|
||||
exports.Debug = require('./debug');
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
"react-dnd": "^1.1.5",
|
||||
"react-redux": "^2.0.0",
|
||||
"redux": "^2.0.0",
|
||||
"redux-logger": "^1.0.6",
|
||||
"redux-thunk": "^0.1.0"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue