From 75cece3358707a3f450754d9fd3c7a8a8cbcdb27 Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Fri, 13 Oct 2017 16:49:16 -0700 Subject: [PATCH] Improve OS menu (#1563) * Remove reload options, new file/help menus, tools/log at bottom * Further menus refactor: install handlers at template creation * WIP: Further tune menus, add custom about window * New About window, new help menu items, menu labels now i18n * Default device name on registration is now computer hostname The OS of the device makes sense for those of us testing across a lot of different OSes. And maybe for a user with just one desktop device. But most users with multiple desktop devices are using the same OS for both. * About window: Only show window when content is ready * Fix typo in app/menu.js --- _locales/en/messages.json | 32 +++++++ about.html | 39 +++++++++ app/menu.js | 175 +++++++++++++++++++++++++------------- js/views/inbox_view.js | 1 - js/views/install_view.js | 8 +- main.js | 139 ++++++++++++++++++++++-------- test/index.html | 1 - 7 files changed, 290 insertions(+), 105 deletions(-) create mode 100644 about.html diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e1b7cebf2..a56d11baa 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -360,6 +360,38 @@ "message": "Submit debug log", "description": "Menu item and header text for debug log modal, title case." }, + "debugLog": { + "message": "Debug Log", + "description": "View menu item to open the debug log, capitalized" + }, + "goToReleaseNotes": { + "message": "Go to release notes", + "description": "" + }, + "goToForums": { + "message": "Go to forums", + "description": "Item under the Help menu, takes you to the forums" + }, + "goToSupportPage": { + "message": "Go to support page", + "description": "Item under the Help menu, takes you to the support page" + }, + "fileABug": { + "message": "File a bug", + "description": "Item under the Help menu, takes you to GitHub new issue form" + }, + "aboutSignalDesktop": { + "message": "About Signal Desktop", + "description": "Item under the Help menu, which opens a small about window" + }, + "speech": { + "message": "Speech", + "description": "Item under the Edit menu, with 'start/stop speaking' items below it" + }, + "show": { + "message": "Show", + "description": "Command under Window menu, to show the window" + }, "searchForPeopleOrGroups": { "message": "Search...", "description": "Placeholder text in the search input" diff --git a/about.html b/about.html new file mode 100644 index 000000000..93eba7e25 --- /dev/null +++ b/about.html @@ -0,0 +1,39 @@ + + + + + + + + + +
+ +
+
+ signal.org +
+ + + + diff --git a/app/menu.js b/app/menu.js index f004f21de..9c29c44b5 100644 --- a/app/menu.js +++ b/app/menu.js @@ -1,35 +1,48 @@ -const {Menu} = require('electron') +function createTemplate(options, messages) { + const showDebugLog = options.showDebugLog; + const showAbout = options.showAbout; + const openReleaseNotes = options.openReleaseNotes; + const openNewBugForm = options.openNewBugForm; + const openSupportPage = options.openSupportPage; + const openForums = options.openForums; -const template = [ + let template = [{ + label: 'File', + submenu: [ + { + role: 'quit', + }, + ] + }, { label: 'Edit', submenu: [ { - role: 'undo' + role: 'undo', }, { - role: 'redo' + role: 'redo', }, { - type: 'separator' + type: 'separator', }, { - role: 'cut' + role: 'cut', }, { - role: 'copy' + role: 'copy', }, { - role: 'paste' + role: 'paste', }, { - role: 'pasteandmatchstyle' + role: 'pasteandmatchstyle', }, { - role: 'delete' + role: 'delete', }, { - role: 'selectall' + role: 'selectall', } ] }, @@ -37,123 +50,163 @@ const template = [ label: 'View', submenu: [ { - label: 'Debug Log' + role: 'resetzoom', }, { - type: 'separator' + role: 'zoomin', }, { - role: 'reload' + role: 'zoomout', }, { - role: 'forcereload' + type: 'separator', }, { - role: 'toggledevtools' + role: 'togglefullscreen', }, { - type: 'separator' + type: 'separator', }, { - role: 'resetzoom' + label: messages.debugLog.message, + click: showDebugLog, }, { - role: 'zoomin' + type: 'separator', }, { - role: 'zoomout' + role: 'toggledevtools', }, - { - type: 'separator' - }, - { - role: 'togglefullscreen' - } ] }, { role: 'window', submenu: [ { - role: 'minimize' + role: 'minimize', + }, + ] + }, + { + role: 'help', + submenu: [ + { + label: messages.goToReleaseNotes.message, + click: openReleaseNotes, }, { - role: 'close' - } + type: 'separator', + }, + { + label: messages.goToForums.message, + click: openForums, + }, + { + label: messages.goToSupportPage.message, + click: openSupportPage, + }, + { + label: messages.fileABug.message, + click: openNewBugForm, + }, + { + type: 'separator', + }, + { + label: messages.aboutSignalDesktop.message, + click: showAbout, + }, ] - } -] + }]; -if (process.platform === 'darwin') { + if (process.platform === 'darwin') { + return updateForMac(template, messages, options); + } + + return template; +} + +function updateForMac(template, messages, options) { + const showWindow = options.showWindow; + const showAbout = options.showAbout; + + // Remove About item and separator from Help menu, since it's on the first menu + template[4].submenu.pop(); + template[4].submenu.pop(); + + // Replace File menu + template.shift(); template.unshift({ submenu: [ { - role: 'about' + label: messages.aboutSignalDesktop.message, + click: showAbout, }, { - type: 'separator' + type: 'separator', }, { - role: 'hide' + role: 'hide', }, { - role: 'hideothers' + role: 'hideothers', }, { - role: 'unhide' + role: 'unhide', }, { - type: 'separator' + type: 'separator', }, { - role: 'quit' - } + role: 'quit', + }, ] - }) - // Edit menu. + }); + + // Add to Edit menu template[1].submenu.push( { type: 'separator' }, { - label: 'Speech', + label: messages.speech.message, submenu: [ { - role: 'startspeaking' + role: 'startspeaking', }, { - role: 'stopspeaking' - } + role: 'stopspeaking', + }, ] } - ) - // Window menu. + ); + + // Add to Window menu template[3].submenu = [ { - label: 'Close', accelerator: 'CmdOrCtrl+W', - role: 'close' + role: 'close', }, { - label: 'Minimize', accelerator: 'CmdOrCtrl+M', - role: 'minimize' + role: 'minimize', }, { - label: 'Zoom', - role: 'zoom' + role: 'zoom', }, { - label: 'Show', + label: messages.show.message, + click: showWindow, }, { - type: 'separator' + type: 'separator', }, { - label: 'Bring All to Front', - role: 'front' - } - ] + role: 'front', + }, + ]; + + return template; } -module.exports = template; +module.exports = createTemplate; diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index e677d0562..bedccd633 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -147,7 +147,6 @@ welcomeToSignal : i18n('welcomeToSignal'), selectAContact : i18n('selectAContact'), searchForPeopleOrGroups : i18n('searchForPeopleOrGroups'), - submitDebugLog : i18n('submitDebugLog'), settings : i18n('settings'), restartSignal : i18n('restartSignal'), }, diff --git a/js/views/install_view.js b/js/views/install_view.js index 9ab37455a..e971ee46b 100644 --- a/js/views/install_view.js +++ b/js/views/install_view.js @@ -45,13 +45,7 @@ var deviceName = textsecure.storage.user.getDeviceName(); if (!deviceName) { - if (navigator.userAgent.match('Mac OS')) { - deviceName = 'Mac'; - } else if (navigator.userAgent.match('Linux')) { - deviceName = 'Linux'; - } else if (navigator.userAgent.match('Windows')) { - deviceName = 'Windows'; - } + deviceName = window.config.hostname; } this.$('#device-name').val(deviceName); diff --git a/main.js b/main.js index 57e98fe80..678112d36 100644 --- a/main.js +++ b/main.js @@ -1,5 +1,6 @@ const path = require('path'); const url = require('url'); +const os = require('os'); const electron = require('electron') @@ -52,6 +53,38 @@ const loadLocale = require('./app/locale').load; let locale; +function prepareURL(pathSegments) { + return url.format({ + pathname: path.join.apply(null, pathSegments), + protocol: 'file:', + slashes: true, + query: { + locale: locale.name, + version: app.getVersion(), + buildExpiration: config.get('buildExpiration'), + serverUrl: config.get('serverUrl'), + cdnUrl: config.get('cdnUrl'), + certificateAuthorities: config.get('certificateAuthorities'), + environment: config.environment, + node_version: process.versions.node, + hostname: os.hostname(), + } + }) +} + +function handleUrl(event, target) { + event.preventDefault(); + const protocol = url.parse(target).protocol; + if (protocol === 'http:' || protocol === 'https:') { + shell.openExternal(target); + } +} + +function captureClicks(window) { + window.webContents.on('will-navigate', handleUrl) + window.webContents.on('new-window', handleUrl); +} + function createWindow () { const windowOptions = Object.assign({ width: 800, @@ -112,24 +145,6 @@ function createWindow () { event.returnValue = locale.messages; }); - function prepareURL(pathSegments) { - return url.format({ - pathname: path.join.apply(null, pathSegments), - protocol: 'file:', - slashes: true, - query: { - locale: locale.name, - version: app.getVersion(), - buildExpiration: config.get('buildExpiration'), - serverUrl: config.get('serverUrl'), - cdnUrl: config.get('cdnUrl'), - certificateAuthorities: config.get('certificateAuthorities'), - environment: config.environment, - node_version: process.versions.node - } - }) - } - if (config.environment === 'test') { mainWindow.loadURL(prepareURL([__dirname, 'test', 'index.html'])); } else { @@ -141,13 +156,7 @@ function createWindow () { mainWindow.webContents.openDevTools() } - mainWindow.webContents.on('new-window', (e, url) => { - e.preventDefault(); - const protocol = require('url').parse(url).protocol - if (protocol === 'http:' || protocol === 'https:') { - shell.openExternal(url) - } - }); + captureClicks(mainWindow); mainWindow.webContents.on('will-navigate', function(e) { logger.info('will-navigate'); @@ -189,6 +198,65 @@ function showDebugLog() { } } +function showWindow() { + if (mainWindow) { + mainWindow.show(); + } +}; + +function openReleaseNotes() { + shell.openExternal('https://github.com/WhisperSystems/Signal-Desktop/releases/tag/v' + app.getVersion()); +} + +function openNewBugForm() { + shell.openExternal('https://github.com/WhisperSystems/Signal-Desktop/issues/new'); +} + +function openSupportPage() { + shell.openExternal('https://support.signal.org/hc/en-us/categories/202319038-Desktop'); +} + +function openForums() { + shell.openExternal('https://whispersystems.discoursehosting.net/'); +} + + +let aboutWindow; +function showAbout() { + if (aboutWindow) { + aboutWindow.show(); + return; + } + + const options = { + width: 500, + height: 400, + resizable: false, + title: locale.messages.aboutSignalDesktop.message, + autoHideMenuBar: true, + backgroundColor: '#2090EA', + show: false, + webPreferences: { + nodeIntegration: false, + preload: path.join(__dirname, 'preload.js') + } + }; + + aboutWindow = new BrowserWindow(options); + + captureClicks(aboutWindow); + + aboutWindow.loadURL(prepareURL([__dirname, 'about.html'])); + + aboutWindow.on('closed', function () { + aboutWindow = null; + }); + + aboutWindow.once('ready-to-show', function() { + aboutWindow.show(); + }); +} + // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. @@ -203,16 +271,17 @@ app.on('ready', function() { createWindow(); - let template = require('./app/menu.js'); - - if (process.platform === 'darwin') { - template[3].submenu[3].click = function() { - mainWindow.show(); - }; - template[2].submenu[0].click = showDebugLog; - } else { - template[1].submenu[0].click = showDebugLog; - } + const options = { + showDebugLog, + showWindow, + showAbout, + openReleaseNotes, + openNewBugForm, + openSupportPage, + openForums, + }; + const createTemplate = require('./app/menu.js'); + const template = createTemplate(options, locale.messages); const menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); diff --git a/test/index.html b/test/index.html index 7f559aa8c..dd7c478b4 100644 --- a/test/index.html +++ b/test/index.html @@ -47,7 +47,6 @@