Invoice Media: Better animation; Message Select Toolbar: Hide unavailable actions (#2121)

This commit is contained in:
Alexander Zinchuk 2022-11-10 18:28:07 +04:00
parent d10df1a705
commit ecd4155fff
8 changed files with 51 additions and 35 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -7,20 +7,21 @@ import type { MessageListType } from '../../global/types';
import { import {
selectCanDeleteSelectedMessages, selectCanDeleteSelectedMessages,
selectCanDownloadSelectedMessages, selectCanDownloadSelectedMessages,
selectCanForwardMessages,
selectCanReportSelectedMessages, selectCanReportSelectedMessages,
selectCurrentMessageList, selectCurrentMessageList,
selectHasProtectedMessage, selectHasProtectedMessage,
selectSelectedMessagesCount, selectSelectedMessagesCount,
} from '../../global/selectors'; } from '../../global/selectors';
import useFlag from '../../hooks/useFlag';
import captureKeyboardListeners from '../../util/captureKeyboardListeners'; import captureKeyboardListeners from '../../util/captureKeyboardListeners';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import useFlag from '../../hooks/useFlag';
import usePrevious from '../../hooks/usePrevious'; import usePrevious from '../../hooks/usePrevious';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import useCopySelectedMessages from './hooks/useCopySelectedMessages'; import useCopySelectedMessages from './hooks/useCopySelectedMessages';
import Button from '../ui/Button'; import Button from '../ui/Button';
import DeleteSelectedMessageModal from './DeleteSelectedMessageModal'; import DeleteSelectedMessageModal from './DeleteSelectedMessageModal';
import ReportModal from '../common/ReportModal'; import ReportModal from '../common/ReportModal';
@ -38,6 +39,7 @@ type StateProps = {
canDeleteMessages?: boolean; canDeleteMessages?: boolean;
canReportMessages?: boolean; canReportMessages?: boolean;
canDownloadMessages?: boolean; canDownloadMessages?: boolean;
canForwardMessages?: boolean;
hasProtectedMessage?: boolean; hasProtectedMessage?: boolean;
isAnyModalOpen?: boolean; isAnyModalOpen?: boolean;
selectedMessageIds?: number[]; selectedMessageIds?: number[];
@ -52,6 +54,7 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
canDeleteMessages, canDeleteMessages,
canReportMessages, canReportMessages,
canDownloadMessages, canDownloadMessages,
canForwardMessages,
hasProtectedMessage, hasProtectedMessage,
isAnyModalOpen, isAnyModalOpen,
selectedMessageIds, selectedMessageIds,
@ -107,7 +110,7 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
); );
const renderButton = ( const renderButton = (
icon: string, label: string, onClick: AnyToVoidFunction, disabled?: boolean, destructive?: boolean, icon: string, label: string, onClick: AnyToVoidFunction, destructive?: boolean,
) => { ) => {
return ( return (
<div <div
@ -115,10 +118,9 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
tabIndex={0} tabIndex={0}
className={buildClassName( className={buildClassName(
'item', 'item',
disabled && 'disabled',
destructive && 'destructive', destructive && 'destructive',
)} )}
onClick={!disabled ? onClick : undefined} onClick={onClick}
title={label} title={label}
> >
<i className={`icon-${icon}`} /> <i className={`icon-${icon}`} />
@ -143,19 +145,23 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
{Boolean(selectedMessagesCount) && ( {Boolean(selectedMessagesCount) && (
<div className="MessageSelectToolbar-actions"> <div className="MessageSelectToolbar-actions">
{messageListType !== 'scheduled' && ( {messageListType !== 'scheduled' && canForwardMessages && (
renderButton( renderButton(
'forward', lang('Chat.ForwardActionHeader'), openForwardMenuForSelectedMessages, hasProtectedMessage, 'forward', lang('Chat.ForwardActionHeader'), openForwardMenuForSelectedMessages,
) )
)} )}
{canReportMessages && ( {canReportMessages && (
renderButton('flag', lang('Conversation.ReportMessages'), openReportModal) renderButton('flag', lang('Conversation.ReportMessages'), openReportModal)
)} )}
{canDownloadMessages && ( {canDownloadMessages && !hasProtectedMessage && (
renderButton('download', lang('lng_media_download'), handleDownload, hasProtectedMessage) renderButton('download', lang('lng_media_download'), handleDownload)
)}
{!hasProtectedMessage && (
renderButton('copy', lang('lng_context_copy_selected_items'), handleCopy)
)}
{canDeleteMessages && (
renderButton('delete', lang('EditAdminGroupDeleteMessages'), openDeleteModal, true)
)} )}
{renderButton('copy', lang('lng_context_copy_selected_items'), handleCopy, hasProtectedMessage)}
{renderButton('delete', lang('EditAdminGroupDeleteMessages'), openDeleteModal, !canDeleteMessages, true)}
</div> </div>
)} )}
</div> </div>
@ -182,6 +188,7 @@ export default memo(withGlobal<OwnProps>(
const canDownload = selectCanDownloadSelectedMessages(global); const canDownload = selectCanDownloadSelectedMessages(global);
const { messageIds: selectedMessageIds } = global.selectedMessages || {}; const { messageIds: selectedMessageIds } = global.selectedMessages || {};
const hasProtectedMessage = chatId ? selectHasProtectedMessage(global, chatId, selectedMessageIds) : false; const hasProtectedMessage = chatId ? selectHasProtectedMessage(global, chatId, selectedMessageIds) : false;
const canForward = chatId ? selectCanForwardMessages(global, chatId, selectedMessageIds) : false;
const isForwardModalOpen = global.forwardMessages.isModalShown; const isForwardModalOpen = global.forwardMessages.isModalShown;
const isAnyModalOpen = Boolean(isForwardModalOpen || global.requestedDraft const isAnyModalOpen = Boolean(isForwardModalOpen || global.requestedDraft
|| global.requestedAttachBotInChat || global.requestedAttachBotInstall); || global.requestedAttachBotInChat || global.requestedAttachBotInstall);
@ -192,6 +199,7 @@ export default memo(withGlobal<OwnProps>(
canDeleteMessages: canDelete, canDeleteMessages: canDelete,
canReportMessages: canReport, canReportMessages: canReport,
canDownloadMessages: canDownload, canDownloadMessages: canDownload,
canForwardMessages: canForward,
selectedMessageIds, selectedMessageIds,
hasProtectedMessage, hasProtectedMessage,
isAnyModalOpen, isAnyModalOpen,

View File

@ -13,20 +13,23 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
--background-url: url('../../../assets/turbulence.png'); --background-url: url('../../../assets/turbulence_1x.png');
--background-size: 256px; --background-size: 256px;
background: rgba(0, 0, 0, 0.3) var(--background-url); background: rgba(0, 0, 0, 0.25) var(--background-url);
background-size: var(--background-size) var(--background-size); background-size: var(--background-size) var(--background-size);
z-index: 1; z-index: 1;
@media (-webkit-min-device-pixel-ratio: 2) {
--background-url: url('../../../assets/turbulence_2x.png');
}
@media (-webkit-min-device-pixel-ratio: 3) {
--background-url: url('../../../assets/turbulence_3x.png');
}
--x-direction: var(--background-size); --x-direction: var(--background-size);
--y-direction: 0; --y-direction: 0;
animation: 10s linear infinite dots; animation: 20s linear infinite dots;
&.highres {
--background-url: url('../../../assets/turbulence_2x.png');
--background-size: 128px;
}
&::before { &::before {
content: ''; content: '';
@ -40,7 +43,7 @@
--x-direction: 0; --x-direction: 0;
--y-direction: var(--background-size); --y-direction: var(--background-size);
animation: 10s linear -4s infinite dots; animation: 20s linear -7s infinite dots;
} }
&::after { &::after {
@ -55,7 +58,7 @@
--x-direction: calc(-1 * var(--background-size)); --x-direction: calc(-1 * var(--background-size));
--y-direction: calc(-1 * var(--background-size)); --y-direction: calc(-1 * var(--background-size));
animation: 10s linear -8s infinite dots; animation: 20s linear -14s infinite dots;
} }
} }
@ -85,16 +88,13 @@
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
padding: 0.375rem 0.625rem; padding: 0.5rem 0.875rem;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.75);
color: #FFFFFF; color: #FFFFFF;
border-radius: 1rem; border-radius: 1rem;
white-space: nowrap; white-space: nowrap;
} line-height: 1rem;
.lock {
margin-bottom: 1px;
} }
.canvas { .canvas {
@ -105,13 +105,8 @@
@keyframes dots { @keyframes dots {
0% { 0% {
background-position: 0 0; background-position: 0 0;
opacity: 1;
}
50% {
opacity: 0.75;
} }
100% { 100% {
background-position: var(--x-direction) var(--y-direction); background-position: var(--x-direction) var(--y-direction);
opacity: 1;
} }
} }

View File

@ -8,7 +8,6 @@ import { getMessageInvoice } from '../../../global/helpers';
import { formatCurrency } from '../../../util/formatCurrency'; import { formatCurrency } from '../../../util/formatCurrency';
import { formatMediaDuration } from '../../../util/dateFormat'; import { formatMediaDuration } from '../../../util/dateFormat';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { DPR } from '../../../util/environment';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import useCanvasBlur from '../../../hooks/useCanvasBlur'; import useCanvasBlur from '../../../hooks/useCanvasBlur';
@ -66,7 +65,7 @@ const InvoiceMediaPreview: FC<OwnProps> = ({
onClick={handleClick} onClick={handleClick}
> >
<canvas ref={canvasRef} className={styles.canvas} width={width} height={height} /> <canvas ref={canvasRef} className={styles.canvas} width={width} height={height} />
<div className={buildClassName(styles.dots, DPR > 1 && styles.highres)} /> <div className={styles.dots} />
{Boolean(duration) && <div className={styles.duration}>{formatMediaDuration(duration)}</div>} {Boolean(duration) && <div className={styles.duration}>{formatMediaDuration(duration)}</div>}
<div className={styles.buy}> <div className={styles.buy}>
<i className={buildClassName('icon-lock', styles.lock)} /> <i className={buildClassName('icon-lock', styles.lock)} />

View File

@ -399,7 +399,7 @@ export function selectAllowedMessageActions(global: GlobalState, message: ApiMes
|| getServerTime(global.serverTimeOffset) - message.date < MESSAGE_EDIT_ALLOWED_TIME || getServerTime(global.serverTimeOffset) - message.date < MESSAGE_EDIT_ALLOWED_TIME
) && !( ) && !(
content.sticker || content.contact || content.poll || content.action || content.audio content.sticker || content.contact || content.poll || content.action || content.audio
|| (content.video?.isRound) || content.location || (content.video?.isRound) || content.location || content.invoice
) )
&& !isForwardedMessage(message) && !isForwardedMessage(message)
&& !message.viaBotId && !message.viaBotId
@ -922,6 +922,20 @@ export function selectHasProtectedMessage(global: GlobalState, chatId: string, m
return messageIds.some((messageId) => messages[messageId]?.isProtected); return messageIds.some((messageId) => messages[messageId]?.isProtected);
} }
export function selectCanForwardMessages(global: GlobalState, chatId: string, messageIds?: number[]) {
if (selectChat(global, chatId)?.isProtected) {
return false;
}
if (!messageIds) {
return false;
}
const messages = selectChatMessages(global, chatId);
return messageIds.every((messageId) => messages[messageId]?.isForwardingAllowed);
}
export function selectSponsoredMessage(global: GlobalState, chatId: string) { export function selectSponsoredMessage(global: GlobalState, chatId: string) {
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
const message = chat && isChatChannel(chat) ? global.messages.sponsoredByChatId[chatId] : undefined; const message = chat && isChatChannel(chat) ? global.messages.sponsoredByChatId[chatId] : undefined;