poc: tray icon render
This commit is contained in:
parent
1c87ce45bc
commit
13777f9eed
12 changed files with 131 additions and 44 deletions
|
|
@ -55,7 +55,7 @@
|
||||||
"@vue/eslint-config-typescript": "^5.0.2",
|
"@vue/eslint-config-typescript": "^5.0.2",
|
||||||
"@vue/test-utils": "^2.0.0-0",
|
"@vue/test-utils": "^2.0.0-0",
|
||||||
"@wasm-tool/wasm-pack-plugin": "^1.3.1",
|
"@wasm-tool/wasm-pack-plugin": "^1.3.1",
|
||||||
"electron": "^8.3.3",
|
"electron": "11.4.10",
|
||||||
"electron-devtools-installer": "^3.1.0",
|
"electron-devtools-installer": "^3.1.0",
|
||||||
"electron-log": "^4.3.4",
|
"electron-log": "^4.3.4",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,6 @@ export const config = {
|
||||||
PLATFORM_URL: `${PLATFORM_IP}:${PLATFORM_PORT}`,
|
PLATFORM_URL: `${PLATFORM_IP}:${PLATFORM_PORT}`,
|
||||||
BUSINESS_URL: `${BUSINESS_IP}:${BUSINESS_PORT}`,
|
BUSINESS_URL: `${BUSINESS_IP}:${BUSINESS_PORT}`,
|
||||||
BUSINESS_PREFIX: '/api',
|
BUSINESS_PREFIX: '/api',
|
||||||
configPath: app.getPath('userData')
|
configPath: app.getPath('userData'),
|
||||||
|
appPath: app.getPath('appData')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4 KiB After Width: | Height: | Size: 4 KiB |
BIN
src/images/testTemplate.png
Normal file
BIN
src/images/testTemplate.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
32
src/main.ts
32
src/main.ts
|
|
@ -12,41 +12,15 @@
|
||||||
import initIpcMain from "@/ipc/index";
|
import initIpcMain from "@/ipc/index";
|
||||||
import { accountAuth } from "./account";
|
import { accountAuth } from "./account";
|
||||||
import createWindow from "./window";
|
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() {
|
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 */
|
/* initiate controls for frontend to use when needed */
|
||||||
initIpcMain();
|
initIpcMain();
|
||||||
|
|
||||||
|
initTray();
|
||||||
|
|
||||||
/* launch browser window */
|
/* launch browser window */
|
||||||
await createWindow();
|
await createWindow();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// All of the Node.js APIs are available in the preload process.
|
// All of the Node.js APIs are available in the preload process.
|
||||||
// It has the same sandbox as a Chrome extension.
|
// 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 {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
@ -12,6 +13,20 @@ window.ipcRenderer = ipcRenderer;
|
||||||
|
|
||||||
process.once("loaded", () => {
|
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 => {
|
window.addEventListener("message", event => {
|
||||||
|
|
||||||
// do something with custom event
|
// do something with custom event
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,13 @@ import { backgroundMitt, ipcEmit } from "@/composables/useEmitter";
|
||||||
import { Notification } from 'electron';
|
import { Notification } from 'electron';
|
||||||
import { getWindowFocus, getWindowOpen } from './store';
|
import { getWindowFocus, getWindowOpen } from './store';
|
||||||
|
|
||||||
|
export const CONNECTION_STATUS = {
|
||||||
|
connected: 'Connected',
|
||||||
|
nominal: 'Nominal',
|
||||||
|
reconnecting: 'Reconnecting',
|
||||||
|
lost: 'Connection Lost',
|
||||||
|
};
|
||||||
|
|
||||||
function showNotification (options: {
|
function showNotification (options: {
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
|
|
@ -29,7 +36,7 @@ const onMessageCallback = (payload: string) => {
|
||||||
|
|
||||||
if (payload === "CLOSE_AUTH_FAIL") {
|
if (payload === "CLOSE_AUTH_FAIL") {
|
||||||
backgroundMitt.emit("close-auth-fail");
|
backgroundMitt.emit("close-auth-fail");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = JSON.parse(payload) as ClientProtocol;
|
const message = JSON.parse(payload) as ClientProtocol;
|
||||||
|
|
@ -58,15 +65,18 @@ const onMessageCallback = (payload: string) => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const connectionStatusCallback = (status: string) => {
|
const connectionStatusCallback = (status: string) => {
|
||||||
|
// update icon
|
||||||
|
// backgroundMitt.emit("update-icon-status", status);
|
||||||
ipcEmit('set-connection-status', status);
|
ipcEmit('set-connection-status', status);
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusOptions = {
|
const statusOptions = {
|
||||||
openMessage: "Connected",
|
openMessage: CONNECTION_STATUS.connected,
|
||||||
pongMessage: "Nominal",
|
pongMessage: CONNECTION_STATUS.nominal,
|
||||||
closeMessage: "Reconnecting",
|
closeMessage: CONNECTION_STATUS.reconnecting,
|
||||||
pingErrorMessage: "Connection Lost",
|
pingErrorMessage: CONNECTION_STATUS.lost,
|
||||||
}
|
}
|
||||||
|
|
||||||
const { connect, send, close } = useWebsockets(
|
const { connect, send, close } = useWebsockets(
|
||||||
|
|
|
||||||
11
src/store.ts
11
src/store.ts
|
|
@ -45,3 +45,14 @@ export const getWindowFocus = (): boolean | undefined => {
|
||||||
return store.get("window.isFocused");
|
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");
|
||||||
|
}
|
||||||
|
|
|
||||||
76
src/tray.ts
Normal file
76
src/tray.ts
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BIN
test.png
Executable file
BIN
test.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 700 B |
14
yarn.lock
14
yarn.lock
|
|
@ -1482,9 +1482,9 @@
|
||||||
integrity sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==
|
integrity sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==
|
||||||
|
|
||||||
"@types/node@^12.0.12":
|
"@types/node@^12.0.12":
|
||||||
version "12.19.3"
|
version "12.20.17"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.3.tgz#a6e252973214079155f749e8bef99cc80af182fa"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.17.tgz#ffd44c2801fc527a6fe6e86bc9b900261df1c87e"
|
||||||
integrity sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg==
|
integrity sha512-so8EHl4S6MmatPS0f9sE1ND94/ocbcEshW5OpyYthRqeRpiYyW2uXYTo/84kmfdfeNrDycARkvuiXl6nO40NGg==
|
||||||
|
|
||||||
"@types/node@^12.12.47":
|
"@types/node@^12.12.47":
|
||||||
version "12.19.15"
|
version "12.19.15"
|
||||||
|
|
@ -5077,10 +5077,10 @@ electron-updater@^4.3.8:
|
||||||
lodash.isequal "^4.5.0"
|
lodash.isequal "^4.5.0"
|
||||||
semver "^7.3.4"
|
semver "^7.3.4"
|
||||||
|
|
||||||
electron@^8.3.3:
|
electron@11.4.10:
|
||||||
version "8.5.5"
|
version "11.4.10"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-8.5.5.tgz#17b12bd70139c0099f750fc5de0d480bf03acb96"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-11.4.10.tgz#7bcbca82810b82c2f2765824c5e11e3061272ea4"
|
||||||
integrity sha512-e355H+tRDial0m+X2v+l+0SnaATAPw4sNjv9qmdk/6MJz/glteVJwVJEnxTjPfEELIJSChrBWDBVpjdDvoBF4Q==
|
integrity sha512-aQTRgRdHwCW68gxz9qvGCfOUvR4NBbdecLB/mEWX8fMncDFvPMmm+dq2D6zSWWVEKywmsj3+wMMVn3UV2Cl2CQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^1.0.1"
|
"@electron/get" "^1.0.1"
|
||||||
"@types/node" "^12.0.12"
|
"@types/node" "^12.0.12"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue