signal-desktop/ts/components/stickers/StickerPreviewModal.tsx

226 lines
6.5 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2019 Signal Messenger, LLC
2020-10-30 20:34:04 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react';
import { isNumber, range } from 'lodash';
import classNames from 'classnames';
import { ConfirmationDialog } from '../ConfirmationDialog';
import type { LocalizerType } from '../../types/Util';
import type { StickerPackType } from '../../state/ducks/stickers';
import { Spinner } from '../Spinner';
2021-09-17 22:24:21 +00:00
import { useRestoreFocus } from '../../hooks/useRestoreFocus';
2022-12-14 00:06:15 +00:00
import { Modal } from '../Modal';
import { Button, ButtonVariant } from '../Button';
2023-04-20 17:03:43 +00:00
import { UserText } from '../UserText';
export type OwnProps = {
2022-12-14 00:06:15 +00:00
readonly onClose?: () => unknown;
readonly closeStickerPackPreview: () => unknown;
readonly downloadStickerPack: (
packId: string,
packKey: string,
options?: { finalStatus?: 'installed' | 'downloaded' }
) => unknown;
readonly installStickerPack: (packId: string, packKey: string) => unknown;
readonly uninstallStickerPack: (packId: string, packKey: string) => unknown;
readonly pack?: StickerPackType;
readonly i18n: LocalizerType;
};
export type Props = OwnProps;
function renderBody({ pack, i18n }: Props) {
if (!pack) {
return null;
}
if (pack && pack.status === 'error') {
return (
2022-12-14 00:06:15 +00:00
<div className="module-sticker-manager__preview-modal__error">
2023-03-30 00:03:25 +00:00
{i18n('icu:stickers--StickerPreview--Error')}
</div>
);
}
if (pack.stickerCount === 0 || !isNumber(pack.stickerCount)) {
2019-06-26 19:33:13 +00:00
return <Spinner svgSize="normal" />;
}
return (
2022-12-14 00:06:15 +00:00
<div className="module-sticker-manager__preview-modal__sticker-grid">
{pack.stickers.map(({ id, url }) => (
<div
key={id}
2022-12-14 00:06:15 +00:00
className="module-sticker-manager__preview-modal__sticker-grid__cell"
>
<img
2022-12-14 00:06:15 +00:00
className="module-sticker-manager__preview-modal__sticker-grid__cell__image"
src={url}
alt={pack.title}
/>
</div>
))}
2022-12-14 00:06:15 +00:00
{range(pack.stickerCount - pack.stickers.length).map(i => (
<div
key={`placeholder-${i}`}
className={classNames(
'module-sticker-manager__preview-modal__sticker-grid__cell',
'module-sticker-manager__preview-modal__sticker-grid__cell--placeholder'
)}
/>
))}
</div>
);
}
2022-11-18 00:45:19 +00:00
export const StickerPreviewModal = React.memo(function StickerPreviewModalInner(
props: Props
) {
2020-09-14 22:14:03 +00:00
const {
closeStickerPackPreview,
2020-09-14 22:14:03 +00:00
downloadStickerPack,
2022-12-14 00:06:15 +00:00
i18n,
2020-09-14 22:14:03 +00:00
installStickerPack,
2022-12-14 00:06:15 +00:00
onClose,
pack,
2020-09-14 22:14:03 +00:00
uninstallStickerPack,
} = props;
const [confirmingUninstall, setConfirmingUninstall] = React.useState(false);
// Restore focus on teardown
const [focusRef] = useRestoreFocus();
2020-09-14 22:14:03 +00:00
React.useEffect(() => {
if (pack && pack.status === 'known') {
downloadStickerPack(pack.id, pack.key);
}
if (
pack &&
pack.status === 'error' &&
(pack.attemptedStatus === 'downloaded' ||
pack.attemptedStatus === 'installed')
) {
downloadStickerPack(pack.id, pack.key, {
finalStatus: pack.attemptedStatus,
});
}
// We only want to attempt downloads on initial load
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
React.useEffect(() => {
if (pack) {
return;
}
// Pack fully uninstalled, don't keep the modal open
closeStickerPackPreview();
}, [pack, closeStickerPackPreview]);
2022-12-14 00:06:15 +00:00
const handleClose = React.useCallback(() => {
if (pack) {
closeStickerPackPreview();
}
2022-12-14 00:06:15 +00:00
onClose?.();
}, [closeStickerPackPreview, onClose, pack]);
2020-09-14 22:14:03 +00:00
const isInstalled = Boolean(pack && pack.status === 'installed');
const handleToggleInstall = React.useCallback(() => {
if (!pack) {
return;
}
if (isInstalled) {
setConfirmingUninstall(true);
} else if (pack.status === 'ephemeral') {
downloadStickerPack(pack.id, pack.key, { finalStatus: 'installed' });
2022-12-14 00:06:15 +00:00
handleClose();
2020-09-14 22:14:03 +00:00
} else {
installStickerPack(pack.id, pack.key);
2022-12-14 00:06:15 +00:00
handleClose();
2020-09-14 22:14:03 +00:00
}
}, [
downloadStickerPack,
installStickerPack,
isInstalled,
2022-12-14 00:06:15 +00:00
handleClose,
2020-09-14 22:14:03 +00:00
pack,
setConfirmingUninstall,
]);
const handleUninstall = React.useCallback(() => {
if (!pack) {
return;
}
uninstallStickerPack(pack.id, pack.key);
setConfirmingUninstall(false);
// closeStickerPackPreview is called by <ConfirmationDialog />'s onClose
2020-09-14 22:14:03 +00:00
}, [uninstallStickerPack, setConfirmingUninstall, pack]);
2022-12-14 00:06:15 +00:00
const buttonLabel = isInstalled
2023-03-30 00:03:25 +00:00
? i18n('icu:stickers--StickerManager--Uninstall')
: i18n('icu:stickers--StickerManager--Install');
2022-12-14 00:06:15 +00:00
const modalFooter =
pack && pack.status !== 'error' ? (
<div className="module-sticker-manager__preview-modal__footer">
<div className="module-sticker-manager__preview-modal__footer--info">
<h3 className="module-sticker-manager__preview-modal__footer--title">
2023-04-20 17:03:43 +00:00
<UserText text={pack.title} />
2022-12-14 00:06:15 +00:00
{pack.isBlessed ? (
<span className="module-sticker-manager__preview-modal__footer--blessed-icon" />
) : null}
</h3>
<h4 className="module-sticker-manager__preview-modal__footer--author">
{pack.author}
</h4>
</div>
<div className="module-sticker-manager__preview-modal__footer--install">
{pack.status === 'pending' ? (
<Spinner svgSize="small" size="14px" />
2020-09-14 22:14:03 +00:00
) : (
2022-12-14 00:06:15 +00:00
<Button
aria-label={buttonLabel}
ref={focusRef}
onClick={handleToggleInstall}
variant={ButtonVariant.Primary}
>
{buttonLabel}
</Button>
2020-09-14 22:14:03 +00:00
)}
2022-12-14 00:06:15 +00:00
</div>
</div>
) : undefined;
return (
<>
{confirmingUninstall && (
<ConfirmationDialog
dialogName="StickerPreviewModal.confirmUninstall"
actions={[
{
style: 'negative',
2023-03-30 00:03:25 +00:00
text: i18n('icu:stickers--StickerManager--Uninstall'),
2022-12-14 00:06:15 +00:00
action: handleUninstall,
},
]}
i18n={i18n}
onClose={() => setConfirmingUninstall(false)}
>
2023-03-30 00:03:25 +00:00
{i18n('icu:stickers--StickerManager--UninstallWarning')}
2022-12-14 00:06:15 +00:00
</ConfirmationDialog>
)}
<Modal
hasXButton
i18n={i18n}
modalFooter={modalFooter}
modalName="StickerPreviewModal"
moduleClassName="module-sticker-manager__preview-modal__modal"
onClose={handleClose}
2023-03-30 00:03:25 +00:00
title={i18n('icu:stickers--StickerPreview--Title')}
2022-12-14 00:06:15 +00:00
>
{renderBody(props)}
</Modal>
</>
);
2020-09-14 22:14:03 +00:00
});