Susi is an AI which replies smartly to anything that you put. Popular Assistants like Siri and Cortana, have their own tray icons that run on top of all apps. So, I thought to add a tray icon to SUSI AI as well.
A tray is an icon in an OS’s notification area usually attached with a context menu.
Platform limitations:
- On Linux, app indicator is used if it is supported else GtkStatusIcon is used
- App indicator is only shown when it has a context menu.
- When app indicator is used all click events are ignored.
Starting Up:
You should have Node and ElectronJS installed
To create a tray I made two methods. One is for creating a tray and other is for creating a window when a tray icon is clicked.
app.on('ready', () => { createTray() createWindow() })
app.on(‘ready’,() => {}) is called when the electron is ready to run. It’s just like the main function.
Then we create the Tray.
const createTray = () => { tray = new Tray(path.join(__dirname, 'static/icons/png/tray.png')) tray.on('right-click', toggleWindow) tray.on('double-click', toggleWindow) tray.on('click', function (event) { toggleWindow()
When some developer is using SUSI he might // Show devtools when command clicked if
(window.isVisible() && process.defaultApp && event.metaKey) { window.openDevTools({mode: 'detach'}) }}) }
Tray = new Tray(ICON HERE) // this creates a new tray with the icon specified.
Since there are 2 themes for the notification bar in OSX, I used a BLUE icon that looks good on both the themes.
I Used the icon above as a tray icon for SUSI.
Then next lines are for opening the tray with right-click or double-click. We can also change these functionalities like on right-click we can open some settings or give user an option to close the app.
const createWindow = () => { window = new BrowserWindow({ width: 300, height: 450, show: false, frame: false, fullscreenable: false, resizable: false, transparent: true, webPreferences: { // Prevents renderer process code from not running when window is // hidden backgroundThrottling: false } }) window.loadURL(`file://${path.join(__dirname, '/static/index.html')}`) // show inspect element in the window // window.openDevTools(); // set window to always be on the top of other windows window.setAlwaysOnTop(true); // Hide the window when it loses focus window.on('blur', () => { if (!window.webContents.isDevToolsOpened()) { window.hide() } }) }
When we call createWindow it creates a Window with the HTML File specified in loadURL
window.loadURL(`file://${path.join(__dirname, '/static/index.html')}`)
In this we created a SUSI Chat Client in HTML and named it as index.html and passed that HTML to be loaded as the application window.
Sometimes when we a running a full screen, Especially in macOS then all apps are launched behind the fullscreen app. To run our tray icon we used another function that set the window to be always on top of all other windows.
window.setAlwaysOnTop(true);
So if someone is reading a news article and wants to find a meaning of a word he need not open SUSI again, because SUSI is running on top of all the applications.
toggleWindow is called when we click the Tray Icon. The work of this function is fairly simple. On click of the tray icon, it makes hides or shows the SUSI application window.
const toggleWindow = () => { if (window.isVisible()) { window.hide() } else { showWindow() } }
showWindow is the function that shows the windows and brings it to focus.
This function brings the SUSI Window to focus and shows it to the user.
const showWindow = () => { const position = getWindowPosition() window.setPosition(position.x, position.y, false) window.show() window.focus() }
Running
Navigate to the project directory and run:
electron .
SUSI icon will be visible in your notification tray.
Resources:
SUSI Desktop App: https://github.com/fossasia/susi_desktop/
Electron Documentation: https://electron.atom.io/
Electron Packager: https://github.com/electron-userland/electron-packager