[Refactoring] Custom Emoji Manager: Do not run during chat opening, fix fasterdom phasing
This commit is contained in:
parent
2f3671899c
commit
577d055d68
@ -62,7 +62,7 @@ export type OwnProps = {
|
||||
attachments: ApiAttachment[];
|
||||
getHtml: Signal<string>;
|
||||
canShowCustomSendMenu?: boolean;
|
||||
isReady?: boolean;
|
||||
isReady: boolean;
|
||||
shouldSchedule?: boolean;
|
||||
shouldSuggestCompression?: boolean;
|
||||
shouldForceCompression?: boolean;
|
||||
@ -595,6 +595,7 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
chatId={chatId}
|
||||
threadId={threadId}
|
||||
isAttachmentModalInput
|
||||
isReady={isReady}
|
||||
isActive={isOpen}
|
||||
getHtml={getHtml}
|
||||
editableInputId={EDITABLE_INPUT_MODAL_ID}
|
||||
|
||||
@ -1421,6 +1421,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
chatId={chatId}
|
||||
canSendPlainText={!isComposerBlocked}
|
||||
threadId={threadId}
|
||||
isReady={isReady}
|
||||
isActive={!hasAttachments}
|
||||
getHtml={getHtml}
|
||||
placeholder={
|
||||
|
||||
@ -47,6 +47,7 @@ type OwnProps = {
|
||||
threadId: number;
|
||||
isAttachmentModalInput?: boolean;
|
||||
editableInputId?: string;
|
||||
isReady: boolean;
|
||||
isActive: boolean;
|
||||
getHtml: Signal<string>;
|
||||
placeholder: string;
|
||||
@ -101,6 +102,7 @@ const MessageInput: FC<OwnProps & StateProps> = ({
|
||||
captionLimit,
|
||||
isAttachmentModalInput,
|
||||
editableInputId,
|
||||
isReady,
|
||||
isActive,
|
||||
getHtml,
|
||||
placeholder,
|
||||
@ -160,6 +162,7 @@ const MessageInput: FC<OwnProps & StateProps> = ({
|
||||
absoluteContainerRef,
|
||||
isAttachmentModalInput ? 'attachment' : 'composer',
|
||||
canPlayAnimatedEmojis,
|
||||
isReady,
|
||||
isActive,
|
||||
);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {
|
||||
useCallback, useEffect, useRef,
|
||||
useCallback, useEffect, useLayoutEffect, useRef,
|
||||
} from '../../../../lib/teact/teact';
|
||||
import { requestMeasure, requestMutation } from '../../../../lib/fasterdom/fasterdom';
|
||||
import { requestMeasure } from '../../../../lib/fasterdom/fasterdom';
|
||||
import { ensureRLottie } from '../../../../lib/rlottie/RLottie.async';
|
||||
|
||||
import type { ApiSticker } from '../../../../api/types';
|
||||
@ -12,7 +12,6 @@ import { selectIsAlwaysHighPriorityEmoji } from '../../../../global/selectors';
|
||||
import {
|
||||
addCustomEmojiInputRenderCallback,
|
||||
getCustomEmojiMediaDataForInput,
|
||||
removeCustomEmojiInputRenderCallback,
|
||||
} from '../../../../util/customEmojiManager';
|
||||
import { round } from '../../../../util/math';
|
||||
import AbsoluteVideo from '../../../../util/AbsoluteVideo';
|
||||
@ -25,6 +24,7 @@ import useBackgroundMode from '../../../../hooks/useBackgroundMode';
|
||||
import useThrottledCallback from '../../../../hooks/useThrottledCallback';
|
||||
import useDynamicColorListener from '../../../../hooks/stickers/useDynamicColorListener';
|
||||
import useEffectWithPrevDeps from '../../../../hooks/useEffectWithPrevDeps';
|
||||
import { useLastCallback } from '../../../../hooks/useLastCallback';
|
||||
|
||||
const SIZE = 1.25 * REM;
|
||||
const THROTTLE_MS = 300;
|
||||
@ -44,9 +44,10 @@ export default function useInputCustomEmojis(
|
||||
absoluteContainerRef: React.RefObject<HTMLElement>,
|
||||
prefixId: string,
|
||||
canPlayAnimatedEmojis: boolean,
|
||||
isReady?: boolean,
|
||||
isActive?: boolean,
|
||||
) {
|
||||
const customColor = useDynamicColorListener(inputRef);
|
||||
const customColor = useDynamicColorListener(inputRef, !isReady);
|
||||
const colorFilter = useColorFilter(customColor, true);
|
||||
const playersById = useRef<Map<string, CustomEmojiPlayer>>(new Map());
|
||||
|
||||
@ -60,12 +61,8 @@ export default function useInputCustomEmojis(
|
||||
});
|
||||
}, []);
|
||||
|
||||
const synchronizeElements = useCallback(() => {
|
||||
if (!inputRef.current || !sharedCanvasRef.current || !sharedCanvasHqRef.current) return;
|
||||
|
||||
requestMutation(() => {
|
||||
document.documentElement.style.setProperty('--input-custom-emoji-filter', colorFilter || 'none');
|
||||
});
|
||||
const synchronizeElements = useLastCallback(() => {
|
||||
if (!isReady || !inputRef.current || !sharedCanvasRef.current || !sharedCanvasHqRef.current) return;
|
||||
|
||||
const global = getGlobal();
|
||||
const playerIdsToClear = new Set(playersById.current.keys());
|
||||
@ -85,65 +82,56 @@ export default function useInputCustomEmojis(
|
||||
return;
|
||||
}
|
||||
|
||||
requestMeasure(() => {
|
||||
const canvasBounds = sharedCanvasRef.current!.getBoundingClientRect();
|
||||
const elementBounds = element.getBoundingClientRect();
|
||||
const x = round((elementBounds.left - canvasBounds.left) / canvasBounds.width, 4);
|
||||
const y = round((elementBounds.top - canvasBounds.top) / canvasBounds.height, 4);
|
||||
const canvasBounds = sharedCanvasRef.current!.getBoundingClientRect();
|
||||
const elementBounds = element.getBoundingClientRect();
|
||||
const x = round((elementBounds.left - canvasBounds.left) / canvasBounds.width, 4);
|
||||
const y = round((elementBounds.top - canvasBounds.top) / canvasBounds.height, 4);
|
||||
|
||||
if (playersById.current.has(playerId)) {
|
||||
const player = playersById.current.get(playerId)!;
|
||||
player.updatePosition(x, y);
|
||||
return;
|
||||
if (playersById.current.has(playerId)) {
|
||||
const player = playersById.current.get(playerId)!;
|
||||
player.updatePosition(x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
const customEmoji = global.customEmojis.byId[documentId];
|
||||
if (!customEmoji) {
|
||||
return;
|
||||
}
|
||||
const isHq = customEmoji?.stickerSetInfo && selectIsAlwaysHighPriorityEmoji(global, customEmoji.stickerSetInfo);
|
||||
const renderId = [
|
||||
prefixId, documentId, customColor,
|
||||
].filter(Boolean).join('_');
|
||||
|
||||
createPlayer({
|
||||
customEmoji,
|
||||
sharedCanvasRef,
|
||||
sharedCanvasHqRef,
|
||||
absoluteContainerRef,
|
||||
renderId,
|
||||
viewId: playerId,
|
||||
mediaUrl,
|
||||
isHq,
|
||||
position: { x, y },
|
||||
textColor: customColor,
|
||||
colorFilter,
|
||||
}).then((animation) => {
|
||||
if (canPlayAnimatedEmojis) {
|
||||
animation.play();
|
||||
}
|
||||
|
||||
const customEmoji = global.customEmojis.byId[documentId];
|
||||
if (!customEmoji) {
|
||||
return;
|
||||
}
|
||||
const isHq = customEmoji?.stickerSetInfo && selectIsAlwaysHighPriorityEmoji(global, customEmoji.stickerSetInfo);
|
||||
const renderId = [
|
||||
prefixId, documentId, customColor,
|
||||
].filter(Boolean).join('_');
|
||||
|
||||
createPlayer({
|
||||
customEmoji,
|
||||
sharedCanvasRef,
|
||||
sharedCanvasHqRef,
|
||||
absoluteContainerRef,
|
||||
renderId,
|
||||
viewId: playerId,
|
||||
mediaUrl,
|
||||
isHq,
|
||||
position: { x, y },
|
||||
textColor: customColor,
|
||||
colorFilter,
|
||||
}).then((animation) => {
|
||||
if (canPlayAnimatedEmojis) {
|
||||
animation.play();
|
||||
}
|
||||
|
||||
playersById.current.set(playerId, animation);
|
||||
});
|
||||
playersById.current.set(playerId, animation);
|
||||
});
|
||||
});
|
||||
|
||||
clearPlayers(Array.from(playerIdsToClear));
|
||||
}, [
|
||||
inputRef, sharedCanvasRef, sharedCanvasHqRef, clearPlayers, prefixId, customColor, absoluteContainerRef,
|
||||
canPlayAnimatedEmojis, colorFilter,
|
||||
]);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
addCustomEmojiInputRenderCallback(synchronizeElements);
|
||||
|
||||
return () => {
|
||||
removeCustomEmojiInputRenderCallback(synchronizeElements);
|
||||
};
|
||||
return addCustomEmojiInputRenderCallback(synchronizeElements);
|
||||
}, [synchronizeElements]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!getHtml() || !inputRef.current || !sharedCanvasRef.current || !isActive) {
|
||||
if (!getHtml() || !inputRef.current || !sharedCanvasRef.current || !isActive || !isReady) {
|
||||
clearPlayers(Array.from(playersById.current.keys()));
|
||||
return;
|
||||
}
|
||||
@ -152,10 +140,14 @@ export default function useInputCustomEmojis(
|
||||
requestMeasure(() => {
|
||||
synchronizeElements();
|
||||
});
|
||||
}, [getHtml, synchronizeElements, inputRef, clearPlayers, sharedCanvasRef, isActive]);
|
||||
}, [getHtml, synchronizeElements, inputRef, clearPlayers, sharedCanvasRef, isActive, isReady]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
document.documentElement.style.setProperty('--input-custom-emoji-filter', colorFilter || 'none');
|
||||
}, [colorFilter]);
|
||||
|
||||
useEffectWithPrevDeps(([prevCustomColor]) => {
|
||||
if (customColor !== prevCustomColor) {
|
||||
if (prevCustomColor !== undefined && customColor !== prevCustomColor) {
|
||||
synchronizeElements();
|
||||
}
|
||||
}, [customColor, synchronizeElements]);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
export function createCallbackManager() {
|
||||
const callbacks = new Set<AnyToVoidFunction>();
|
||||
export function createCallbackManager<T extends AnyToVoidFunction = AnyToVoidFunction>() {
|
||||
const callbacks = new Set<T>();
|
||||
|
||||
function addCallback(cb: AnyToVoidFunction) {
|
||||
function addCallback(cb: T) {
|
||||
callbacks.add(cb);
|
||||
|
||||
return () => {
|
||||
@ -9,11 +9,11 @@ export function createCallbackManager() {
|
||||
};
|
||||
}
|
||||
|
||||
function removeCallback(cb: AnyToVoidFunction) {
|
||||
function removeCallback(cb: T) {
|
||||
callbacks.delete(cb);
|
||||
}
|
||||
|
||||
function runCallbacks(...args: any[]) {
|
||||
function runCallbacks(...args: Parameters<T>) {
|
||||
callbacks.forEach((callback) => {
|
||||
callback(...args);
|
||||
});
|
||||
@ -31,4 +31,5 @@ export function createCallbackManager() {
|
||||
};
|
||||
}
|
||||
|
||||
export type CallbackManager = ReturnType<typeof createCallbackManager>;
|
||||
export type CallbackManager<T extends AnyToVoidFunction = AnyToVoidFunction>
|
||||
= ReturnType<typeof createCallbackManager<T>>;
|
||||
|
||||
@ -12,6 +12,7 @@ import * as mediaLoader from './mediaLoader';
|
||||
import { throttle } from './schedulers';
|
||||
import generateIdFor from './generateIdFor';
|
||||
import { IS_WEBM_SUPPORTED } from './windowEnvironment';
|
||||
import { createCallbackManager } from './callbacks';
|
||||
|
||||
import placeholderSrc from '../assets/square.svg';
|
||||
import blankSrc from '../assets/blank.png';
|
||||
@ -25,7 +26,7 @@ const DOM_PROCESS_THROTTLE = 500;
|
||||
const INPUT_WAITING_CUSTOM_EMOJI_IDS: Set<string> = new Set();
|
||||
|
||||
const handlers = new Map<CustomEmojiLoadCallback, string>();
|
||||
const renderHandlers = new Set<CustomEmojiInputRenderCallback>();
|
||||
const renderCallbacks = createCallbackManager<CustomEmojiInputRenderCallback>();
|
||||
|
||||
let prevGlobal: GlobalState | undefined;
|
||||
|
||||
@ -55,17 +56,8 @@ export function removeCustomEmojiCallback(handler: CustomEmojiLoadCallback) {
|
||||
handlers.delete(handler);
|
||||
}
|
||||
|
||||
export function addCustomEmojiInputRenderCallback(handler: AnyToVoidFunction) {
|
||||
renderHandlers.add(handler);
|
||||
}
|
||||
|
||||
export function removeCustomEmojiInputRenderCallback(handler: AnyToVoidFunction) {
|
||||
renderHandlers.delete(handler);
|
||||
}
|
||||
|
||||
const callInputRenderHandlers = throttle((emojiId: string) => {
|
||||
renderHandlers.forEach((handler) => handler(emojiId));
|
||||
}, DOM_PROCESS_THROTTLE);
|
||||
export const addCustomEmojiInputRenderCallback = renderCallbacks.addCallback;
|
||||
const callInputRenderHandlers = throttle(renderCallbacks.runCallbacks, DOM_PROCESS_THROTTLE);
|
||||
|
||||
function processDomForCustomEmoji() {
|
||||
const emojis = document.querySelectorAll<HTMLImageElement>('.custom-emoji.placeholder');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user