refactor: improve native menu links

This commit is contained in:
Carlos Valente
2024-10-03 20:58:38 +02:00
committed by Carlos Valente
parent f1cac8d1c4
commit 0a53018930
15 changed files with 385 additions and 228 deletions
+260 -178
View File
@@ -1,185 +1,267 @@
const { shell } = require('electron');
const { Menu, shell } = require('electron');
const { linkToGitHub, linkToDocs, linkToDiscord, isMac, releaseTag, downloadPath } = require('../external');
/**
* Build description of application menu
* @param {boolean} isMac - Whether the target platform is mac
* Creates the application menu
* @param {function} askToQuit - function for quitting process
* @param {string} clientUrl - base url for the application
* @param {string} serverUrl - base url for the application
* @param {function} redirectWindow - function to redirect main window content
* @param {function} download - function to download a resource from url
* @returns {Menu} - application menu
*/
function getApplicationMenu(isMac, askToQuit, urlBase, version, redirectWindow) {
return [
...(isMac
? [
{
label: 'Ontime',
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ type: 'separator' },
{
label: 'Quit',
click: () => askToQuit(),
accelerator: 'Cmd+Q',
},
],
},
]
: []),
{
label: 'File',
submenu: [isMac ? { role: 'close' } : { role: 'quit' }],
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
...(isMac
? [
{ role: 'pasteAndMatchStyle' },
{ role: 'delete' },
{ role: 'selectAll' },
{ type: 'separator' },
{
label: 'Speech',
submenu: [{ role: 'startSpeaking' }, { role: 'stopSpeaking' }],
},
]
: [{ role: 'delete' }, { type: 'separator' }, { role: 'selectAll' }]),
],
},
{
label: 'Views',
submenu: [
{
label: 'Ontime Views (opens in browser)',
submenu: [
{
label: 'Public',
click: async () => {
await shell.openExternal(`${urlBase}/public`);
},
},
{
label: 'Lower Thirds',
click: async () => {
await shell.openExternal(`${urlBase}/lower`);
},
},
{ type: 'separator' },
{
label: 'Timer',
accelerator: 'CmdOrCtrl+V',
click: async () => {
await shell.openExternal(`${urlBase}/timer`);
},
},
{
label: 'Clock',
click: async () => {
await shell.openExternal(`${urlBase}/clock`);
},
},
{
label: 'Minimal Timer',
click: async () => {
await shell.openExternal(`${urlBase}/minimal`);
},
},
{
label: 'Backstage',
click: async () => {
await shell.openExternal(`${urlBase}/backstage`);
},
},
{
label: 'Timeline (beta)',
click: async () => {
await shell.openExternal(`${urlBase}/timeline`);
},
},
{
label: 'Studio Clock',
click: async () => {
await shell.openExternal(`${urlBase}/studio`);
},
},
{
label: 'Countdown',
click: async () => {
await shell.openExternal(`${urlBase}/countdown`);
},
},
{ type: 'separator' },
{
label: 'Editor',
click: async () => {
await shell.openExternal(`${urlBase}/editor`);
},
},
{
label: 'Cuesheet',
click: async () => {
await shell.openExternal(`${urlBase}/cuesheet`);
},
},
{
label: 'Operator',
click: async () => {
await shell.openExternal(`${urlBase}/op`);
},
},
],
},
{ type: 'separator' },
{ role: 'forceReload' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
],
},
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
...(isMac
? [{ type: 'separator' }, { role: 'front' }, { type: 'separator' }, { role: 'window' }]
: [{ role: 'close' }]),
],
},
{
role: 'help',
submenu: [
{
label: 'About',
click: () => redirectWindow('editor?settings=about'),
},
{
label: version,
click: () => redirectWindow('editor?settings=about'),
},
{
label: 'See on github',
click: async () => {
await shell.openExternal('https://github.com/cpvalente/ontime');
},
},
{
label: 'Online documentation',
click: async () => {
await shell.openExternal('https://docs.getontime.no/');
},
},
],
},
function getApplicationMenu(askToQuit, clientUrl, serverUrl, redirectWindow, download) {
const template = [
...(isMac ? [makeMacMenu(askToQuit)] : []),
makeFileMenu(serverUrl, redirectWindow, download),
makeViewMenu(clientUrl),
makeSettingsMenu(redirectWindow),
makeHelpMenu(redirectWindow),
];
return Menu.buildFromTemplate(template);
}
/**
* Utility function generates the app menu (macOS only)
* @param {function} askToQuit - function for quitting process
* @returns {Object}
*/
function makeMacMenu(askToQuit) {
return {
label: 'Ontime',
submenu: [
{ role: 'about', label: 'About Ontime' },
{ type: 'separator' },
{ role: 'hide', label: 'Hide Ontime' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ type: 'separator' },
{
label: 'Quit',
click: () => askToQuit(),
accelerator: isMac ? 'Cmd+Q' : 'Alt+F4',
},
],
};
}
/**
* Utility function generates the file menu
* @param {string} serverUrl - base url for the application
* @param {function} redirectWindow - function to redirect main window content
* @param {function} download - function to download a resource from url
* @returns {Object}
*/
function makeFileMenu(serverUrl, redirectWindow, download) {
const downloadProject = () => {
try {
download(serverUrl + downloadPath);
} catch (_error) {
/** unhandled error */
}
};
return {
label: 'File',
submenu: [
{
label: 'New project...',
click: () => redirectWindow('editor?settings=project__manage&create=true'),
},
{
label: 'Edit project info',
click: () => redirectWindow('editor?settings=project__data'),
},
{
label: 'Manage projects...',
click: () => redirectWindow('editor?settings=project__manage'),
},
{
label: 'Download project',
click: downloadProject,
},
{ role: isMac ? 'close' : 'quit' },
],
};
}
/**
* Utility function generates the views menu
* @param {string} clientUrl - base url for the application
* @returns {Object}
*/
function makeViewMenu(clientUrl) {
return {
label: 'Views',
submenu: [
makeItemOpenInShell('Public', `${clientUrl}/public`),
makeItemOpenInShell('Lower Thirds', `${clientUrl}/lower`),
{ type: 'separator' },
makeItemOpenInShell('Timer', `${clientUrl}/timer`),
makeItemOpenInShell('Minimal Timer', `${clientUrl}/minimal`),
makeItemOpenInShell('Clock', `${clientUrl}/clock`),
makeItemOpenInShell('Backstage', `${clientUrl}/backstage`),
makeItemOpenInShell('Timeline (beta)', `${clientUrl}/timeline`),
makeItemOpenInShell('Studio Clock', `${clientUrl}/studio`),
makeItemOpenInShell('Countdown', `${clientUrl}/countdown`),
{ type: 'separator' },
makeItemOpenInShell('Editor', `${clientUrl}/editor`),
makeItemOpenInShell('Cuesheet', `${clientUrl}/cuesheet`),
makeItemOpenInShell('Operator', `${clientUrl}/op`),
{ type: 'separator' },
{ role: 'forceReload' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' },
],
};
}
/**
* Utility function generates the settings menu
* @param {function} redirectWindow - function to redirect main window content
* @returns {Object}
*/
function makeSettingsMenu(redirectWindow) {
return {
label: 'Settings',
submenu: [
{
label: 'Open Settings',
accelerator: 'CommandOrControl+,',
click: () => redirectWindow('editor?settings=project'),
},
{
label: 'Project',
submenu: [
{
label: 'Project data',
click: () => redirectWindow('editor?settings=project__data'),
},
{
label: 'Manage projects',
click: () => redirectWindow('editor?settings=project__manage'),
},
],
},
{
label: 'App Settings',
submenu: [
{
label: 'General settings',
click: () => redirectWindow('editor?settings=general__settings'),
},
{
label: 'Editor settings',
click: () => redirectWindow('editor?settings=general__editor'),
},
{
label: 'View settings',
click: () => redirectWindow('editor?settings=general__view'),
},
],
},
{
label: 'Feature Settings',
submenu: [
{
label: 'Custom fields',
click: () => redirectWindow('editor?settings=feature_settings__custom'),
},
{
label: 'URL presets',
click: () => redirectWindow('editor?settings=feature_settings__urlpresets'),
},
],
},
{
label: 'Data Sources',
submenu: [
{
label: 'Import spreadsheet',
click: () => redirectWindow('editor?settings=sources__xlsx'),
},
{
label: 'Sync with Google Sheet',
click: () => redirectWindow('editor?settings=sources__gsheet'),
},
],
},
{
label: 'Integrations',
submenu: [
{
label: 'OSC settings',
click: () => redirectWindow('editor?settings=integrations__osc'),
},
{
label: 'HTTP settings',
click: () => redirectWindow('editor?settings=integrations__http'),
},
],
},
{
label: 'Network',
submenu: [
{
label: 'Event log',
click: () => redirectWindow('editor?settings=network__log'),
},
{
label: 'Manage cleints',
click: () => redirectWindow('editor?settings=network__clients'),
},
],
},
],
};
}
/**
* Utility function generates the help menu
* @param {function} redirectWindow - function to redirect main window content
* @returns {Object}
*/
function makeHelpMenu(redirectWindow) {
return {
role: 'help',
submenu: [
{
label: `Ontime ${releaseTag}`,
click: () => redirectWindow('editor?settings=about'),
},
{
type: 'separator',
},
makeItemOpenInShell('See on github', linkToGitHub),
makeItemOpenInShell('Online documentation', linkToDocs),
makeItemOpenInShell('Join us on Discord', linkToDiscord),
],
};
}
/**
* Utility function to safely open a URL in the default browser
* @param {string} label
* @param {string} url
* @returns {object} - MenuItem
*/
function makeItemOpenInShell(label, url) {
return {
label: `${label}`,
click: async () => {
try {
await shell.openExternal(url);
} catch (_error) {
/** unhandled error */
}
},
};
}
module.exports = { getApplicationMenu };
+8 -5
View File
@@ -1,19 +1,22 @@
const { Menu } = require('electron');
/**
* Build description of tray context menu
* Creates the application tray menu
* @param {function} showApp - function for making the window visible
* @param {function} askToQuit - function for quitting process
* @returns {Menu} - application tray menu
*/
function getTrayMenu(showApp, askToQuit) {
return [
return Menu.buildFromTemplate([
{
label: 'Show App',
click: () => showApp(),
click: showApp,
},
{
label: 'Shutdown',
click: () => askToQuit(),
click: askToQuit,
},
];
]);
}
module.exports = { getTrayMenu };