diff --git a/index.js b/index.js index fabf3312..7c79a1b6 100644 --- a/index.js +++ b/index.js @@ -75,6 +75,7 @@ function createMainWindow() { const windowSize = config.get("window-size"); const windowMaximized = config.get("window-maximized"); const windowPosition = config.get("window-position"); + const useInlineMenu = config.plugins.isEnabled("in-app-menu"); const win = new electron.BrowserWindow({ icon: icon, @@ -99,8 +100,12 @@ function createMainWindow() { } : undefined), }, - frame: !is.macOS() && !config.plugins.isEnabled("styled-bars"), - titleBarStyle: is.macOS() ? "hiddenInset" : "default", + frame: !is.macOS() && !useInlineMenu, + titleBarStyle: useInlineMenu + ? "hidden" + : is.macOS() + ? "hiddenInset" + : "default", autoHideMenuBar: config.get("options.hideMenu"), }); if (windowPosition) { diff --git a/menu.js b/menu.js index 68c96e77..f974c4e4 100644 --- a/menu.js +++ b/menu.js @@ -7,7 +7,7 @@ const is = require("electron-is"); const { getAllPlugins } = require("./plugins/utils"); const config = require("./config"); -const pluginEnabledMenu = (win, plugin, label = "", hasSubmenu=false) => ({ +const pluginEnabledMenu = (win, plugin, label = "", hasSubmenu = false) => ({ label: label || plugin, type: "checkbox", checked: config.plugins.isEnabled(plugin), @@ -17,13 +17,13 @@ const pluginEnabledMenu = (win, plugin, label = "", hasSubmenu=false) => ({ } else { config.plugins.disable(plugin); } - if(hasSubmenu) { + if (hasSubmenu) { this.setApplicationMenu(win); } }, }); -const mainMenuTemplate = (win) => [ +const mainMenuTemplate = (win, withRoles = true, isTray = false) => [ { label: "Plugins", submenu: [ @@ -34,6 +34,7 @@ const mainMenuTemplate = (win) => [ if (!config.plugins.isEnabled(plugin)) { return pluginEnabledMenu(win, plugin, "", true); } + const getPluginMenu = require(pluginPath); return { label: plugin, @@ -191,17 +192,59 @@ const mainMenuTemplate = (win) => [ }, ], }, - { - label: "View", - submenu: [ - { role: "reload" }, - { role: "forceReload" }, - { type: "separator" }, - { role: "zoomIn" }, - { role: "zoomOut" }, - { role: "resetZoom" }, - ], - }, + ...(!isTray + ? [ + { + label: "View", + submenu: withRoles + ? [ + { role: "reload" }, + { role: "forceReload" }, + { type: "separator" }, + { role: "zoomIn" }, + { role: "zoomOut" }, + { role: "resetZoom" }, + ] + : [ + { + label: "Reload", + click: () => { + win.webContents.reload(); + }, + }, + { + label: "Force Reload", + click: () => { + win.webContents.reloadIgnoringCache(); + }, + }, + { type: "separator" }, + { + label: "Zoom In", + click: () => { + win.webContents.setZoomLevel( + win.webContents.getZoomLevel() + 1 + ); + }, + }, + { + label: "Zoom Out", + click: () => { + win.webContents.setZoomLevel( + win.webContents.getZoomLevel() - 1 + ); + }, + }, + { + label: "Reset Zoom", + click: () => { + win.webContents.setZoomLevel(0); + }, + }, + ], + }, + ] + : []), { label: "Navigation", submenu: [ @@ -222,13 +265,22 @@ const mainMenuTemplate = (win) => [ }, }, { - label: 'Restart App', - click: () => {app.relaunch(); app.quit();} - } , - { - label: 'Quit App', - click: () => {app.quit();} - } + label: "Restart App", + click: () => { + app.relaunch(); + app.quit(); + }, + }, + ...(!isTray + ? [ + { + label: "Quit App", + click: () => { + app.quit(); + }, + }, + ] + : []), ], }, ]; diff --git a/plugins/in-app-menu/back.js b/plugins/in-app-menu/back.js new file mode 100644 index 00000000..3c77c377 --- /dev/null +++ b/plugins/in-app-menu/back.js @@ -0,0 +1,76 @@ +const path = require("path"); + +const { Menu } = require("electron"); +const electronLocalshortcut = require("electron-localshortcut"); + +const config = require("../../config"); +const { setApplicationMenu } = require("../../menu"); +const { injectCSS } = require("../utils"); + +//check that menu doesn't get created twice +let done = false; +// win hook for fixing menu +let win; + +const originalBuildMenu = Menu.buildFromTemplate; +// This function natively gets called on all submenu so no more reason to use recursion +Menu.buildFromTemplate = (template) => { + // Fix checkboxes and radio buttons + updateCheckboxesAndRadioButtons(win, template); + + // return as normal + return originalBuildMenu(template); +}; + +module.exports = (winImport) => { + win = winImport; + + // css for custom scrollbar + disable drag area(was causing bugs) + injectCSS(win.webContents, path.join(__dirname, "style.css")); + + win.on("ready-to-show", () => { + // (apparently ready-to-show is called twice) + if (done) { + return; + } + done = true; + + setApplicationMenu(win); + + //register keyboard shortcut && hide menu if hideMenu is enabled + if (config.get("options.hideMenu")) { + switchMenuVisibility(win); + electronLocalshortcut.register(win, "Esc", () => { + switchMenuVisibility(win); + }); + } + }); +}; + +let visible = true; +function switchMenuVisibility(win) { + visible = !visible; + win.webContents.send("updateMenu", visible); +} + +function checkCheckbox(win, item) { + //check item + item.checked = !item.checked; + //update menu (closes it) + win.webContents.send("updateMenu", true); +} + +// Update checkboxes/radio buttons +function updateCheckboxesAndRadioButtons(win, template) { + for (let item of template) { + // Change onClick of checkbox+radio + if ((item.type === "checkbox" || item.type === "radio") && !item.fixed) { + let originalOnclick = item.click; + item.click = (itemClicked) => { + originalOnclick(itemClicked); + checkCheckbox(win, itemClicked); + }; + item.fixed = true; + } + } +} diff --git a/plugins/in-app-menu/front.js b/plugins/in-app-menu/front.js new file mode 100644 index 00000000..3287dc5d --- /dev/null +++ b/plugins/in-app-menu/front.js @@ -0,0 +1,24 @@ +const { remote, ipcRenderer } = require("electron"); + +const customTitlebar = require("custom-electron-titlebar"); + +module.exports = () => { + const bar = new customTitlebar.Titlebar({ + backgroundColor: customTitlebar.Color.fromHex("#050505"), + itemBackgroundColor: customTitlebar.Color.fromHex("#121212"), + }); + bar.updateTitle(" "); + document.title = "Youtube Music"; + + ipcRenderer.on("updateMenu", function (event, menu) { + if (menu) { + bar.updateMenu(remote.Menu.getApplicationMenu()); + } else { + try { + bar.updateMenu(null); + } catch (e) { + //will always throw type error - null isn't menu, but it works + } + } + }); +}; diff --git a/plugins/styled-bars/style.css b/plugins/in-app-menu/style.css similarity index 53% rename from plugins/styled-bars/style.css rename to plugins/in-app-menu/style.css index f0d0c88b..25ae7c4a 100644 --- a/plugins/styled-bars/style.css +++ b/plugins/in-app-menu/style.css @@ -1,21 +1,22 @@ /* increase font size for menu and menuItems */ -.titlebar, .menubar-menu-container .action-label{ - font-size: 14px !important; +.titlebar, +.menubar-menu-container .action-label { + font-size: 14px !important; } /* allow submenu's to show correctly */ -.menubar-menu-container{ - overflow-y: visible !important; +.menubar-menu-container { + overflow-y: visible !important; } /* fixes scrollbar positioning relative to nav bar */ #nav-bar-background.ytmusic-app-layout { - right: 15px !important; + right: 15px !important; } /* remove window dragging for nav bar (conflict with titlebar drag) */ -ytmusic-nav-bar, +ytmusic-nav-bar, .tab-titleiron-icon, ytmusic-pivot-bar-item-renderer { - -webkit-app-region : unset; + -webkit-app-region: unset; } /* Move navBar downwards and make it opaque */ @@ -28,34 +29,41 @@ ytmusic-search-box.ytmusic-nav-bar { } .center-content.ytmusic-nav-bar { - background: #030303; + background: #030303; } -yt-page-navigation-progress, +yt-page-navigation-progress, #progress.yt-page-navigation-progress, -ytmusic-item-section-renderer[has-item-section-tabbed-header-renderer_] #header.ytmusic-item-section-renderer, +ytmusic-item-section-renderer[has-item-section-tabbed-header-renderer_] + #header.ytmusic-item-section-renderer, ytmusic-header-renderer.ytmusic-search-page { - top: 90px !important; + top: 90px !important; } /* Custom scrollbar */ ::-webkit-scrollbar { - width: 12px; - background-color: #030303; - -webkit-border-radius: 100px; + width: 12px; + background-color: #030303; + border-radius: 100px; + -moz-border-radius: 100px; + -webkit-border-radius: 100px; } /* hover effect for both scrollbar area, and scrollbar 'thumb' */ ::-webkit-scrollbar:hover { - background-color: rgba(15, 15, 15, 0.699); + background-color: rgba(15, 15, 15, 0.699); } /* The scrollbar 'thumb' ...that marque oval shape in a scrollbar */ ::-webkit-scrollbar-thumb:vertical { - background-clip: padding-box; - border: 2px solid rgba(0, 0, 0, 0); + background-clip: padding-box; + border: 2px solid rgba(0, 0, 0, 0); - background: rgb(49, 0, 0); - -webkit-border-radius: 100px; + background: rgb(49, 0, 0); + border-radius: 100px; + -moz-border-radius: 100px; + -webkit-border-radius: 100px; } ::-webkit-scrollbar-thumb:vertical:active { - background: rgb(56, 0, 0); /* Some darker color when you click it */ - -webkit-border-radius: 100px; -} \ No newline at end of file + background: rgb(56, 0, 0); /* Some darker color when you click it */ + border-radius: 100px; + -moz-border-radius: 100px; + -webkit-border-radius: 100px; +} diff --git a/plugins/styled-bars/back.js b/plugins/styled-bars/back.js deleted file mode 100644 index 65b55fc1..00000000 --- a/plugins/styled-bars/back.js +++ /dev/null @@ -1,107 +0,0 @@ -const { injectCSS } = require('../utils'); -const { Menu } = require('electron'); -const path = require('path'); -const electronLocalshortcut = require("electron-localshortcut"); -const config = require('../../config'); -const { setApplicationMenu } = require("../../menu"); - -//override Menu.buildFromTemplate, making it also fix the template -const originBuildMenu = Menu.buildFromTemplate; -//this function natively gets called on all submenu so no more reason to use recursion -Menu.buildFromTemplate = function (template) { - //fix checkbox and roles - fixMenu(template); - //return as normal - return originBuildMenu(template); -} - -//win hook for fixing menu -let win; - -//check that menu doesn't get created twice -let done = false; - -module.exports = winImport => { - win = winImport; - // css for custom scrollbar + disable drag area(was causing bugs) - injectCSS(win.webContents, path.join(__dirname, 'style.css')); - win.on('ready-to-show', () => { - // (apparently ready-to-show is called twice) - if (done) { - return - } - done = true; - - //refresh menu to fix it - setApplicationMenu(win); - - //register keyboard shortcut && hide menu if hideMenu is enabled - if (config.get('options.hideMenu')) { - switchMenuVisibility(); - electronLocalshortcut.register(win, 'Esc', () => { - switchMenuVisibility(); - }); - } - }); -}; - -let visible = true; -function switchMenuVisibility() { - visible=!visible; - win.webContents.send('updateMenu',visible) -} - -//go over each item in menu -function fixMenu(template) { - for (let item of template) { - //change onClick of checkbox+radio if not fixed - if ((item.type === 'checkbox' || item.type === 'radio') && !item.fixed) { - let ogOnclick = item.click; - item.click = (itemClicked) => { - ogOnclick(itemClicked); - checkCheckbox(itemClicked); - }; - item.fixed = true; - } - //customize roles (will be deleted soon) - else if (item.role != null) { - fixRoles(item) - } - } -} - -//custom menu doesn't support roles, so they get injected manually -function fixRoles(MenuItem) { - switch (MenuItem.role) { - case 'reload': - MenuItem.label = 'Reload'; - MenuItem.click = () => { win.webContents.reload(); } - break; - case 'forceReload': - MenuItem.label = 'Force Reload'; - MenuItem.click = () => { win.webContents.reloadIgnoringCache(); } - break; - case 'zoomIn': - MenuItem.label = 'Zoom In'; - MenuItem.click = () => { win.webContents.setZoomLevel(win.webContents.getZoomLevel() + 1); } - break; - case 'zoomOut': - MenuItem.label = 'Zoom Out'; - MenuItem.click = () => { win.webContents.setZoomLevel(win.webContents.getZoomLevel() - 1); } - break; - case 'resetZoom': - MenuItem.label = 'Reset Zoom'; - MenuItem.click = () => { win.webContents.setZoomLevel(0); } - break; - default: - console.log(`Error fixing MenuRoles: "${MenuItem.role}" was not expected`); - } - delete MenuItem.role; -} - -function checkCheckbox(item) { - //check item - item.checked = !item.checked; - //update menu (closes it) - win.webContents.send('updateMenu', true); -} diff --git a/plugins/styled-bars/front.js b/plugins/styled-bars/front.js deleted file mode 100644 index d5274364..00000000 --- a/plugins/styled-bars/front.js +++ /dev/null @@ -1,23 +0,0 @@ -const customTitlebar = require('custom-electron-titlebar'); -const {remote, ipcRenderer} = require('electron'); - -module.exports = () => { - const myBar = new customTitlebar.Titlebar({ - backgroundColor: customTitlebar.Color.fromHex('#050505'), - itemBackgroundColor: customTitlebar.Color.fromHex('#121212') - }); - myBar.updateTitle(' '); - document.title = 'Youtube Music'; - - ipcRenderer.on('updateMenu', function (event, menu) { - if (menu) { - myBar.updateMenu(remote.Menu.getApplicationMenu()); - } else { - try { - myBar.updateMenu(null); - } catch (e) { - //will always throw type error - null isn't menu, but it works - } - } - }); -}; \ No newline at end of file diff --git a/tray.js b/tray.js index e8eb22d3..e871f4bf 100644 --- a/tray.js +++ b/tray.js @@ -57,7 +57,7 @@ module.exports.setUpTray = (app, win) => { win.show(); }, }, - ...mainMenuTemplate(win), + ...mainMenuTemplate(win, true, true), { label: "Quit", click: () => { @@ -66,18 +66,6 @@ module.exports.setUpTray = (app, win) => { }, ]; - // delete quit button from navigation submenu - let navigation = getIndex(template,'Navigation'); - let quit = getIndex(template[navigation].submenu,'Quit App'); - delete template[navigation].submenu[quit]; - - // delete View submenu (all buttons are useless in tray) - delete template[getIndex(template, 'View')]; - const trayMenu = Menu.buildFromTemplate(template); tray.setContextMenu(trayMenu); }; - -function getIndex(arr,label) { - return arr.findIndex(item => item.label === label) -}