Merge pull request #3909 from vector-im/t3chguy/favicon_improvements
Electron Tray Improvementspull/3975/head
						commit
						a9b5282ba3
					
				|  | @ -5,13 +5,12 @@ | |||
| /key.pem | ||||
| /lib | ||||
| /node_modules | ||||
| /electron/node_modules | ||||
| /electron_app/node_modules | ||||
| /electron_app/dist | ||||
| /packages/ | ||||
| /webapp | ||||
| /.npmrc | ||||
| .DS_Store | ||||
| npm-debug.log | ||||
| electron/dist | ||||
| electron/pub | ||||
| /config.json | ||||
| /src/component-index.js | ||||
|  |  | |||
|  | @ -161,12 +161,31 @@ function startAutoUpdate(update_base_url) { | |||
| // no other way to catch this error).
 | ||||
| // Assuming we generally run from the console when developing,
 | ||||
| // this is far preferable.
 | ||||
| process.on('uncaughtException', function (error) { | ||||
| process.on('uncaughtException', function(error) { | ||||
|     console.log("Unhandled exception", error); | ||||
| }); | ||||
| 
 | ||||
| electron.ipcMain.on('install_update', installUpdate); | ||||
| 
 | ||||
| let focusHandlerAttached = false; | ||||
| electron.ipcMain.on('setBadgeCount', function(ev, count) { | ||||
|     electron.app.setBadgeCount(count); | ||||
|     if (process.platform === 'win32' && mainWindow && !mainWindow.isFocused()) { | ||||
|         if (count > 0) { | ||||
|             if (!focusHandlerAttached) { | ||||
|                 mainWindow.once('focus', () => { | ||||
|                     mainWindow.flashFrame(false); | ||||
|                     focusHandlerAttached = false; | ||||
|                 }); | ||||
|                 focusHandlerAttached = true; | ||||
|             } | ||||
|             mainWindow.flashFrame(true); | ||||
|         } else { | ||||
|             mainWindow.flashFrame(false); | ||||
|         } | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| electron.app.commandLine.appendSwitch('--enable-usermedia-screen-capturing'); | ||||
| 
 | ||||
| const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirectory) => { | ||||
|  |  | |||
|  | @ -15,26 +15,21 @@ See the License for the specific language governing permissions and | |||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| const path = require('path'); | ||||
| const electron = require('electron'); | ||||
| 
 | ||||
| const app = electron.app; | ||||
| const Tray = electron.Tray; | ||||
| const MenuItem = electron.MenuItem; | ||||
| const {app, Tray, Menu, nativeImage} = require('electron'); | ||||
| 
 | ||||
| let trayIcon = null; | ||||
| 
 | ||||
| exports.hasTray = function hasTray() { | ||||
|     return (trayIcon !== null); | ||||
| } | ||||
| }; | ||||
| 
 | ||||
| exports.create = function (win, config) { | ||||
| exports.create = function(win, config) { | ||||
|     // no trays on darwin
 | ||||
|     if (process.platform === 'darwin' || trayIcon) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const toggleWin = function () { | ||||
|     const toggleWin = function() { | ||||
|         if (win.isVisible() && !win.isMinimized()) { | ||||
|             win.hide(); | ||||
|         } else { | ||||
|  | @ -44,24 +39,48 @@ exports.create = function (win, config) { | |||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     const contextMenu = electron.Menu.buildFromTemplate([ | ||||
|     const contextMenu = Menu.buildFromTemplate([ | ||||
|         { | ||||
|             label: 'Show/Hide ' + config.brand, | ||||
|             click: toggleWin | ||||
|             click: toggleWin, | ||||
|         }, | ||||
|         { | ||||
|             type: 'separator' | ||||
|             type: 'separator', | ||||
|         }, | ||||
|         { | ||||
|             label: 'Quit', | ||||
|             click: function () { | ||||
|             click: function() { | ||||
|                 app.quit(); | ||||
|             } | ||||
|         } | ||||
|             }, | ||||
|         }, | ||||
|     ]); | ||||
| 
 | ||||
|     trayIcon = new Tray(config.icon_path); | ||||
|     trayIcon.setToolTip(config.brand); | ||||
|     trayIcon.setContextMenu(contextMenu); | ||||
|     trayIcon.on('click', toggleWin); | ||||
| 
 | ||||
|     let lastFavicon = null; | ||||
|     win.webContents.on('page-favicon-updated', function(ev, favicons) { | ||||
|         let newFavicon = config.icon_path; | ||||
|         if (favicons && favicons.length > 0 && favicons[0].startsWith('data:')) { | ||||
|             newFavicon = favicons[0]; | ||||
|         } | ||||
| 
 | ||||
|         // No need to change, shortcut
 | ||||
|         if (newFavicon === lastFavicon) return; | ||||
|         lastFavicon = newFavicon; | ||||
| 
 | ||||
|         // if its not default we have to construct into nativeImage
 | ||||
|         if (newFavicon !== config.icon_path) { | ||||
|             newFavicon = nativeImage.createFromDataURL(favicons[0]); | ||||
|         } | ||||
| 
 | ||||
|         trayIcon.setImage(newFavicon); | ||||
|         win.setIcon(newFavicon); | ||||
|     }); | ||||
| 
 | ||||
|     win.webContents.on('page-title-updated', function(ev, title) { | ||||
|         trayIcon.setToolTip(title); | ||||
|     }); | ||||
| }; | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ limitations under the License. | |||
| import VectorBasePlatform from './VectorBasePlatform'; | ||||
| import dis from 'matrix-react-sdk/lib/dispatcher'; | ||||
| import q from 'q'; | ||||
| import electron, {remote} from 'electron'; | ||||
| import electron, {remote, ipcRenderer} from 'electron'; | ||||
| 
 | ||||
| remote.autoUpdater.on('update-downloaded', onUpdateDownloaded); | ||||
| 
 | ||||
|  | @ -58,16 +58,8 @@ export default class ElectronPlatform extends VectorBasePlatform { | |||
|     setNotificationCount(count: number) { | ||||
|         if (this.notificationCount === count) return; | ||||
|         super.setNotificationCount(count); | ||||
|         // this sometimes throws because electron is made of fail:
 | ||||
|         // https://github.com/electron/electron/issues/7351
 | ||||
|         // For now, let's catch the error, but I suspect it may
 | ||||
|         // continue to fail and we might just have to accept that
 | ||||
|         // electron's remote RPC is a non-starter for now and use IPC
 | ||||
|         try { | ||||
|             remote.app.setBadgeCount(count); | ||||
|         } catch (e) { | ||||
|             console.error('Failed to set notification count', e); | ||||
|         } | ||||
| 
 | ||||
|         ipcRenderer.send('setBadgeCount', count); | ||||
|     } | ||||
| 
 | ||||
|     supportsNotifications(): boolean { | ||||
|  |  | |||
|  | @ -17,12 +17,57 @@ See the License for the specific language governing permissions and | |||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import BasePlatform from 'matrix-react-sdk/lib/BasePlatform' | ||||
| import BasePlatform from 'matrix-react-sdk/lib/BasePlatform'; | ||||
| import Favico from 'favico.js'; | ||||
| 
 | ||||
| /** | ||||
|  * Vector-specific extensions to the BasePlatform template | ||||
|  */ | ||||
| export default class VectorBasePlatform extends BasePlatform { | ||||
|     constructor() { | ||||
|         super(); | ||||
| 
 | ||||
|         // The 'animations' are really low framerate and look terrible.
 | ||||
|         // Also it re-starts the animationb every time you set the badge,
 | ||||
|         // and we set the state each time, even if the value hasn't changed,
 | ||||
|         // so we'd need to fix that if enabling the animation.
 | ||||
|         this.favicon = new Favico({animation: 'none'}); | ||||
|         this._updateFavicon(); | ||||
|     } | ||||
| 
 | ||||
|     _updateFavicon() { | ||||
|         try { | ||||
|             // This needs to be in in a try block as it will throw
 | ||||
|             // if there are more than 100 badge count changes in
 | ||||
|             // its internal queue
 | ||||
|             let bgColor = "#d00", | ||||
|                 notif = this.notificationCount; | ||||
| 
 | ||||
|             if (this.errorDidOccur) { | ||||
|                 notif = notif || "×"; | ||||
|                 bgColor = "#f00"; | ||||
|             } | ||||
| 
 | ||||
|             this.favicon.badge(notif, { | ||||
|                 bgColor: bgColor, | ||||
|             }); | ||||
|         } catch (e) { | ||||
|             console.warn(`Failed to set badge count: ${e.message}`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     setNotificationCount(count: number) { | ||||
|         if (this.notificationCount === count) return; | ||||
|         super.setNotificationCount(count); | ||||
|         this._updateFavicon(); | ||||
|     } | ||||
| 
 | ||||
|     setErrorStatus(errorDidOccur: boolean) { | ||||
|         if (this.errorDidOccur === errorDidOccur) return; | ||||
|         super.setErrorStatus(errorDidOccur); | ||||
|         this._updateFavicon(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check for the availability of an update to the version of the | ||||
|      * app that's currently running. | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ limitations under the License. | |||
| */ | ||||
| 
 | ||||
| import VectorBasePlatform from './VectorBasePlatform'; | ||||
| import Favico from 'favico.js'; | ||||
| import request from 'browser-request'; | ||||
| import dis from 'matrix-react-sdk/lib/dispatcher.js'; | ||||
| import q from 'q'; | ||||
|  | @ -27,49 +26,6 @@ import url from 'url'; | |||
| import UAParser from 'ua-parser-js'; | ||||
| 
 | ||||
| export default class WebPlatform extends VectorBasePlatform { | ||||
|     constructor() { | ||||
|         super(); | ||||
|         this.runningVersion = null; | ||||
|         // The 'animations' are really low framerate and look terrible.
 | ||||
|         // Also it re-starts the animationb every time you set the badge,
 | ||||
|         // and we set the state each time, even if the value hasn't changed,
 | ||||
|         // so we'd need to fix that if enabling the animation.
 | ||||
|         this.favicon = new Favico({animation: 'none'}); | ||||
|         this._updateFavicon(); | ||||
|     } | ||||
| 
 | ||||
|     _updateFavicon() { | ||||
|         try { | ||||
|             // This needs to be in in a try block as it will throw
 | ||||
|             // if there are more than 100 badge count changes in
 | ||||
|             // its internal queue
 | ||||
|             let bgColor = "#d00", | ||||
|                 notif = this.notificationCount; | ||||
| 
 | ||||
|             if (this.errorDidOccur) { | ||||
|                 notif = notif || "×"; | ||||
|                 bgColor = "#f00"; | ||||
|             } | ||||
| 
 | ||||
|             this.favicon.badge(notif, { | ||||
|                 bgColor: bgColor, | ||||
|             }); | ||||
|         } catch (e) { | ||||
|             console.warn(`Failed to set badge count: ${e.message}`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     setNotificationCount(count: number) { | ||||
|         if (this.notificationCount === count) return; | ||||
|         super.setNotificationCount(count); | ||||
|         this._updateFavicon(); | ||||
|     } | ||||
| 
 | ||||
|     setErrorStatus(errorDidOccur: boolean) { | ||||
|         if (this.errorDidOccur === errorDidOccur) return; | ||||
|         super.setErrorStatus(errorDidOccur); | ||||
|         this._updateFavicon(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns true if the platform supports displaying | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 David Baker
						David Baker