Added Show in Dock Toggle and System Tray Feature (#90)

* Issue #62 Added Show in Dock, System Tray Toggle

* show dock toggle for mac only

* Add Open Heynote and Quit Heynote to Tray context menu

* Add Template Image as menu bar icon on MacOS

https://www.electronjs.org/docs/latest/api/native-image#template-image

* Use isMac, isWindows and isLinux for platform checks

* Add new tray/favicon

* Use favicon.ico as windows tray icon

* Show window on Tray double-click

* Open window when Tray is single clicked on non Mac platforms

* Fix indentation

* Remove unused import

---------

Co-authored-by: Jonatan Heyman <jonatan@heyman.info>
This commit is contained in:
Tanuj Pancholi 2024-01-02 00:32:30 +05:30 committed by GitHub
parent 4274e6237b
commit 0ba5820cf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 106 additions and 7 deletions

View File

@ -30,6 +30,8 @@ const schema = {
"enableGlobalHotkey": {type: "boolean", default: false}, "enableGlobalHotkey": {type: "boolean", default: false},
"globalHotkey": {type: "string", default: "CmdOrCtrl+Shift+H"}, "globalHotkey": {type: "string", default: "CmdOrCtrl+Shift+H"},
"bufferPath" : {type: "string", default: ""}, "bufferPath" : {type: "string", default: ""},
"showInDock": {type: "boolean", default: true},
"showInMenu": {type: "boolean", default: false},
}, },
}, },
@ -55,6 +57,8 @@ const defaults = {
enableGlobalHotkey: false, enableGlobalHotkey: false,
globalHotkey: "CmdOrCtrl+Shift+H", globalHotkey: "CmdOrCtrl+Shift+H",
bufferPath: "", bufferPath: "",
showInDock: true,
showInMenu: false,
}, },
theme: "system", theme: "system",
} }

View File

@ -1,14 +1,14 @@
import { app, BrowserWindow, shell, ipcMain, Menu, nativeTheme, globalShortcut } from 'electron' import { app, BrowserWindow, Tray, shell, ipcMain, Menu, nativeTheme, globalShortcut, nativeImage } from 'electron'
import { release } from 'node:os' import { release } from 'node:os'
import { join } from 'node:path' import { join } from 'node:path'
import * as jetpack from "fs-jetpack"; import * as jetpack from "fs-jetpack";
import menu from './menu' import { menu, getTrayMenu } from './menu'
import { initialContent, initialDevContent } from '../initial-content' import { initialContent, initialDevContent } from '../initial-content'
import { WINDOW_CLOSE_EVENT, SETTINGS_CHANGE_EVENT } from '../constants'; import { WINDOW_CLOSE_EVENT, SETTINGS_CHANGE_EVENT } from '../constants';
import CONFIG from "../config" import CONFIG from "../config"
import { onBeforeInputEvent } from "../keymap" import { onBeforeInputEvent } from "../keymap"
import { isDev } from '../detect-platform'; import { isDev, isMac, isWindows } from '../detect-platform';
import { initializeAutoUpdate, checkForUpdates } from './auto-update'; import { initializeAutoUpdate, checkForUpdates } from './auto-update';
import { fixElectronCors } from './cors'; import { fixElectronCors } from './cors';
import { getBufferFilePath, Buffer } from './buffer'; import { getBufferFilePath, Buffer } from './buffer';
@ -34,7 +34,7 @@ process.env.PUBLIC = process.env.VITE_DEV_SERVER_URL
if (release().startsWith('6.1')) app.disableHardwareAcceleration() if (release().startsWith('6.1')) app.disableHardwareAcceleration()
// Set application name for Windows 10+ notifications // Set application name for Windows 10+ notifications
if (process.platform === 'win32') app.setAppUserModelId(app.getName()) if (isWindows) app.setAppUserModelId(app.getName())
if (!process.env.VITE_DEV_SERVER_URL && !app.requestSingleInstanceLock()) { if (!process.env.VITE_DEV_SERVER_URL && !app.requestSingleInstanceLock()) {
app.quit() app.quit()
@ -51,6 +51,7 @@ Menu.setApplicationMenu(menu)
// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true' // process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
export let win: BrowserWindow | null = null export let win: BrowserWindow | null = null
let tray: Tray | null = null;
// Here, you can also use other preload // Here, you can also use other preload
const preload = join(__dirname, '../preload/index.js') const preload = join(__dirname, '../preload/index.js')
const url = process.env.VITE_DEV_SERVER_URL const url = process.env.VITE_DEV_SERVER_URL
@ -148,6 +149,23 @@ async function createWindow() {
fixElectronCors(win) fixElectronCors(win)
} }
function createTray() {
let img
if (isMac) {
img = nativeImage.createFromPath(join(process.env.PUBLIC, "iconTemplate.png"))
} else {
img = nativeImage.createFromPath(join(process.env.PUBLIC, 'favicon.ico'));
}
tray = new Tray(img);
tray.setToolTip("Heynote");
tray.setContextMenu(getTrayMenu(win));
tray.addListener("click", () => {
if (!isMac) {
win?.show()
}
})
}
function registerGlobalHotkey() { function registerGlobalHotkey() {
globalShortcut.unregisterAll() globalShortcut.unregisterAll()
if (CONFIG.get("settings.enableGlobalHotkey")) { if (CONFIG.get("settings.enableGlobalHotkey")) {
@ -176,14 +194,37 @@ function registerGlobalHotkey() {
} }
} }
function registerShowInDock() {
// dock is only available on macOS
if (isMac) {
if (CONFIG.get("settings.showInDock")) {
app.dock.show().catch((error) => {
console.log("Could not show app in dock: ", error);
});
} else {
app.dock.hide();
}
}
}
function registerShowInMenu() {
if (CONFIG.get("settings.showInMenu")) {
createTray()
} else {
tray?.destroy()
}
}
app.whenReady().then(createWindow).then(async () => { app.whenReady().then(createWindow).then(async () => {
initializeAutoUpdate(win) initializeAutoUpdate(win)
registerGlobalHotkey() registerGlobalHotkey()
registerShowInDock()
registerShowInMenu()
}) })
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
win = null win = null
if (process.platform !== 'darwin') app.quit() if (!isMac) app.quit()
}) })
app.on('second-instance', () => { app.on('second-instance', () => {
@ -245,7 +286,8 @@ ipcMain.handle('settings:set', (event, settings) => {
currentKeymap = settings.keymap currentKeymap = settings.keymap
} }
let globalHotkeyChanged = settings.enableGlobalHotkey !== CONFIG.get("settings.enableGlobalHotkey") || settings.globalHotkey !== CONFIG.get("settings.globalHotkey") let globalHotkeyChanged = settings.enableGlobalHotkey !== CONFIG.get("settings.enableGlobalHotkey") || settings.globalHotkey !== CONFIG.get("settings.globalHotkey")
let showInDockChanged = settings.showInDock !== CONFIG.get("settings.showInDock");
let showInMenuChanged = settings.showInMenu !== CONFIG.get("settings.showInMenu");
CONFIG.set("settings", settings) CONFIG.set("settings", settings)
win?.webContents.send(SETTINGS_CHANGE_EVENT, settings) win?.webContents.send(SETTINGS_CHANGE_EVENT, settings)
@ -253,4 +295,10 @@ ipcMain.handle('settings:set', (event, settings) => {
if (globalHotkeyChanged) { if (globalHotkeyChanged) {
registerGlobalHotkey() registerGlobalHotkey()
} }
if (showInDockChanged) {
registerShowInDock()
}
if (showInMenuChanged) {
registerShowInMenu()
}
}) })

View File

@ -140,5 +140,26 @@ const template = [
} }
] ]
export default Menu.buildFromTemplate(template) export const menu = Menu.buildFromTemplate(template)
export function getTrayMenu(win) {
return Menu.buildFromTemplate([
{
label: 'Open Heynote',
click: () => {
win.show()
},
},
{ type: 'separator' },
...template,
{ type: 'separator' },
{
label: 'Quit',
click: () => {
app.quit()
},
},
])
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/iconTemplate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
public/iconTemplate@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -28,6 +28,8 @@
allowBetaVersions: this.initialSettings.allowBetaVersions, allowBetaVersions: this.initialSettings.allowBetaVersions,
enableGlobalHotkey: this.initialSettings.enableGlobalHotkey, enableGlobalHotkey: this.initialSettings.enableGlobalHotkey,
globalHotkey: this.initialSettings.globalHotkey, globalHotkey: this.initialSettings.globalHotkey,
showInDock: this.initialSettings.showInDock,
showInMenu: this.initialSettings.showInMenu,
autoUpdate: this.initialSettings.autoUpdate, autoUpdate: this.initialSettings.autoUpdate,
activeTab: "general", activeTab: "general",
@ -58,6 +60,8 @@
allowBetaVersions: this.allowBetaVersions, allowBetaVersions: this.allowBetaVersions,
enableGlobalHotkey: this.enableGlobalHotkey, enableGlobalHotkey: this.enableGlobalHotkey,
globalHotkey: this.globalHotkey, globalHotkey: this.globalHotkey,
showInDock: this.showInDock,
showInMenu: this.showInMenu || !this.showInDock,
autoUpdate: this.autoUpdate, autoUpdate: this.autoUpdate,
}) })
}, },
@ -130,6 +134,28 @@
/> />
</div> </div>
</div> </div>
<div class="row">
<div class="entry">
<h2>Show In</h2>
<label v-if="isMac">
<input
type="checkbox"
v-model="showInDock"
@change="updateSettings"
/>
Show in dock
</label>
<label>
<input
type="checkbox"
:disabled="!showInDock"
v-model="showInMenu"
@change="updateSettings"
/>
Show system tray
</label>
</div>
</div>
</TabContent> </TabContent>
<TabContent tab="appearance" :activeTab="activeTab"> <TabContent tab="appearance" :activeTab="activeTab">