mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Replace downloads list with updater tool
This commit is contained in:
@@ -69,17 +69,32 @@
|
||||
, "optionsBridgeNoAction": {
|
||||
"message": "No action needed."
|
||||
}
|
||||
, "optionsBridgeDownloadsGet": {
|
||||
"message": "Fetch downloads"
|
||||
, "optionsBridgeUpdateCheck": {
|
||||
"message": "Check for Updates"
|
||||
}
|
||||
, "optionsBridgeDownloadsLoading": {
|
||||
"message": "Fetching downloads$1"
|
||||
, "optionsBridgeUpdateChecking": {
|
||||
"message": "Checking for Updates$1"
|
||||
}
|
||||
, "optionsBridgeDownloadsGetFailed": {
|
||||
"message": "Failed to fetch downloads"
|
||||
, "optionsBridgeUpdateStatusNoUpdates": {
|
||||
"message": "No updates available"
|
||||
}
|
||||
, "optionsBridgeUpdateStatusError": {
|
||||
"message": "Error checking for updates"
|
||||
}
|
||||
, "optionsBridgeUpdateAvailable": {
|
||||
"message": "An update is available:"
|
||||
}
|
||||
, "optionsBridgeUpdatePackageTypeSelect": {
|
||||
"message": "Select package type"
|
||||
}
|
||||
, "optionsBridgeDownloadsTitle": {
|
||||
"message": "Bridge downloads"
|
||||
, "optionsBridgeUpdatePackageTypeDeb": {
|
||||
"message": ".deb (Debian/Ubuntu)"
|
||||
}
|
||||
, "optionsBridgeUpdatePackageTypeRpm": {
|
||||
"message": ".rpm (Fedora)"
|
||||
}
|
||||
, "optionsBridgeUpdate": {
|
||||
"message": "Update Now..."
|
||||
}
|
||||
|
||||
, "optionsMediaCategoryName": {
|
||||
@@ -167,4 +182,24 @@
|
||||
, "optionsSaved": {
|
||||
"message": "Saved!"
|
||||
}
|
||||
|
||||
|
||||
, "updaterCancel": {
|
||||
"message": "Cancel"
|
||||
}
|
||||
, "updaterDescriptionDownloading": {
|
||||
"message": "Downloading..."
|
||||
}
|
||||
, "updaterAdditionalDescriptionDownloading": {
|
||||
"message": "Fetching update package"
|
||||
}
|
||||
, "updaterDescriptionInstallReady": {
|
||||
"message": "Ready to install"
|
||||
}
|
||||
, "updaterAdditionalDescriptionInstallReady": {
|
||||
"message": "The install package has been downloaded to your default downloads location."
|
||||
}
|
||||
, "updaterInstall": {
|
||||
"message": "Install..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ export default async function getBridgeInfo () {
|
||||
|
||||
applicationVersion = response.data;
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { Component } from "react";
|
||||
import semver from "semver";
|
||||
|
||||
import { getNextEllipsis } from "../lib/utils";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
@@ -91,28 +93,35 @@ export default class Bridge extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.onGetDownloads = this.onGetDownloads.bind(this);
|
||||
this.onGetDownloadsResponse = this.onGetDownloadsResponse.bind(this);
|
||||
this.onGetDownloadsError = this.onGetDownloadsError.bind(this);
|
||||
this.onCheckUpdates = this.onCheckUpdates.bind(this);
|
||||
this.onCheckUpdatesResponse = this.onCheckUpdatesResponse.bind(this);
|
||||
this.onCheckUpdatesError = this.onCheckUpdatesError.bind(this);
|
||||
this.onUpdate = this.onUpdate.bind(this);
|
||||
this.onPackageTypeChange = this.onPackageTypeChange.bind(this);
|
||||
|
||||
this.updateData = null;
|
||||
this.updateStatusTimeout = null;
|
||||
|
||||
this.state = {
|
||||
downloads: null
|
||||
, isLoadingDownloads: false
|
||||
, wasErrorLoadingDownloads: false
|
||||
, downloadsLoadingEllipsis: "..."
|
||||
isCheckingUpdates: false
|
||||
, isUpdateAvailable: false
|
||||
, wasErrorCheckingUpdates: false
|
||||
, checkUpdatesEllipsis: "..."
|
||||
, updateStatus: null
|
||||
, packageType: null
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
onGetDownloads () {
|
||||
onCheckUpdates () {
|
||||
this.setState({
|
||||
isLoadingDownloads: true
|
||||
isCheckingUpdates: true
|
||||
});
|
||||
|
||||
const timeout = setInterval(() => {
|
||||
this.setState(state => ({
|
||||
downloadsLoadingEllipsis: getNextEllipsis(
|
||||
state.downloadsLoadingEllipsis)
|
||||
checkUpdatesEllipsis: getNextEllipsis(
|
||||
state.checkUpdatesEllipsis)
|
||||
}));
|
||||
}, 500);
|
||||
|
||||
@@ -121,46 +130,113 @@ export default class Bridge extends Component {
|
||||
window.clearTimeout(timeout);
|
||||
return res.json()
|
||||
})
|
||||
.then(this.onGetDownloadsResponse)
|
||||
.catch(this.onGetDownloadsError);
|
||||
.then(this.onCheckUpdatesResponse)
|
||||
.catch(this.onCheckUpdatesError);
|
||||
}
|
||||
|
||||
async onGetDownloadsResponse (res) {
|
||||
const platformInfo = await browser.runtime.getPlatformInfo();
|
||||
const downloads = res.assets
|
||||
.reduce((acc, asset) => {
|
||||
const download = {
|
||||
name: asset.name
|
||||
, url: asset.browser_download_url
|
||||
};
|
||||
showUpdateStatus () {
|
||||
if (this.updateStatusTimeout) {
|
||||
window.clearTimeout(this.updateStatusTimeout);
|
||||
}
|
||||
this.updateStatusTimeout = window.setTimeout(() => {
|
||||
this.setState({
|
||||
updateStatus: null
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
const platformExtensions = {
|
||||
"exe": "win"
|
||||
, "pkg": "mac"
|
||||
, "deb": "deb"
|
||||
, "rpm": "rpm"
|
||||
};
|
||||
async onUpdate () {
|
||||
const width = 400;
|
||||
const height = 150;
|
||||
|
||||
const fileExtension = asset.name.match(/.*\.(.*)$/).pop();
|
||||
// Current window to base centered position on
|
||||
const win = await browser.windows.getCurrent();
|
||||
|
||||
if (fileExtension in platformExtensions) {
|
||||
const platform = platformExtensions[fileExtension];
|
||||
acc[platform] = download;
|
||||
}
|
||||
// Top(mid)-center position
|
||||
const centerX = win.left + (win.width / 2);
|
||||
const centerY = win.top + (win.height / 3);
|
||||
|
||||
return acc;
|
||||
}, { platform: platformInfo.os });
|
||||
const left = Math.floor(centerX - (width / 2));
|
||||
const top = Math.floor(centerY - (height / 2));
|
||||
|
||||
this.setState({
|
||||
isLoadingDownloads: false
|
||||
, downloads
|
||||
const updaterPopup = await browser.windows.create({
|
||||
url: "../updater/index.html"
|
||||
, type: "popup"
|
||||
, width
|
||||
, height
|
||||
, left
|
||||
, top
|
||||
});
|
||||
|
||||
// Size/position not set correctly on creation (bug?)
|
||||
await browser.windows.update(updaterPopup.id, {
|
||||
width
|
||||
, height
|
||||
, left
|
||||
, top
|
||||
});
|
||||
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
if (port.name === "updater") {
|
||||
const asset = this.updateData.assets.find(asset => {
|
||||
const fileExtension = asset.name.match(/.*\.(.*)$/).pop();
|
||||
const currentPlatform = (this.props.platform === "linux")
|
||||
? this.state.packageType
|
||||
: this.props.platform;
|
||||
|
||||
switch (fileExtension) {
|
||||
case "exe": return "win" === currentPlatform;
|
||||
case "pkg": return "mac" === currentPlatform;
|
||||
case "deb": return "deb" === currentPlatform;
|
||||
case "rpm": return "rpm" === currentPlatform;
|
||||
}
|
||||
});
|
||||
|
||||
port.postMessage({
|
||||
subject: "updater:/updateData"
|
||||
, data: asset
|
||||
});
|
||||
|
||||
port.onDisconnect.addListener(() => {
|
||||
browser.windows.remove(updaterPopup.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onGetDownloadsError (err) {
|
||||
|
||||
async onCheckUpdatesResponse (res) {
|
||||
const isUpdateAvailable = !this.props.info || semver.lt(
|
||||
this.props.info.version, res.tag_name);
|
||||
|
||||
if (isUpdateAvailable) {
|
||||
this.updateData = res;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoadingDownloads: false
|
||||
, wasErrorLoadingDownloads: true
|
||||
isCheckingUpdates: false
|
||||
, isUpdateAvailable
|
||||
, updateStatus: !isUpdateAvailable
|
||||
? _("optionsBridgeUpdateStatusNoUpdates")
|
||||
: null
|
||||
});
|
||||
|
||||
this.showUpdateStatus();
|
||||
}
|
||||
|
||||
onCheckUpdatesError (err) {
|
||||
this.setState({
|
||||
isCheckingUpdates: false
|
||||
, wasErrorCheckingUpdates: true
|
||||
, updateStatus: _("optionsBridgeUpdateStatusError")
|
||||
});
|
||||
|
||||
this.showUpdateStatus();
|
||||
}
|
||||
|
||||
onPackageTypeChange (ev) {
|
||||
this.setState({
|
||||
packageType: ev.target.value
|
||||
});
|
||||
}
|
||||
|
||||
@@ -224,35 +300,65 @@ export default class Bridge extends Component {
|
||||
}}
|
||||
|
||||
{ do {
|
||||
if (!this.props.loading
|
||||
&& (!this.props.info
|
||||
|| !this.props.info.isVersionCompatible)) {
|
||||
<div className="bridge__download-info">
|
||||
<h2 className="bridge__download-info-title">
|
||||
{ _("optionsBridgeDownloadsTitle") }
|
||||
</h2>
|
||||
if (!this.props.loading) {
|
||||
<div className="bridge__update-info">
|
||||
{ do {
|
||||
if (this.state.downloads) {
|
||||
<BridgeDownloads info={ this.state.downloads }/>
|
||||
} else if (this.state.wasErrorLoadingDownloads) {
|
||||
<div className="bridge__download-info-get-error">
|
||||
{ _("optionsBridgeDownloadsGetFailed") }
|
||||
if (this.state.isUpdateAvailable) {
|
||||
<div className="bridge__update">
|
||||
<p className="bridge__update-label">
|
||||
{ _("optionsBridgeUpdateAvailable") }
|
||||
</p>
|
||||
<div className="bridge__update-options">
|
||||
{ do {
|
||||
if (this.props.platform === "linux") {
|
||||
<select className="bridge__update-package-type"
|
||||
onChange={ this.onPackageTypeChange }
|
||||
value={ this.state.packageType }>
|
||||
<option value="" disabled selected>
|
||||
{ _("optionsBridgeUpdatePackageTypeSelect") }
|
||||
</option>
|
||||
<option value="deb">
|
||||
{ _("optionsBridgeUpdatePackageTypeDeb") }
|
||||
</option>
|
||||
<option value="rpm">
|
||||
{ _("optionsBridgeUpdatePackageTypeRpm") }
|
||||
</option>
|
||||
</select>
|
||||
}
|
||||
}}
|
||||
<button className="bridge__update-start"
|
||||
onClick={ this.onUpdate }
|
||||
disabled={ this.props.platform === "linux"
|
||||
&& !this.state.packageType }>
|
||||
{ _("optionsBridgeUpdate") }
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
} else {
|
||||
<button className="bridge__download-info-get"
|
||||
onClick={ this.onGetDownloads }
|
||||
disabled={ this.state.isLoadingDownloads }>
|
||||
<button className="bridge__update-check"
|
||||
disabled={ this.state.isCheckingUpdates }
|
||||
onClick={ this.onCheckUpdates }>
|
||||
|
||||
{ do {
|
||||
if (this.state.isLoadingDownloads) {
|
||||
_("optionsBridgeDownloadsLoading"
|
||||
, getNextEllipsis(this.state.downloadsLoadingEllipsis));
|
||||
if (this.state.isCheckingUpdates) {
|
||||
_("optionsBridgeUpdateChecking"
|
||||
, getNextEllipsis(this.state.checkUpdatesEllipsis));
|
||||
} else {
|
||||
_("optionsBridgeDownloadsGet");
|
||||
_("optionsBridgeUpdateCheck");
|
||||
}
|
||||
}}
|
||||
</button>
|
||||
}
|
||||
}}
|
||||
|
||||
<div className="bridge--update-status">
|
||||
{ do {
|
||||
if (this.state.updateStatus
|
||||
&& !this.state.isUpdateAvailable) {
|
||||
this.state.updateStatus;
|
||||
}
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -46,6 +46,7 @@ class App extends Component {
|
||||
this.state = {
|
||||
options: props.options
|
||||
, bridgeInfo: null
|
||||
, platform: null
|
||||
, bridgeLoading: true
|
||||
, isFormValid: true
|
||||
, hasSaved: false
|
||||
@@ -63,8 +64,10 @@ class App extends Component {
|
||||
|
||||
async componentDidMount () {
|
||||
const bridgeInfo = await getBridgeInfo();
|
||||
const platform = await browser.runtime.getPlatformInfo();
|
||||
this.setState({
|
||||
bridgeInfo
|
||||
, platform: platform.os
|
||||
, bridgeLoading: false
|
||||
});
|
||||
}
|
||||
@@ -168,6 +171,7 @@ class App extends Component {
|
||||
return (
|
||||
<div>
|
||||
<Bridge info={ this.state.bridgeInfo }
|
||||
platform={ this.state.platform }
|
||||
loading={ this.state.bridgeLoading } />
|
||||
|
||||
<form id="form" ref={ form => { this.form = form; }}
|
||||
|
||||
@@ -90,18 +90,29 @@
|
||||
}
|
||||
|
||||
.bridge__info--not-found .bridge__status {
|
||||
flex-direction: row;
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-template-rows: min-content min-content;
|
||||
grid-template-areas:
|
||||
"status-icon status-title"
|
||||
"status-icon status-text";
|
||||
}
|
||||
.bridge__info--found .bridge__status-icon {
|
||||
margin-block-end: 5px;
|
||||
}
|
||||
.bridge__info--not-found .bridge__status-icon {
|
||||
grid-area: status-icon;
|
||||
margin-inline-end: 10px;
|
||||
}
|
||||
.bridge__info--not-found .bridge__status-title {
|
||||
grid-area: status-title;
|
||||
font-weight: normal;
|
||||
white-space: normal;
|
||||
}
|
||||
.bridge__info--not-found .bridge__status-text {
|
||||
grid-area: status-text;
|
||||
margin-top: initial;
|
||||
}
|
||||
|
||||
.bridge__stats {
|
||||
border-collapse: collapse;
|
||||
@@ -113,41 +124,36 @@
|
||||
font-weight: 500;
|
||||
padding-inline-end: 10px;
|
||||
text-align: end;
|
||||
white-space: nowrap;
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bridge__download-info {
|
||||
.bridge__update-info {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bridge__update-label {
|
||||
display: inline-block;
|
||||
margin: initial;
|
||||
}
|
||||
|
||||
.bridge__update-options {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
width: -moz-available;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.bridge__download-info-get {
|
||||
align-self: flex-start;
|
||||
justify-content: center;
|
||||
.bridge__update-start {
|
||||
align-self: flex-end;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.bridge__download-info-title {
|
||||
font-weight: 500;
|
||||
font-size: 1.25em;
|
||||
.bridge--update-status {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.bridge-downloads {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bridge-downloads__download {
|
||||
|
||||
}
|
||||
|
||||
.bridge-downloads__linux {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.category {
|
||||
border: initial;
|
||||
|
||||
@@ -18,6 +18,7 @@ button[default]:not(:hover):active {
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
button {
|
||||
button,
|
||||
select {
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
11
ext/src/updater/index.html
Normal file
11
ext/src/updater/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="styles/index.css">
|
||||
<script src="bundle.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
216
ext/src/updater/index.jsx
Normal file
216
ext/src/updater/index.jsx
Normal file
@@ -0,0 +1,216 @@
|
||||
"use strict";
|
||||
|
||||
import React, { Component } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { getNextEllipsis } from "../lib/utils";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
// macOS styles
|
||||
browser.runtime.getPlatformInfo()
|
||||
.then(platformInfo => {
|
||||
if (platformInfo.os === "mac") {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = "styles/mac.css";
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const Updater = (props) => (
|
||||
<div className="updater">
|
||||
<div className="updater__description">
|
||||
{ props.description }
|
||||
</div>
|
||||
<div className="updater__additional-description">
|
||||
{ props.additionalDescription }
|
||||
</div>
|
||||
<progress className="updater__progress"
|
||||
max={ props.downloadTotal }
|
||||
value={ props.downloadCurrent }>
|
||||
</progress>
|
||||
<button className="updater__install"
|
||||
onClick={ props.onInstall }
|
||||
disabled={ props.isDownloading }>
|
||||
{ _("updaterInstall") }
|
||||
</button>
|
||||
<button className="updater__cancel"
|
||||
onClick={ props.onCancel }
|
||||
disabled={ !props.isDownloading }>
|
||||
{ _("updaterCancel") }
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
class App extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.downloadId = null;
|
||||
this.downloadProgressInterval = null;
|
||||
|
||||
this.onMessage = this.onMessage.bind(this);
|
||||
this.onDownloadChanged = this.onDownloadChanged.bind(this);
|
||||
this.updateDownloadProgress = this.updateDownloadProgress.bind(this);
|
||||
this.onCancel = this.onCancel.bind(this);
|
||||
this.onInstall = this.onInstall.bind(this);
|
||||
|
||||
this.state = {
|
||||
hasLoaded: false
|
||||
, isDownloading: true
|
||||
, description: _("updaterDescriptionDownloading")
|
||||
, additionalDescription: _("updaterAdditionalDescriptionDownloading")
|
||||
, downloadTotal: 0
|
||||
, downloadCurrent: 0
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount () {
|
||||
this.port = browser.runtime.connect({
|
||||
name: "updater"
|
||||
});
|
||||
|
||||
this.port.onMessage.addListener(this.onMessage);
|
||||
browser.downloads.onChanged.addListener(this.onDownloadChanged);
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
// Size window to content
|
||||
browser.windows.update(this.win.id, {
|
||||
width: document.body.clientWidth + this.frameWidth
|
||||
, height: document.body.clientHeight + this.frameHeight
|
||||
});
|
||||
}
|
||||
|
||||
closeWindow () {
|
||||
window.clearInterval(this.downloadProgressInterval);
|
||||
browser.downloads.onChanged.removeListener(this.onDownloadChanged);
|
||||
this.port.onMessage.removeListener(this.onMessage);
|
||||
this.port.disconnect();
|
||||
}
|
||||
|
||||
async onMessage (message) {
|
||||
switch (message.subject) {
|
||||
case "updater:/updateData": {
|
||||
// Only run once
|
||||
if (this.downloadId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.win = await browser.windows.getCurrent();
|
||||
this.frameWidth = this.win.width - window.innerWidth;
|
||||
this.frameHeight = this.win.height - window.innerHeight;
|
||||
|
||||
// Cleanup
|
||||
if (this.downloadId) {
|
||||
browser.downloads.cancel(this.downloadId);
|
||||
}
|
||||
if (this.downloadProgressInterval) {
|
||||
window.clearInterval(this.downloadProgressInterval);
|
||||
}
|
||||
|
||||
this.downloadId = await browser.downloads.download({
|
||||
url: message.data.browser_download_url
|
||||
, filename: message.data.name
|
||||
});
|
||||
|
||||
this.updateDownloadProgress();
|
||||
|
||||
this.downloadProgressInterval = window.setInterval(
|
||||
this.updateDownloadProgress, 500);
|
||||
|
||||
this.setState({
|
||||
hasLoaded: true
|
||||
, isDownloading: true
|
||||
});
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
onDownloadChanged (downloadItem) {
|
||||
if (downloadItem.id !== this.downloadId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (downloadItem.canResume) {
|
||||
// Paused
|
||||
if (downloadItem.canResume.current) {
|
||||
window.clearInterval(this.downloadProgressInterval);
|
||||
this.setState({
|
||||
isDownloading: false
|
||||
});
|
||||
|
||||
// Cancelled
|
||||
} else {
|
||||
window.clearInterval(this.downloadProgressInterval);
|
||||
this.setState({
|
||||
isDownloading: false
|
||||
});
|
||||
}
|
||||
|
||||
// Download finished
|
||||
} else if (downloadItem.state
|
||||
&& downloadItem.state.current === "complete") {
|
||||
|
||||
window.clearInterval(this.downloadProgressInterval);
|
||||
this.setState({
|
||||
isDownloading: false
|
||||
, downloadTotal: 1
|
||||
, downloadCurrent: 1
|
||||
, description: _("updaterDescriptionInstallReady")
|
||||
, additionalDescription: _("updaterAdditionalDescriptionInstallReady")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async updateDownloadProgress () {
|
||||
const [ download ] = await browser.downloads.search({
|
||||
id: this.downloadId
|
||||
});
|
||||
|
||||
this.setState({
|
||||
downloadTotal: download.totalBytes
|
||||
, downloadCurrent: download.bytesReceived
|
||||
});
|
||||
}
|
||||
|
||||
async onCancel () {
|
||||
try {
|
||||
await browser.downloads.cancel(this.downloadId);
|
||||
this.closeWindow();
|
||||
} catch (err) {
|
||||
// Already cancelled or finished
|
||||
}
|
||||
}
|
||||
|
||||
async onInstall () {
|
||||
try {
|
||||
await browser.downloads.open(this.downloadId);
|
||||
this.closeWindow();
|
||||
} catch (err) {
|
||||
// Cancelled or not finished
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return do {
|
||||
if (this.state.hasLoaded) {
|
||||
<Updater description={ this.state.description }
|
||||
additionalDescription={ this.state.additionalDescription }
|
||||
downloadTotal={ this.state.downloadTotal }
|
||||
downloadCurrent={ this.state.downloadCurrent }
|
||||
isDownloading={ this.state.isDownloading }
|
||||
onCancel={ this.onCancel }
|
||||
onInstall={ this.onInstall } />
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<App />
|
||||
, document.querySelector("#root"));
|
||||
38
ext/src/updater/styles/index.css
Executable file
38
ext/src/updater/styles/index.css
Executable file
@@ -0,0 +1,38 @@
|
||||
body {
|
||||
background: -moz-dialog;
|
||||
color: -moz-dialogtext;
|
||||
margin: initial;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
.updater {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
gap: 0.75em;
|
||||
grid-template-rows: min-content min-content 1fr min-content;
|
||||
grid-template-columns: 1fr min-content min-content;
|
||||
grid-template-areas:
|
||||
"description description description"
|
||||
"additional-description additional-description additional-description"
|
||||
"progress progress progress"
|
||||
". cancel install";
|
||||
padding: 0.75em;
|
||||
}
|
||||
|
||||
.updater__description {
|
||||
grid-area: description;
|
||||
}
|
||||
.updater__additional-description {
|
||||
font-size: 0.9em;
|
||||
grid-area: additional-description;
|
||||
margin-top: -0.75em;
|
||||
}
|
||||
.updater__progress {
|
||||
grid-area: progress;
|
||||
}
|
||||
.updater__install {
|
||||
grid-area: install;
|
||||
}
|
||||
.updater__cancel {
|
||||
grid-area: cancel;
|
||||
}
|
||||
13
ext/src/updater/styles/mac.css
Executable file
13
ext/src/updater/styles/mac.css
Executable file
@@ -0,0 +1,13 @@
|
||||
body {
|
||||
background: rgb(236, 236, 236);
|
||||
font: menu;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
button:not([disabled]):hover:active {
|
||||
color: -moz-mac-buttonactivetext;
|
||||
}
|
||||
@@ -10,6 +10,7 @@ module.exports = (env) => ({
|
||||
, "popup/bundle" : `${env.includePath}/popup/index.jsx`
|
||||
, "options/bundle" : `${env.includePath}/options/index.jsx`
|
||||
, "shim/bundle" : `${env.includePath}/shim/index.js`
|
||||
, "updater/bundle" : `${env.includePath}/updater/index.jsx`
|
||||
, "content" : `${env.includePath}/content.js`
|
||||
, "contentSetup" : `${env.includePath}/contentSetup.js`
|
||||
, "mediaCast" : `${env.includePath}/mediaCast.js`
|
||||
|
||||
Reference in New Issue
Block a user