mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-04-27 19:26:09 -04:00
feat(gui): Display dialog when update is available (#132)
* feat(tauri): Use new tauri signing key * feat(gui): Display MUI dialog when update is available
This commit is contained in:
parent
a9b1d05af0
commit
c1afc7aa2a
@ -9,6 +9,7 @@ import HistoryPage from "./pages/history/HistoryPage";
|
||||
import SwapPage from "./pages/swap/SwapPage";
|
||||
import WalletPage from "./pages/wallet/WalletPage";
|
||||
import GlobalSnackbarProvider from "./snackbar/GlobalSnackbarProvider";
|
||||
import UpdaterDialog from "./modal/updater/UpdaterDialog";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
innerContent: {
|
||||
@ -58,6 +59,7 @@ export default function App() {
|
||||
<Router>
|
||||
<Navigation />
|
||||
<InnerContent />
|
||||
<UpdaterDialog/>
|
||||
</Router>
|
||||
</GlobalSnackbarProvider>
|
||||
</ThemeProvider>
|
||||
|
166
src-gui/src/renderer/components/modal/updater/UpdaterDialog.tsx
Normal file
166
src-gui/src/renderer/components/modal/updater/UpdaterDialog.tsx
Normal file
@ -0,0 +1,166 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
Button,
|
||||
LinearProgress,
|
||||
Typography,
|
||||
makeStyles,
|
||||
LinearProgressProps,
|
||||
Box,
|
||||
} from '@material-ui/core';
|
||||
import SystemUpdateIcon from '@material-ui/icons/SystemUpdate';
|
||||
import { check, Update, DownloadEvent } from '@tauri-apps/plugin-updater';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { relaunch } from '@tauri-apps/plugin-process';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
progress: {
|
||||
marginTop: theme.spacing(2)
|
||||
},
|
||||
releaseNotes: {
|
||||
marginTop: theme.spacing(2),
|
||||
marginBottom: theme.spacing(1)
|
||||
},
|
||||
noteContent: {
|
||||
whiteSpace: 'pre-line'
|
||||
}
|
||||
}));
|
||||
|
||||
interface DownloadProgress {
|
||||
contentLength: number | null;
|
||||
downloadedBytes: number;
|
||||
}
|
||||
|
||||
function LinearProgressWithLabel(props: LinearProgressProps & { label?: string }) {
|
||||
return (
|
||||
<Box display="flex" alignItems="center">
|
||||
<Box width="100%" mr={1}>
|
||||
<LinearProgress variant="determinate" {...props} />
|
||||
</Box>
|
||||
<Box minWidth={85}>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
{props.label || `${Math.round(props.value)}%`}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default function UpdaterDialog() {
|
||||
const classes = useStyles();
|
||||
const [availableUpdate, setAvailableUpdate] = useState<Update | null>(null);
|
||||
const [downloadProgress, setDownloadProgress] = useState<DownloadProgress | null>(null);
|
||||
const {enqueueSnackbar} = useSnackbar();
|
||||
|
||||
useEffect(() => {
|
||||
// Check for updates when component mounts
|
||||
check().then((updateResponse) => {
|
||||
setAvailableUpdate(updateResponse);
|
||||
}).catch((err) => {
|
||||
enqueueSnackbar(`Failed to check for updates: ${err}`, {
|
||||
variant: 'error',
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
// If no update is available, don't render the dialog
|
||||
if (!availableUpdate?.available) return null;
|
||||
|
||||
function hideNotification() {
|
||||
setAvailableUpdate(null);
|
||||
};
|
||||
|
||||
async function handleInstall() {
|
||||
try {
|
||||
await availableUpdate.downloadAndInstall((event: DownloadEvent) => {
|
||||
if (event.event === 'Started') {
|
||||
setDownloadProgress({
|
||||
contentLength: event.data.contentLength || null,
|
||||
downloadedBytes: 0,
|
||||
});
|
||||
} else if (event.event === 'Progress') {
|
||||
setDownloadProgress(prev => ({
|
||||
...prev,
|
||||
downloadedBytes: prev.downloadedBytes + event.data.chunkLength,
|
||||
}));
|
||||
} else if (event.event === 'Finished') {
|
||||
// Relaunch the application for the new version to be used
|
||||
relaunch();
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
enqueueSnackbar(`Failed to install update: ${err}`, {
|
||||
variant: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isDownloading = downloadProgress !== null;
|
||||
|
||||
const progress = isDownloading
|
||||
? Math.round((downloadProgress.downloadedBytes / downloadProgress.contentLength) * 100)
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullWidth
|
||||
maxWidth="sm"
|
||||
open={availableUpdate.available}
|
||||
onClose={hideNotification}
|
||||
>
|
||||
<DialogTitle>Update Available</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
A new version (v{availableUpdate.version}) is available. Your current version is {availableUpdate.currentVersion}.
|
||||
The update will be verified using PGP signature verification to ensure authenticity.
|
||||
{availableUpdate.body && (
|
||||
<>
|
||||
<Typography variant="h6" className={classes.releaseNotes}>
|
||||
Release Notes:
|
||||
</Typography>
|
||||
<Typography variant="body2" component="div" className={classes.noteContent}>
|
||||
{availableUpdate.body}
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
</DialogContentText>
|
||||
|
||||
{isDownloading && (
|
||||
<Box className={classes.progress}>
|
||||
<LinearProgressWithLabel
|
||||
value={progress}
|
||||
label={`${(downloadProgress.downloadedBytes / 1024 / 1024).toFixed(1)} MB${
|
||||
downloadProgress.contentLength
|
||||
? ` / ${(downloadProgress.contentLength / 1024 / 1024).toFixed(1)} MB`
|
||||
: ''
|
||||
}`}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
variant="text"
|
||||
color="default"
|
||||
onClick={hideNotification}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
Remind me later
|
||||
</Button>
|
||||
<Button
|
||||
endIcon={<SystemUpdateIcon />}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleInstall}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
{isDownloading ? 'DOWNLOADING...' : 'INSTALL UPDATE'}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@ -18,8 +18,6 @@ import {
|
||||
import App from "./components/App";
|
||||
import { initEventListeners } from "./rpc";
|
||||
import { persistor, store } from "./store/storeRenderer";
|
||||
import { Box } from "@material-ui/core";
|
||||
import { checkForAppUpdates } from "./updater";
|
||||
|
||||
const container = document.getElementById("root");
|
||||
const root = createRoot(container!);
|
||||
@ -76,5 +74,4 @@ async function fetchInitialData() {
|
||||
}
|
||||
|
||||
fetchInitialData();
|
||||
initEventListeners();
|
||||
checkForAppUpdates();
|
||||
initEventListeners();
|
@ -1,27 +0,0 @@
|
||||
import { check } from "@tauri-apps/plugin-updater";
|
||||
import { ask, message } from "@tauri-apps/plugin-dialog";
|
||||
import { relaunch } from "@tauri-apps/plugin-process";
|
||||
|
||||
export async function checkForAppUpdates() {
|
||||
const update = await check();
|
||||
|
||||
if (update?.available) {
|
||||
const yes = await ask(
|
||||
`
|
||||
Update to ${update.version} is available!
|
||||
Release notes: ${update.body}
|
||||
`,
|
||||
{
|
||||
title: "Update Now!",
|
||||
kind: "info",
|
||||
okLabel: "Update",
|
||||
cancelLabel: "Cancel",
|
||||
}
|
||||
);
|
||||
|
||||
if (yes) {
|
||||
await update.downloadAndInstall();
|
||||
await relaunch();
|
||||
}
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@
|
||||
"endpoints": [
|
||||
"https://cdn.crabnebula.app/update/unstoppableswap/unstoppableswap-gui-rs/{{target}}-{{arch}}/{{current_version}}"
|
||||
],
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyNTQ3NTQxQTQ2MkI4N0IKUldSN3VHS2tRWFZVMGpWYytkRFg4dFBzNEh5ZnlxaHBubGpRalVMMG5nVytiR3JPOUE3QjRxc00K"
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEE2MDgxRDEwMDZENkYxNUMKUldSYzhkWUdFQjBJcGwzN24yZlduTzNndFZnVW9Qa1k2WFVTMEMxcHBSc2dSVVlzbVNHdGNFQ0EK"
|
||||
},
|
||||
"cli": {
|
||||
"description": "Start the GUI application",
|
||||
|
Loading…
x
Reference in New Issue
Block a user