mirror of https://github.com/vector-im/riot-web
Merge pull request #4669 from matrix-org/t3chguy/toasts6_1
Allow deferring of Update Toast until the next morningpull/21833/head
commit
6472ca451e
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Based on https://stackoverflow.com/a/53229857/3532235
|
||||||
|
export type Without<T, U> = {[P in Exclude<keyof T, keyof U>] ? : never}
|
||||||
|
export type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
|
|
@ -23,6 +23,7 @@ import BaseEventIndexManager from './indexing/BaseEventIndexManager';
|
||||||
import {ActionPayload} from "./dispatcher/payloads";
|
import {ActionPayload} from "./dispatcher/payloads";
|
||||||
import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload";
|
import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload";
|
||||||
import {Action} from "./dispatcher/actions";
|
import {Action} from "./dispatcher/actions";
|
||||||
|
import {hideToast as hideUpdateToast} from "./toasts/UpdateToast";
|
||||||
|
|
||||||
export enum UpdateCheckStatus {
|
export enum UpdateCheckStatus {
|
||||||
Checking = "CHECKING",
|
Checking = "CHECKING",
|
||||||
|
@ -32,6 +33,8 @@ export enum UpdateCheckStatus {
|
||||||
Ready = "READY",
|
Ready = "READY",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UPDATE_DEFER_KEY = "mx_defer_update";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for classes that provide platform-specific functionality
|
* Base class for classes that provide platform-specific functionality
|
||||||
* eg. Setting an application badge or displaying notifications
|
* eg. Setting an application badge or displaying notifications
|
||||||
|
@ -74,12 +77,45 @@ export default abstract class BasePlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
startUpdateCheck() {
|
startUpdateCheck() {
|
||||||
|
hideUpdateToast();
|
||||||
|
localStorage.removeItem(UPDATE_DEFER_KEY);
|
||||||
dis.dispatch<CheckUpdatesPayload>({
|
dis.dispatch<CheckUpdatesPayload>({
|
||||||
action: Action.CheckUpdates,
|
action: Action.CheckUpdates,
|
||||||
status: UpdateCheckStatus.Checking,
|
status: UpdateCheckStatus.Checking,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the currently running app to the latest available version
|
||||||
|
* and replace this instance of the app with the new version.
|
||||||
|
*/
|
||||||
|
installUpdate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the version update has been deferred and that deferment is still in effect
|
||||||
|
* @param newVersion the version string to check
|
||||||
|
*/
|
||||||
|
protected shouldShowUpdate(newVersion: string): boolean {
|
||||||
|
try {
|
||||||
|
const [version, deferUntil] = JSON.parse(localStorage.getItem(UPDATE_DEFER_KEY));
|
||||||
|
return newVersion !== version || Date.now() > deferUntil;
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore the pending update and don't prompt about this version
|
||||||
|
* until the next morning (8am).
|
||||||
|
*/
|
||||||
|
deferUpdate(newVersion: string) {
|
||||||
|
const date = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
||||||
|
date.setHours(8, 0, 0, 0); // set to next 8am
|
||||||
|
localStorage.setItem(UPDATE_DEFER_KEY, JSON.stringify([newVersion, date.getTime()]));
|
||||||
|
hideUpdateToast();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the platform supports displaying
|
* Returns true if the platform supports displaying
|
||||||
* notifications, otherwise false.
|
* notifications, otherwise false.
|
||||||
|
|
|
@ -18,7 +18,6 @@ import React, {useState} from "react";
|
||||||
|
|
||||||
import {UpdateCheckStatus} from "../../../BasePlatform";
|
import {UpdateCheckStatus} from "../../../BasePlatform";
|
||||||
import PlatformPeg from "../../../PlatformPeg";
|
import PlatformPeg from "../../../PlatformPeg";
|
||||||
import {hideToast as hideUpdateToast} from "../../../toasts/UpdateToast";
|
|
||||||
import {useDispatcher} from "../../../hooks/useDispatcher";
|
import {useDispatcher} from "../../../hooks/useDispatcher";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import {Action} from "../../../dispatcher/actions";
|
import {Action} from "../../../dispatcher/actions";
|
||||||
|
@ -60,7 +59,6 @@ const UpdateCheckButton = () => {
|
||||||
const onCheckForUpdateClick = () => {
|
const onCheckForUpdateClick = () => {
|
||||||
setState(null);
|
setState(null);
|
||||||
PlatformPeg.get().startUpdateCheck();
|
PlatformPeg.get().startUpdateCheck();
|
||||||
hideUpdateToast();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useDispatcher(dis, ({action, ...params}) => {
|
useDispatcher(dis, ({action, ...params}) => {
|
||||||
|
|
|
@ -17,17 +17,21 @@ limitations under the License.
|
||||||
import React, {ReactChild} from "react";
|
import React, {ReactChild} from "react";
|
||||||
|
|
||||||
import FormButton from "../elements/FormButton";
|
import FormButton from "../elements/FormButton";
|
||||||
|
import {XOR} from "../../../@types/common";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
description: ReactChild;
|
description: ReactChild;
|
||||||
acceptLabel: string;
|
acceptLabel: string;
|
||||||
rejectLabel?: string;
|
|
||||||
|
|
||||||
onAccept();
|
onAccept();
|
||||||
onReject?();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const GenericToast: React.FC<IProps> = ({description, acceptLabel, rejectLabel, onAccept, onReject}) => {
|
interface IPropsExtended extends IProps {
|
||||||
|
rejectLabel: string;
|
||||||
|
onReject();
|
||||||
|
}
|
||||||
|
|
||||||
|
const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({description, acceptLabel, rejectLabel, onAccept, onReject}) => {
|
||||||
return <div>
|
return <div>
|
||||||
<div className="mx_Toast_description">
|
<div className="mx_Toast_description">
|
||||||
{ description }
|
{ description }
|
||||||
|
|
|
@ -40,6 +40,10 @@ function installUpdate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showToast = (version: string, newVersion: string, releaseNotes?: string) => {
|
export const showToast = (version: string, newVersion: string, releaseNotes?: string) => {
|
||||||
|
function onReject() {
|
||||||
|
PlatformPeg.get().deferUpdate(newVersion);
|
||||||
|
}
|
||||||
|
|
||||||
let onAccept;
|
let onAccept;
|
||||||
let acceptLabel = _t("What's new?");
|
let acceptLabel = _t("What's new?");
|
||||||
if (releaseNotes) {
|
if (releaseNotes) {
|
||||||
|
@ -79,6 +83,8 @@ export const showToast = (version: string, newVersion: string, releaseNotes?: st
|
||||||
description: _t("A new version of Riot is available!"),
|
description: _t("A new version of Riot is available!"),
|
||||||
acceptLabel,
|
acceptLabel,
|
||||||
onAccept,
|
onAccept,
|
||||||
|
rejectLabel: _t("Later"),
|
||||||
|
onReject,
|
||||||
},
|
},
|
||||||
component: GenericToast,
|
component: GenericToast,
|
||||||
priority: 20,
|
priority: 20,
|
||||||
|
|
Loading…
Reference in New Issue