diff --git a/js/background.js b/js/background.js index 6d119c0c12..e03ee9d34d 100644 --- a/js/background.js +++ b/js/background.js @@ -566,7 +566,8 @@ window.reduxActions.network ); window.Signal.Services.initializeUpdateListener( - window.reduxActions.updates + window.reduxActions.updates, + window.Whisper.events ); window.reduxActions.expiration.hydrateExpirationStatus( window.Signal.Util.hasExpired() diff --git a/ts/components/UpdateDialog.stories.tsx b/ts/components/UpdateDialog.stories.tsx index 7028d1e88d..d5827fd212 100644 --- a/ts/components/UpdateDialog.stories.tsx +++ b/ts/components/UpdateDialog.stories.tsx @@ -17,6 +17,9 @@ const defaultProps = { dismissDialog: action('dismiss-dialog'), hasNetworkDialog: false, i18n, + didSnooze: false, + showEventsCount: 0, + snoozeUpdate: action('snooze-update'), startUpdate: action('start-update'), }; @@ -27,6 +30,13 @@ const permutations = [ dialogType: 1, }, }, + { + title: 'Update (didSnooze=true)', + props: { + dialogType: 1, + didSnooze: true, + }, + }, { title: 'Cannot Update', props: { @@ -54,11 +64,13 @@ storiesOf('Components/UpdateDialog', module) 1 ); const hasNetworkDialog = boolean('hasNetworkDialog', false); + const didSnooze = boolean('didSnooze', false); return ( ); diff --git a/ts/components/UpdateDialog.tsx b/ts/components/UpdateDialog.tsx index 13c0943334..8b7bbab834 100644 --- a/ts/components/UpdateDialog.tsx +++ b/ts/components/UpdateDialog.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import moment from 'moment'; import { Dialogs } from '../types/Dialogs'; import { Intl } from './Intl'; @@ -8,46 +7,25 @@ import { LocalizerType } from '../types/Util'; export interface PropsType { ackRender: () => void; dialogType: Dialogs; + didSnooze: boolean; dismissDialog: () => void; hasNetworkDialog: boolean; i18n: LocalizerType; + showEventsCount: number; + snoozeUpdate: () => void; startUpdate: () => void; } -type MaybeMoment = moment.Moment | null; -type ReactSnoozeHook = React.Dispatch>; - -const SNOOZE_TIMER = 60 * 1000 * 30; - -function handleSnooze(setSnoozeForLater: ReactSnoozeHook) { - setSnoozeForLater(moment().add(SNOOZE_TIMER)); - setTimeout(() => { - setSnoozeForLater(moment()); - }, SNOOZE_TIMER); -} - -function canSnooze(snoozeUntil: MaybeMoment) { - return snoozeUntil === null; -} - -function isSnoozed(snoozeUntil: MaybeMoment) { - if (snoozeUntil === null) { - return false; - } - - return moment().isBefore(snoozeUntil); -} - export const UpdateDialog = ({ ackRender, dialogType, + didSnooze, dismissDialog, hasNetworkDialog, i18n, + snoozeUpdate, startUpdate, }: PropsType): JSX.Element | null => { - const [snoozeUntil, setSnoozeForLater] = React.useState(null); - React.useEffect(() => { ackRender(); }); @@ -56,7 +34,7 @@ export const UpdateDialog = ({ return null; } - if (dialogType === Dialogs.None || isSnoozed(snoozeUntil)) { + if (dialogType === Dialogs.None) { return null; } @@ -116,12 +94,10 @@ export const UpdateDialog = ({ {i18n('autoUpdateNewVersionMessage')}
- {canSnooze(snoozeUntil) && ( + {!didSnooze && ( diff --git a/ts/services/updateListener.ts b/ts/services/updateListener.ts index 19d76858af..7f0402ea53 100644 --- a/ts/services/updateListener.ts +++ b/ts/services/updateListener.ts @@ -6,8 +6,19 @@ type UpdatesActions = { showUpdateDialog: (x: Dialogs) => ShowUpdateDialogAction; }; -export function initializeUpdateListener(updatesActions: UpdatesActions) { +type EventsType = { + once: (ev: string, f: () => void) => void; +}; + +export function initializeUpdateListener( + updatesActions: UpdatesActions, + events: EventsType +) { ipcRenderer.on('show-update-dialog', (_, dialogType: Dialogs) => { updatesActions.showUpdateDialog(dialogType); }); + + events.once('snooze-update', () => { + updatesActions.showUpdateDialog(Dialogs.Update); + }); } diff --git a/ts/state/ducks/updates.ts b/ts/state/ducks/updates.ts index cc29788ece..ac44839e97 100644 --- a/ts/state/ducks/updates.ts +++ b/ts/state/ducks/updates.ts @@ -1,10 +1,13 @@ import { Dialogs } from '../../types/Dialogs'; import * as updateIpc from '../../shims/updateIpc'; +import { trigger } from '../../shims/events'; // State export type UpdatesStateType = { dialogType: Dialogs; + didSnooze: boolean; + showEventsCount: number; }; // Actions @@ -12,6 +15,7 @@ export type UpdatesStateType = { const ACK_RENDER = 'updates/ACK_RENDER'; const DISMISS_DIALOG = 'updates/DISMISS_DIALOG'; const SHOW_UPDATE_DIALOG = 'updates/SHOW_UPDATE_DIALOG'; +const SNOOZE_UPDATE = 'updates/SNOOZE_UPDATE'; const START_UPDATE = 'updates/START_UPDATE'; type AckRenderAction = { @@ -27,6 +31,10 @@ export type ShowUpdateDialogAction = { payload: Dialogs; }; +type SnoozeUpdateActionType = { + type: 'updates/SNOOZE_UPDATE'; +}; + type StartUpdateAction = { type: 'updates/START_UPDATE'; }; @@ -35,6 +43,7 @@ export type UpdatesActionType = | AckRenderAction | DismissDialogAction | ShowUpdateDialogAction + | SnoozeUpdateActionType | StartUpdateAction; // Action Creators @@ -60,6 +69,18 @@ function showUpdateDialog(dialogType: Dialogs): ShowUpdateDialogAction { }; } +const SNOOZE_TIMER = 60 * 1000 * 30; + +function snoozeUpdate(): SnoozeUpdateActionType { + setTimeout(() => { + trigger('snooze-update'); + }, SNOOZE_TIMER); + + return { + type: SNOOZE_UPDATE, + }; +} + function startUpdate(): StartUpdateAction { updateIpc.startUpdate(); @@ -72,6 +93,7 @@ export const actions = { ackRender, dismissDialog, showUpdateDialog, + snoozeUpdate, startUpdate, }; @@ -80,6 +102,8 @@ export const actions = { function getEmptyState(): UpdatesStateType { return { dialogType: Dialogs.None, + didSnooze: false, + showEventsCount: 0, }; } @@ -90,6 +114,16 @@ export function reducer( if (action.type === SHOW_UPDATE_DIALOG) { return { dialogType: action.payload, + didSnooze: state.didSnooze, + showEventsCount: state.showEventsCount + 1, + }; + } + + if (action.type === SNOOZE_UPDATE) { + return { + dialogType: Dialogs.None, + didSnooze: true, + showEventsCount: state.showEventsCount, }; } @@ -99,6 +133,8 @@ export function reducer( ) { return { dialogType: Dialogs.None, + didSnooze: state.didSnooze, + showEventsCount: state.showEventsCount, }; }