diff --git a/src/main.js b/src/main.js index 8e0ab9d5..4829edad 100644 --- a/src/main.js +++ b/src/main.js @@ -26,29 +26,6 @@ import {protocols} from '../electron-builder.json'; import CriticalErrorHandler from './main/CriticalErrorHandler'; import {upgradeAutoLaunch} from './main/autoLaunch'; -import {createUpdaterWindow} from './main/autoUpdater'; - -autoUpdater.on('error', (err) => { - console.log('autoUpdater.on error'); - console.error(err); -}).on('checking-for-update', () => { - console.log('checking-for-update'); -}).on('update-available', (info) => { - console.log('update-available'); - console.log(info); -}).on('update-not-available', (info) => { - console.log('update-not-available'); - console.log(info); -}).on('download-progress', (progress) => { - console.log('download-progress'); - console.log(progress); -}).on('update-downloaded', (info) => { - console.log('update-downloaded'); - console.log(info); - setTimeout(() => { - autoUpdater.quitAndInstall(); - }, 5000); -}); const criticalErrorHandler = new CriticalErrorHandler(); @@ -78,7 +55,6 @@ const assetsDir = path.resolve(app.getAppPath(), 'assets'); // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. var mainWindow = null; -let updaterWindow; let spellChecker = null; let deeplinkingUrl = null; let scheme = null; @@ -675,6 +651,16 @@ app.on('ready', () => { permissionManager = new PermissionManager(permissionFile, trustedURLs); session.defaultSession.setPermissionRequestHandler(permissionRequestHandler(mainWindow, permissionManager)); + autoUpdater.initialize(appState, mainWindow); + ipcMain.on('check-for-updates', () => { + if (global.isDev) { + console.log('Development mode: Skip checking for updates'); + } else { + autoUpdater.checkForUpdates(); + } + }); + ipcMain.emit('check-for-updates'); + // Open the DevTools. // mainWindow.openDevTools(); }); diff --git a/src/main/AppStateManager.js b/src/main/AppStateManager.js index 847d3e13..0e4dec0f 100644 --- a/src/main/AppStateManager.js +++ b/src/main/AppStateManager.js @@ -11,4 +11,24 @@ export default class AppStateManager extends JsonFileManager { get lastAppVersion() { return this.getValue('lastAppVersion'); } + + set skippedVersion(version) { + this.setValue('skippedVersion', version); + } + + get skippedVersion() { + return this.getValue('skippedVersion'); + } + + set updateCheckedDate(date) { + this.setValue('updateCheckedDate', date.toISOString()); + } + + get updateCheckedDate() { + const date = this.getValue('updateCheckedDate'); + if (date) { + return new Date(date); + } + return null; + } } diff --git a/src/main/autoUpdater.js b/src/main/autoUpdater.js index 3a54e2d4..8d13887d 100644 --- a/src/main/autoUpdater.js +++ b/src/main/autoUpdater.js @@ -1,4 +1,11 @@ -const {app, BrowserWindow, ipcMain} = require('electron'); +const {app, BrowserWindow, dialog, ipcMain, shell} = require('electron'); +const path = require('path'); +const {autoUpdater} = require('electron-updater'); +const semver = require('semver'); + +const interval48hours = 172800000; // 48 * 60 * 60 * 1000 + +let updaterWindow = null; function setEvent(win, eventName) { ipcMain.on(eventName, (event) => { @@ -39,6 +46,56 @@ function createUpdaterWindow(options) { return win; } +function isUpdateApplicable(appState, updateInfo) { + if (appState.updateCheckedDate.value - (new Date(updateInfo.releaseDate)).value < interval48hours) { + return false; + } + return (appState.skippedVersion !== null) && semver.gt(updateInfo.version, appState.skippedVersion); +} + +function initialize(appState, mainWindow) { + const assetsDir = path.resolve(app.getAppPath(), 'assets'); + autoUpdater.on('error', (err) => { + console.error('Error in autoUpdater:', err.message); + }).on('checking-for-update', () => { + appState.updateCheckedDate = new Date(); + }).on('update-available', (info) => { + if (isUpdateApplicable(appState, info)) { + updaterWindow = createUpdaterWindow({linuxAppIcon: path.join(assetsDir, 'appicon.png'), nextVersion: '0.0.0'}); + updaterWindow.on('close', () => { + updaterWindow = null; + }); + updaterWindow.on('click-skip', () => { + appState.skippedVersion = info.version; + updaterWindow.close(); + }).on('click-remind', () => { + setTimeout(autoUpdater.checkForUpdates, interval48hours); + updaterWindow.close(); + }).on('click-install', () => { + autoUpdater.quitAndInstall(); + updaterWindow.close(); + }).on('click-release-notes', () => { + shell.openExternal(`https://github.com/mattermost/desktop/releases/v${info.version}`); + }); + } + }).on('update-not-available', () => { + dialog.showMessageBox(mainWindow, { + type: 'info', + buttons: ['Close'], + title: 'Your Desktop App is up to date', + message: 'You have the latest version of the Mattermost Desktop App.' + }, () => {}); // eslint-disable-line no-empty-function + setTimeout(autoUpdater.checkForUpdates, interval48hours); + }); +} + +function checkForUpdates() { + if (!updaterWindow) { + autoUpdater.checkForUpdates(); + } +} + module.exports = { - createUpdaterWindow + checkForUpdates, + initialize }; diff --git a/src/package.json b/src/package.json index 714eb325..91ea6860 100644 --- a/src/package.json +++ b/src/package.json @@ -21,6 +21,7 @@ "react-bootstrap": "~0.32.1", "react-dom": "^16.4.0", "react-transition-group": "^2.3.1", + "semver": "^5.5.0", "simple-spellchecker": "^0.9.6", "underscore": "^1.9.1", "yargs": "^3.32.0"