Before we used native method from electron for updating and notifying (`checkForUpdatesAndNotify`). It simply checked if there's an update, downloaded it, applied in the background and showed OS notification. The flow is now updated. Updates will be checked, user will be asked to confirm about whether to download and apply the updates, then a UI with progress bar will be shown and user will be asked to restart the application. This commit also moves electron related logic to `/electron/` folder (as there are now multiple files) to keep them structured. Also the electon entrypoint `background.ts` is renamed to `main.ts`. The reason it was named `background.ts` by vue-cli-plugin-electron-builder was to remove the confusion between `main.ts` of Vue itself. However, as they are kept in different folders, but this is not the case for us. Better than `checkForUpdatesAndNotify`. Organizes electron desktop app logic in same folder to allow using multiple files in a structured manner.
84 lines
2.8 KiB
TypeScript
84 lines
2.8 KiB
TypeScript
import { app, dialog } from 'electron';
|
|
import { autoUpdater, UpdateInfo } from 'electron-updater';
|
|
import { ProgressInfo } from 'electron-builder';
|
|
import log from 'electron-log';
|
|
import { UpdateProgressBar } from './UpdateProgressBar';
|
|
|
|
interface IUpdater {
|
|
checkForUpdatesAsync(): Promise<void>;
|
|
}
|
|
|
|
export function setupAutoUpdater(): IUpdater {
|
|
autoUpdater.logger = log;
|
|
autoUpdater.on('error', (error: Error) => {
|
|
log.error('@error@\n', error);
|
|
});
|
|
autoUpdater.on('update-available', async (info: UpdateInfo) => {
|
|
log.info('@update-available@\n', info);
|
|
await handleAvailableUpdateAsync();
|
|
});
|
|
return {
|
|
checkForUpdatesAsync: async () => {
|
|
await autoUpdater.checkForUpdates();
|
|
},
|
|
};
|
|
}
|
|
|
|
async function handleAvailableUpdateAsync() {
|
|
if (!await dialogs.askDownloadAndInstallAsync()) {
|
|
return;
|
|
}
|
|
autoUpdater.downloadUpdate();
|
|
handleUpdateProgress();
|
|
}
|
|
|
|
function handleUpdateProgress() {
|
|
const progressBar = new UpdateProgressBar();
|
|
progressBar.showIndeterminateState();
|
|
autoUpdater.on('error', (e) => {
|
|
progressBar.showError(e);
|
|
});
|
|
autoUpdater.on('download-progress', (progress: ProgressInfo) => {
|
|
/*
|
|
On macOS, download-progress event is not called
|
|
so the indeterminate progress will continue until download is finished.
|
|
*/
|
|
log.info('@update-progress@\n', progress);
|
|
progressBar.showProgress(progress);
|
|
});
|
|
autoUpdater.on('update-downloaded', async (info: UpdateInfo) => {
|
|
log.info('@update-downloaded@\n', info);
|
|
progressBar.close();
|
|
await handleUpdateDownloadedAsync();
|
|
});
|
|
}
|
|
|
|
const dialogs = {
|
|
askDownloadAndInstallAsync: async () => {
|
|
const updateDialogResult = await dialog.showMessageBox({
|
|
type: 'question',
|
|
buttons: ['Install', 'Not now' ],
|
|
title: 'Confirm Update',
|
|
message: 'Update available.\n\nWould you like to download and install new version?',
|
|
detail: 'Application will automatically restart to apply update after download',
|
|
});
|
|
return updateDialogResult.response === 0;
|
|
},
|
|
askRestartAndInstallAsync: async () => {
|
|
const installDialogResult = await dialog.showMessageBox({
|
|
type: 'question',
|
|
buttons: ['Install and restart', 'Later'],
|
|
defaultId: 0,
|
|
message: 'A new version of ' + app.name + ' has been downloaded',
|
|
detail: 'It will be installed the next time you restart the application',
|
|
});
|
|
return installDialogResult.response === 0;
|
|
},
|
|
};
|
|
|
|
async function handleUpdateDownloadedAsync() {
|
|
if (await dialogs.askRestartAndInstallAsync()) {
|
|
setTimeout(() => autoUpdater.quitAndInstall(), 1);
|
|
}
|
|
}
|