From 743c11c279fdd89f0c1a497f0641a174bb059cf6 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Aug 2020 20:42:09 +0100 Subject: [PATCH] Android release v1.0.338 --- .../gui/KeymapConfig/KeymapConfigScreen.js | 127 ++++++++++++++++++ .../gui/KeymapConfig/ShortcutRecorder.js | 51 +++++++ .../gui/KeymapConfig/styles/index.js | 53 ++++++++ .../gui/KeymapConfig/utils/getLabel.js | 33 +++++ .../KeymapConfig/utils/useCommandStatus.js | 25 ++++ .../gui/KeymapConfig/utils/useKeymap.js | 68 ++++++++++ README.md | 2 +- ReactNativeClient/android/app/build.gradle | 4 +- 8 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js create mode 100644 ElectronClient/gui/KeymapConfig/ShortcutRecorder.js create mode 100644 ElectronClient/gui/KeymapConfig/styles/index.js create mode 100644 ElectronClient/gui/KeymapConfig/utils/getLabel.js create mode 100644 ElectronClient/gui/KeymapConfig/utils/useCommandStatus.js create mode 100644 ElectronClient/gui/KeymapConfig/utils/useKeymap.js diff --git a/ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js b/ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js new file mode 100644 index 000000000..f29ca73e2 --- /dev/null +++ b/ElectronClient/gui/KeymapConfig/KeymapConfigScreen.js @@ -0,0 +1,127 @@ +'use strict'; +const __awaiter = (this && this.__awaiter) || function(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function(resolve) { resolve(value); }); } + return new (P || (P = Promise))(function(resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator['throw'](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, '__esModule', { value: true }); +const React = require('react'); +const react_1 = require('react'); +const ShortcutRecorder_1 = require('./ShortcutRecorder'); +const getLabel_1 = require('./utils/getLabel'); +const useKeymap_1 = require('./utils/useKeymap'); +const useCommandStatus_1 = require('./utils/useCommandStatus'); +const styles_1 = require('./styles'); +const { bridge } = require('electron').remote.require('./bridge'); +const { shim } = require('lib/shim'); +const { _ } = require('lib/locale'); +exports.KeymapConfigScreen = ({ themeId }) => { + const styles = styles_1.default(themeId); + const [filter, setFilter] = react_1.useState(''); + const [keymapItems, keymapError, overrideKeymapItems, exportCustomKeymap, setAccelerator, resetAccelerator] = useKeymap_1.default(); + const [recorderError, setRecorderError] = react_1.useState(null); + const [editing, enableEditing, disableEditing] = useCommandStatus_1.default(); + const [hovering, enableHovering, disableHovering] = useCommandStatus_1.default(); + const handleSave = (event) => { + const { commandName, accelerator } = event; + setAccelerator(commandName, accelerator); + disableEditing(commandName); + }; + const handleReset = (event) => { + const { commandName } = event; + resetAccelerator(commandName); + disableEditing(commandName); + }; + const handleCancel = (event) => { + const { commandName } = event; + disableEditing(commandName); + }; + const handleError = (event) => { + const { recorderError } = event; + setRecorderError(recorderError); + }; + const handleImport = () => __awaiter(void 0, void 0, void 0, function* () { + const filePath = bridge().showOpenDialog({ + properties: ['openFile'], + defaultPath: 'keymap-desktop', + filters: [{ name: 'Joplin Keymaps (keymap-desktop.json)', extensions: ['json'] }], + }); + if (filePath) { + const actualFilePath = filePath[0]; + try { + const keymapFile = yield shim.fsDriver().readFile(actualFilePath, 'utf-8'); + overrideKeymapItems(JSON.parse(keymapFile)); + } catch (err) { + bridge().showErrorMessageBox(`${_('An unexpected error occured while importing the keymap!')}\n${err.message}`); + } + } + }); + const handleExport = () => __awaiter(void 0, void 0, void 0, function* () { + const filePath = bridge().showSaveDialog({ + defaultPath: 'keymap-desktop', + filters: [{ name: 'Joplin Keymaps (keymap-desktop.json)', extensions: ['json'] }], + }); + if (filePath) { + try { + // KeymapService is already synchronized with the in-state keymap + yield exportCustomKeymap(filePath); + } catch (err) { + bridge().showErrorMessageBox(`${_('An unexpected error occured while exporting the keymap!')}\n${err.message}`); + } + } + }); + const renderAccelerator = (accelerator) => { + return (React.createElement('div', null, accelerator.split('+').map(part => React.createElement('kbd', { style: styles.kbd, key: part }, part)).reduce((accumulator, part) => (accumulator.length ? [...accumulator, ' + ', part] : [part]), []))); + }; + const renderStatus = (commandName) => { + if (editing[commandName]) { + return (recorderError && React.createElement('i', { className: 'fa fa-exclamation-triangle' })); + } else if (hovering[commandName]) { + return (React.createElement('i', { className: 'fa fa-pen' })); + } else { + return null; + } + }; + const renderError = (error) => { + return (React.createElement('div', { style: styles.warning }, + React.createElement('p', { style: styles.text }, + React.createElement('span', null, error.message)))); + }; + const renderKeymapRow = ({ command, accelerator }) => { + const handleClick = () => enableEditing(command); + const handleMouseEnter = () => enableHovering(command); + const handleMouseLeave = () => disableHovering(command); + const cellContent = React.createElement('div', { style: styles.tableCell, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave }, + editing[command] ? + React.createElement(ShortcutRecorder_1.ShortcutRecorder, { onSave: handleSave, onReset: handleReset, onCancel: handleCancel, onError: handleError, initialAccelerator: accelerator || '' /* Because accelerator is null if disabled */, commandName: command, themeId: themeId }) : + React.createElement('div', { style: styles.tableCellContent, onClick: handleClick }, accelerator + ? renderAccelerator(accelerator) + : React.createElement('div', { style: styles.disabled }, _('Disabled'))), + React.createElement('div', { style: styles.tableCellStatus, onClick: handleClick }, renderStatus(command))); + return (React.createElement('tr', { key: command }, + React.createElement('td', { style: styles.tableCommandColumn }, getLabel_1.default(command)), + React.createElement('td', { style: styles.tableShortcutColumn }, cellContent))); + }; + return (React.createElement('div', null, + keymapError && renderError(keymapError), + React.createElement('div', { style: styles.container }, + React.createElement('div', { style: styles.actionsContainer }, + React.createElement('label', { style: styles.label }, _('Search')), + React.createElement('input', { value: filter, onChange: event => setFilter(event.target.value), placeholder: _('Search...'), style: styles.filterInput }), + React.createElement('button', { style: styles.inlineButton, onClick: handleImport }, _('Import')), + React.createElement('button', { style: styles.inlineButton, onClick: handleExport }, _('Export'))), + React.createElement('table', { style: styles.table }, + React.createElement('thead', null, + React.createElement('tr', null, + React.createElement('th', { style: styles.tableCommandColumn }, _('Command')), + React.createElement('th', { style: styles.tableShortcutColumn }, _('Keyboard Shortcut')))), + React.createElement('tbody', null, keymapItems.filter(({ command }) => { + const filterLowerCase = filter.toLowerCase(); + return (command.toLowerCase().includes(filterLowerCase) || getLabel_1.default(command).toLowerCase().includes(filterLowerCase)); + }).map(item => renderKeymapRow(item))))))); +}; +// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiS2V5bWFwQ29uZmlnU2NyZWVuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiS2V5bWFwQ29uZmlnU2NyZWVuLnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBLCtCQUErQjtBQUMvQixpQ0FBaUM7QUFHakMseURBQXNEO0FBQ3RELCtDQUF3QztBQUN4QyxpREFBMEM7QUFDMUMsK0RBQXdEO0FBQ3hELHFDQUErQjtBQUUvQixNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDbEUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUNyQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBTXZCLFFBQUEsa0JBQWtCLEdBQUcsQ0FBQyxFQUFFLE9BQU8sRUFBMkIsRUFBRSxFQUFFO0lBQzFFLE1BQU0sTUFBTSxHQUFHLGdCQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFaEMsTUFBTSxDQUFDLE1BQU0sRUFBRSxTQUFTLENBQUMsR0FBRyxnQkFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3pDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsV0FBVyxFQUFFLG1CQUFtQixFQUFFLGtCQUFrQixFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsQ0FBQyxHQUFHLG1CQUFTLEVBQUUsQ0FBQztJQUMxSCxNQUFNLENBQUMsYUFBYSxFQUFFLGdCQUFnQixDQUFDLEdBQUcsZ0JBQVEsQ0FBUSxJQUFJLENBQUMsQ0FBQztJQUNoRSxNQUFNLENBQUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxjQUFjLENBQUMsR0FBRywwQkFBZ0IsRUFBRSxDQUFDO0lBQ3BFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsY0FBYyxFQUFFLGVBQWUsQ0FBQyxHQUFHLDBCQUFnQixFQUFFLENBQUM7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 diff --git a/ElectronClient/gui/KeymapConfig/ShortcutRecorder.js b/ElectronClient/gui/KeymapConfig/ShortcutRecorder.js new file mode 100644 index 000000000..9923cc180 --- /dev/null +++ b/ElectronClient/gui/KeymapConfig/ShortcutRecorder.js @@ -0,0 +1,51 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const React = require('react'); +const react_1 = require('react'); +const KeymapService_1 = require('../../lib/services/KeymapService'); +const styles_1 = require('./styles'); +const { _ } = require('lib/locale'); +const keymapService = KeymapService_1.default.instance(); +exports.ShortcutRecorder = ({ onSave, onReset, onCancel, onError, initialAccelerator, commandName, themeId }) => { + const styles = styles_1.default(themeId); + const [accelerator, setAccelerator] = react_1.useState(initialAccelerator); + const [saveAllowed, setSaveAllowed] = react_1.useState(true); + react_1.useEffect(() => { + try { + // Only perform validations if there's an accelerator provided + // Otherwise performing a save means that it's going to be disabled + if (accelerator) { + keymapService.validateAccelerator(accelerator); + keymapService.validateKeymap({ accelerator, command: commandName }); + } + // Discard previous errors + onError({ recorderError: null }); + setSaveAllowed(true); + } catch (recorderError) { + onError({ recorderError }); + setSaveAllowed(false); + } + }, [accelerator]); + const handleKeydown = (event) => { + event.preventDefault(); + const newAccelerator = keymapService.domToElectronAccelerator(event); + switch (newAccelerator) { + case 'Enter': + if (saveAllowed) { return onSave({ commandName, accelerator }); } + break; + case 'Escape': + return onCancel({ commandName }); + case 'Backspace': + case 'Delete': + return setAccelerator(''); + default: + setAccelerator(newAccelerator); + } + }; + return (React.createElement('div', { style: styles.recorderContainer }, + React.createElement('input', { value: accelerator, placeholder: _('Press the shortcut'), onKeyDown: handleKeydown, style: styles.recorderInput, readOnly: true, autoFocus: true }), + React.createElement('button', { style: styles.inlineButton, disabled: !saveAllowed, onClick: () => onSave({ commandName, accelerator }) }, _('Save')), + React.createElement('button', { style: styles.inlineButton, onClick: () => onReset({ commandName }) }, _('Restore')), + React.createElement('button', { style: styles.inlineButton, onClick: () => onCancel({ commandName }) }, _('Cancel')))); +}; +// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2hvcnRjdXRSZWNvcmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIlNob3J0Y3V0UmVjb3JkZXIudHN4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsK0JBQStCO0FBQy9CLGlDQUEyRDtBQUUzRCxvRUFBNkQ7QUFDN0QscUNBQStCO0FBRS9CLE1BQU0sRUFBRSxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7QUFDcEMsTUFBTSxhQUFhLEdBQUcsdUJBQWEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztBQVlsQyxRQUFBLGdCQUFnQixHQUFHLENBQUMsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBeUIsRUFBRSxFQUFFO0lBQzNJLE1BQU0sTUFBTSxHQUFHLGdCQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFaEMsTUFBTSxDQUFDLFdBQVcsRUFBRSxjQUFjLENBQUMsR0FBRyxnQkFBUSxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDbkUsTUFBTSxDQUFDLFdBQVcsRUFBRSxjQUFjLENBQUMsR0FBRyxnQkFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRXJELGlCQUFTLENBQUMsR0FBRyxFQUFFO1FBQ2QsSUFBSTtZQUNILDhEQUE4RDtZQUM5RCxtRUFBbUU7WUFDbkUsSUFBSSxXQUFXLEVBQUU7Z0JBQ2hCLGFBQWEsQ0FBQyxtQkFBbUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDL0MsYUFBYSxDQUFDLGNBQWMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQzthQUNwRTtZQUVELDBCQUEwQjtZQUMxQixPQUFPLENBQUMsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUNqQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDckI7UUFBQyxPQUFPLGFBQWEsRUFBRTtZQUN2QixPQUFPLENBQUMsRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1lBQzNCLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUN0QjtJQUNGLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFFbEIsTUFBTSxhQUFhLEdBQUcsQ0FBQyxLQUFvQyxFQUFFLEVBQUU7UUFDOUQsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sY0FBYyxHQUFHLGFBQWEsQ0FBQyx3QkFBd0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVyRSxRQUFRLGNBQWMsRUFBRTtZQUN4QixLQUFLLE9BQU87Z0JBQ1gsSUFBSSxXQUFXO29CQUFFLE9BQU8sTUFBTSxDQUFDLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7Z0JBQzdELE1BQU07WUFDUCxLQUFLLFFBQVE7Z0JBQ1osT0FBTyxRQUFRLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO1lBQ2xDLEtBQUssV0FBVyxDQUFDO1lBQ2pCLEtBQUssUUFBUTtnQkFDWixPQUFPLGNBQWMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUMzQjtnQkFDQyxjQUFjLENBQUMsY0FBYyxDQUFDLENBQUM7U0FDL0I7SUFDRixDQUFDLENBQUM7SUFFRixPQUFPLENBQ04sNkJBQUssS0FBSyxFQUFFLE1BQU0sQ0FBQyxpQkFBaUI7UUFDbkMsK0JBQ0MsS0FBSyxFQUFFLFdBQVcsRUFDbEIsV0FBVyxFQUFFLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxFQUNwQyxTQUFTLEVBQUUsYUFBYSxFQUN4QixLQUFLLEVBQUUsTUFBTSxDQUFDLGFBQWEsRUFDM0IsUUFBUSxRQUNSLFNBQVMsU0FDUjtRQUVGLGdDQUFRLEtBQUssRUFBRSxNQUFNLENBQUMsWUFBWSxFQUFFLFFBQVEsRUFBRSxDQUFDLFdBQVcsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxDQUFDLElBQzdHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FDRjtRQUNULGdDQUFRLEtBQUssRUFBRSxNQUFNLENBQUMsWUFBWSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxJQUN6RSxDQUFDLENBQUMsU0FBUyxDQUFDLENBQ0w7UUFDVCxnQ0FBUSxLQUFLLEVBQUUsTUFBTSxDQUFDLFlBQVksRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsV0FBVyxFQUFFLENBQUMsSUFDMUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUNKLENBQ0osQ0FDTixDQUFDO0FBQ0gsQ0FBQyxDQUFDIn0= diff --git a/ElectronClient/gui/KeymapConfig/styles/index.js b/ElectronClient/gui/KeymapConfig/styles/index.js new file mode 100644 index 000000000..5592833e7 --- /dev/null +++ b/ElectronClient/gui/KeymapConfig/styles/index.js @@ -0,0 +1,53 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const { buildStyle } = require('lib/theme'); +function styles(themeId) { + return buildStyle('KeymapConfigScreen', themeId, (theme) => { + return { + container: Object.assign(Object.assign({}, theme.containerStyle), { padding: 16 }), + actionsContainer: { + display: 'flex', + flexDirection: 'row', + }, + recorderContainer: { + padding: 2, + flexGrow: 1, + }, + filterInput: Object.assign(Object.assign({}, theme.inputStyle), { flexGrow: 1, minHeight: 29, alignSelf: 'center' }), + recorderInput: Object.assign(Object.assign({}, theme.inputStyle), { minHeight: 29 }), + label: Object.assign(Object.assign({}, theme.textStyle), { alignSelf: 'center', marginRight: 10 }), + table: Object.assign(Object.assign({}, theme.containerStyle), { marginTop: 16, overflow: 'auto', width: '100%' }), + tableShortcutColumn: Object.assign(Object.assign({}, theme.textStyle), { width: '60%' }), + tableCommandColumn: Object.assign(Object.assign({}, theme.textStyle), { width: 'auto' }), + tableCell: { + display: 'flex', + flexDirection: 'row', + }, + tableCellContent: { + flexGrow: 1, + alignSelf: 'center', + }, + tableCellStatus: { + height: '100%', + alignSelf: 'center', + }, + kbd: { + fontFamily: 'sans-serif', + border: '1px solid', + borderRadius: 4, + backgroundColor: theme.raisedBackgroundColor, + padding: 2, + paddingLeft: 6, + paddingRight: 6, + }, + disabled: { + color: theme.colorFaded, + fontStyle: 'italic', + }, + inlineButton: Object.assign(Object.assign({}, theme.buttonStyle), { marginLeft: 12 }), + warning: Object.assign(Object.assign({}, theme.textStyle), { backgroundColor: theme.warningBackgroundColor, paddingLeft: 16, paddingRight: 16, paddingTop: 2, paddingBottom: 2 }), + }; + }); +} +exports.default = styles; +// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7QUFFNUMsU0FBd0IsTUFBTSxDQUFDLE9BQWU7SUFDN0MsT0FBTyxVQUFVLENBQUMsb0JBQW9CLEVBQUUsT0FBTyxFQUFFLENBQUMsS0FBVSxFQUFFLEVBQUU7UUFDL0QsT0FBTztZQUNOLFNBQVMsa0NBQ0wsS0FBSyxDQUFDLGNBQWMsS0FDdkIsT0FBTyxFQUFFLEVBQUUsR0FDWDtZQUNELGdCQUFnQixFQUFFO2dCQUNqQixPQUFPLEVBQUUsTUFBTTtnQkFDZixhQUFhLEVBQUUsS0FBSzthQUNwQjtZQUNELGlCQUFpQixFQUFFO2dCQUNsQixPQUFPLEVBQUUsQ0FBQztnQkFDVixRQUFRLEVBQUUsQ0FBQzthQUNYO1lBQ0QsV0FBVyxrQ0FDUCxLQUFLLENBQUMsVUFBVSxLQUNuQixRQUFRLEVBQUUsQ0FBQyxFQUNYLFNBQVMsRUFBRSxFQUFFLEVBQ2IsU0FBUyxFQUFFLFFBQVEsR0FDbkI7WUFDRCxhQUFhLGtDQUNULEtBQUssQ0FBQyxVQUFVLEtBQ25CLFNBQVMsRUFBRSxFQUFFLEdBQ2I7WUFDRCxLQUFLLGtDQUNELEtBQUssQ0FBQyxTQUFTLEtBQ2xCLFNBQVMsRUFBRSxRQUFRLEVBQ25CLFdBQVcsRUFBRSxFQUFFLEdBQ2Y7WUFDRCxLQUFLLGtDQUNELEtBQUssQ0FBQyxjQUFjLEtBQ3ZCLFNBQVMsRUFBRSxFQUFFLEVBQ2IsUUFBUSxFQUFFLE1BQU0sRUFDaEIsS0FBSyxFQUFFLE1BQU0sR0FDYjtZQUNELG1CQUFtQixrQ0FDZixLQUFLLENBQUMsU0FBUyxLQUNsQixLQUFLLEVBQUUsS0FBSyxHQUNaO1lBQ0Qsa0JBQWtCLGtDQUNkLEtBQUssQ0FBQyxTQUFTLEtBQ2xCLEtBQUssRUFBRSxNQUFNLEdBQ2I7WUFDRCxTQUFTLEVBQUU7Z0JBQ1YsT0FBTyxFQUFFLE1BQU07Z0JBQ2YsYUFBYSxFQUFFLEtBQUs7YUFDcEI7WUFDRCxnQkFBZ0IsRUFBRTtnQkFDakIsUUFBUSxFQUFFLENBQUM7Z0JBQ1gsU0FBUyxFQUFFLFFBQVE7YUFDbkI7WUFDRCxlQUFlLEVBQUU7Z0JBQ2hCLE1BQU0sRUFBRSxNQUFNO2dCQUNkLFNBQVMsRUFBRSxRQUFRO2FBQ25CO1lBQ0QsR0FBRyxFQUFFO2dCQUNKLFVBQVUsRUFBRSxZQUFZO2dCQUN4QixNQUFNLEVBQUUsV0FBVztnQkFDbkIsWUFBWSxFQUFFLENBQUM7Z0JBQ2YsZUFBZSxFQUFFLEtBQUssQ0FBQyxxQkFBcUI7Z0JBQzVDLE9BQU8sRUFBRSxDQUFDO2dCQUNWLFdBQVcsRUFBRSxDQUFDO2dCQUNkLFlBQVksRUFBRSxDQUFDO2FBQ2Y7WUFDRCxRQUFRLEVBQUU7Z0JBQ1QsS0FBSyxFQUFFLEtBQUssQ0FBQyxVQUFVO2dCQUN2QixTQUFTLEVBQUUsUUFBUTthQUNuQjtZQUNELFlBQVksa0NBQ1IsS0FBSyxDQUFDLFdBQVcsS0FDcEIsVUFBVSxFQUFFLEVBQUUsR0FDZDtZQUNELE9BQU8sa0NBQ0gsS0FBSyxDQUFDLFNBQVMsS0FDbEIsZUFBZSxFQUFFLEtBQUssQ0FBQyxzQkFBc0IsRUFDN0MsV0FBVyxFQUFFLEVBQUUsRUFDZixZQUFZLEVBQUUsRUFBRSxFQUNoQixVQUFVLEVBQUUsQ0FBQyxFQUNiLGFBQWEsRUFBRSxDQUFDLEdBQ2hCO1NBQ0QsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQW5GRCx5QkFtRkMifQ== diff --git a/ElectronClient/gui/KeymapConfig/utils/getLabel.js b/ElectronClient/gui/KeymapConfig/utils/getLabel.js new file mode 100644 index 000000000..9963ef63b --- /dev/null +++ b/ElectronClient/gui/KeymapConfig/utils/getLabel.js @@ -0,0 +1,33 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const CommandService_1 = require('../../../lib/services/CommandService'); +const { _ } = require('lib/locale'); +const { shim } = require('lib/shim'); +const commandService = CommandService_1.default.instance(); +const getLabel = (commandName) => { + if (commandService.exists(commandName)) { return commandService.label(commandName); } + // Some commands are not registered in CommandService at the moment + // Following hard-coded labels are used as a workaround + switch (commandName) { + case 'quit': + return _('Quit'); + case 'insertTemplate': + return _('Insert template'); + case 'zoomActualSize': + return _('Actual Size'); + case 'gotoAnything': + return _('Goto Anything...'); + case 'help': + return _('Website and documentation'); + case 'hideApp': + return _('Hide Joplin'); + case 'closeWindow': + return _('Close Window'); + case 'config': + return shim.isMac() ? _('Preferences') : _('Options'); + default: + throw new Error(`Command: ${commandName} is unknown`); + } +}; +exports.default = getLabel; +// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0TGFiZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJnZXRMYWJlbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHlFQUFrRTtBQUVsRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBQ3BDLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7QUFFckMsTUFBTSxjQUFjLEdBQUcsd0JBQWMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztBQUVqRCxNQUFNLFFBQVEsR0FBRyxDQUFDLFdBQW1CLEVBQUUsRUFBRTtJQUN4QyxJQUFJLGNBQWMsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO1FBQUUsT0FBTyxjQUFjLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBRWpGLG1FQUFtRTtJQUNuRSx1REFBdUQ7SUFFdkQsUUFBUSxXQUFXLEVBQUU7UUFDckIsS0FBSyxNQUFNO1lBQ1YsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEIsS0FBSyxnQkFBZ0I7WUFDcEIsT0FBTyxDQUFDLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUM3QixLQUFLLGdCQUFnQjtZQUNwQixPQUFPLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN6QixLQUFLLGNBQWM7WUFDbEIsT0FBTyxDQUFDLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUM5QixLQUFLLE1BQU07WUFDVixPQUFPLENBQUMsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1FBQ3ZDLEtBQUssU0FBUztZQUNiLE9BQU8sQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ3pCLEtBQUssYUFBYTtZQUNqQixPQUFPLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUMxQixLQUFLLFFBQVE7WUFDWixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDdkQ7WUFDQyxNQUFNLElBQUksS0FBSyxDQUFDLFlBQVksV0FBVyxhQUFhLENBQUMsQ0FBQztLQUN0RDtBQUNGLENBQUMsQ0FBQztBQUVGLGtCQUFlLFFBQVEsQ0FBQyJ9 diff --git a/ElectronClient/gui/KeymapConfig/utils/useCommandStatus.js b/ElectronClient/gui/KeymapConfig/utils/useCommandStatus.js new file mode 100644 index 000000000..d63e0e788 --- /dev/null +++ b/ElectronClient/gui/KeymapConfig/utils/useCommandStatus.js @@ -0,0 +1,25 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const react_1 = require('react'); +const KeymapService_1 = require('../../../lib/services/KeymapService'); +const keymapService = KeymapService_1.default.instance(); +const useCommandStatus = () => { + const [status, setStatus] = react_1.useState(() => keymapService.getCommandNames().reduce((accumulator, command) => { + accumulator[command] = false; + return accumulator; + }, {})); + const disableStatus = (commandName) => setStatus(prevStatus => (Object.assign(Object.assign({}, prevStatus), { [commandName]: false }))); + const enableStatus = (commandName) => setStatus(prevStatus => { + // Falsify all the commands; Only one command should be truthy at any given time + const newStatus = Object.keys(prevStatus).reduce((accumulator, command) => { + accumulator[command] = false; + return accumulator; + }, {}); + // Make the appropriate command truthful + newStatus[commandName] = true; + return newStatus; + }); + return [status, enableStatus, disableStatus]; +}; +exports.default = useCommandStatus; +// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlQ29tbWFuZFN0YXR1cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInVzZUNvbW1hbmRTdGF0dXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxpQ0FBaUM7QUFDakMsdUVBQWdFO0FBRWhFLE1BQU0sYUFBYSxHQUFHLHVCQUFhLENBQUMsUUFBUSxFQUFFLENBQUM7QUFNL0MsTUFBTSxnQkFBZ0IsR0FBRyxHQUFrRixFQUFFO0lBQzVHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLEdBQUcsZ0JBQVEsQ0FBZ0IsR0FBRyxFQUFFLENBQ3hELGFBQWEsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxXQUEwQixFQUFFLE9BQWUsRUFBRSxFQUFFO1FBQ3RGLFdBQVcsQ0FBQyxPQUFPLENBQUMsR0FBRyxLQUFLLENBQUM7UUFDN0IsT0FBTyxXQUFXLENBQUM7SUFDcEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUNOLENBQUM7SUFFRixNQUFNLGFBQWEsR0FBRyxDQUFDLFdBQW1CLEVBQUUsRUFBRSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLGlDQUFNLFVBQVUsS0FBRSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEtBQUssSUFBRyxDQUFDLENBQUM7SUFDbEgsTUFBTSxZQUFZLEdBQUcsQ0FBQyxXQUFtQixFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLEVBQUU7UUFDcEUsZ0ZBQWdGO1FBQ2hGLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsV0FBMEIsRUFBRSxPQUFlLEVBQUUsRUFBRTtZQUNoRyxXQUFXLENBQUMsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFDO1lBQzdCLE9BQU8sV0FBVyxDQUFDO1FBQ3BCLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVQLHdDQUF3QztRQUN4QyxTQUFTLENBQUMsV0FBVyxDQUFDLEdBQUcsSUFBSSxDQUFDO1FBQzlCLE9BQU8sU0FBUyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBRUgsT0FBTyxDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsYUFBYSxDQUFDLENBQUM7QUFDOUMsQ0FBQyxDQUFDO0FBRUYsa0JBQWUsZ0JBQWdCLENBQUMifQ== diff --git a/ElectronClient/gui/KeymapConfig/utils/useKeymap.js b/ElectronClient/gui/KeymapConfig/utils/useKeymap.js new file mode 100644 index 000000000..cd7e72ad5 --- /dev/null +++ b/ElectronClient/gui/KeymapConfig/utils/useKeymap.js @@ -0,0 +1,68 @@ +'use strict'; +const __awaiter = (this && this.__awaiter) || function(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function(resolve) { resolve(value); }); } + return new (P || (P = Promise))(function(resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator['throw'](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, '__esModule', { value: true }); +const react_1 = require('react'); +const KeymapService_1 = require('../../../lib/services/KeymapService'); +const keymapService = KeymapService_1.default.instance(); +// This custom hook provides a synchronized snapshot of the keymap residing at KeymapService +// All the logic regarding altering and interacting with the keymap is isolated from the components +const useKeymap = () => { + const [keymapItems, setKeymapItems] = react_1.useState(() => keymapService.getKeymapItems()); + const [keymapError, setKeymapError] = react_1.useState(null); + const setAccelerator = (commandName, accelerator) => { + setKeymapItems(prevKeymap => { + const newKeymap = [...prevKeymap]; + newKeymap.find(item => item.command === commandName).accelerator = accelerator || null /* Disabled */; + return newKeymap; + }); + }; + const resetAccelerator = (commandName) => { + const defaultAccelerator = keymapService.getDefaultAccelerator(commandName); + setKeymapItems(prevKeymap => { + const newKeymap = [...prevKeymap]; + newKeymap.find(item => item.command === commandName).accelerator = defaultAccelerator; + return newKeymap; + }); + }; + const overrideKeymapItems = (customKeymapItems) => { + const oldKeymapItems = [...customKeymapItems]; + keymapService.initialize(); // Start with a fresh keymap + try { + // First, try to update the in-memory keymap of KeymapService + // This function will throw if there are any issues with the new custom keymap + keymapService.overrideKeymap(customKeymapItems); + // Then, update the state with the data from KeymapService + // Side-effect: Changes will also be saved to the disk + setKeymapItems(keymapService.getKeymapItems()); + } catch (err) { + // oldKeymapItems includes even the unchanged keymap items + // However, it is not an issue because the logic accounts for such scenarios + keymapService.overrideKeymap(oldKeymapItems); + throw err; + } + }; + const exportCustomKeymap = (customKeymapPath) => __awaiter(void 0, void 0, void 0, function* () { + // KeymapService is already synchronized automatically with the in-state keymap + yield keymapService.saveCustomKeymap(customKeymapPath); + }); + react_1.useEffect(() => { + try { + keymapService.overrideKeymap(keymapItems); + keymapService.saveCustomKeymap(); + setKeymapError(null); + } catch (err) { + setKeymapError(err); + } + }, [keymapItems]); + return [keymapItems, keymapError, overrideKeymapItems, exportCustomKeymap, setAccelerator, resetAccelerator]; +}; +exports.default = useKeymap; +// # sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlS2V5bWFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidXNlS2V5bWFwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUEsaUNBQTRDO0FBQzVDLHVFQUFnRjtBQUVoRixNQUFNLGFBQWEsR0FBRyx1QkFBYSxDQUFDLFFBQVEsRUFBRSxDQUFDO0FBRS9DLDRGQUE0RjtBQUM1RixtR0FBbUc7QUFFbkcsTUFBTSxTQUFTLEdBQUcsR0FPaEIsRUFBRTtJQUNILE1BQU0sQ0FBQyxXQUFXLEVBQUUsY0FBYyxDQUFDLEdBQUcsZ0JBQVEsQ0FBZSxHQUFHLEVBQUUsQ0FBQyxhQUFhLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQztJQUNuRyxNQUFNLENBQUMsV0FBVyxFQUFFLGNBQWMsQ0FBQyxHQUFHLGdCQUFRLENBQVEsSUFBSSxDQUFDLENBQUM7SUFFNUQsTUFBTSxjQUFjLEdBQUcsQ0FBQyxXQUFtQixFQUFFLFdBQW1CLEVBQUUsRUFBRTtRQUNuRSxjQUFjLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDM0IsTUFBTSxTQUFTLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxDQUFDO1lBRWxDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxLQUFLLFdBQVcsQ0FBQyxDQUFDLFdBQVcsR0FBRyxXQUFXLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQztZQUN0RyxPQUFPLFNBQVMsQ0FBQztRQUNsQixDQUFDLENBQUMsQ0FBQztJQUNKLENBQUMsQ0FBQztJQUVGLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxXQUFtQixFQUFFLEVBQUU7UUFDaEQsTUFBTSxrQkFBa0IsR0FBRyxhQUFhLENBQUMscUJBQXFCLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDNUUsY0FBYyxDQUFDLFVBQVUsQ0FBQyxFQUFFO1lBQzNCLE1BQU0sU0FBUyxHQUFHLENBQUMsR0FBRyxVQUFVLENBQUMsQ0FBQztZQUVsQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sS0FBSyxXQUFXLENBQUMsQ0FBQyxXQUFXLEdBQUcsa0JBQWtCLENBQUM7WUFDdEYsT0FBTyxTQUFTLENBQUM7UUFDbEIsQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDLENBQUM7SUFFRixNQUFNLG1CQUFtQixHQUFHLENBQUMsaUJBQStCLEVBQUUsRUFBRTtRQUMvRCxNQUFNLGNBQWMsR0FBRyxDQUFDLEdBQUcsaUJBQWlCLENBQUMsQ0FBQztRQUM5QyxhQUFhLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyw0QkFBNEI7UUFFeEQsSUFBSTtZQUNILDZEQUE2RDtZQUM3RCw4RUFBOEU7WUFDOUUsYUFBYSxDQUFDLGNBQWMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQ2hELDBEQUEwRDtZQUMxRCxzREFBc0Q7WUFDdEQsY0FBYyxDQUFDLGFBQWEsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1NBQy9DO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDYiwwREFBMEQ7WUFDMUQsNEVBQTRFO1lBQzVFLGFBQWEsQ0FBQyxjQUFjLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDN0MsTUFBTSxHQUFHLENBQUM7U0FDVjtJQUNGLENBQUMsQ0FBQztJQUVGLE1BQU0sa0JBQWtCLEdBQUcsQ0FBTyxnQkFBd0IsRUFBRSxFQUFFO1FBQzdELCtFQUErRTtRQUMvRSxNQUFNLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ3hELENBQUMsQ0FBQSxDQUFDO0lBRUYsaUJBQVMsQ0FBQyxHQUFHLEVBQUU7UUFDZCxJQUFJO1lBQ0gsYUFBYSxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMxQyxhQUFhLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUNqQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDckI7UUFBQyxPQUFPLEdBQUcsRUFBRTtZQUNiLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNwQjtJQUNGLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFFbEIsT0FBTyxDQUFDLFdBQVcsRUFBRSxXQUFXLEVBQUUsbUJBQW1CLEVBQUUsa0JBQWtCLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixDQUFDLENBQUM7QUFDOUcsQ0FBQyxDQUFDO0FBRUYsa0JBQWUsU0FBUyxDQUFDIn0= diff --git a/README.md b/README.md index 88a597950..d609c43aa 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Linux | Get it on Google Play | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.337/joplin-v1.0.337.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.337/joplin-v1.0.337-32bit.apk) +Android | Get it on Google Play | or download the APK file: [64-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.338/joplin-v1.0.338.apk) [32-bit](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.338/joplin-v1.0.338-32bit.apk) iOS | Get it on the App Store | - ## Terminal application diff --git a/ReactNativeClient/android/app/build.gradle b/ReactNativeClient/android/app/build.gradle index 968b6af6f..4da327e36 100644 --- a/ReactNativeClient/android/app/build.gradle +++ b/ReactNativeClient/android/app/build.gradle @@ -125,8 +125,8 @@ android { applicationId "net.cozic.joplin" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 2097573 - versionName "1.0.337" + versionCode 2097574 + versionName "1.0.338" ndk { abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" }