/* * MIT License * * Copyright (c) 2022 Robin E. R. Davies * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import React from 'react'; import Button from '@mui/material/Button'; import Typography from '@mui/material/Typography'; import Divider from '@mui/material/Divider'; import DialogEx from './DialogEx'; import DialogTitle from '@mui/material/DialogTitle'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import { UpdateStatus, UpdateRelease, UpdatePolicyT, intToUpdatePolicyT } from './Updater'; import { PiPedalModelFactory, PiPedalModel } from './PiPedalModel'; import Select from '@mui/material/Select'; import MenuItem from '@mui/material/MenuItem'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; const UPDATE_CHECK_DELAY = 86400000; // one day in ms. // const UPDATE_CHECK_DELAY = 30 * 1000; // testing export interface UpdateDialogProps { open: boolean; }; export interface UpdateDialogState { updateStatus: UpdateStatus; compactWidth: boolean; alertDialogOpen: boolean; alertDialogMessage: string; }; export default class UpdateDialog extends ResizeResponsiveComponent { private model: PiPedalModel; constructor(props: UpdateDialogProps) { super(props); this.model = PiPedalModelFactory.getInstance(); let updateStatus = this.model.updateStatus.get(); this.state = { updateStatus: updateStatus, compactWidth: this.isCompactWidth(), alertDialogOpen: false, alertDialogMessage: "" }; this.onUpdateStatusChanged = this.onUpdateStatusChanged.bind(this); } isCompactWidth() { return this.windowSize.width < 420; } onUpdateStatusChanged(newValue: UpdateStatus) { if (!newValue.equals(this.state.updateStatus)) { this.setState({ updateStatus: newValue }); } } private mounted: boolean = false; componentDidMount() { super.componentDidMount(); this.mounted = true; this.model.updateStatus.addOnChangedHandler(this.onUpdateStatusChanged); } componentWillUnmount() { super.componentWillUnmount(); this.model.updateStatus.removeOnChangedHandler(this.onUpdateStatusChanged); this.mounted = false; } onWindowSizeChanged(width: number, height: number): void { super.onWindowSizeChanged(width, height); if (this.isCompactWidth() !== this.state.compactWidth) { this.setState({ compactWidth: this.isCompactWidth() }); } } private handleOK() { this.model.showUpdateDialog(false); } private handleUpdateNow() { this.model.updateNow() .then(() => { }) // all handling is done by model, so we can run ui-less. .catch((e: any) => { this.showAlert(e.toString()); }); } private handleUpdateLater() { this.model.updateLater(UPDATE_CHECK_DELAY); this.model.showUpdateDialog(false); // allow close if launched from the settings window. } private handleClose() { // ideally, we'd like to not close at all, but it screws up the nav backstack if we dont. // so, close, but do so very briefly if (this.canUpgrade()) { this.model.updateLater(UPDATE_CHECK_DELAY); // close and re-open immediately. } this.model.showUpdateDialog(false); } handleCloseAlert() { this.setState({ alertDialogOpen: false, alertDialogMessage: "" }) } showAlert(message: string) { this.setState({ alertDialogOpen: true, alertDialogMessage: message }); } onViewReleaseNotes() { this.model.launchExternalUrl("https://rerdavies.github.io/pipedal/ReleaseNotes.html"); } upToDate(): boolean { let updateStatus = this.state.updateStatus; let updateRelease: UpdateRelease = updateStatus.getActiveRelease(); return !updateRelease.updateAvailable } canUpgrade(): boolean { let updateStatus = this.state.updateStatus; if (updateStatus.updatePolicy === UpdatePolicyT.Disable) { return false; } if (updateStatus.errorMessage !== "") { return false; } let updateRelease = updateStatus.getActiveRelease(); return updateStatus.isValid && updateStatus.isOnline && updateRelease.updateAvailable; } private onPolicySelected(newValue: string | number): void { if (newValue.toString() === "") return; let updatePolicy = intToUpdatePolicyT(newValue as number); this.model.setUpdatePolicy(updatePolicy); } render() { let updateStatus = this.state.updateStatus; let updateRelease = updateStatus.getActiveRelease(); let upToDate = this.upToDate(); let canUpgrade = this.canUpgrade(); let showUpgradeVersion = !upToDate && updateStatus.isValid && updateRelease.upgradeVersionDisplayName !== ""; let compactWidth = this.state.compactWidth; return ( { this.handleClose(); }} style={{ userSelect: "none" }} >
Updates
{(upToDate) && ( PiPedal is up to date. ) } {(canUpgrade) && ( A new version of the PiPedal server is available. Would you like to update now? ) } { (compactWidth) ? (
Current version: {updateStatus.currentVersionDisplayName} {(showUpgradeVersion) && (
Update version: {updateRelease.upgradeVersionDisplayName}
)}
) : (
Current version: {(showUpgradeVersion) && ( Update version: ) }
{updateStatus.currentVersionDisplayName} {(showUpgradeVersion) && ( {updateRelease.upgradeVersionDisplayName} ) }
) } { (updateStatus.errorMessage.length !== 0) && ( { updateStatus.errorMessage } ) }
{ (canUpgrade) ? (
) : (
) } { this.handleCloseAlert(); }} aria-describedby="Alert Dialog" > { this.state.alertDialogMessage } ); } }