Multiple fixes in auto updates.
- Add "disable auto updates" setting (prevents downloading updates in the background but will still notify if there are newer versions) - Prevent downloading multiple times the same update - Hide nag when auto update modal is displayed
This commit is contained in:
parent
aa40a44ce3
commit
48c5f58a8e
10 changed files with 115 additions and 2 deletions
|
@ -39,6 +39,12 @@ let autoUpdateDownloaded = false;
|
||||||
// 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 showingAutoUpdateCloseAlert = false;
|
let showingAutoUpdateCloseAlert = false;
|
||||||
|
|
||||||
|
// This is used to prevent downloading updates multiple times.
|
||||||
|
// As read in the documentation:
|
||||||
|
// "Calling autoUpdater.checkForUpdates() twice will download the update two times."
|
||||||
|
// https://www.electronjs.org/docs/latest/api/auto-updater#autoupdatercheckforupdates
|
||||||
|
let keepCheckingForUpdates = true;
|
||||||
|
|
||||||
// Keep a global reference, if you don't, they will be closed automatically when the JavaScript
|
// Keep a global reference, if you don't, they will be closed automatically when the JavaScript
|
||||||
// object is garbage collected.
|
// object is garbage collected.
|
||||||
let rendererWindow;
|
let rendererWindow;
|
||||||
|
@ -315,16 +321,49 @@ ipcMain.on('upgrade', (event, installerPath) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('check-for-updates', () => {
|
ipcMain.on('check-for-updates', () => {
|
||||||
|
// Prevent downloading the same update multiple times.
|
||||||
|
if (!keepCheckingForUpdates) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
keepCheckingForUpdates = false;
|
||||||
autoUpdater.checkForUpdates();
|
autoUpdater.checkForUpdates();
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-downloaded', () => {
|
autoUpdater.on('update-downloaded', () => {
|
||||||
autoUpdateDownloaded = true;
|
autoUpdateDownloaded = true;
|
||||||
|
|
||||||
|
// If this download was trigger by
|
||||||
|
// autoUpdateAccepted it means, the user
|
||||||
|
// wants to install the new update but
|
||||||
|
// needed to downloaded the files first.
|
||||||
|
if (appState.autoUpdateAccepted) {
|
||||||
|
autoUpdater.quitAndInstall();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
autoUpdater.on('update-not-available', () => {
|
||||||
|
keepCheckingForUpdates = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('autoUpdateAccepted', () => {
|
ipcMain.on('autoUpdateAccepted', () => {
|
||||||
appState.autoUpdateAccepted = true;
|
appState.autoUpdateAccepted = true;
|
||||||
autoUpdater.quitAndInstall();
|
|
||||||
|
// quitAndInstall can only be called if the
|
||||||
|
// update has been downloaded. Since the user
|
||||||
|
// can disable auto updates, we have to make
|
||||||
|
// sure it has been downloaded first.
|
||||||
|
if (autoUpdateDownloaded) {
|
||||||
|
autoUpdater.quitAndInstall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the update hasn't been downloaded,
|
||||||
|
// start downloading it. After it's done, the
|
||||||
|
// event 'update-downloaded' will be triggered,
|
||||||
|
// where we will be able to resume the
|
||||||
|
// update installation.
|
||||||
|
autoUpdater.downloadUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('version-info-requested', () => {
|
ipcMain.on('version-info-requested', () => {
|
||||||
|
|
|
@ -2285,5 +2285,7 @@
|
||||||
"Enable Automatic Hosting": "Enable Automatic Hosting",
|
"Enable Automatic Hosting": "Enable Automatic Hosting",
|
||||||
"Download and serve arbitrary data on the network.": "Download and serve arbitrary data on the network.",
|
"Download and serve arbitrary data on the network.": "Download and serve arbitrary data on the network.",
|
||||||
"View History Hosting": "View History Hosting",
|
"View History Hosting": "View History Hosting",
|
||||||
|
"Disable automatic updates": "Disable automatic updates",
|
||||||
|
"Preven't new updates to be downloaded automatically in the background (we will keep notifying you if there is an update)": "Preven't new updates to be downloaded automatically in the background (we will keep notifying you if there is an update)",
|
||||||
"--end--": "--end--"
|
"--end--": "--end--"
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
selectAutoUpdateDownloaded,
|
selectAutoUpdateDownloaded,
|
||||||
selectModal,
|
selectModal,
|
||||||
selectActiveChannelClaim,
|
selectActiveChannelClaim,
|
||||||
|
selectIsUpdateModelDisplayed,
|
||||||
} from 'redux/selectors/app';
|
} from 'redux/selectors/app';
|
||||||
import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings';
|
import { doGetWalletSyncPreference, doSetLanguage } from 'redux/actions/settings';
|
||||||
import { doSyncLoop } from 'redux/actions/sync';
|
import { doSyncLoop } from 'redux/actions/sync';
|
||||||
|
@ -50,6 +51,7 @@ const select = (state) => ({
|
||||||
myChannelUrls: selectMyChannelUrls(state),
|
myChannelUrls: selectMyChannelUrls(state),
|
||||||
myChannelClaimIds: selectMyChannelClaimIds(state),
|
myChannelClaimIds: selectMyChannelClaimIds(state),
|
||||||
subscriptions: selectSubscriptions(state),
|
subscriptions: selectSubscriptions(state),
|
||||||
|
isUpdateModalDisplayed: selectIsUpdateModelDisplayed(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
|
|
|
@ -76,6 +76,7 @@ type Props = {
|
||||||
fetchModBlockedList: () => void,
|
fetchModBlockedList: () => void,
|
||||||
resolveUris: (Array<string>) => void,
|
resolveUris: (Array<string>) => void,
|
||||||
fetchModAmIList: () => void,
|
fetchModAmIList: () => void,
|
||||||
|
isUpdateModalDisplayed: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function App(props: Props) {
|
function App(props: Props) {
|
||||||
|
@ -111,6 +112,7 @@ function App(props: Props) {
|
||||||
resolveUris,
|
resolveUris,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
fetchModAmIList,
|
fetchModAmIList,
|
||||||
|
isUpdateModalDisplayed,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const appRef = useRef();
|
const appRef = useRef();
|
||||||
|
@ -345,7 +347,7 @@ function App(props: Props) {
|
||||||
<FileRenderFloating />
|
<FileRenderFloating />
|
||||||
{isEnhancedLayout && <Yrbl className="yrbl--enhanced" />}
|
{isEnhancedLayout && <Yrbl className="yrbl--enhanced" />}
|
||||||
|
|
||||||
{showUpgradeButton && (
|
{showUpgradeButton && !isUpdateModalDisplayed && (
|
||||||
<Nag
|
<Nag
|
||||||
message={__('An upgrade is available.')}
|
message={__('An upgrade is available.')}
|
||||||
actionText={__('Install Now')}
|
actionText={__('Install Now')}
|
||||||
|
|
17
ui/component/settingDisableAutoUpdates/index.js
Normal file
17
ui/component/settingDisableAutoUpdates/index.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import SettingDisableAutoUpdates from './view';
|
||||||
|
import * as SETTINGS from 'constants/settings';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
|
|
||||||
|
const select = (state) => {
|
||||||
|
return {
|
||||||
|
disableAutoUpdates: makeSelectClientSetting(SETTINGS.DISABLE_AUTO_UPDATES)(state),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const perform = (dispatch) => ({
|
||||||
|
setClientSetting: (value) => dispatch(doSetClientSetting(SETTINGS.DISABLE_AUTO_UPDATES, value)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(SettingDisableAutoUpdates);
|
30
ui/component/settingDisableAutoUpdates/view.jsx
Normal file
30
ui/component/settingDisableAutoUpdates/view.jsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import * as remote from '@electron/remote';
|
||||||
|
import { FormField } from 'component/common/form';
|
||||||
|
|
||||||
|
const { autoUpdater } = remote.require('electron-updater');
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
setClientSetting: (boolean) => void,
|
||||||
|
disableAutoUpdates: boolean,
|
||||||
|
};
|
||||||
|
function SettingDisableAutoUpdates(props: Props) {
|
||||||
|
const { setClientSetting, disableAutoUpdates } = props;
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="autoupdates"
|
||||||
|
onChange={() => {
|
||||||
|
const newDisableAutoUpdates = !disableAutoUpdates;
|
||||||
|
autoUpdater.autoDownload = !newDisableAutoUpdates;
|
||||||
|
setClientSetting(newDisableAutoUpdates);
|
||||||
|
}}
|
||||||
|
checked={disableAutoUpdates}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SettingDisableAutoUpdates;
|
|
@ -18,6 +18,7 @@ import Spinner from 'component/spinner';
|
||||||
import { getPasswordFromCookie } from 'util/saved-passwords';
|
import { getPasswordFromCookie } from 'util/saved-passwords';
|
||||||
import * as DAEMON_SETTINGS from 'constants/daemon_settings';
|
import * as DAEMON_SETTINGS from 'constants/daemon_settings';
|
||||||
import SettingEnablePrereleases from 'component/settingEnablePrereleases';
|
import SettingEnablePrereleases from 'component/settingEnablePrereleases';
|
||||||
|
import SettingDisableAutoUpdates from 'component/settingDisableAutoUpdates';
|
||||||
|
|
||||||
const IS_MAC = process.platform === 'darwin';
|
const IS_MAC = process.platform === 'darwin';
|
||||||
|
|
||||||
|
@ -222,6 +223,14 @@ export default function SettingSystem(props: Props) {
|
||||||
>
|
>
|
||||||
<SettingEnablePrereleases />
|
<SettingEnablePrereleases />
|
||||||
</SettingsRow>
|
</SettingsRow>
|
||||||
|
<SettingsRow
|
||||||
|
title={__('Disable automatic updates')}
|
||||||
|
subtitle={__(
|
||||||
|
"Preven't new updates to be downloaded automatically in the background (we will keep notifying you if there is an update)"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<SettingDisableAutoUpdates />
|
||||||
|
</SettingsRow>
|
||||||
<SettingsRow
|
<SettingsRow
|
||||||
title={
|
title={
|
||||||
<span>
|
<span>
|
||||||
|
|
|
@ -45,6 +45,7 @@ export const CUSTOM_COMMENTS_SERVERS = 'custom_comments_servers';
|
||||||
export const CUSTOM_SHARE_URL_ENABLED = 'custom_share_url_enabled';
|
export const CUSTOM_SHARE_URL_ENABLED = 'custom_share_url_enabled';
|
||||||
export const CUSTOM_SHARE_URL = 'custom_share_url';
|
export const CUSTOM_SHARE_URL = 'custom_share_url';
|
||||||
export const ENABLE_PRERELEASE_UPDATES = 'enable_prerelease_updates';
|
export const ENABLE_PRERELEASE_UPDATES = 'enable_prerelease_updates';
|
||||||
|
export const DISABLE_AUTO_UPDATES = 'disable_auto_updates';
|
||||||
|
|
||||||
export const SETTINGS_GRP = {
|
export const SETTINGS_GRP = {
|
||||||
APPEARANCE: 'appearance',
|
APPEARANCE: 'appearance',
|
||||||
|
|
|
@ -200,6 +200,12 @@ function AppWrapper() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// @if TARGET='app'
|
// @if TARGET='app'
|
||||||
|
|
||||||
|
// Enable/disable automatic updates download based on user's settings.
|
||||||
|
const state = store.getState();
|
||||||
|
const autoUpdatesDisabled = makeSelectClientSetting(SETTINGS.DISABLE_AUTO_UPDATES)(state);
|
||||||
|
autoUpdater.autoDownload = !autoUpdatesDisabled;
|
||||||
|
|
||||||
moment.locale(remote.app.getLocale());
|
moment.locale(remote.app.getLocale());
|
||||||
|
|
||||||
autoUpdater.on('error', (error) => {
|
autoUpdater.on('error', (error) => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { selectClaimsById, selectMyChannelClaims, selectTotalStakedAmountForChannelUri } from 'redux/selectors/claims';
|
import { selectClaimsById, selectMyChannelClaims, selectTotalStakedAmountForChannelUri } from 'redux/selectors/claims';
|
||||||
|
import { AUTO_UPDATE_DOWNLOADED } from 'constants/modal_types';
|
||||||
|
|
||||||
export const selectState = (state) => state.app || {};
|
export const selectState = (state) => state.app || {};
|
||||||
|
|
||||||
|
@ -51,6 +52,10 @@ export const selectAutoUpdateDownloaded = createSelector(selectState, (state) =>
|
||||||
|
|
||||||
export const selectAutoUpdateDeclined = createSelector(selectState, (state) => state.autoUpdateDeclined);
|
export const selectAutoUpdateDeclined = createSelector(selectState, (state) => state.autoUpdateDeclined);
|
||||||
|
|
||||||
|
export const selectIsUpdateModelDisplayed = createSelector(selectState, (state) => {
|
||||||
|
return state.modal === AUTO_UPDATE_DOWNLOADED;
|
||||||
|
});
|
||||||
|
|
||||||
export const selectDaemonVersionMatched = createSelector(selectState, (state) => state.daemonVersionMatched);
|
export const selectDaemonVersionMatched = createSelector(selectState, (state) => state.daemonVersionMatched);
|
||||||
|
|
||||||
export const selectVolume = createSelector(selectState, (state) => state.volume);
|
export const selectVolume = createSelector(selectState, (state) => state.volume);
|
||||||
|
|
Loading…
Reference in a new issue