Convert Windows update alert dialog to native dialog in main process

Maybe a bit less polished, but I couldn't find a way to prevent the
main window from closing that works on the current version of Electron,
and in general it was starting to get too complicated.
This commit is contained in:
Alex Liebowitz 2018-01-05 01:29:31 -05:00
parent b08d96da1e
commit b03623eb68
8 changed files with 32 additions and 66 deletions

View file

@ -8,7 +8,7 @@ import Https from 'https';
import Keytar from 'keytar'; import Keytar from 'keytar';
import ChildProcess from 'child_process'; import ChildProcess from 'child_process';
import Assert from 'assert'; import Assert from 'assert';
import { app, BrowserWindow, globalShortcut, ipcMain, Menu, Tray } from 'electron'; import { app, dialog, BrowserWindow, globalShortcut, ipcMain, Menu, Tray } from 'electron';
import { autoUpdater } from 'electron-updater'; import { autoUpdater } from 'electron-updater';
import log from 'electron-log'; import log from 'electron-log';
import mainMenu from './menu/mainMenu'; import mainMenu from './menu/mainMenu';
@ -48,18 +48,14 @@ let daemonSubprocess;
// if it dies when we didn't ask it to shut down, we want to alert the user. // if it dies when we didn't ask it to shut down, we want to alert the user.
let daemonStopRequested = false; let daemonStopRequested = false;
// This keeps track of whether a new file has been downloaded. We mostly // This keeps track of whether the user has declined an update that was downloaded
// handle auto-update stuff in the render process, but need to know this // through the Electron auto-update system. When the user declines an update on Windows,
// in order to display the extra confirmation dialog we show on close // they will get a confusing dialog, so we show our own dialog first.
// on Windows. let autoUpdateDeclined = false;
let updateDownloaded;
if (process.platform === 'win32') {
updateDownloaded = false;
}
// This is used to keep track of whether we are showing he special dialog // This is used to keep track of whether we are showing he special dialog
// that we show on Windows after you decline an upgrade and close the app later. // that we show on Windows after you decline an upgrade and close the app later.
let showingUpdateCloseAlert = false; let showingAutoUpdateCloseAlert = false;
// When a quit is attempted, we cancel the quit, do some preparations, then // When a quit is attempted, we cancel the quit, do some preparations, then
@ -420,10 +416,6 @@ if (isDevelopment) {
}); });
} }
autoUpdater.on('update-downloaded', () => {
updateDownloaded = true;
});
app.setAsDefaultProtocolClient('lbry'); app.setAsDefaultProtocolClient('lbry');
app.on('ready', () => { app.on('ready', () => {
@ -449,18 +441,25 @@ app.on('window-all-closed', () => {
}); });
app.on('before-quit', event => { app.on('before-quit', event => {
if (process.platform === 'darwin' && updateDownloaded && !showingUpdateCloseAlert) { if (!readyToQuit) {
// We haven't shown the special dialog that we show on Windows
// if the user declines an update and then quits later
rendererWindow.webContents.send('quitRequested');
showingUpdateCloseAlert = true;
} else if (!readyToQuit) {
// We need to shutdown the daemon before we're ready to actually quit. This // We need to shutdown the daemon before we're ready to actually quit. This
// event will be triggered re-entrantly once preparation is done. // event will be triggered re-entrantly once preparation is done.
event.preventDefault(); event.preventDefault();
shutdownDaemonAndQuit(); shutdownDaemonAndQuit();
} else { } else if (process.platform == 'win32' && autoUpdateDeclined && !showingAutoUpdateCloseAlert) {
console.log('Quitting.'); // On Windows, if the user declined an update and closes the app later,
// they get a confusing permission escalation dialog, so we display a
// dialog to warn them.
event.preventDefault();
showingAutoUpdateCloseAlert = true;
dialog.showMessageBox({
type: "info",
title: "LBRY Will Upgrade",
message: "Please select \"Yes\" at the upgrade prompt shown after the app closes.",
}, () => {
// After the user approves the dialog, we can quit once and for all.
quitNow();
});
} }
}); });
@ -549,7 +548,11 @@ ipcMain.on('version-info-requested', () => {
ipcMain.on('autoUpdate', () => { ipcMain.on('autoUpdate', () => {
minimize = false; minimize = false;
autoUpdater.quitAndInstall(); app.quit();
});
ipcMain.on('autoUpdateDeclined', () => {
autoUpdateDeclined = true;
}); });
ipcMain.on('get-auth-token', event => { ipcMain.on('get-auth-token', event => {

View file

@ -3,7 +3,6 @@ export const INCOMPATIBLE_DAEMON = 'incompatibleDaemon';
export const FILE_TIMEOUT = 'file_timeout'; export const FILE_TIMEOUT = 'file_timeout';
export const DOWNLOADING = 'downloading'; export const DOWNLOADING = 'downloading';
export const AUTO_UPDATE_DOWNLOADED = "auto_update_downloaded"; export const AUTO_UPDATE_DOWNLOADED = "auto_update_downloaded";
export const UPDATE_CLOSE_ALERT = "updateCloseAlert";
export const ERROR = 'error'; export const ERROR = 'error';
export const INSUFFICIENT_CREDITS = 'insufficient_credits'; export const INSUFFICIENT_CREDITS = 'insufficient_credits';
export const UPGRADE = 'upgrade'; export const UPGRADE = 'upgrade';

View file

@ -9,7 +9,7 @@ import lbry from 'lbry';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { doConditionalAuthNavigate, doOpenModal, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app'; import { doConditionalAuthNavigate, doDaemonReady, doShowSnackBar, doAutoUpdate } from 'redux/actions/app';
import { doNavigate } from 'redux/actions/navigation'; import { doNavigate } from 'redux/actions/navigation';
import { doDownloadLanguages } from 'redux/actions/settings'; import { doDownloadLanguages } from 'redux/actions/settings';
import { doUserEmailVerify } from 'redux/actions/user'; import { doUserEmailVerify } from 'redux/actions/user';
@ -62,7 +62,7 @@ ipcRenderer.on('window-is-focused', () => {
dock.setBadge(''); dock.setBadge('');
}); });
(function(history, ...args) { ((history, ...args) => {
const { replaceState } = history; const { replaceState } = history;
const newHistory = history; const newHistory = history;
newHistory.replaceState = (_, __, path) => { newHistory.replaceState = (_, __, path) => {

View file

@ -2,7 +2,6 @@ import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { doCloseModal } from "redux/actions/app"; import { doCloseModal } from "redux/actions/app";
import ModalAutoUpdateDownloaded from "./view"; import ModalAutoUpdateDownloaded from "./view";
import { doCloseModal } from "redux/actions/app";
const perform = dispatch => ({ const perform = dispatch => ({
closeModal: () => dispatch(doCloseModal()), closeModal: () => dispatch(doCloseModal()),

View file

@ -19,7 +19,10 @@ class ModalAutoUpdateDownloaded extends React.PureComponent {
onConfirmed={() => { onConfirmed={() => {
ipcRenderer.send("autoUpdate"); ipcRenderer.send("autoUpdate");
}} }}
onAborted={closeModal} onAborted={() => {
ipcRenderer.send("autoUpdateDeclined");
closeModal();
}}
> >
<section> <section>
<h3 className="text-center">{__("LBRY Leveled Up")}</h3> <h3 className="text-center">{__("LBRY Leveled Up")}</h3>

View file

@ -3,7 +3,6 @@ import ModalError from 'modal/modalError';
import ModalAuthFailure from 'modal/modalAuthFailure'; import ModalAuthFailure from 'modal/modalAuthFailure';
import ModalDownloading from 'modal/modalDownloading'; import ModalDownloading from 'modal/modalDownloading';
import ModalAutoUpdateDownloaded from "modal/modalAutoUpdateDownloaded"; import ModalAutoUpdateDownloaded from "modal/modalAutoUpdateDownloaded";
import ModalUpdateCloseAlert from "modal/modalUpdateCloseAlert";
import ModalUpgrade from 'modal/modalUpgrade'; import ModalUpgrade from 'modal/modalUpgrade';
import ModalWelcome from 'modal/modalWelcome'; import ModalWelcome from 'modal/modalWelcome';
import ModalFirstReward from 'modal/modalFirstReward'; import ModalFirstReward from 'modal/modalFirstReward';
@ -106,8 +105,6 @@ class ModalRouter extends React.PureComponent {
return <ModalDownloading {...modalProps} />; return <ModalDownloading {...modalProps} />;
case modals.AUTO_UPDATE_DOWNLOADED: case modals.AUTO_UPDATE_DOWNLOADED:
return <ModalAutoUpdateDownloaded {...modalProps} />; return <ModalAutoUpdateDownloaded {...modalProps} />;
case modals.UPDATE_CLOSE_ALERT:
return <ModalUpdateCloseAlert {...modalProps} />;
case modals.ERROR: case modals.ERROR:
return <ModalError {...modalProps} />; return <ModalError {...modalProps} />;
case modals.FILE_TIMEOUT: case modals.FILE_TIMEOUT:

View file

@ -1,12 +0,0 @@
import React from 'react';
import { connect } from 'react-redux';
import { doQuit } from 'redux/actions/app';
import ModalUpdateCloseAlert from './view';
const select = state => ({});
const perform = dispatch => ({
quit: () => dispatch(doSkipUpgrade()),
});
export default connect(select, perform)(ModalUpdateCloseAlert);

View file

@ -1,23 +0,0 @@
import React from 'react';
import { Modal } from 'modal/modal';
import Link from 'component/link';
class ModalUpdateCloseAlert extends React.PureComponent {
render() {
const { quit } = this.props;
return (
<Modal
isOpen
type="alert"
confirmButtonLabel={__('Close Now')}
onConfirmed={quit}
>
<h3 className="text-center">{__('LBRY Will Upgrade')}</h3>
<p>{__('Please select yes to the upgrade prompt shown after the app closes.')}</p>
</Modal>
);
}
}
export default ModalUpdateCloseAlert;