From 13777f9eedc5f743b4c9921ca02dc64f9915941e Mon Sep 17 00:00:00 2001 From: "Enrique H. Oliva" Date: Sun, 1 Aug 2021 09:49:37 -0500 Subject: [PATCH] poc: tray icon render --- package.json | 2 +- src/config.ts | 3 +- src/images/{icon.png => iconTemplate.png} | Bin .../{icon@2x.png => iconTemplate@2x.png} | Bin src/images/testTemplate.png | Bin 0 -> 4937 bytes src/main.ts | 32 +------- src/render/preload.ts | 17 +++- src/session.ts | 20 +++-- src/store.ts | 11 +++ src/tray.ts | 76 ++++++++++++++++++ test.png | Bin 0 -> 700 bytes yarn.lock | 14 ++-- 12 files changed, 131 insertions(+), 44 deletions(-) rename src/images/{icon.png => iconTemplate.png} (100%) rename src/images/{icon@2x.png => iconTemplate@2x.png} (100%) create mode 100644 src/images/testTemplate.png create mode 100644 src/tray.ts create mode 100755 test.png diff --git a/package.json b/package.json index 3cc50ff..e65cad6 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@vue/eslint-config-typescript": "^5.0.2", "@vue/test-utils": "^2.0.0-0", "@wasm-tool/wasm-pack-plugin": "^1.3.1", - "electron": "^8.3.3", + "electron": "11.4.10", "electron-devtools-installer": "^3.1.0", "electron-log": "^4.3.4", "eslint": "^6.7.2", diff --git a/src/config.ts b/src/config.ts index 855b1b2..ceab21f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,5 +13,6 @@ export const config = { PLATFORM_URL: `${PLATFORM_IP}:${PLATFORM_PORT}`, BUSINESS_URL: `${BUSINESS_IP}:${BUSINESS_PORT}`, BUSINESS_PREFIX: '/api', - configPath: app.getPath('userData') + configPath: app.getPath('userData'), + appPath: app.getPath('appData') } diff --git a/src/images/icon.png b/src/images/iconTemplate.png similarity index 100% rename from src/images/icon.png rename to src/images/iconTemplate.png diff --git a/src/images/icon@2x.png b/src/images/iconTemplate@2x.png similarity index 100% rename from src/images/icon@2x.png rename to src/images/iconTemplate@2x.png diff --git a/src/images/testTemplate.png b/src/images/testTemplate.png new file mode 100644 index 0000000000000000000000000000000000000000..7f89df3656dee384a5c793589890f88a0c02b9c9 GIT binary patch literal 4937 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 Hu0mjfS`REF literal 0 HcmV?d00001 diff --git a/src/main.ts b/src/main.ts index 2cb205c..588b416 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,41 +12,15 @@ import initIpcMain from "@/ipc/index"; import { accountAuth } from "./account"; import createWindow from "./window"; +import { initTray } from './tray'; -import { Menu, Tray } from 'electron'; -const nativeImage = require('electron').nativeImage -import path, {resolve} from 'path'; - -let tray = null export default async function main() { - // TODO: fix image paths - // currently looking in dist-electron directory - // should be looking in source - console.log(resolve(__dirname, './images', 'icon.png')) - console.log(path.join(__dirname, './images/icon.png')) - try { - const image = nativeImage.createFromPath(resolve(__dirname, 'images', 'icon_16x16.png')); - const urlImage = nativeImage.createFromDataURL('https://github.com/vladimiry-playground/electron-quick-start-tray-issue/blob/master/icon.png'); - console.log(image) - console.log(urlImage) - tray = new Tray(resolve(__dirname, 'images', 'icon_16x16.png')) - } catch(e) { - console.log(e) - } - // const contextMenu = Menu.buildFromTemplate([ - // { label: 'Item1', type: 'radio' }, - // { label: 'Item2', type: 'radio' }, - // { label: 'Item3', type: 'radio', checked: true }, - // { label: 'Item4', type: 'radio' } - // ]) - // tray.setToolTip('This is my application.') - // tray.setContextMenu(contextMenu) - - /* initiate controls for frontend to use when needed */ initIpcMain(); + initTray(); + /* launch browser window */ await createWindow(); diff --git a/src/render/preload.ts b/src/render/preload.ts index 054f672..3cfbff5 100644 --- a/src/render/preload.ts +++ b/src/render/preload.ts @@ -1,6 +1,7 @@ // All of the Node.js APIs are available in the preload process. // It has the same sandbox as a Chrome extension. -import { ipcRenderer } from "electron"; +import { ipcRenderer, Tray, nativeImage } from "electron"; +const path = require('path') declare global { interface Window { @@ -12,6 +13,20 @@ window.ipcRenderer = ipcRenderer; process.once("loaded", () => { + const read = path.join(__dirname, 'icon_16x16.png') + console.log(read) + + const imgRead = nativeImage.createFromPath(read) + + let tray = undefined; + + + // Automatic generation of menu + tray = new Tray(imgRead) + + tray.destroy() + tray = new Tray(imgRead) + window.addEventListener("message", event => { // do something with custom event diff --git a/src/session.ts b/src/session.ts index f379f88..a1937b4 100644 --- a/src/session.ts +++ b/src/session.ts @@ -7,6 +7,13 @@ import { backgroundMitt, ipcEmit } from "@/composables/useEmitter"; import { Notification } from 'electron'; import { getWindowFocus, getWindowOpen } from './store'; +export const CONNECTION_STATUS = { + connected: 'Connected', + nominal: 'Nominal', + reconnecting: 'Reconnecting', + lost: 'Connection Lost', +}; + function showNotification (options: { title: string; subtitle?: string; @@ -29,7 +36,7 @@ const onMessageCallback = (payload: string) => { if (payload === "CLOSE_AUTH_FAIL") { backgroundMitt.emit("close-auth-fail"); - return + return; } const message = JSON.parse(payload) as ClientProtocol; @@ -58,15 +65,18 @@ const onMessageCallback = (payload: string) => { } + const connectionStatusCallback = (status: string) => { + // update icon + // backgroundMitt.emit("update-icon-status", status); ipcEmit('set-connection-status', status); } const statusOptions = { - openMessage: "Connected", - pongMessage: "Nominal", - closeMessage: "Reconnecting", - pingErrorMessage: "Connection Lost", + openMessage: CONNECTION_STATUS.connected, + pongMessage: CONNECTION_STATUS.nominal, + closeMessage: CONNECTION_STATUS.reconnecting, + pingErrorMessage: CONNECTION_STATUS.lost, } const { connect, send, close } = useWebsockets( diff --git a/src/store.ts b/src/store.ts index eab4cc7..227ac82 100644 --- a/src/store.ts +++ b/src/store.ts @@ -45,3 +45,14 @@ export const getWindowFocus = (): boolean | undefined => { return store.get("window.isFocused"); } + +/* + * Icon state management +* */ +export const setIconState = (state: string): void => { + store.set("iconStatus", state); +} + +export const getIconState = (): string | undefined => { + return store.get("iconStatus"); +} diff --git a/src/tray.ts b/src/tray.ts new file mode 100644 index 0000000..ac34bbd --- /dev/null +++ b/src/tray.ts @@ -0,0 +1,76 @@ + +import { Tray } from 'electron'; +const nativeImage = require('electron').nativeImage +import {NativeImage} from 'electron' +import path from 'path'; +import { backgroundMitt } from "@/composables/useEmitter"; +import { getIconState, setIconState } from "@/store"; +import { CONNECTION_STATUS } from '@/session'; +const fs = require('fs'); +import { config } from '@/config'; + +let tray: Tray | null = null + +const TRAY_STATUS = { + playback: 'playback', + recording: 'recording', + ...CONNECTION_STATUS +} + +const defaultIconPath = path.relative('src/main.ts', 'src/images/testTemplate.png'); + +console.log(path.join(__dirname, 'iconTemplate.png')) + +const imageBuffer = fs.readFileSync('test.png'); +const icon = nativeImage.createFromBuffer(imageBuffer); + +backgroundMitt.on('update-icon-status', (payload: string) => { + updateTray(payload); +}); + +const initIcon = (path: string): NativeImage => { + const icon = nativeImage.createFromPath(path); + icon.resize({ width: 16, height: 16 }); + icon.setTemplateImage(true); + return icon; +}; + +const icons = { + default: initIcon(defaultIconPath), +}; + +const updateTray = (status: string) => { + // read icon state + const current = getIconState(); + if (current !== status) { + setIconState(status); + if (tray) { + switch(status) { + case(TRAY_STATUS.recording): + break; + case(TRAY_STATUS.playback): + break; + case(TRAY_STATUS.nominal): + break; + case(TRAY_STATUS.lost): + break; + default: + tray.setImage(icons.default); + } + } + } +} + +console.log('app path', config.configPath) +export const initTray = () => { + try { + // check config path for icons + // if no icons + // fetch + // load from userData path + tray = new Tray(icon); + } catch(e) { + console.log('Error initilizing tray', e); + } +} + diff --git a/test.png b/test.png new file mode 100755 index 0000000000000000000000000000000000000000..f3b74a2a868ad980d3c0ae636d538d16eb7351fd GIT binary patch literal 700 zcmV;t0z>_YP)}-7)1bS0f(QW8eQK^~b&N)mcMP3vVbXMbq z5&^NdE}e6`TFnhgX7=ito`>xUNBo>JR{&$ zpjCMr|BTmDF_@b7EiYepX{cHfAt1lAUD|I59&mvkZ$q>mtg8aiiDBFse*t!751c;5 z5D*|qA5BBx=7MBaP>Dz1#?bd^Xtf}@Jf()h8#RW&OuXlkC9Q(FrwYEFQ_~H_uCky=5Y*UNJY9!#Zm>A`fv^}DK zZwP)VO_D{vd|&j+Z2QGi<_b>-uaK3PIJ=1e@ropiBuNPY2_zY`cPcq7T*}IhH=8;) z&l-ZPgp2rZkx1xCLhdF;kK^$X^V(bGrWpp-S~9`-^PkAd=N4jwC?g3IZpv1%O*ZW~ ibDnuizOt^3KiNOai@EeXWd#rb0000