Skip to content

Commit

Permalink
#4 append and update first N clipboard items in tray menu
Browse files Browse the repository at this point in the history
  • Loading branch information
skoro committed Dec 15, 2024
1 parent 497520f commit 95db053
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 13 deletions.
35 changes: 23 additions & 12 deletions src/main/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { clipboardEventEmitter } from './clipboard';
import { keyboard } from '../renderer/keyshortcuts';
import {
setStartAppAtLogin, isPlatformLinux, isPlatformDarwin, saveImage, saveText, quitApp,
updateTrayContextMenu,
} from './system';

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
Expand All @@ -15,9 +16,20 @@ if (require('electron-squirrel-startup')) {
app.quit();
}

class AppBrowserWindow extends BrowserWindow {
/** @type {?Electron.Menu} */
trayContextMenu = null;
/** @type {?Electron.Tray} */
tray = null;

toggleVisibility() {
this.isVisible() ? this.hide() : this.show();
};
}

const createMainWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
const mainWindow = new AppBrowserWindow({
width: 380,
height: 640,
minWidth: 260,
Expand Down Expand Up @@ -70,28 +82,23 @@ const createMainWindow = () => {
ipcMain.on('open:url', (_, url) => shell.openExternal(url));
ipcMain.on('save:image', (_, image) => saveImage(mainWindow, image));
ipcMain.on('save:text', (_, text) => saveText(mainWindow, text));
// updates clipboard items in tray context menu
ipcMain.on('clipboard:top', (_, clips) => updateTrayContextMenu(mainWindow.tray, mainWindow.trayContextMenu, clips));

return mainWindow;
};

// Create and setup the application tray icon.
/**
* @param {BrowserWindow} mainWindow
* @param {AppBrowserWindow} mainWindow
*/
const createTrayIcon = (mainWindow) => {
const icon = nativeImage.createFromPath(path.join(__dirname, '..', '..', 'resources', 'icon.png'));
const tray = new Tray(icon);

const showHideCallback = () => {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show();
}
};

const contextMenu = Menu.buildFromTemplate([
{
id: 'quit',
label: 'Quit',
click: quitApp,
},
Expand All @@ -101,16 +108,20 @@ const createTrayIcon = (mainWindow) => {
// There is a menu item does the same as clicking on the icon to show/hide the main window.
if (isPlatformLinux()) {
contextMenu.insert(0, new MenuItem({
id: 'lnx-show-toggle',
label: 'Show/Hide',
click: () => showHideCallback(),
click: () => mainWindow.toggleVisibility(),
}));
contextMenu.insert(1, new MenuItem({ type: 'separator' }));
}

tray.setContextMenu(contextMenu);
tray.setToolTip('Pasted');

tray.on('click', () => showHideCallback());
tray.on('click', () => mainWindow.toggleVisibility());

mainWindow.trayContextMenu = contextMenu;
mainWindow.tray = tray;
};

/**
Expand Down
63 changes: 62 additions & 1 deletion src/main/system.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { app, dialog, nativeImage } from 'electron';
import {
app, dialog, nativeImage, MenuItem, Menu,
} from 'electron';
import path from 'node:path';
import { writeFile } from 'node:fs/promises';
import * as linux from './linux';
import { clipboardEventEmitter } from './clipboard';

/**
* @returns {boolean}
Expand Down Expand Up @@ -150,6 +153,63 @@ async function saveText(parentWindow, text, filename) {
}
}

/**
* Updates the application tray icon menu.
*
* @param {Electron.Tray} tray
* @param {Electron.Menu} contextMenu The tray context menu.
* @param {import('../models/clip').Model[]} clipItems=[] Appends the clipboard items to the context menu.
* @returns {Electron.Menu} The modified context menu.
*/
function updateTrayContextMenu(tray, contextMenu, clipItems) {
// Remove previously added clipboard items.
const menuItems = contextMenu.items.filter((item) => ! item.id?.startsWith('clipboard--'));

contextMenu = Menu.buildFromTemplate(menuItems);

if (clipItems?.length > 0) {
contextMenu.insert(0, new MenuItem({
id: 'clipboard--sep',
type: 'separator',
}));

for (const clipItem of clipItems) {
const label = stringCut(clipItem.data, 50);
contextMenu.insert(0, new MenuItem({
id: `clipboard--item-${clipItem.id}`,
label,
click: () => clipboardEventEmitter.copy(clipItem),
}));
}
}

// Linux: In order for changes made to individual MenuItems to take effect, you have to call setContextMenu again.
// https://www.electronjs.org/docs/latest/api/tray
if (isPlatformLinux()) {
tray.setContextMenu(contextMenu);
}

return contextMenu;
}

/**
* Cuts a string to the specified limit of characters.
*
* @param {string} str
* @param {number} limit A desired string limit.
* @param {string} trail='...' A trail appended to the end of the string longer than limit.
* @return {string}
*/
function stringCut(str, limit, trail = '...') {
const cutStr = str.trim();

if (cutStr.length <= limit) {
return cutStr;
}

return cutStr.slice(0, limit) + trail;
}

export {
isPlatformLinux,
isPlatformWindows,
Expand All @@ -158,4 +218,5 @@ export {
saveImage,
saveText,
quitApp,
updateTrayContextMenu,
};

0 comments on commit 95db053

Please sign in to comment.