Wire up electron download progress to toasts

t3chguy/fix/7104
Michael Telatynski 2021-04-14 10:58:11 +01:00
parent fb0bc34042
commit c70327819a
3 changed files with 147 additions and 20 deletions

View File

@ -30,8 +30,7 @@ type ElectronChannel =
"seshatReply" | "seshatReply" |
"setBadgeCount" | "setBadgeCount" |
"update-downloaded" | "update-downloaded" |
"userDownloadCompleted" | "userDownload";
"userDownloadOpen";
declare global { declare global {
interface Window { interface Window {
@ -50,6 +49,7 @@ declare global {
interface Electron { interface Electron {
on(channel: ElectronChannel, listener: (event: Event, ...args: any[]) => void): void; on(channel: ElectronChannel, listener: (event: Event, ...args: any[]) => void): void;
removeListener(event: ElectronChannel, listener: (...args: any[]) => void): void;
send(channel: ElectronChannel, ...args: any[]): void; send(channel: ElectronChannel, ...args: any[]): void;
} }

View File

@ -0,0 +1,104 @@
/*
Copyright 2021 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.
*/
import React, {useState} from "react";
import GenericToast from "matrix-react-sdk/src/components/views/toasts/GenericToast";
import { useEventEmitter } from "matrix-react-sdk/src/hooks/useEventEmitter";
import ToastStore from "matrix-react-sdk/src/stores/ToastStore";
import {_t} from "../../../vector/init";
const electron = window.electron;
interface IProps {
downloadPath: string;
name: string;
totalBytes: number;
receivedBytes: number;
toastKey: string;
}
const ElectronDownloadToast: React.FC<IProps> = ({
downloadPath,
name,
totalBytes,
receivedBytes: initialReceivedBytes,
toastKey,
}) => {
const [state, setState] = useState<"progressing" | "paused" | "cancelled" | "failed">("progressing");
const [receivedBytes, setReceivedBytes] = useState(initialReceivedBytes);
useEventEmitter(electron, "userDownload", (ev, {state, path, name, totalBytes, receivedBytes, terminal, begin}) => {
if (path !== downloadPath) return;
setReceivedBytes(receivedBytes);
switch (state) {
case "progressing":
setState("progressing");
break;
case "interrupted":
if (terminal) {
setState("failed");
} else {
setState("paused");
}
break;
case "cancelled":
setState("cancelled");
break;
}
});
let acceptLabel: string;
let acceptFn;
// TODO decide if this should be cancel/dismiss
let rejectLabel = _t("Dismiss");
let rejectFn = () => {
ToastStore.sharedInstance().dismissToast(toastKey);
};
switch (state) {
case "progressing":
acceptLabel = _t("Pause");
acceptFn = () => {
electron.send("userDownload", {
action: "pause",
path: downloadPath,
});
};
break;
case "paused":
acceptLabel = _t("Resume");
acceptFn = () => {
electron.send("userDownload", {
action: "resume",
path: downloadPath,
});
};
break;
case "failed":
rejectLabel = null;
rejectFn = null;
}
return <GenericToast
description={`${name}: ${receivedBytes}b / ${totalBytes}b`}
acceptLabel={acceptLabel}
onAccept={acceptFn}
rejectLabel={rejectLabel}
onReject={rejectFn}
/>;
};
export default ElectronDownloadToast;

View File

@ -47,6 +47,7 @@ import {showToast as showUpdateToast} from "matrix-react-sdk/src/toasts/UpdateTo
import {CheckUpdatesPayload} from "matrix-react-sdk/src/dispatcher/payloads/CheckUpdatesPayload"; import {CheckUpdatesPayload} from "matrix-react-sdk/src/dispatcher/payloads/CheckUpdatesPayload";
import ToastStore from "matrix-react-sdk/src/stores/ToastStore"; import ToastStore from "matrix-react-sdk/src/stores/ToastStore";
import GenericExpiringToast from "matrix-react-sdk/src/components/views/toasts/GenericExpiringToast"; import GenericExpiringToast from "matrix-react-sdk/src/components/views/toasts/GenericExpiringToast";
import ElectronDownloadToast from "../../components/views/toasts/ElectronDownloadToast";
const electron = window.electron; const electron = window.electron;
const isMac = navigator.platform.toUpperCase().includes('MAC'); const isMac = navigator.platform.toUpperCase().includes('MAC');
@ -249,24 +250,46 @@ export default class ElectronPlatform extends VectorBasePlatform {
dis.fire(Action.ViewUserSettings); dis.fire(Action.ViewUserSettings);
}); });
electron.on('userDownloadCompleted', (ev, {path, name}) => { electron.on("userDownload", (ev, {state, path, name, totalBytes, receivedBytes, begin}) => {
const onAccept = () => { if (begin) {
electron.send('userDownloadOpen', {path}); ToastStore.sharedInstance().addOrReplaceToast({
}; key: `DOWNLOAD_TOAST_${path}`,
title: _t("Downloading..."),
props: {
downloadPath: path,
receivedBytes,
totalBytes,
name,
},
component: ElectronDownloadToast,
priority: 99,
});
} else if (state === "completed") {
ToastStore.sharedInstance().addOrReplaceToast({ ToastStore.sharedInstance().addOrReplaceToast({
key: `DOWNLOAD_TOAST_${path}`, key: `DOWNLOAD_TOAST_${path}`,
title: _t("Download Completed"), title: _t("Download Completed"),
props: { props: {
description: name, description: name,
acceptLabel: _t("Open"), acceptLabel: _t("Open"),
onAccept, onAccept: () => {
electron.send("userDownload", {
action: "download",
path,
});
},
dismissLabel: _t("Dismiss"), dismissLabel: _t("Dismiss"),
numSeconds: 10, numSeconds: 10,
onDismiss: () => {
electron.send("userDownload", {
action: "done",
path,
});
},
}, },
component: GenericExpiringToast, component: GenericExpiringToast,
priority: 99, priority: 99,
}); });
}
}); });
// register OS-specific shortcuts // register OS-specific shortcuts