Spoilers: Various fixes

This commit is contained in:
Alexander Zinchuk 2022-01-28 02:11:02 +01:00
parent bc18224114
commit a71a13414a
6 changed files with 59 additions and 54 deletions

View File

@ -305,7 +305,7 @@ function processEntity(
if (isSimple) {
const text = renderNestedMessagePart();
if (entity.type === ApiMessageEntityTypes.Spoiler) {
return <Spoiler isInactive>{text}</Spoiler>;
return <Spoiler>{text}</Spoiler>;
}
return text;
}

View File

@ -1,31 +1,34 @@
.Spoiler {
transition: color 250ms ease;
.text-entity-link {
transition: color 250ms ease;
}
&:not(.is-revealed) {
&.concealed {
cursor: pointer;
color: transparent;
background-image: url('../../../assets/spoiler-dots-black.png');
background-size: auto 100%;
background-size: auto min(100%, 1.125rem);
border-radius: 0.5rem;
&.animate {
animation: pulse-opacity-light 1.75s linear infinite;
html.theme-dark &,
html.theme-light .ListItem.selected &,
.ActionMessage &,
.MediaViewerFooter & {
background-image: url('../../../assets/spoiler-dots-white.png');
}
.text-entity-link {
color: transparent !important;
pointer-events: none;
.emoji-only & {
background-size: auto 1.125rem;
}
}
html.theme-dark &:not(.is-revealed),
html.theme-light .ListItem.selected &:not(.is-revealed),
html.theme-light .ActionMessage &:not(.is-revealed) {
background-image: url('../../../assets/spoiler-dots-white.png');
&.animated {
animation: pulse-opacity-light 1.75s linear infinite;
}
span {
opacity: 1;
transition: opacity 250ms ease;
}
&.concealed span {
visibility: hidden;
opacity: 0;
}
}

View File

@ -1,3 +1,4 @@
import { MouseEvent as ReactMouseEvent } from 'react';
import React, {
FC, memo, useCallback, useEffect,
} from '../../../lib/teact/teact';
@ -10,7 +11,6 @@ import './Spoiler.scss';
type OwnProps = {
children?: React.ReactNode;
messageId?: number;
isInactive?: boolean;
};
const spoilersByMessageId: Map<number, VoidFunction[]> = new Map();
@ -18,22 +18,17 @@ const spoilersByMessageId: Map<number, VoidFunction[]> = new Map();
const Spoiler: FC<OwnProps> = ({
children,
messageId,
isInactive,
}) => {
const [isRevealed, reveal] = useFlag();
const handleClick = useCallback(() => {
if (!messageId) return;
const handleClick = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
e.preventDefault();
e.stopPropagation();
spoilersByMessageId.get(messageId)?.forEach((_reveal) => _reveal());
spoilersByMessageId.get(messageId!)?.forEach((_reveal) => _reveal());
}, [messageId]);
useEffect(() => {
if (isRevealed && messageId) {
spoilersByMessageId.delete(messageId);
return undefined;
}
if (!messageId) {
return undefined;
}
@ -53,12 +48,14 @@ const Spoiler: FC<OwnProps> = ({
<span
className={buildClassName(
'Spoiler',
isRevealed && 'is-revealed',
!isInactive && 'animate',
!isRevealed && 'concealed',
!isRevealed && Boolean(messageId) && 'animated',
)}
onClick={!isInactive && !isRevealed ? handleClick : undefined}
onClick={messageId && !isRevealed ? handleClick : undefined}
>
{children}
<span>
{children}
</span>
</span>
);
};

View File

@ -430,7 +430,7 @@ const MediaViewer: FC<StateProps> = ({
return captureEvents(element, {
// eslint-disable-next-line max-len
excludedClosestSelector: `.backdrop, .navigation, .media-viewer-head, .media-viewer-footer${!shouldCloseOnVideo ? ', .VideoPlayer' : ''}`,
excludedClosestSelector: `.backdrop, .navigation, .media-viewer-head, .Spoiler, .media-viewer-footer${!shouldCloseOnVideo ? ', .VideoPlayer' : ''}`,
onClick: close,
});
}, [close, isGif, isZoomed, messageId]);

View File

@ -5,6 +5,7 @@ import {
getMessageMediaHash,
getMessagePhoto,
getMessageText,
getMessageTextWithSpoilers,
getMessageWebPagePhoto,
getMessageWebPageVideo,
hasMessageLocalBlobUrl,
@ -52,7 +53,7 @@ export function getMessageCopyOptions(
options.push({
label: getCopyLabel(hasSelection),
handler: () => {
const clipboardText = hasSelection && selection ? selection.toString() : text;
const clipboardText = hasSelection && selection ? selection.toString() : getMessageTextWithSpoilers(message)!;
copyTextToClipboard(clipboardText);
if (afterEffect) {

View File

@ -15,30 +15,34 @@ export function getMessageSummaryText(
) {
const emoji = !noEmoji && getMessageSummaryEmoji(message);
const emojiWithSpace = emoji ? `${emoji} ` : '';
let text = getMessageText(message);
if (text) {
const { entities } = message.content.text || {};
if (entities?.length) {
text = entities.reduce((accText, { type, offset, length }) => {
if (type !== ApiMessageEntityTypes.Spoiler) {
return accText;
}
const spoiler = generateBrailleSpoiler(length);
return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`;
}, text);
}
text = text.substr(0, truncateLength);
}
const text = getMessageTextWithSpoilers(message)?.substr(0, truncateLength);
const description = getMessageSummaryDescription(lang, message, text);
return `${emojiWithSpace}${description}`;
}
export function getMessageTextWithSpoilers(message: ApiMessage) {
const text = getMessageText(message);
if (!text) {
return undefined;
}
const { entities } = message.content.text || {};
if (!entities?.length) {
return text;
}
return entities.reduce((accText, { type, offset, length }) => {
if (type !== ApiMessageEntityTypes.Spoiler) {
return accText;
}
const spoiler = generateBrailleSpoiler(length);
return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`;
}, text);
}
export function getMessageSummaryEmoji(message: ApiMessage) {
const {
photo, video, audio, voice, document, sticker, poll,