1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Improved UI usability

This commit is contained in:
Laurent Cozic 2017-10-08 23:34:01 +01:00
parent 3704f5be27
commit 1abab26041
8 changed files with 337 additions and 78 deletions

View File

@ -3,6 +3,7 @@ import { Folder } from 'lib/models/folder.js';
import { Note } from 'lib/models/note.js';
import { cliUtils } from './cli-utils.js';
import { reducer, defaultState } from 'lib/reducer.js';
import { _ } from 'lib/locale.js';
const tk = require('terminal-kit');
const termutils = require('tkwidgets/framework/termutils.js');
@ -45,11 +46,16 @@ class AppGui {
});
this.shortcuts_ = this.setupShortcuts();
this.inputMode_ = AppGui.INPUT_MODE_NORMAL;
this.currentShortcutKeys_ = '';
this.lastShortcutKeyTime_ = 0;
}
buildUi() {
this.rootWidget_ = new ReduxRootWidget(this.store_);
this.rootWidget_.name = 'rootWidget';
this.rootWidget_.name = 'root';
const folderList = new FolderListWidget();
folderList.setStyle({ borderBottomWidth: 1 });
@ -123,7 +129,7 @@ class AppGui {
const vLayout = new VLayoutWidget();
vLayout.name = 'vLayout';
vLayout.addChild(hLayout, { type: 'stretch', factor: 1 });
vLayout.addChild(consoleWidget, { type: 'fixed', factor: 5 });
vLayout.addChild(consoleWidget, { type: 'fixed', factor: 6 });
const win1 = new WindowWidget();
win1.addChild(vLayout);
@ -137,39 +143,101 @@ class AppGui {
const consoleWidget = this.widget('console');
shortcuts['DELETE'] = 'rm $n';
shortcuts['DELETE'] = {
description: _('Delete a note'),
action: 'rm $n',
};
shortcuts[' '] = 'todo toggle $n';
shortcuts['c'] = () => {
consoleWidget.focus();
shortcuts[' '] = {
friendlyName: 'SPACE',
description: _('Set a todo as completed / not completed'),
action: 'todo toggle $n',
}
shortcuts['ENTER'] = () => {
const w = this.widget('mainWindow').focusedWidget();
if (w.name == 'folderList') {
this.widget('noteList').focus();
} else if (w.name == 'noteList') {
this.processCommand('edit $n');
}
shortcuts['c'] = {
description: _('Enter the console'),
action: () => { consoleWidget.focus(); }
};
shortcuts['ESC'] = {
description: _('Exit the console'),
isDocOnly: true,
};
shortcuts['ENTER'] = {
description: null,
action: () => {
const w = this.widget('mainWindow').focusedWidget();
if (w.name == 'folderList') {
this.widget('noteList').focus();
} else if (w.name == 'noteList') {
this.processCommand('edit $n');
}
},
}
shortcuts[':nn'] = () => {
consoleWidget.focus('mknote ');
shortcuts['nt'] = {
description: _('Create a new todo'),
action: () => { consoleWidget.focus('mktodo '); },
}
shortcuts[':nt'] = () => {
consoleWidget.focus('mktodo ');
shortcuts['nn'] = {
description: _('Create a new note'),
action: () => { consoleWidget.focus('mknote '); },
}
shortcuts[':nb'] = () => {
consoleWidget.focus('mkbook ');
shortcuts['nt'] = {
description: _('Create a new todo'),
action: () => { consoleWidget.focus('mktodo '); },
}
shortcuts['nb'] = {
description: _('Create a new notebook'),
action: () => { consoleWidget.focus('mkbook '); },
}
shortcuts['CTRL_JCTRL_Z'] = {
friendlyName: 'Ctrl+J Ctrl+Z',
description: _('Maximise/minimise the console'),
action: () => { this.toggleMaximizeConsole(); },
}
return shortcuts;
}
toggleMaximizeConsole() {
this.maximizeConsole(!this.consoleIsMaximized());
}
maximizeConsole(doMaximize = true) {
const consoleWidget = this.widget('console');
if (consoleWidget.isMaximized__ === undefined) {
consoleWidget.isMaximized__ = false;
}
if (consoleWidget.isMaximized__ === doMaximize) return;
let constraints = {
type: 'fixed',
factor: !doMaximize ? 5 : this.widget('vLayout').height() - 4,
};
consoleWidget.isMaximized__ = doMaximize;
this.widget('vLayout').setWidgetConstraints(consoleWidget, constraints);
}
minimizeConsole() {
this.maximizeConsole(false);
}
consoleIsMaximized() {
return this.widget('console').isMaximized__ === true;
}
widget(name) {
if (name === 'root') return this.rootWidget_;
return this.rootWidget_.childByName(name);
}
@ -185,6 +253,10 @@ class AppGui {
return this.logger_;
}
shortcuts() {
return this.shortcuts_;
}
term() {
return this.term_;
}
@ -218,30 +290,6 @@ class AppGui {
cmd = cmd.trim();
if (!cmd.length) return;
const consoleWidget = this.widget('console');
if (cmd === ':m') {
if (consoleWidget.isMaximized__ === undefined) {
consoleWidget.isMaximized__ = false;
}
let constraints = {
type: 'fixed',
factor: consoleWidget.isMaximized__ ? 5 : this.widget('vLayout').height() - 4,
};
consoleWidget.isMaximized__ = !consoleWidget.isMaximized__;
this.widget('vLayout').setWidgetConstraints(consoleWidget, constraints);
return;
} else if (cmd[0] === ':') {
if (this.shortcuts_[cmd]) {
this.shortcuts_[cmd]();
return;
}
}
let note = this.widget('noteList').currentItem;
let folder = this.widget('folderList').currentItem;
let args = cliUtils.splitCommandString(cmd);
@ -260,7 +308,7 @@ class AppGui {
try {
await this.app().execCommand(args);
} catch (error) {
consoleWidget.bufferPush(error.message);
this.widget('console').bufferPush(error.message);
}
}
@ -281,6 +329,10 @@ class AppGui {
this.widget('noteText').text = text;
}
isSpecialKey(name) {
return ['ENTER', 'DOWN', 'UP', 'LEFT', 'RIGHT', 'DELETE', 'BACKSPACE', 'ESCAPE', 'TAB', 'SHIFT_TAB'].indexOf(name) >= 0;
}
async start() {
const term = this.term();
@ -302,16 +354,31 @@ class AppGui {
return;
}
if (!consoleWidget.hasFocus()) {
if (name == ':') {
consoleWidget.focus(':');
} else if (name in this.shortcuts_) {
const cmd = this.shortcuts_[name];
if (typeof cmd === 'function') {
cmd();
} else {
consoleWidget.bufferPush(cmd);
await this.processCommand(cmd);
const now = (new Date()).getTime();
if (now - this.lastShortcutKeyTime_ > 1000 || this.isSpecialKey(name)) {
this.currentShortcutKeys_ = name;
} else {
this.currentShortcutKeys_ += name;
}
this.lastShortcutKeyTime_ = now;
// Don't process shortcut keys if the console is active, except if the shortcut
// starts with CTRL (eg. CTRL+J CTRL+Z to maximize the console window).
if (!consoleWidget.hasFocus() || this.currentShortcutKeys_.indexOf('CTRL') === 0) {
this.logger().debug('Now: ' + name + ', Keys: ' + this.currentShortcutKeys_);
if (this.currentShortcutKeys_ in this.shortcuts_) {
const cmd = this.shortcuts_[this.currentShortcutKeys_].action;
if (!cmd.isDocOnly) {
this.currentShortcutKeys_ = '';
if (typeof cmd === 'function') {
cmd();
} else {
consoleWidget.bufferPush(cmd);
await this.processCommand(cmd);
}
}
}
}
@ -333,4 +400,7 @@ class AppGui {
}
AppGui.INPUT_MODE_NORMAL = 1;
AppGui.INPUT_MODE_META = 2;
module.exports = AppGui;

View File

@ -37,6 +37,10 @@ class Application {
this.eventEmitter_ = new EventEmitter();
}
gui() {
return this.gui_;
}
logger() {
return this.logger_;
}
@ -49,6 +53,10 @@ class Application {
return this.currentFolder_;
}
commandStdoutMaxWidth() {
return 78;
}
async refreshCurrentFolder() {
let newFolder = null;

View File

@ -3,8 +3,9 @@ import { app } from './app.js';
import { renderCommandHelp } from './help-utils.js';
import { Database } from 'lib/database.js';
import { Setting } from 'lib/models/setting.js';
import { wrap } from 'lib/string-utils.js';
import { _ } from 'lib/locale.js';
import { ReportService } from 'lib/services/report.js';
import { cliUtils } from './cli-utils.js';
class Command extends BaseCommand {
@ -17,18 +18,54 @@ class Command extends BaseCommand {
}
async action(args) {
const commands = args['command'] ? [app().findCommandByName(args['command'])] : app().commands();
const stdoutWidth = app().commandStdoutMaxWidth();
let output = [];
for (let n in commands) {
if (!commands.hasOwnProperty(n)) continue;
const command = commands[n];
output.push(renderCommandHelp(command));
if (args.command === 'shortcuts') {
const shortcuts = app().gui().shortcuts();
let rows = [];
for (let n in shortcuts) {
if (!shortcuts.hasOwnProperty(n)) continue;
const shortcut = shortcuts[n];
if (!shortcut.description) continue;
n = shortcut.friendlyName ? shortcut.friendlyName : n;
rows.push([n, shortcut.description]);
}
cliUtils.printArray(this.stdout.bind(this), rows);
} else if (args.command) {
const command = app().findCommandByName(args['command']);
if (!command) throw new Error(_('Cannot find "%s".', args.command));
this.stdout(renderCommandHelp(command, stdoutWidth));
} else {
const commands = app().commands();
let commandNames = [];
for (let n in commands) {
if (!commands.hasOwnProperty(n)) continue;
const command = commands[n];
commandNames.push(command.name());
}
commandNames.sort();
let lines = [];
lines.push(_('Type `help [command]` for more information about a command.'));
lines.push('');
lines.push(_('The possible commands are:'));
lines.push('');
lines.push(commandNames.join(', '));
lines.push('');
lines.push(_('To maximise/minimise the console, press Ctrl+J Ctrl+Z.'));
lines.push(_('To enter the console, press C'));
lines.push(_('To exit the console, press ESCAPE'));
lines.push(_('To view a list of available shortcuts type `help shortcuts`'));
this.stdout(wrap(lines.join("\n"), '', stdoutWidth));
}
output.sort();
this.stdout(output.join("\n\n"));
app().gui().maximizeConsole();
}
}

View File

@ -2,22 +2,22 @@ require('source-map-support').install();
require('babel-plugin-transform-runtime');
import fs from 'fs-extra';
import { wrap } from 'lib/string-utils.js';
import { fileExtension, basename, dirname } from 'lib/path-utils.js';
import wrap_ from 'word-wrap';
import { _, setLocale, languageCode } from 'lib/locale.js';
const rootDir = dirname(dirname(__dirname));
const MAX_WIDTH = 78;
const INDENT = ' ';
function wrap(text, indent) {
return wrap_(text, {
width: MAX_WIDTH - indent.length,
indent: indent,
});
}
// function wrap(text, indent, width) {
// return wrap_(text, {
// width: width - indent.length,
// indent: indent,
// });
// }
function renderOptions(options, baseIndent) {
function renderOptions(options, baseIndent, width) {
let output = [];
const optionColWidth = getOptionColWidth(options);
@ -26,7 +26,7 @@ function renderOptions(options, baseIndent) {
const flag = option[0];
const indent = baseIndent + INDENT + ' '.repeat(optionColWidth + 2);
let r = wrap(option[1], indent);
let r = wrap(option[1], indent, width);
r = r.substr(flag.length + (baseIndent + INDENT).length);
r = baseIndent + INDENT + flag + r;
output.push(r);
@ -35,15 +35,17 @@ function renderOptions(options, baseIndent) {
return output.join("\n");
}
function renderCommandHelp(cmd) {
function renderCommandHelp(cmd, width = null) {
if (width === null) width = MAX_WIDTH;
const baseIndent = '';
let output = [];
output.push(baseIndent + cmd.usage());
output.push('');
output.push(wrap(cmd.description(), baseIndent + INDENT));
output.push(wrap(cmd.description(), baseIndent + INDENT, width));
const optionString = renderOptions(cmd.options(), baseIndent);
const optionString = renderOptions(cmd.options(), baseIndent, width);
if (optionString) {
output.push('');

View File

@ -15,6 +15,30 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Delete a note"
msgstr ""
msgid "Set a todo as completed / not completed"
msgstr ""
msgid "Enter the console"
msgstr ""
msgid "Exit the console"
msgstr ""
msgid "Create a new todo"
msgstr ""
msgid "Create a new note"
msgstr ""
msgid "Create a new notebook"
msgstr ""
msgid "Maximise/minimise the console"
msgstr ""
msgid "[Cancel]"
msgstr ""
@ -180,6 +204,24 @@ msgstr ""
msgid "Displays usage information."
msgstr ""
msgid "Type `help [command]` for more information about a command."
msgstr ""
msgid "The possible commands are:"
msgstr ""
msgid "To maximise/minimise the console, press Ctrl+J Ctrl+Z."
msgstr ""
msgid "To enter the console, press C"
msgstr ""
msgid "To exit the console, press ESCAPE"
msgstr ""
msgid "To view a list of available shortcuts type `help shortcuts`"
msgstr ""
msgid "Imports an Evernote notebook file (.enex file)."
msgstr ""

View File

@ -15,6 +15,37 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.0.3\n"
#, fuzzy
msgid "Delete a note"
msgstr "Supprimer la note"
#, fuzzy
msgid "Set a todo as completed / not completed"
msgstr "Tâches non-complétées et récentes"
msgid "Enter the console"
msgstr ""
#, fuzzy
msgid "Exit the console"
msgstr "Quitter le logiciel."
#, fuzzy
msgid "Create a new todo"
msgstr "Créer une nouvelle tâche."
#, fuzzy
msgid "Create a new note"
msgstr "Créer une note."
#, fuzzy
msgid "Create a new notebook"
msgstr "Créer un carnet."
#, fuzzy
msgid "Maximise/minimise the console"
msgstr "Quitter le logiciel."
#, fuzzy
msgid "[Cancel]"
msgstr "Annulation..."
@ -197,6 +228,24 @@ msgstr "Afficher l'URL de l'emplacement de la note."
msgid "Displays usage information."
msgstr "Affiche les informations de version"
msgid "Type `help [command]` for more information about a command."
msgstr ""
msgid "The possible commands are:"
msgstr ""
msgid "To maximise/minimise the console, press Ctrl+J Ctrl+Z."
msgstr ""
msgid "To enter the console, press C"
msgstr ""
msgid "To exit the console, press ESCAPE"
msgstr ""
msgid "To view a list of available shortcuts type `help shortcuts`"
msgstr ""
msgid "Imports an Evernote notebook file (.enex file)."
msgstr "Importer un carnet Evernote (fichier .enex)."

View File

@ -15,6 +15,30 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Delete a note"
msgstr ""
msgid "Set a todo as completed / not completed"
msgstr ""
msgid "Enter the console"
msgstr ""
msgid "Exit the console"
msgstr ""
msgid "Create a new todo"
msgstr ""
msgid "Create a new note"
msgstr ""
msgid "Create a new notebook"
msgstr ""
msgid "Maximise/minimise the console"
msgstr ""
msgid "[Cancel]"
msgstr ""
@ -180,6 +204,24 @@ msgstr ""
msgid "Displays usage information."
msgstr ""
msgid "Type `help [command]` for more information about a command."
msgstr ""
msgid "The possible commands are:"
msgstr ""
msgid "To maximise/minimise the console, press Ctrl+J Ctrl+Z."
msgstr ""
msgid "To enter the console, press C"
msgstr ""
msgid "To exit the console, press ESCAPE"
msgstr ""
msgid "To view a list of available shortcuts type `help shortcuts`"
msgstr ""
msgid "Imports an Evernote notebook file (.enex file)."
msgstr ""

View File

@ -113,4 +113,13 @@ function escapeFilename(s, maxLength = 32) {
return output.substr(0, maxLength);
}
export { removeDiacritics, escapeFilename };
function wrap(text, indent, width) {
const wrap_ = require('word-wrap');
return wrap_(text, {
width: width - indent.length,
indent: indent,
});
}
export { removeDiacritics, escapeFilename, wrap };