Skip to content

Commit

Permalink
feature: add modal for restart smapp and install application. Revert …
Browse files Browse the repository at this point in the history
…system modal changes.
  • Loading branch information
maparr committed Dec 20, 2023
1 parent 594f9e7 commit 6bf1af3
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 107 deletions.
38 changes: 37 additions & 1 deletion app/components/common/Version.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import { getNetworkInfo } from '../../redux/network/selectors';
import { checkUpdates as checkUpdatesIco } from '../../assets/images';
import { AppThDispatch } from '../../types';
import updaterSlice from '../../redux/updater/slice';
import { SECOND } from '../../../shared/constants';
import { Loader } from '../../basicComponents';
import UpdateApplicationWarningModal from '../../screens/modal/UpdateApplicationWarningModal';
import FeedbackButton from './Feedback';

const Container = styled.div`
Expand Down Expand Up @@ -194,6 +197,29 @@ const UpdateStatus = () => {
const isDownloading = useSelector(isUpdateDownloading);
const isDownloaded = useSelector(isUpdateDownloaded);
const error = useSelector(getError);
const [
isOpenUpdateApplicationWarningModal,
setIsOpenUpdateApplicationWarningModal,
] = useState(false);
const [
showUpdateApplicationLoader,
setShowUpdateApplicationLoader,
] = useState(false);

const handleRestartNow = () => {
setIsOpenUpdateApplicationWarningModal(false);
setShowUpdateApplicationLoader(true);
eventsService.installUpdate();

setTimeout(() => {
setShowUpdateApplicationLoader(false);
}, 10 * SECOND);
};

const handlePostpone = () => {
setIsOpenUpdateApplicationWarningModal(false); // Just close the modal
};

if (!isDownloading && !isDownloaded) return null;

if (progress !== null && !isDownloaded) {
Expand All @@ -207,9 +233,19 @@ const UpdateStatus = () => {
return (
<>
<ProgressChunk>Update is ready to install</ProgressChunk>
<PrimaryAction onClick={() => eventsService.installUpdate()}>
<PrimaryAction
onClick={() => setIsOpenUpdateApplicationWarningModal(true)}
>
Restart Smapp
</PrimaryAction>
<UpdateApplicationWarningModal
isOpen={isOpenUpdateApplicationWarningModal}
onApprove={handleRestartNow}
onCancel={handlePostpone}
/>
{showUpdateApplicationLoader && (
<Loader size={Loader.sizes.BIG} note="UPDATE IN PROGESS..." />
)}
</>
);
}
Expand Down
67 changes: 67 additions & 0 deletions app/screens/modal/UpdateApplicationWarningModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import styled from 'styled-components';
import Modal from '../../components/common/Modal';
import { Button } from '../../basicComponents';
import { smColors } from '../../vars';

const ButtonsWrapper = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
margin: auto 0 15px 0;
padding-top: 30px;
`;

const Message = styled.pre`
font-size: 14px;
line-height: 1.33em;
word-wrap: break-word;
white-space: pre-wrap;
overflow-y: auto;
margin-top: 15px;
ul {
list-style: none;
margin-left: 10px;
}
li {
margin: 10px 0;
}
li:before {
content: '• ';
padding: 5px;
}
`;

const UpdateApplicationWarningModal = ({ isOpen, onApprove, onCancel }) => {
if (!isOpen) return null;

return (
<Modal header="Update SMAPP" height={380}>
<Message>
<p>
Restarting now is <b>CRITICAL</b> and may impact your node’s
performance and rewards.
</p>
<ul>
<li>
Click <b style={{ color: smColors.green }}>RESTART NOW</b> to apply
the update immediately. Delaying the update could result in
potential loss of rewards.
</li>
<li>
Click <b style={{ color: smColors.purple }}>POSTPONE</b> to delay
the update. Be aware that postponing may slow down your node’s
performance and future rewards.
</li>
</ul>
</Message>
<ButtonsWrapper>
<Button onClick={onCancel} isPrimary={false} text="POSTPONE" />
<Button onClick={onApprove} text="RESTART NOW" />
</ButtonsWrapper>
</Modal>
);
};

export default UpdateApplicationWarningModal;
153 changes: 50 additions & 103 deletions desktop/main/promptBeforeClose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ import Logger from '../logger';
import { Managers } from './app.types';
import { showNotification } from './utils';

enum UpdatePromptResult {
RESTART_NOW = 1,
POSTPONE_UPDATE = 2,
CANCELED = 3,
}

enum CloseAppPromptResult {
CANCELED = 1, // To avoid conversion to `false`
KEEP_SMESHING = 2,
Expand All @@ -21,64 +15,41 @@ const logger = Logger({ className: 'promptBeforeClose' });

let isCloseTriggered = false;

const showPrompt = async (mainWindow: BrowserWindow) => {
if (!mainWindow) return CloseAppPromptResult.KEEP_SMESHING;
const { response } = await dialog.showMessageBox(mainWindow, {
title: 'Quit App',
message:
'\nQuitting stops smeshing and may cause loss of future due smeshing rewards.' +
'\n\n\n• Click RUN IN BACKGROUND to close the App window and to keep smeshing in the background.' +
'\n\n• Click QUIT to close the app and stop smeshing.\n',
buttons: ['RUN IN BACKGROUND', 'QUIT', 'Cancel'],
cancelId: 2,
});
switch (response) {
default:
case 2:
return CloseAppPromptResult.CANCELED;
case 0:
return CloseAppPromptResult.KEEP_SMESHING;
case 1:
return CloseAppPromptResult.CLOSE;
}
};

const showUpdatePrompt = async (mainWindow: BrowserWindow) => {
if (!mainWindow) return UpdatePromptResult.CANCELED;
const { response } = await dialog.showMessageBox(mainWindow, {
title: 'Restart to Complete Update',
message:
'Restarting now is critical and may impact your node’s performance and rewards.' +
'\n\n\n• Click RESTART NOW to apply the update immediately. Delaying the update could result in decreased node efficiency or potential loss of rewards.' +
'\n\n• Click POSTPONE to delay the update. Be aware that postponing may jeopardize your node’s performance and future rewards.' +
'\n\n• Click CANCEL to dismiss this message. Remember to restart later to complete the update.',
buttons: ['RESTART NOW', 'POSTPONE', 'CANCEL'],
cancelId: 2,
});
switch (response) {
default:
case 2:
return UpdatePromptResult.CANCELED;
case 0:
return UpdatePromptResult.RESTART_NOW;
case 1:
return UpdatePromptResult.POSTPONE_UPDATE;
}
};

const notify = (mainWindow: BrowserWindow) =>
showNotification(mainWindow, {
title: 'Spacemesh',
body: 'Smesher is running in the background.',
});

const promptBeforeClose = (
mainWindow: BrowserWindow,
managers: Partial<Managers>,
$isAppClosing: BehaviorSubject<boolean>,
$showWindowOnLoad: Subject<boolean>,
$isUpdateInProgress: BehaviorSubject<boolean>
) => {
const showPrompt = async () => {
if (!mainWindow) return CloseAppPromptResult.KEEP_SMESHING;
const { response } = await dialog.showMessageBox(mainWindow, {
title: 'Quit App',
message:
'\nQuitting stops smeshing and may cause loss of future due smeshing rewards.' +
'\n\n\n• Click RUN IN BACKGROUND to close the App window and to keep smeshing in the background.' +
'\n\n• Click QUIT to close the app and stop smeshing.\n',
buttons: ['RUN IN BACKGROUND', 'QUIT', 'Cancel'],
cancelId: 2,
});
switch (response) {
default:
case 2:
return CloseAppPromptResult.CANCELED;
case 0:
return CloseAppPromptResult.KEEP_SMESHING;
case 1:
return CloseAppPromptResult.CLOSE;
}
};
const isNodeRunning = async () => managers?.node?.isNodeRunning() || false;
const notify = () =>
showNotification(mainWindow, {
title: 'Spacemesh',
body: 'Smesher is running in the background.',
});

const quit = async () => {
try {
mainWindow.hide();
Expand All @@ -93,60 +64,36 @@ const promptBeforeClose = (
}
};

const hideWindow = () => {
setTimeout(notify, 1000, mainWindow);
mainWindow.hide();
$showWindowOnLoad.next(false);
$isUpdateInProgress.next(false);
mainWindow.reload();
};
const handleClosingApp = async (event: Electron.Event) => {
event.preventDefault();

const closeApp = async () => {
isCloseTriggered = true;
mainWindow.webContents.send(ipcConsts.CLOSING_APP);
await quit();
};

const handlePromptResult = async (
promptResult: CloseAppPromptResult | UpdatePromptResult
) => {
if (
promptResult === UpdatePromptResult.RESTART_NOW ||
promptResult === CloseAppPromptResult.CLOSE
) {
await closeApp();
} else if (
promptResult === UpdatePromptResult.POSTPONE_UPDATE ||
promptResult === CloseAppPromptResult.KEEP_SMESHING
) {
hideWindow();
if ($isUpdateInProgress.value || !mainWindow) {
await quit();
return;
}
};

return async (event: Electron.Event) => {
event?.preventDefault();
if (!mainWindow || isCloseTriggered) {
if (!mainWindow) await quit();
else mainWindow.hide();
if (isCloseTriggered) {
mainWindow.hide();
return;
}

logger.log(
'handleClosingApp',
'isUpdateInProgress',
$isUpdateInProgress.value
);
const promptResult =
((await isNodeRunning()) && (await showPrompt())) ||
CloseAppPromptResult.CLOSE;

const promptResult = $isUpdateInProgress.value
? (await showUpdatePrompt(mainWindow)) || UpdatePromptResult.RESTART_NOW
: (Boolean(await managers?.node?.isNodeRunning()) &&
(await showPrompt(mainWindow))) ||
CloseAppPromptResult.CLOSE;

logger.log('handleClosingApp', 'promptResult', promptResult);

await handlePromptResult(promptResult);
if (promptResult === CloseAppPromptResult.KEEP_SMESHING) {
setTimeout(notify, 1000);
mainWindow.hide();
$showWindowOnLoad.next(false);
mainWindow.reload();
} else if (promptResult === CloseAppPromptResult.CLOSE) {
isCloseTriggered = true;
mainWindow.webContents.send(ipcConsts.CLOSING_APP);
await quit();
}
};

return handleClosingApp;
};

export default promptBeforeClose;
1 change: 0 additions & 1 deletion desktop/main/sources/autoUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ const handleAutoUpdates = (
}),
// Trigger installation
fromIPC<void>(ipcConsts.AU_REQUEST_INSTALL).subscribe(() => {
logger.log('ipcConsts.AU_REQUEST_INSTALL', 'installUpdate');
$isUpdateInProgress.next(true);
return installUpdate();
}),
Expand Down
4 changes: 2 additions & 2 deletions shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export enum ExternalLinks {
}

export const BITS_PER_LABEL = 128;

export const MINUTE = 60 * 1000;
export const SECOND = 1000;
export const MINUTE = 60 * SECOND;

export const HOUR = MINUTE * 60;

Expand Down

0 comments on commit 6bf1af3

Please sign in to comment.