From 09735b7f47fdcfbedf805ab09ff5a308bf00a637 Mon Sep 17 00:00:00 2001 From: Rokt33r Date: Fri, 8 Jan 2016 14:38:29 +0900 Subject: [PATCH] embed hotkey, config to preferences modal & fix datasaving sequence(Async, Queue) --- browser/components/CodeEditor.js | 100 ++++++++++--- browser/components/MarkdownPreview.js | 46 +++--- browser/finder/FinderDetail.js | 2 +- browser/lib/dataStore.js | 32 ++++- .../HomePage/ArticleDetail/ArticleEditor.js | 34 +++-- browser/main/HomePage/ArticleDetail/index.js | 136 +++++++----------- browser/main/HomePage/ArticleList.js | 2 +- browser/main/modal/CreateNewFolder.js | 2 +- .../main/modal/Preference/AppSettingTab.js | 87 +++++++++-- browser/main/modal/Tutorial.js | 2 +- browser/styles/main/modal/Preferences.styl | 32 ++++- lib/config.js | 53 +++++++ lib/hotkey.js | 126 ++++++++++------ lib/main-app.js | 1 + 14 files changed, 461 insertions(+), 194 deletions(-) create mode 100644 lib/config.js diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 952e026e..830cb48b 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -3,10 +3,35 @@ import ReactDOM from 'react-dom' import modes from '../lib/modes' import _ from 'lodash' -const remote = require('electron').remote +const electron = require('electron') +const remote = electron.remote +const ipc = electron.ipcRenderer + const ace = window.ace +function getConfig () { + return Object.assign({}, remote.getGlobal('config')) +} + +let config = getConfig() + export default class CodeEditor extends React.Component { + constructor (props) { + super(props) + + this.configApplyHandler = e => this.handleConfigApply(e) + this.changeHandler = e => this.handleChange(e) + + this.state = { + fontSize: config['editor-font-size'], + fontFamily: config['editor-font-family'], + indentType: config['editor-indent-type'], + indentSize: config['editor-indent-size'] + } + + this.silentChange = false + } + componentWillReceiveProps (nextProps) { if (nextProps.readOnly !== this.props.readOnly) { this.editor.setReadOnly(!!nextProps.readOnly) @@ -14,6 +39,7 @@ export default class CodeEditor extends React.Component { } componentDidMount () { + let { article } = this.props var el = ReactDOM.findDOMNode(this) var editor = this.editor = ace.edit(el) editor.$blockScrolling = Infinity @@ -21,6 +47,7 @@ export default class CodeEditor extends React.Component { editor.setTheme('ace/theme/xcode') editor.moveCursorTo(0, 0) editor.setReadOnly(!!this.props.readOnly) + editor.setFontSize(this.state.fontSize) editor.commands.addCommand({ name: 'Emacs cursor up', @@ -45,32 +72,38 @@ export default class CodeEditor extends React.Component { }) var session = editor.getSession() - let mode = _.findWhere(modes, {name: this.props.mode}) + let mode = _.findWhere(modes, {name: article.mode}) let syntaxMode = mode != null ? mode.mode : 'text' session.setMode('ace/mode/' + syntaxMode) - session.setUseSoftTabs(true) - session.setOption('useWorker', false) + session.setUseSoftTabs(this.state.indentType === 'space') + session.setTabSize(!isNaN(this.state.indentSize) ? parseInt(this.state.indentSize, 10) : 4) + session.setOption('useWorker', true) session.setUseWrapMode(true) - session.setValue(this.props.code) + session.setValue(this.props.article.content) - session.on('change', e => { - if (this.props.onChange != null) { - var value = editor.getValue() - this.props.onChange(e, value) - } - }) + session.on('change', this.changeHandler) + + ipc.on('config-apply', this.configApplyHandler) } - componentDidUpdate (prevProps) { + componentWillUnmount () { + ipc.removeListener('config-apply', this.configApplyHandler) + this.editor.getSession().removeListener('change', this.changeHandler) + } + + componentDidUpdate (prevProps, prevState) { var session = this.editor.getSession() - if (this.editor.getValue() !== this.props.code) { - session.setValue(this.props.code) + if (this.props.article.key !== prevProps.article.key) { + session.removeListener('change', this.changeHandler) + session.setValue(this.props.article.content) + session.getUndoManager().reset() + session.on('change', this.changeHandler) } - if (prevProps.mode !== this.props.mode) { - let mode = _.findWhere(modes, {name: this.props.mode}) + if (prevProps.article.mode !== this.props.article.mode) { + let mode = _.findWhere(modes, {name: this.props.article.mode}) let syntaxMode = mode != null ? mode.mode : 'text' @@ -78,6 +111,26 @@ export default class CodeEditor extends React.Component { } } + handleConfigApply () { + config = getConfig() + this.setState({ + fontSize: config['editor-font-size'], + fontFamily: config['editor-font-family'], + indentType: config['editor-indent-type'], + indentSize: config['editor-indent-size'] + }, function () { + var session = this.editor.getSession() + session.setUseSoftTabs(this.state.indentType === 'space') + session.setTabSize(!isNaN(this.state.indentSize) ? parseInt(this.state.indentSize, 10) : 4) + }) + } + handleChange (e) { + if (this.props.onChange) { + var value = this.editor.getValue() + this.props.onChange(value) + } + } + getFirstVisibleRow () { return this.editor.getFirstVisibleRow() } @@ -96,14 +149,23 @@ export default class CodeEditor extends React.Component { render () { return ( -
+
) } } CodeEditor.propTypes = { - code: PropTypes.string, - mode: PropTypes.string, + article: PropTypes.shape({ + content: PropTypes.string, + mode: PropTypes.string, + key: PropTypes.string + }), className: PropTypes.string, onChange: PropTypes.func, onBlur: PropTypes.func, diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index 08f50b26..eddff52e 100644 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -2,11 +2,12 @@ import React, { PropTypes } from 'react' import markdown from '../lib/markdown' import ReactDOM from 'react-dom' import sanitizeHtml from '@rokt33r/sanitize-html' -import hljs from 'highlight.js' import _ from 'lodash' const electron = require('electron') const shell = electron.shell +const remote = electron.remote +const ipc = electron.ipcRenderer const katex = window.katex @@ -65,41 +66,43 @@ function math2Katex (display) { } } +function getConfig () { + return Object.assign({}, remote.getGlobal('config')) +} + +let config = getConfig() + export default class MarkdownPreview extends React.Component { + constructor (props) { + super(props) + + this.configApplyHandler = e => this.handleConfigApply(e) + + this.state = { + fontSize: config['preview-font-size'], + fontFamily: config['preview-font-family'] + } + } componentDidMount () { this.addListener() - // this.renderCode() this.renderMath() + ipc.on('config-apply', this.configApplyHandler) } componentDidUpdate () { this.addListener() - // this.renderCode() this.renderMath() } componentWillUnmount () { this.removeListener() + ipc.removeListener('config-apply', this.configApplyHandler) } componentWillUpdate () { this.removeListener() } - renderCode () { - let codes = ReactDOM.findDOMNode(this).querySelectorAll('code:not(.rendered)') - Array.prototype.forEach.call(codes, el => { - let matched = el.className.match(/language-(.+)/) - let lang = matched ? matched[1] : null - try { - let result = hljs.highlight(lang, el.innerHTML) - el.innerHTML = result.value - el.className += ' rendered' - } catch (e) { - } - }) - } - renderMath () { let inline = ReactDOM.findDOMNode(this).querySelectorAll('span.math') Array.prototype.forEach.call(inline, math2Katex(false)) @@ -157,6 +160,14 @@ export default class MarkdownPreview extends React.Component { } } + handleConfigApply () { + config = getConfig() + this.setState({ + fontSize: config['preview-font-size'], + fontFamily: config['preview-font-family'] + }) + } + render () { let isEmpty = this.props.content.trim().length === 0 let content = isEmpty @@ -174,6 +185,7 @@ export default class MarkdownPreview extends React.Component { onMouseMove={e => this.handleMouseMove(e)} onMouseUp={e => this.handleMouseUp(e)} dangerouslySetInnerHTML={{__html: ' ' + content}} + style={{fontSize: this.state.fontSize, fontFamily: this.state.fontFamily}} /> ) } diff --git a/browser/finder/FinderDetail.js b/browser/finder/FinderDetail.js index de815e27..5e4cfc3f 100644 --- a/browser/finder/FinderDetail.js +++ b/browser/finder/FinderDetail.js @@ -24,7 +24,7 @@ export default class FinderDetail extends React.Component {
{activeArticle.mode === 'markdown' ? - : + : }
diff --git a/browser/lib/dataStore.js b/browser/lib/dataStore.js index e116b71a..14a53860 100644 --- a/browser/lib/dataStore.js +++ b/browser/lib/dataStore.js @@ -105,7 +105,7 @@ export function init () { folders: [defaultFolder], version: '0.4' } - jetpack.write(getLocalPath(), data) + queueSave() } } @@ -114,18 +114,44 @@ export function getData () { return data } +let timer = null +let isSaving = false +let saveAgain = false +function saveData () { + timer = null + isSaving = true + jetpack.writeAsync(getLocalPath(), data) + .then(function () { + isSaving = false + if (saveAgain) { + saveAgain = false + queueSave() + } + }) +} +function queueSave () { + if (!isSaving) { + if (timer) { + clearTimeout(timer) + } + timer = setTimeout(saveData, 3000) + } else { + saveAgain = true + } +} + export function setArticles (articles) { if (!_.isArray(articles)) throw new Error('Articles must be an array') let data = getData() data.articles = articles - jetpack.write(getLocalPath(), data) + queueSave() } export function setFolders (folders) { if (!_.isArray(folders)) throw new Error('Folders must be an array') let data = getData() data.folders = folders - jetpack.write(getLocalPath(), data) + queueSave() } function isFinderCalled () { diff --git a/browser/main/HomePage/ArticleDetail/ArticleEditor.js b/browser/main/HomePage/ArticleDetail/ArticleEditor.js index 2718283e..42a24e1e 100644 --- a/browser/main/HomePage/ArticleDetail/ArticleEditor.js +++ b/browser/main/HomePage/ArticleDetail/ArticleEditor.js @@ -17,6 +17,14 @@ export default class ArticleEditor extends React.Component { } } + componentWillReceiveProps (nextProps) { + if (nextProps.article.key !== this.props.article.key) { + this.setState({ + content: this.props.article.content + }) + } + } + resetCursorPosition () { this.setState({ cursorPosition: null, @@ -77,13 +85,19 @@ export default class ArticleEditor extends React.Component { } handleBlurCodeEditor () { - if (this.props.mode === 'markdown') { + let { article } = this.props + if (article.mode === 'markdown') { this.switchPreviewMode() } } + handleCodeEditorChange (value) { + this.props.onChange(value) + } + render () { - let showPreview = this.props.mode === 'markdown' && this.state.status === PREVIEW_MODE + let { article } = this.props + let showPreview = article.mode === 'markdown' && this.state.status === PREVIEW_MODE if (showPreview) { return (
@@ -92,7 +106,7 @@ export default class ArticleEditor extends React.Component { onMouseUp={e => this.handlePreviewMouseUp(e)} onMouseDown={e => this.handlePreviewMouseDown(e)} onMouseMove={e => this.handlePreviewMouseMove(e)} - content={this.props.content} + content={article.content} />
Click to Edit
@@ -104,11 +118,10 @@ export default class ArticleEditor extends React.Component { this.handleBlurCodeEditor(e)} - onChange={this.props.onChange} - mode={this.props.mode} - code={this.props.content} + onChange={value => this.handleCodeEditorChange(value)} + article={article} /> - {this.props.mode === 'markdown' + {article.mode === 'markdown' ? (
Press ESC to watch Preview
) @@ -120,7 +133,10 @@ export default class ArticleEditor extends React.Component { } ArticleEditor.propTypes = { - content: PropTypes.string, - mode: PropTypes.string, + article: PropTypes.shape({ + content: PropTypes.string, + key: PropTypes.string, + mode: PropTypes.string + }), onChange: PropTypes.func } diff --git a/browser/main/HomePage/ArticleDetail/index.js b/browser/main/HomePage/ArticleDetail/index.js index e95b71fb..3e1188b9 100644 --- a/browser/main/HomePage/ArticleDetail/index.js +++ b/browser/main/HomePage/ArticleDetail/index.js @@ -18,9 +18,9 @@ import DeleteArticleModal from '../../modal/DeleteArticleModal' import ArticleEditor from './ArticleEditor' const electron = require('electron') const ipc = electron.ipcRenderer -const remote = electron.remote -const { Menu, MenuItem } = remote - +let count = 0 +// const remote = electron.remote +// const { Menu, MenuItem } = remote // const othersMenu = new Menu() // othersMenu.append(new MenuItem({ // label: 'Delete Post', @@ -152,18 +152,6 @@ export default class ArticleDetail extends React.Component { ipc.removeListener('detail-edit', this.editHandler) } - componentWillReceiveProps (nextProps) { - let nextArticle = nextProps.activeArticle - let nextModified = nextArticle != null ? _.findWhere(nextProps.modified, {key: nextArticle.key}) : null - - let article = Object.assign({content: ''}, nextProps.activeArticle, nextModified) - let nextState = { - article - } - - this.setState(nextState) - } - componentDidUpdate (prevProps, prevState) { if (this.props.activeArticle == null || prevProps.activeArticle == null || this.props.activeArticle.key !== prevProps.activeArticle.key) { this.refs.editor.resetCursorPosition() @@ -175,20 +163,6 @@ export default class ArticleDetail extends React.Component { ReactDOM.findDOMNode(this.refs.title).select() } - cacheArticle () { - let { dispatch, status, folders } = this.props - - let input = Object.assign({}, this.props.activeArticle.key, this.state.article, {updatedAt: new Date()}) - - dispatch(updateArticle(input)) - - let targetFolderKey = this.state.article.FolderKey - if (status.targetFolders.length > 0) { - let targetFolder = _.findWhere(folders, {key: targetFolderKey}) - dispatch(switchFolder(targetFolder.name)) - } - } - renderEmpty () { return (
@@ -199,68 +173,64 @@ export default class ArticleDetail extends React.Component { ) } - handleSaveButtonClick (e) { - // let { dispatch, folders, status } = this.props - - // let targetFolderKey = this.state.article.FolderKey - // dispatch(saveArticle(this.props.activeArticle.key, this.state.article), true) - // if (status.targetFolders.length > 0) { - // let targetFolder = _.findWhere(folders, {key: targetFolderKey}) - // dispatch(switchFolder(targetFolder.name)) - // } - } - handleOthersButtonClick (e) { this.deleteHandler() } handleFolderKeyChange (e) { - let article = this.state.article - article.FolderKey = e.target.value + let { dispatch, activeArticle, status, folders } = this.props + let article = Object.assign({}, activeArticle, { + FolderKey: e.target.value, + updatedAt: new Date() + }) - this.setState({article: article}, () => this.cacheArticle()) + dispatch(updateArticle(article)) + + let targetFolderKey = this.state.article.FolderKey + if (status.targetFolders.length > 0) { + let targetFolder = _.findWhere(folders, {key: targetFolderKey}) + dispatch(switchFolder(targetFolder.name)) + } } handleTitleChange (e) { - let { article } = this.state - article.title = e.target.value - - this.setState({ - article - }, () => this.cacheArticle()) + let { dispatch, activeArticle } = this.props + let article = Object.assign({}, activeArticle, { + title: e.target.value, + updatedAt: new Date() + }) + dispatch(updateArticle(article)) } handleTagsChange (newTag, tags) { - let article = this.state.article - article.tags = tags + let { dispatch, activeArticle } = this.props + let article = Object.assign({}, activeArticle, { + tags: tags, + updatedAt: new Date() + }) - this.setState({ - article - }, () => this.cacheArticle()) + dispatch(updateArticle(article)) } handleModeChange (value) { - let { article } = this.state - article.mode = value - this.setState({ - article - }, () => this.cacheArticle()) + let { dispatch, activeArticle } = this.props + let article = Object.assign({}, activeArticle, { + mode: value, + updatedAt: new Date() + }) + + dispatch(updateArticle(article)) } - handleContentChange (e, value) { - let { article } = this.state - article.content = value - - this.setState({ - article - }, () => this.cacheArticle()) - } - - handleCodeEditorBlur (e) { - if (this.state.article.mode === 'markdown' && !this.state.previewMode) { - this.setState({ - previewMode: true + handleContentChange (value) { + let { dispatch, activeArticle } = this.props + if (activeArticle.content !== value) { + let article = Object.assign({}, activeArticle, { + content: value, + updatedAt: new Date() }) + + dispatch(updateArticle(article)) } } @@ -270,13 +240,6 @@ export default class ArticleDetail extends React.Component { } } - handleUncache (e) { - if (this.props.activeArticle) { - let { dispatch, activeArticle } = this.props - dispatch(uncacheArticle(activeArticle.key)) - } - } - handleTitleKeyDown (e) { if (e.keyCode === 9 && !e.shiftKey) { e.preventDefault() @@ -312,7 +275,7 @@ export default class ArticleDetail extends React.Component {
this.handleConfigKeyDown(e)} type='text'/> +
+
+ + this.handleConfigKeyDown(e)} type='text'/> +
+
+ +
+ type + + size + +
+
+
+ + this.handleConfigKeyDown(e)} type='text'/> +
+
+ + this.handleConfigKeyDown(e)} type='text'/> +
+ { + true// !OSX + ? ( +
+ + this.handleConfigKeyDown(e)} type='checkbox'/> +
+ ) + : null + } + +
+ +
+
Hotkey
+
+ + this.handleKeyDown(e)} valueLink={this.linkState('keymap.toggleMain')} type='text'/> +
this.handleKeyDown(e)} valueLink={this.linkState('keymap.toggleFinder')} type='text'/> @@ -142,5 +210,8 @@ export default class AppSettingTab extends React.Component { AppSettingTab.prototype.linkState = linkState AppSettingTab.propTypes = { + user: PropTypes.shape({ + name: PropTypes.string + }), dispatch: PropTypes.func } diff --git a/browser/main/modal/Tutorial.js b/browser/main/modal/Tutorial.js index e76c3e10..737fe904 100644 --- a/browser/main/modal/Tutorial.js +++ b/browser/main/modal/Tutorial.js @@ -89,7 +89,7 @@ export default class Tutorial extends React.Component {
Easy to access with Finder
The Finder helps you organize all of the files and documents.
- There is a short-cut key [control + shift + tab] to open the Finder.
+ There is a short-cut key [⌘ + alt + s] to open the Finder.
It is available to save your articles on the Clipboard
by selecting your file with pressing Enter key,
and to paste the contents of the Clipboard with [{process.platform === 'darwin' ? 'Command' : 'Control'}-V] diff --git a/browser/styles/main/modal/Preferences.styl b/browser/styles/main/modal/Preferences.styl index 26f04971..8e759f18 100644 --- a/browser/styles/main/modal/Preferences.styl +++ b/browser/styles/main/modal/Preferences.styl @@ -89,6 +89,31 @@ iptFocusBorderColor = #369DCD outline none &:focus border-color iptFocusBorderColor + &>.sectionSelect + + margin-bottom 5px + clearfix() + height 33px + label + width 150px + padding-left 15px + float left + line-height 33px + .sectionSelect-input + float left + select + width 80px + height 25px + margin-top 4px + border-radius 5px + border 1px solid borderColor + padding 0 10px + font-size 14px + outline none + margin-left 5px + margin-right 15px + &:focus + border-color iptFocusBorderColor &>.sectionConfirm clearfix() padding 5px 15px @@ -624,10 +649,3 @@ iptFocusBorderColor = #369DCD color brandColor &:hover color lighten(brandColor, 10%) - - - - - - - diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 00000000..6c2632db --- /dev/null +++ b/lib/config.js @@ -0,0 +1,53 @@ +const electron = require('electron') +const app = electron.app +const ipc = electron.ipcMain +const jetpack = require('fs-jetpack') +const mainWindow = require('./main-window') + +const defaultConfig = { + 'editor-font-size': '14', + 'editor-font-family': 'Monaco, Ubuntu Mono, Consolas, source-code-pro, monospace', + 'editor-indent-type': 'space', + 'editor-indent-size': '4', + 'preview-font-size': '14', + 'preview-font-family': 'Lato, helvetica, arial, sans-serif', + 'disable-direct-write': false +} +const configFile = 'config.json' + +var userDataPath = app.getPath('userData') + +function getConfig () { + var userDataPath = app.getPath('userData') + if (jetpack.cwd(userDataPath).exists(configFile)) { + try { + return JSON.parse(jetpack.cwd(userDataPath).read(configFile, 'utf-8')) + } catch (err) {} + } + return {} +} + +function saveConfig () { + var content + try { + content = JSON.stringify(global.config) + } catch (e) { + global.config = {} + content = JSON.stringify(global.config) + } + jetpack.cwd(userDataPath).file(configFile, { content }) +} + +// Init +global.config = Object.assign({}, defaultConfig, getConfig()) + +function applyConfig () { + mainWindow.webContents.send('config-apply') +} + +ipc.on('configUpdated', function (event, newConfig) { + global.config = Object.assign({}, defaultConfig, global.config, newConfig) + saveConfig() + applyConfig() +}) + diff --git a/lib/hotkey.js b/lib/hotkey.js index 3ed4fd56..f1034878 100644 --- a/lib/hotkey.js +++ b/lib/hotkey.js @@ -1,54 +1,40 @@ const electron = require('electron') const app = electron.app const ipc = electron.ipcMain +const Menu = electron.Menu const globalShortcut = electron.globalShortcut const jetpack = require('fs-jetpack') const mainWindow = require('./main-window') const nodeIpc = require('@rokt33r/node-ipc') +const defaultKeymap = { + toggleFinder: 'Cmd + alt + s', + toggleMain: 'Cmd + alt + v' +} +const keymapFilename = 'keymap.json' + var userDataPath = app.getPath('userData') -if (!jetpack.cwd(userDataPath).exists('keymap.json')) { - jetpack.cwd(userDataPath).file('keymap.json', {content: '{}'}) -} -try { - global.keymap = JSON.parse(jetpack.cwd(userDataPath).read('keymap.json', 'utf-8')) -} catch (err) { - jetpack.cwd(userDataPath).file('keymap.json', {content: '{}'}) - global.keymap = {} -} -if (global.keymap.toggleFinder == null) global.keymap.toggleFinder = 'ctrl+tab+shift' -var toggleFinderKey = global.keymap.toggleFinder -try { - globalShortcut.register(toggleFinderKey, function () { - emitToFinder('open-finder') - mainWindow.webContents.send('open-finder', {}) - }) -} catch (err) { - console.log(err.name) -} - -ipc.on('hotkeyUpdated', function (event, newKeymap) { - console.log('got new keymap') - console.log(newKeymap) - globalShortcut.unregisterAll() - global.keymap = newKeymap - jetpack.cwd(userDataPath).file('keymap.json', {content: JSON.stringify(global.keymap)}) - - var toggleFinderKey = global.keymap.toggleFinder != null ? global.keymap.toggleFinder : 'ctrl+tab+shift' - try { - globalShortcut.register(toggleFinderKey, function () { - emitToFinder('open-finder') - mainWindow.webContents.send('open-finder', {}) - }) - mainWindow.webContents.send('APP_SETTING_DONE', {}) - } catch (err) { - console.error(err) - mainWindow.webContents.send('APP_SETTING_ERROR', { - message: 'Failed to apply hotkey: Invalid format' - }) +function getKeymap () { + var userDataPath = app.getPath('userData') + if (jetpack.cwd(userDataPath).exists(keymapFilename)) { + try { + return JSON.parse(jetpack.cwd(userDataPath).read(keymapFilename, 'utf-8')) + } catch (err) {} } -}) + return {} +} + +function saveKeymap () { + var content + try { + content = JSON.stringify(global.keymap) + } catch (e) { + global.keymap = {} + content = JSON.stringify(global.keymap) + } + jetpack.cwd(userDataPath).file(keymapFilename, { content }) +} function emitToFinder (type, data) { var payload = { @@ -58,3 +44,63 @@ function emitToFinder (type, data) { nodeIpc.server.broadcast('message', payload) } + +function toggleFinder () { + emitToFinder('open-finder') + mainWindow.webContents.send('open-finder', {}) +} + +function toggleMain () { + if (mainWindow.isFocused()) { + if (process.platform === 'darwin') { + Menu.sendActionToFirstResponder('hide:') + } else { + mainWindow.minimize() + } + } else { + if (process.platform === 'darwin') { + mainWindow.show() + } else { + mainWindow.minimize() + mainWindow.restore() + } + mainWindow.webContents.send('list-focus') + } +} + +// Init +global.keymap = Object.assign({}, defaultKeymap, getKeymap()) + +function registerKey (name, callback, broadcast) { + if (broadcast == null) broadcast = true + + try { + globalShortcut.register(global.keymap[name], callback) + if (broadcast) { + mainWindow.webContents.send('APP_SETTING_DONE', {}) + } + } catch (err) { + console.log(err) + if (broadcast) { + mainWindow.webContents.send('APP_SETTING_ERROR', { + message: 'Failed to apply hotkey: Invalid format' + }) + } + } +} + +function registerAllKeys (broadcast) { + if (broadcast == null) broadcast = true + registerKey('toggleFinder', toggleFinder, broadcast) + registerKey('toggleMain', toggleMain, broadcast) +} + +registerAllKeys(false) + +ipc.on('hotkeyUpdated', function (event, newKeymap) { + global.keymap = Object.assign({}, defaultKeymap, global.keymap, newKeymap) + saveKeymap() + globalShortcut.unregisterAll() + registerAllKeys() +}) + diff --git a/lib/main-app.js b/lib/main-app.js index f00d9c96..0d594d72 100644 --- a/lib/main-app.js +++ b/lib/main-app.js @@ -295,6 +295,7 @@ app.on('ready', function () { }) require('./hotkey') + require('./config') }) module.exports = app