More improvements for shared canvas emoji
This commit is contained in:
parent
a2a0161cc9
commit
7cc64ed6bb
@ -7,7 +7,6 @@ import type { FC, TeactNode } from '../../lib/teact/teact';
|
||||
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
||||
import { ApiMessageEntityTypes } from '../../api/types';
|
||||
|
||||
import { REM } from './helpers/mediaDimensions';
|
||||
import { getPropertyHexColor } from '../../util/themeStyle';
|
||||
import { hexToRgb } from '../../util/switchTheme';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
@ -79,8 +78,6 @@ const CustomEmoji: FC<OwnProps> = ({
|
||||
const [customColor, setCustomColor] = useState<[number, number, number] | undefined>();
|
||||
const hasCustomColor = customEmoji && selectIsDefaultEmojiStatusPack(getGlobal(), customEmoji.stickerSetInfo);
|
||||
|
||||
const [realSize, setRealSize] = useState<number>(size);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasCustomColor) {
|
||||
setCustomColor(undefined);
|
||||
@ -95,13 +92,6 @@ const CustomEmoji: FC<OwnProps> = ({
|
||||
setCustomColor([customColorRgb.r, customColorRgb.g, customColorRgb.b]);
|
||||
}, [hasCustomColor]);
|
||||
|
||||
useEffect(() => {
|
||||
const computedSize = getComputedStyle(containerRef.current!).getPropertyValue('--custom-emoji-size');
|
||||
if (computedSize) {
|
||||
setRealSize(Math.round(Number(computedSize.replace(/[^\d.]/g, '')) * REM));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleVideoEnded = useCallback((e) => {
|
||||
if (!loopLimit) return;
|
||||
|
||||
@ -154,7 +144,7 @@ const CustomEmoji: FC<OwnProps> = ({
|
||||
containerRef={containerRef}
|
||||
sticker={customEmoji}
|
||||
isSmall
|
||||
size={realSize}
|
||||
size={size}
|
||||
customColor={customColor}
|
||||
thumbClassName={styles.thumb}
|
||||
fullMediaClassName={styles.media}
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
bottom: 0.625rem;
|
||||
}
|
||||
|
||||
img:not(.emoji) {
|
||||
.pictogram {
|
||||
margin-inline-start: 0.5rem;
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
img:not(.emoji) {
|
||||
.pictogram {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
object-fit: cover;
|
||||
@ -144,7 +144,7 @@
|
||||
bottom: 0.3125rem;
|
||||
}
|
||||
|
||||
img:not(.emoji) {
|
||||
.pictogram {
|
||||
margin-left: 0.125rem;
|
||||
}
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ function renderPictogram(
|
||||
width={width}
|
||||
height={height}
|
||||
alt=""
|
||||
className={isRoundVideo ? 'round' : ''}
|
||||
className={buildClassName('pictogram', isRoundVideo && 'round')}
|
||||
draggable={!isProtected}
|
||||
/>
|
||||
{isProtected && <span className="protector" />}
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
--custom-emoji-size: 1.25rem;
|
||||
|
||||
> h3 {
|
||||
margin-bottom: 0;
|
||||
|
||||
@ -17,7 +17,7 @@ import { useIsIntersecting } from '../../hooks/useIntersectionObserver';
|
||||
import useThumbnail from '../../hooks/useThumbnail';
|
||||
import useMediaTransition from '../../hooks/useMediaTransition';
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useSharedCanvasCoords from '../../hooks/useSharedCanvasCoords';
|
||||
import useBoundsInSharedCanvas from '../../hooks/useBoundsInSharedCanvas';
|
||||
|
||||
import AnimatedSticker from './AnimatedSticker';
|
||||
import OptimizedVideo from '../ui/OptimizedVideo';
|
||||
@ -114,14 +114,15 @@ const StickerView: FC<OwnProps> = ({
|
||||
const fullMediaClassNames = useMediaTransition(isFullMediaReady);
|
||||
const noTransition = isLottie && preloadedPreviewData;
|
||||
|
||||
const sharedCanvasCoords = useSharedCanvasCoords(containerRef, sharedCanvasRef);
|
||||
const bounds = useBoundsInSharedCanvas(containerRef, sharedCanvasRef);
|
||||
const realSize = bounds.size || size;
|
||||
|
||||
// Preload preview for Message Input and local message
|
||||
useMedia(previewMediaHash, !shouldLoad || !shouldPreloadPreview, undefined, cacheBuster);
|
||||
|
||||
const randomIdPrefix = useMemo(() => generateIdFor(ID_STORE, true), []);
|
||||
const idKey = [
|
||||
(withSharedAnimation ? SHARED_PREFIX : randomIdPrefix), id, size, customColor?.join(','),
|
||||
(withSharedAnimation ? SHARED_PREFIX : randomIdPrefix), id, realSize, customColor?.join(','),
|
||||
].filter(Boolean).join('_');
|
||||
|
||||
return (
|
||||
@ -141,7 +142,7 @@ const StickerView: FC<OwnProps> = ({
|
||||
<AnimatedSticker
|
||||
key={idKey}
|
||||
animationId={idKey}
|
||||
size={size}
|
||||
size={realSize}
|
||||
className={buildClassName(
|
||||
styles.media,
|
||||
(noTransition || isThumbOpaque) && styles.noTransition,
|
||||
@ -155,7 +156,7 @@ const StickerView: FC<OwnProps> = ({
|
||||
forceOnHeavyAnimation={forceOnHeavyAnimation}
|
||||
isLowPriority={isSmall && !selectIsAlwaysHighPriorityEmoji(getGlobal(), stickerSetInfo)}
|
||||
sharedCanvas={sharedCanvasRef?.current || undefined}
|
||||
sharedCanvasCoords={sharedCanvasCoords}
|
||||
sharedCanvasCoords={bounds.coords}
|
||||
onLoad={markPlayerReady}
|
||||
onLoop={onAnimatedStickerLoop}
|
||||
onEnded={onAnimatedStickerLoop}
|
||||
|
||||
@ -175,10 +175,6 @@
|
||||
vertical-align: -0.125rem;
|
||||
}
|
||||
|
||||
.custom-emoji {
|
||||
--custom-emoji-size: 1.25rem;
|
||||
}
|
||||
|
||||
.icon-play {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
@ -263,7 +263,7 @@ const Chat: FC<OwnProps & StateProps> = ({
|
||||
const isChat = chat && (isChatChannel(chat) || lastMessage.senderId === lastMessage.chatId);
|
||||
|
||||
return (
|
||||
<p className="last-message" dir={lang.isRtl ? 'auto' : 'ltr'}>
|
||||
<p className="last-message shared-canvas-container" dir={lang.isRtl ? 'auto' : 'ltr'}>
|
||||
{renderActionMessageText(
|
||||
lang,
|
||||
lastMessage,
|
||||
@ -281,7 +281,7 @@ const Chat: FC<OwnProps & StateProps> = ({
|
||||
const senderName = getMessageSenderName(lang, chatId, lastMessageSender);
|
||||
|
||||
return (
|
||||
<p className="last-message" dir={lang.isRtl ? 'auto' : 'ltr'}>
|
||||
<p className="last-message shared-canvas-container" dir={lang.isRtl ? 'auto' : 'ltr'}>
|
||||
{senderName && (
|
||||
<>
|
||||
<span className="sender-name">{renderText(senderName)}</span>
|
||||
|
||||
@ -73,10 +73,6 @@
|
||||
vertical-align: -2px;
|
||||
}
|
||||
|
||||
.custom-emoji {
|
||||
--custom-emoji-size: 1.25rem;
|
||||
}
|
||||
|
||||
&.multiline {
|
||||
&::before {
|
||||
content: "";
|
||||
|
||||
@ -519,10 +519,6 @@
|
||||
body.is-ios & {
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
|
||||
.custom-emoji {
|
||||
--custom-emoji-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -572,7 +572,6 @@
|
||||
}
|
||||
|
||||
.custom-emoji {
|
||||
--custom-emoji-size: 1.25rem;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import buildClassName from '../../../util/buildClassName';
|
||||
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||
import useMedia from '../../../hooks/useMedia';
|
||||
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||
import useSharedCanvasCoords from '../../../hooks/useSharedCanvasCoords';
|
||||
import useBoundsInSharedCanvas from '../../../hooks/useBoundsInSharedCanvas';
|
||||
|
||||
import AnimatedSticker from '../../common/AnimatedSticker';
|
||||
import OptimizedVideo from '../../ui/OptimizedVideo';
|
||||
@ -46,7 +46,7 @@ const StickerSetCover: FC<OwnProps> = ({
|
||||
const isReady = mediaData && (!isVideo || IS_WEBM_SUPPORTED);
|
||||
const transitionClassNames = useMediaTransition(isReady);
|
||||
|
||||
const sharedCanvasCoords = useSharedCanvasCoords(containerRef, sharedCanvasRef);
|
||||
const bounds = useBoundsInSharedCanvas(containerRef, sharedCanvasRef);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="sticker-set-cover">
|
||||
@ -55,11 +55,11 @@ const StickerSetCover: FC<OwnProps> = ({
|
||||
<AnimatedSticker
|
||||
className={transitionClassNames}
|
||||
tgsUrl={mediaData}
|
||||
size={size}
|
||||
size={size || bounds.size}
|
||||
play={isIntersecting && !noAnimate}
|
||||
isLowPriority={!selectIsAlwaysHighPriorityEmoji(getGlobal(), stickerSet)}
|
||||
sharedCanvas={sharedCanvasRef?.current || undefined}
|
||||
sharedCanvasCoords={sharedCanvasCoords}
|
||||
sharedCanvasCoords={bounds.coords}
|
||||
/>
|
||||
) : isVideo ? (
|
||||
<OptimizedVideo
|
||||
|
||||
@ -95,6 +95,7 @@ import useOuterHandlers from './hooks/useOuterHandlers';
|
||||
import useInnerHandlers from './hooks/useInnerHandlers';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { isElementInViewport } from '../../../util/isElementInViewport';
|
||||
import { getCustomEmojiSize } from '../composer/helpers/customEmoji';
|
||||
|
||||
import Button from '../../ui/Button';
|
||||
import Avatar from '../../common/Avatar';
|
||||
@ -126,10 +127,9 @@ import DotAnimation from '../../common/DotAnimation';
|
||||
import CustomEmoji from '../../common/CustomEmoji';
|
||||
import PremiumIcon from '../../common/PremiumIcon';
|
||||
import FakeIcon from '../../common/FakeIcon';
|
||||
import MessageText from '../../common/MessageText';
|
||||
|
||||
import './Message.scss';
|
||||
import MessageText from '../../common/MessageText';
|
||||
import { getCustomEmojiSize } from '../composer/helpers/customEmoji';
|
||||
|
||||
type MessagePositionProperties = {
|
||||
isFirstInGroup: boolean;
|
||||
|
||||
@ -272,7 +272,6 @@
|
||||
}
|
||||
|
||||
.custom-emoji {
|
||||
--custom-emoji-size: 1.25rem;
|
||||
margin-left: 0.25rem;
|
||||
|
||||
&.custom-color {
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import {
|
||||
useCallback, useEffect, useMemo, useState,
|
||||
useCallback, useEffect, useLayoutEffect, useMemo, useState,
|
||||
} from '../lib/teact/teact';
|
||||
|
||||
import { throttle } from '../util/schedulers';
|
||||
import { round } from '../util/math';
|
||||
|
||||
export default function useSharedCanvasCoords(
|
||||
export default function useBoundsInSharedCanvas(
|
||||
containerRef: React.RefObject<HTMLDivElement>,
|
||||
sharedCanvasRef?: React.RefObject<HTMLCanvasElement>,
|
||||
) {
|
||||
const [x, setX] = useState<number>();
|
||||
const [y, setY] = useState<number>();
|
||||
const [size, setSize] = useState<number>();
|
||||
|
||||
const recalculate = useCallback(() => {
|
||||
const container = containerRef.current;
|
||||
@ -25,8 +27,11 @@ export default function useSharedCanvasCoords(
|
||||
// Factor coords are used to support rendering while being rescaled (e.g. message appearance animation)
|
||||
setX(round((targetBounds.left - canvasBounds.left) / canvasBounds.width, 4));
|
||||
setY(round((targetBounds.top - canvasBounds.top) / canvasBounds.height, 4));
|
||||
setSize(Math.round(targetBounds.width));
|
||||
}, [containerRef, sharedCanvasRef]);
|
||||
|
||||
useLayoutEffect(recalculate, [recalculate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!('ResizeObserver' in window) || !sharedCanvasRef?.current) {
|
||||
return undefined;
|
||||
@ -48,5 +53,7 @@ export default function useSharedCanvasCoords(
|
||||
};
|
||||
}, [recalculate, sharedCanvasRef]);
|
||||
|
||||
return useMemo(() => (x !== undefined && y !== undefined ? { x, y } : undefined), [x, y]);
|
||||
const coords = useMemo(() => (x !== undefined && y !== undefined ? { x, y } : undefined), [x, y]);
|
||||
|
||||
return { coords, size };
|
||||
}
|
||||
@ -28,6 +28,7 @@ const rLottieApiPromise = new Promise<void>((resolve) => {
|
||||
|
||||
const HIGH_PRIORITY_MAX_FPS = 60;
|
||||
const LOW_PRIORITY_MAX_FPS = 30;
|
||||
const DESTROY_REPEAT_DELAY = 1000;
|
||||
|
||||
const renderers = new Map<string, {
|
||||
imgSize: number;
|
||||
@ -150,12 +151,17 @@ function applyColor(arr: Uint8ClampedArray, color: [number, number, number]) {
|
||||
}
|
||||
}
|
||||
|
||||
function destroy(key: string) {
|
||||
const renderer = renderers.get(key)!;
|
||||
|
||||
rLottieApi.destroy(renderer.handle);
|
||||
|
||||
renderers.delete(key);
|
||||
function destroy(key: string, isRepeated = false) {
|
||||
try {
|
||||
const renderer = renderers.get(key)!;
|
||||
rLottieApi.destroy(renderer.handle);
|
||||
renderers.delete(key);
|
||||
} catch (err) {
|
||||
// `destroy` sometimes can be called before the initialization is finished
|
||||
if (!isRepeated) {
|
||||
setTimeout(() => destroy(key, true), DESTROY_REPEAT_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createWorkerInterface({
|
||||
|
||||
@ -184,7 +184,7 @@ $color-message-reaction-own-hover: #b5e0a4;
|
||||
--messages-container-width: 45.5rem;
|
||||
--right-column-width: 26.5rem;
|
||||
--header-height: 3.5rem;
|
||||
--custom-emoji-size: 1.5rem;
|
||||
--custom-emoji-size: 1.25rem;
|
||||
|
||||
--symbol-menu-width: 26.25rem;
|
||||
--symbol-menu-height: 23.25rem;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user