Media Viewer: Support deleting messages (#2086)
This commit is contained in:
parent
dc9ee50c46
commit
df19a8489b
@ -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));
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user