Media Viewer: Support deleting messages (#2086)

This commit is contained in:
Alexander Zinchuk 2022-11-01 18:53:09 +01:00
parent dc9ee50c46
commit df19a8489b
2 changed files with 100 additions and 33 deletions

View File

@ -7,23 +7,31 @@ import React, {
import { getActions, withGlobal } from '../../global'; import { getActions, withGlobal } from '../../global';
import type { ApiMessage } from '../../api/types'; import type { ApiMessage } from '../../api/types';
import type { MessageListType } from '../../global/types';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment'; import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { getMessageMediaFormat, getMessageMediaHash } from '../../global/helpers'; import { getMessageMediaFormat, getMessageMediaHash } from '../../global/helpers';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import useMediaWithLoadProgress from '../../hooks/useMediaWithLoadProgress'; import useMediaWithLoadProgress from '../../hooks/useMediaWithLoadProgress';
import { selectIsDownloading, selectIsMessageProtected } from '../../global/selectors'; import useFlag from '../../hooks/useFlag';
import {
selectIsDownloading, selectIsMessageProtected, selectAllowedMessageActions, selectCurrentMessageList,
} from '../../global/selectors';
import Button from '../ui/Button'; import Button from '../ui/Button';
import DropdownMenu from '../ui/DropdownMenu'; import DropdownMenu from '../ui/DropdownMenu';
import type { MenuItemProps } from '../ui/MenuItem';
import MenuItem from '../ui/MenuItem'; import MenuItem from '../ui/MenuItem';
import ProgressSpinner from '../ui/ProgressSpinner'; import ProgressSpinner from '../ui/ProgressSpinner';
import DeleteMessageModal from '../common/DeleteMessageModal';
import './MediaViewerActions.scss'; import './MediaViewerActions.scss';
type StateProps = { type StateProps = {
isDownloading: boolean; isDownloading: boolean;
isProtected?: boolean; isProtected?: boolean;
canDelete?: boolean;
messageListType?: MessageListType;
}; };
type OwnProps = { type OwnProps = {
@ -53,8 +61,12 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
onCloseMediaViewer, onCloseMediaViewer,
zoomLevelChange, zoomLevelChange,
setZoomLevelChange, setZoomLevelChange,
canDelete,
onForward, onForward,
messageListType,
}) => { }) => {
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag(false);
const { const {
downloadMessageMedia, downloadMessageMedia,
cancelMessageMediaDownload, cancelMessageMediaDownload,
@ -135,7 +147,48 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
} }
if (IS_SINGLE_COLUMN_LAYOUT) { if (IS_SINGLE_COLUMN_LAYOUT) {
if (isProtected) { const menuItems: MenuItemProps[] = [];
if (!isAvatar && !isProtected) {
menuItems.push({
icon: 'forward',
onClick: onForward,
children: lang('Forward'),
});
}
if (!isProtected) {
if (isVideo) {
menuItems.push({
icon: isDownloading ? 'cancel' : 'download',
onClick: handleDownloadClick,
children: isDownloading ? `${Math.round(downloadProgress * 100)}% Downloading...` : 'Download',
});
} else {
menuItems.push({
icon: 'download',
href: mediaData,
download: fileName,
children: lang('AccActionDownload'),
});
}
}
if (canReport) {
menuItems.push({
icon: 'report',
onClick: onReport,
children: lang('ReportPeer.Report'),
});
}
if (canDelete) {
menuItems.push({
icon: 'delete',
onClick: openDeleteModal,
children: lang('Delete'),
});
}
if (menuItems.length === 0) {
return undefined; return undefined;
} }
@ -145,40 +198,29 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
trigger={MenuButton} trigger={MenuButton}
positionX="right" positionX="right"
> >
{!isAvatar && ( {menuItems.map(({
icon, onClick, href, download, children,
}) => (
<MenuItem <MenuItem
icon="forward" key={icon}
onClick={onForward} icon={icon}
href={href}
download={download}
onClick={onClick}
> >
{lang('Forward')} {children}
</MenuItem> </MenuItem>
)} ))}
{isVideo ? (
<MenuItem
icon={isDownloading ? 'close' : 'download'}
onClick={handleDownloadClick}
>
{isDownloading ? `${Math.round(downloadProgress * 100)}% Downloading...` : 'Download'}
</MenuItem>
) : (
<MenuItem
icon="download"
href={mediaData}
download={fileName}
>
{lang('AccActionDownload')}
</MenuItem>
)}
{canReport && (
<MenuItem
icon="flag"
onClick={onReport}
>
{lang('ReportPeer.Report')}
</MenuItem>
)}
</DropdownMenu> </DropdownMenu>
{isDownloading && <ProgressSpinner progress={downloadProgress} size="s" noCross />} {isDownloading && <ProgressSpinner progress={downloadProgress} size="s" noCross />}
{message && canDelete && (
<DeleteMessageModal
isOpen={isDeleteModalOpen}
isSchedule={messageListType === 'scheduled'}
onClose={closeDeleteModal}
message={message}
/>
)}
</div> </div>
); );
} }
@ -226,6 +268,17 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
<i className="icon-flag" /> <i className="icon-flag" />
</Button> </Button>
)} )}
{canDelete && (
<Button
round
size="smaller"
color="translucent-white"
ariaLabel={lang('Delete')}
onClick={openDeleteModal}
>
<i className="icon-delete" />
</Button>
)}
<Button <Button
round round
size="smaller" size="smaller"
@ -235,18 +288,32 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
> >
<i className="icon-close" /> <i className="icon-close" />
</Button> </Button>
{message && canDelete && (
<DeleteMessageModal
isOpen={isDeleteModalOpen}
isSchedule={messageListType === 'scheduled'}
onClose={closeDeleteModal}
message={message}
/>
)}
</div> </div>
); );
}; };
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global, { message }): StateProps => { (global, { message }): StateProps => {
const currentMessageList = selectCurrentMessageList(global);
const { threadId } = selectCurrentMessageList(global) || {};
const isDownloading = message ? selectIsDownloading(global, message) : false; const isDownloading = message ? selectIsDownloading(global, message) : false;
const isProtected = selectIsMessageProtected(global, message); const isProtected = selectIsMessageProtected(global, message);
const { canDelete } = (threadId && message && selectAllowedMessageActions(global, message, threadId)) || {};
const messageListType = currentMessageList?.type;
return { return {
isDownloading, isDownloading,
isProtected, isProtected,
canDelete,
messageListType,
}; };
}, },
)(MediaViewerActions)); )(MediaViewerActions));

View File

@ -10,7 +10,7 @@ import './MenuItem.scss';
type OnClickHandler = (e: React.SyntheticEvent<HTMLDivElement | HTMLAnchorElement>) => void; type OnClickHandler = (e: React.SyntheticEvent<HTMLDivElement | HTMLAnchorElement>) => void;
type OwnProps = { export type MenuItemProps = {
icon?: string; icon?: string;
customIcon?: React.ReactNode; customIcon?: React.ReactNode;
className?: string; className?: string;
@ -25,7 +25,7 @@ type OwnProps = {
withWrap?: boolean; withWrap?: boolean;
}; };
const MenuItem: FC<OwnProps> = (props) => { const MenuItem: FC<MenuItemProps> = (props) => {
const { const {
icon, icon,
customIcon, customIcon,