Files
suwayomi-material-you-webui/src/components/ExtensionCard.tsx

168 lines
6.1 KiB
TypeScript
Raw Normal View History

/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
2021-01-26 23:32:12 +03:30
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
2021-01-26 23:32:12 +03:30
2020-12-25 03:08:08 +03:30
import React, { useState } from 'react';
2021-09-09 17:51:22 +04:30
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Button from '@mui/material/Button';
import Avatar from '@mui/material/Avatar';
import Typography from '@mui/material/Typography';
import { Box } from '@mui/material';
import { useTranslation } from 'react-i18next';
import { IExtension, TranslationKey } from '@/typings';
import requestManager from '@/lib/RequestManager';
2020-12-24 16:50:50 +01:00
interface IProps {
extension: IExtension;
notifyInstall: () => void;
2020-12-24 16:50:50 +01:00
}
enum ExtensionAction {
UPDATE = 'UPDATE',
UNINSTALL = 'UNINSTALL',
INSTALL = 'INSTALL',
}
enum ExtensionState {
OBSOLETE = 'OBSOLETE',
UPDATING = 'UPDATING',
UNINSTALLING = 'UNINSTALLING',
INSTALLING = 'INSTALLING',
}
type InstalledStates = ExtensionAction | ExtensionState;
const InstalledState = { ...ExtensionAction, ...ExtensionState } as const;
const EXTENSION_ACTION_TO_STATE_MAP: { [action in ExtensionAction]: ExtensionState } = {
[ExtensionAction.UPDATE]: ExtensionState.UPDATING,
[ExtensionAction.UNINSTALL]: ExtensionState.UNINSTALLING,
[ExtensionAction.INSTALL]: ExtensionState.INSTALLING,
} as const;
const EXTENSION_ACTION_TO_NEXT_ACTION_MAP: { [action in ExtensionAction]: ExtensionAction } = {
[ExtensionAction.UPDATE]: ExtensionAction.UNINSTALL,
[ExtensionAction.UNINSTALL]: ExtensionAction.INSTALL,
[ExtensionAction.INSTALL]: ExtensionAction.UNINSTALL,
} as const;
const INSTALLED_STATE_TO_TRANSLATION_KEY_MAP: { [installedState in InstalledStates]: TranslationKey } = {
[InstalledState.UNINSTALL]: 'extension.action.label.uninstall',
[InstalledState.INSTALL]: 'extension.action.label.install',
[InstalledState.UPDATE]: 'extension.action.label.update',
[InstalledState.OBSOLETE]: 'extension.state.label.obsolete',
[InstalledState.UPDATING]: 'extension.state.label.updating',
[InstalledState.UNINSTALLING]: 'extension.state.label.uninstalling',
[InstalledState.INSTALLING]: 'extension.state.label.installing',
} as const;
2020-12-25 03:08:08 +03:30
export default function ExtensionCard(props: IProps) {
const { t } = useTranslation();
2020-12-25 03:08:08 +03:30
const {
extension: { name, lang, versionName, installed, hasUpdate, obsolete, pkgName, iconUrl, isNsfw },
2021-03-08 21:04:42 +03:30
notifyInstall,
2020-12-25 03:08:08 +03:30
} = props;
const [installedState, setInstalledState] = useState<InstalledStates>(() => {
if (obsolete) {
return InstalledState.OBSOLETE;
}
if (hasUpdate) {
return InstalledState.UPDATE;
}
return installed ? InstalledState.UNINSTALL : InstalledState.INSTALL;
});
2020-12-25 03:08:08 +03:30
const langPress = lang === 'all' ? t('extension.language.all') : lang.toUpperCase();
2020-12-24 16:50:50 +01:00
const requestExtensionAction = async (action: ExtensionAction): Promise<void> => {
const nextAction = EXTENSION_ACTION_TO_NEXT_ACTION_MAP[action];
const state = EXTENSION_ACTION_TO_STATE_MAP[action];
2020-12-25 03:08:08 +03:30
setInstalledState(state);
switch (action) {
case ExtensionAction.INSTALL:
await requestManager.installExtension(pkgName).response;
break;
case ExtensionAction.UNINSTALL:
await requestManager.uninstallExtension(pkgName).response;
break;
case ExtensionAction.UPDATE:
await requestManager.updateExtension(pkgName).response;
break;
default:
throw new Error(`Unexpected ExtensionAction "${action}"`);
}
setInstalledState(nextAction);
notifyInstall();
};
2021-01-29 15:23:29 +03:30
function handleButtonClick() {
2021-03-29 02:47:51 +04:30
switch (installedState) {
case ExtensionAction.INSTALL:
case ExtensionAction.UPDATE:
case ExtensionAction.UNINSTALL:
requestExtensionAction(installedState).catch(() => {});
2021-03-29 02:47:51 +04:30
break;
case ExtensionState.OBSOLETE:
requestExtensionAction(ExtensionAction.UNINSTALL).catch(() => {});
2021-03-29 02:47:51 +04:30
break;
default:
break;
2021-01-29 15:23:29 +03:30
}
}
2020-12-24 16:50:50 +01:00
return (
<Card sx={{ margin: '10px' }}>
<CardContent
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
p: 2,
}}
>
<Box sx={{ display: 'flex' }}>
2020-12-24 16:50:50 +01:00
<Avatar
variant="rounded"
sx={{
width: 56,
height: 56,
flex: '0 0 auto',
mr: 2,
}}
2020-12-24 16:50:50 +01:00
alt={name}
src={requestManager.getValidImgUrlFor(iconUrl)}
2020-12-24 16:50:50 +01:00
/>
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
2020-12-24 16:50:50 +01:00
<Typography variant="h5" component="h2">
{name}
</Typography>
<Typography variant="caption" display="block" gutterBottom>
{langPress} {versionName}
{isNsfw && (
<Typography variant="caption" display="inline" gutterBottom color="red">
{' 18+'}
</Typography>
)}
2020-12-24 16:50:50 +01:00
</Typography>
</Box>
</Box>
2020-12-24 16:50:50 +01:00
2021-03-29 02:47:51 +04:30
<Button
variant="outlined"
sx={{ color: installedState === InstalledState.OBSOLETE ? 'red' : 'inherit' }}
2021-03-29 02:47:51 +04:30
onClick={() => handleButtonClick()}
>
{t(INSTALLED_STATE_TO_TRANSLATION_KEY_MAP[installedState]) as string}
2021-03-29 02:47:51 +04:30
</Button>
2020-12-24 16:50:50 +01:00
</CardContent>
</Card>
);
}