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
pull/749/head
Scott Nonnenberg 8 years ago committed by GitHub
parent 61a2a1a8f8
commit 75cece3358

@ -360,6 +360,38 @@
"message": "Submit debug log", "message": "Submit debug log",
"description": "Menu item and header text for debug log modal, title case." "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": { "searchForPeopleOrGroups": {
"message": "Search...", "message": "Search...",
"description": "Placeholder text in the search input" "description": "Placeholder text in the search input"

@ -0,0 +1,39 @@
<html>
<head>
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
<style>
body {
text-align: center;
background-color: #2090EA;
color: white;
font-size: 14px;
}
img {
margin-top: 2em;
margin-bottom: 1em;
}
a {
color: white;
}
</style>
</head>
<body>
<img src='images/icon_250.png'>
<div>
<script>
document.write('v', window.config.version);
</script>
</div>
<div>
<a href="https://signal.org">signal.org</a>
</div>
</body>
</html>

@ -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', label: 'Edit',
submenu: [ 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', label: 'View',
submenu: [ 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',
}, },
]
},
{
role: 'window',
submenu: [
{ {
type: 'separator' role: 'minimize',
}, },
{
role: 'togglefullscreen'
}
] ]
}, },
{ {
role: 'window', role: 'help',
submenu: [ submenu: [
{ {
role: 'minimize' 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') {
return updateForMac(template, messages, options);
} }
]
if (process.platform === 'darwin') { 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({ template.unshift({
submenu: [ 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( template[1].submenu.push(
{ {
type: 'separator' type: 'separator'
}, },
{ {
label: 'Speech', label: messages.speech.message,
submenu: [ submenu: [
{ {
role: 'startspeaking' role: 'startspeaking',
}, },
{ {
role: 'stopspeaking' role: 'stopspeaking',
} },
] ]
} }
) );
// Window menu.
// Add to Window menu
template[3].submenu = [ template[3].submenu = [
{ {
label: 'Close',
accelerator: 'CmdOrCtrl+W', accelerator: 'CmdOrCtrl+W',
role: 'close' role: 'close',
}, },
{ {
label: 'Minimize',
accelerator: 'CmdOrCtrl+M', 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;

@ -147,7 +147,6 @@
welcomeToSignal : i18n('welcomeToSignal'), welcomeToSignal : i18n('welcomeToSignal'),
selectAContact : i18n('selectAContact'), selectAContact : i18n('selectAContact'),
searchForPeopleOrGroups : i18n('searchForPeopleOrGroups'), searchForPeopleOrGroups : i18n('searchForPeopleOrGroups'),
submitDebugLog : i18n('submitDebugLog'),
settings : i18n('settings'), settings : i18n('settings'),
restartSignal : i18n('restartSignal'), restartSignal : i18n('restartSignal'),
}, },

@ -45,13 +45,7 @@
var deviceName = textsecure.storage.user.getDeviceName(); var deviceName = textsecure.storage.user.getDeviceName();
if (!deviceName) { if (!deviceName) {
if (navigator.userAgent.match('Mac OS')) { deviceName = window.config.hostname;
deviceName = 'Mac';
} else if (navigator.userAgent.match('Linux')) {
deviceName = 'Linux';
} else if (navigator.userAgent.match('Windows')) {
deviceName = 'Windows';
}
} }
this.$('#device-name').val(deviceName); this.$('#device-name').val(deviceName);

@ -1,5 +1,6 @@
const path = require('path'); const path = require('path');
const url = require('url'); const url = require('url');
const os = require('os');
const electron = require('electron') const electron = require('electron')
@ -52,6 +53,38 @@ const loadLocale = require('./app/locale').load;
let locale; 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 () { function createWindow () {
const windowOptions = Object.assign({ const windowOptions = Object.assign({
width: 800, width: 800,
@ -112,24 +145,6 @@ function createWindow () {
event.returnValue = locale.messages; 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') { if (config.environment === 'test') {
mainWindow.loadURL(prepareURL([__dirname, 'test', 'index.html'])); mainWindow.loadURL(prepareURL([__dirname, 'test', 'index.html']));
} else { } else {
@ -141,13 +156,7 @@ function createWindow () {
mainWindow.webContents.openDevTools() mainWindow.webContents.openDevTools()
} }
mainWindow.webContents.on('new-window', (e, url) => { captureClicks(mainWindow);
e.preventDefault();
const protocol = require('url').parse(url).protocol
if (protocol === 'http:' || protocol === 'https:') {
shell.openExternal(url)
}
});
mainWindow.webContents.on('will-navigate', function(e) { mainWindow.webContents.on('will-navigate', function(e) {
logger.info('will-navigate'); 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 // This method will be called when Electron has finished
// initialization and is ready to create browser windows. // initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs. // Some APIs can only be used after this event occurs.
@ -203,16 +271,17 @@ app.on('ready', function() {
createWindow(); createWindow();
let template = require('./app/menu.js'); const options = {
showDebugLog,
if (process.platform === 'darwin') { showWindow,
template[3].submenu[3].click = function() { showAbout,
mainWindow.show(); openReleaseNotes,
}; openNewBugForm,
template[2].submenu[0].click = showDebugLog; openSupportPage,
} else { openForums,
template[1].submenu[0].click = showDebugLog; };
} const createTemplate = require('./app/menu.js');
const template = createTemplate(options, locale.messages);
const menu = Menu.buildFromTemplate(template); const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu); Menu.setApplicationMenu(menu);

@ -47,7 +47,6 @@
<button class='hamburger' alt='signal menu'></button> <button class='hamburger' alt='signal menu'></button>
<ul class='menu-list'> <ul class='menu-list'>
<li class='showSettings'>{{ settings }}</li> <li class='showSettings'>{{ settings }}</li>
<li class='show-debug-log'>{{ submitDebugLog }}</li>
<li class='restart-signal'>{{ restartSignal }}</li> <li class='restart-signal'>{{ restartSignal }}</li>
</ul> </ul>
</div> </div>

Loading…
Cancel
Save