handle core initialization error with a ui dialog

This commit is contained in:
nklhrstv 2021-11-02 18:34:20 +02:00
parent 0ea77ede67
commit 2a8d7ab0cb
5 changed files with 141 additions and 18 deletions

View file

@ -7,6 +7,7 @@ const { Core, Shell, Chromecast, KeyboardShortcuts, ServicesProvider } = require
const { NotFound } = require('stremio/routes');
const { ToastProvider, sanitizeLocationPath, CONSTANTS } = require('stremio/common');
const CoreEventsToaster = require('./CoreEventsToaster');
const ErrorDialog = require('./ErrorDialog');
const routerViewsConfig = require('./routerViewsConfig');
const styles = require('./styles');
@ -26,8 +27,7 @@ const App = () => {
chromecast: new Chromecast(),
keyboardShortcuts: new KeyboardShortcuts()
}), []);
const [coreInitialized, setCoreInitialized] = React.useState(false);
const [shellInitialized, setShellInitialized] = React.useState(false);
const [initialized, setInitialized] = React.useState(false);
React.useEffect(() => {
let prevPath = window.location.hash.slice(1);
const onLocationHashChange = () => {
@ -46,13 +46,16 @@ const App = () => {
}, []);
React.useEffect(() => {
const onCoreStateChanged = () => {
setCoreInitialized(services.core.active);
if (services.core.error) {
alert(services.core.error);
}
setInitialized(
(services.core.active || services.core.error instanceof Error) &&
(services.shell.active || services.shell.error instanceof Error)
);
};
const onShellStateChanged = () => {
setShellInitialized(services.shell.active || services.shell.error instanceof Error);
setInitialized(
(services.core.active || services.core.error instanceof Error) &&
(services.shell.active || services.shell.error instanceof Error)
);
};
const onChromecastStateChange = () => {
if (services.chromecast.active) {
@ -86,17 +89,20 @@ const App = () => {
<React.StrictMode>
<ServicesProvider services={services}>
{
coreInitialized && shellInitialized ?
<ToastProvider className={styles['toasts-container']}>
<CoreEventsToaster />
<Router
className={styles['router']}
viewsConfig={routerViewsConfig}
onPathNotMatch={onPathNotMatch}
/>
</ToastProvider>
initialized ?
services.core.error instanceof Error ?
<ErrorDialog className={styles['error-container']} />
:
<ToastProvider className={styles['toasts-container']}>
<CoreEventsToaster />
<Router
className={styles['router']}
viewsConfig={routerViewsConfig}
onPathNotMatch={onPathNotMatch}
/>
</ToastProvider>
:
<div className={styles['app-loader']} />
<div className={styles['loader-container']} />
}
</ServicesProvider>
</React.StrictMode>

View file

@ -0,0 +1,42 @@
// Copyright (C) 2017-2020 Smart code 203358507
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const { Button, Image } = require('stremio/common');
const styles = require('./styles');
const ErrorDialog = ({ className }) => {
const reload = React.useCallback(() => {
window.location.reload();
}, []);
const clearData = React.useCallback(() => {
window.localStorage.clear();
}, []);
return (
<div className={classnames(className, styles['error-container'])}>
<Image
className={styles['error-image']}
src={require('/images/empty.png')}
alt={' '}
/>
<div className={styles['error-message']}>Something went wrong!</div>
<div className={styles['buttons-container']}>
<Button className={styles['button-container']} title={'Try again'} onClick={reload}>
<div className={styles['label']}>Try again</div>
</Button>
<Button className={styles['button-container']} title={'Clear data'} onClick={clearData}>
<div className={styles['label']}>Clear data</div>
</Button>
</div>
</div>
);
};
ErrorDialog.displayName = 'ErrorDialog';
ErrorDialog.propTypes = {
className: PropTypes.string
};
module.exports = ErrorDialog;

View file

@ -0,0 +1,5 @@
// Copyright (C) 2017-2020 Smart code 203358507
const ErrorDialog = require('./ErrorDialog');
module.exports = ErrorDialog;

View file

@ -0,0 +1,70 @@
// Copyright (C) 2017-2020 Smart code 203358507
@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less';
.error-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.error-image {
flex: none;
width: 12rem;
height: 12rem;
margin-bottom: 1rem;
object-fit: contain;
object-position: center;
opacity: 0.9;
}
.error-message {
flex: none;
padding: 0 3rem;
font-size: 2rem;
max-height: 3.6em;
text-align: center;
color: @color-surface-light5-90;
}
.buttons-container {
flex: none;
align-self: stretch;
margin: 0 2rem;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
.button-container {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin: 2rem 1rem 0;
padding: 0 1rem;
min-width: 8rem;
height: 3rem;
background-color: @color-accent3;
&:hover {
background-color: @color-accent3-light1;
}
.label {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
max-height: 2.4em;
font-size: 1.1rem;
font-weight: 500;
text-align: center;
color: @color-surface-light5-90;
}
}
}
}

View file

@ -104,7 +104,7 @@ html {
height: 100%;
}
.app-loader {
.loader-container, .error-container {
width: 100%;
height: 100%;
background-color: @color-background-dark2;