|
5 | 5 |
|
6 | 6 | import path from 'path'; |
7 | 7 | import url from 'url'; |
8 | | -import { app, Menu } from 'electron'; |
| 8 | +import { app, Menu, Tray } from 'electron'; |
9 | 9 | import { autoUpdater } from 'electron-updater'; |
10 | 10 | import { baseMenuTemplate } from './menu/base_menu_template'; |
11 | 11 | import { devMenuTemplate } from './menu/dev_menu_template'; |
12 | 12 | import { helpMenuTemplate } from './menu/help_menu_template'; |
13 | 13 | import createWindow from './helpers/window'; |
14 | | -import { IS_WINDOWS } from './constants'; |
| 14 | +import { IS_MAC, IS_WINDOWS, IS_LINUX, IS_DEV } from './constants'; |
15 | 15 |
|
16 | 16 | // Special module holding environment variables which you declared |
17 | 17 | // in config/env_xxx.json file. |
18 | 18 | import env from 'env'; |
19 | 19 |
|
20 | | -const setApplicationMenu = () => { |
21 | | - const menus = baseMenuTemplate; |
| 20 | +let mainWindow = null; |
| 21 | + |
| 22 | +// Prevent multiple instances of the app which causes many problems with an app like ours |
| 23 | +// Without this, if an instance were minimized to the tray in Windows, clicking a shortcut would launch another instance, icky |
| 24 | +// Adapted from https://github.com/electron/electron/blob/v2.0.2/docs/api/app.md#appmakesingleinstancecallback |
| 25 | +const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => { |
| 26 | + // Someone tried to run a second instance, let's show our existing instance instead |
| 27 | + if (mainWindow) { |
| 28 | + if (!mainWindow.isVisible()) { |
| 29 | + mainWindow.show(); |
| 30 | + } |
| 31 | + } |
| 32 | +}); |
| 33 | + |
| 34 | +if (isSecondInstance) { |
| 35 | + app.quit() |
| 36 | +} else { |
| 37 | + let tray; // Must declare reference to instance of Tray as a variable, not a const, or bad/weird things happen |
| 38 | + |
| 39 | + const setApplicationMenu = () => { |
| 40 | + const menus = baseMenuTemplate; |
| 41 | + if (env.name !== 'production') { |
| 42 | + menus.push(devMenuTemplate); |
| 43 | + } |
| 44 | + menus.push(helpMenuTemplate); |
| 45 | + Menu.setApplicationMenu(Menu.buildFromTemplate(menus)); |
| 46 | + }; |
| 47 | + |
| 48 | + // Save userData in separate folders for each environment. |
| 49 | + // Thanks to this you can use production and development versions of the app |
| 50 | + // on same machine like those are two separate apps. |
22 | 51 | if (env.name !== 'production') { |
23 | | - menus.push(devMenuTemplate); |
| 52 | + const userDataPath = app.getPath('userData'); |
| 53 | + app.setPath('userData', `${userDataPath} (${env.name})`); |
24 | 54 | } |
25 | | - menus.push(helpMenuTemplate); |
26 | | - Menu.setApplicationMenu(Menu.buildFromTemplate(menus)); |
27 | | -}; |
28 | | - |
29 | | -// Save userData in separate folders for each environment. |
30 | | -// Thanks to this you can use production and development versions of the app |
31 | | -// on same machine like those are two separate apps. |
32 | | -if (env.name !== 'production') { |
33 | | - const userDataPath = app.getPath('userData'); |
34 | | - app.setPath('userData', `${userDataPath} (${env.name})`); |
35 | | -} |
36 | 55 |
|
37 | | -if (IS_WINDOWS) { |
38 | | - // Stupid, DUMB calls that have to be made to let notifications come through on Windows (only Windows 10?) |
39 | | - // See: https://github.com/electron/electron/issues/10864#issuecomment-382519150 |
40 | | - app.setAppUserModelId('com.knepper.android-messages-desktop'); |
41 | | - app.setAsDefaultProtocolClient('android-messages-desktop'); |
42 | | -} |
| 56 | + if (IS_WINDOWS) { |
| 57 | + // Stupid, DUMB calls that have to be made to let notifications come through on Windows (only Windows 10?) |
| 58 | + // See: https://github.com/electron/electron/issues/10864#issuecomment-382519150 |
| 59 | + app.setAppUserModelId('com.knepper.android-messages-desktop'); |
| 60 | + app.setAsDefaultProtocolClient('android-messages-desktop'); |
| 61 | + } |
43 | 62 |
|
44 | | -app.on('ready', () => { |
45 | | - setApplicationMenu(); |
46 | | - autoUpdater.checkForUpdatesAndNotify(); |
| 63 | + app.on('ready', () => { |
| 64 | + setApplicationMenu(); |
| 65 | + autoUpdater.checkForUpdatesAndNotify(); |
47 | 66 |
|
48 | | - const mainWindow = createWindow('main', { |
49 | | - width: 1100, |
50 | | - height: 800 |
51 | | - }); |
| 67 | + mainWindow = createWindow('main', { |
| 68 | + width: 1100, |
| 69 | + height: 800 |
| 70 | + }); |
52 | 71 |
|
53 | | - mainWindow.loadURL( |
54 | | - url.format({ |
55 | | - pathname: path.join(__dirname, 'app.html'), |
56 | | - protocol: 'file:', |
57 | | - slashes: true |
58 | | - }) |
59 | | - ); |
| 72 | + mainWindow.loadURL( |
| 73 | + url.format({ |
| 74 | + pathname: path.join(__dirname, 'app.html'), |
| 75 | + protocol: 'file:', |
| 76 | + slashes: true |
| 77 | + }) |
| 78 | + ); |
60 | 79 |
|
61 | | - if (env.name === 'development') { |
62 | | - mainWindow.openDevTools(); |
63 | | - } |
64 | | -}); |
| 80 | + app.mainWindow = mainWindow; // Quick and dirty way for renderer process to access mainWindow for communication |
65 | 81 |
|
66 | | -app.on('window-all-closed', () => { |
67 | | - app.quit(); |
68 | | -}); |
| 82 | + if (IS_MAC) { |
| 83 | + let quitViaContext = false; |
| 84 | + app.on('before-quit', () => { |
| 85 | + quitViaContext = true; |
| 86 | + }); |
| 87 | + |
| 88 | + mainWindow.on('close', (event) => { |
| 89 | + if (!quitViaContext) { |
| 90 | + event.preventDefault(); |
| 91 | + mainWindow.hide(); |
| 92 | + } |
| 93 | + }); |
| 94 | + |
| 95 | + app.on('activate', () => { |
| 96 | + mainWindow.show(); |
| 97 | + }); |
| 98 | + } |
| 99 | + |
| 100 | + if (IS_WINDOWS) { |
| 101 | + mainWindow.on('close', (event) => { |
| 102 | + app.quit(); |
| 103 | + }); |
| 104 | + |
| 105 | + tray = new Tray(__dirname + '../../resources/icon.ico'); |
| 106 | + |
| 107 | + let contextMenu = Menu.buildFromTemplate([ |
| 108 | + { |
| 109 | + label: 'Show', |
| 110 | + click: () => { |
| 111 | + mainWindow.show(); |
| 112 | + } |
| 113 | + }, |
| 114 | + { |
| 115 | + label: 'Quit', |
| 116 | + click: () => { |
| 117 | + app.quit(); |
| 118 | + } |
| 119 | + } |
| 120 | + ]); |
| 121 | + |
| 122 | + tray.setContextMenu(contextMenu); |
| 123 | + |
| 124 | + tray.on('double-click', (event) => { |
| 125 | + event.preventDefault(); |
| 126 | + mainWindow.show(); |
| 127 | + }); |
| 128 | + |
| 129 | + mainWindow.on('minimize', (event) => { |
| 130 | + event.preventDefault(); |
| 131 | + mainWindow.hide(); |
| 132 | + }); |
| 133 | + } |
| 134 | + |
| 135 | + // TODO: Better UX for Linux...likely similar to Windows as far as tray behavior |
| 136 | + if (IS_LINUX) { |
| 137 | + app.on('window-all-closed', (event) => { |
| 138 | + app.quit(); |
| 139 | + }); |
| 140 | + } |
| 141 | + |
| 142 | + if (IS_DEV) { |
| 143 | + mainWindow.openDevTools(); |
| 144 | + } |
| 145 | + }); |
| 146 | +} |
0 commit comments