Introduce WebM stickers; GramJs: Update layer to 138 (#1681)

This commit is contained in:
Alexander Zinchuk 2022-02-02 22:49:44 +01:00
parent 19cb5101da
commit 9456aafc8c
27 changed files with 242 additions and 86 deletions

View File

@ -50,7 +50,7 @@ export function buildApiThumbnailFromCached(photoSize: GramJs.PhotoCachedSize):
export function buildApiThumbnailFromPath( export function buildApiThumbnailFromPath(
photoSize: GramJs.PhotoPathSize, photoSize: GramJs.PhotoPathSize,
sizeAttribute: GramJs.DocumentAttributeImageSize, sizeAttribute: GramJs.DocumentAttributeImageSize | GramJs.DocumentAttributeVideo,
): ApiThumbnail | undefined { ): ApiThumbnail | undefined {
const { w, h } = sizeAttribute; const { w, h } = sizeAttribute;
const dataUri = `data:image/svg+xml;utf8,${pathBytesToSvg(photoSize.bytes, w, h)}`; const dataUri = `data:image/svg+xml;utf8,${pathBytesToSvg(photoSize.bytes, w, h)}`;

View File

@ -155,7 +155,7 @@ export function buildApiMessageWithChatId(chatId: string, mtpMessage: UniversalM
const forwardInfo = mtpMessage.fwdFrom && buildApiMessageForwardInfo(mtpMessage.fwdFrom, isChatWithSelf); const forwardInfo = mtpMessage.fwdFrom && buildApiMessageForwardInfo(mtpMessage.fwdFrom, isChatWithSelf);
const { replies, mediaUnread: isMediaUnread, postAuthor } = mtpMessage; const { replies, mediaUnread: isMediaUnread, postAuthor } = mtpMessage;
const groupedId = mtpMessage.groupedId && String(mtpMessage.groupedId); const groupedId = mtpMessage.groupedId && String(mtpMessage.groupedId);
const isInAlbum = Boolean(groupedId) && !(content.document || content.audio); const isInAlbum = Boolean(groupedId) && !(content.document || content.audio || content.sticker);
const shouldHideKeyboardButtons = mtpMessage.replyMarkup instanceof GramJs.ReplyKeyboardHide; const shouldHideKeyboardButtons = mtpMessage.replyMarkup instanceof GramJs.ReplyKeyboardHide;
return { return {
@ -192,13 +192,13 @@ export function buildApiMessageWithChatId(chatId: string, mtpMessage: UniversalM
export function buildMessageReactions(reactions: GramJs.MessageReactions): ApiReactions { export function buildMessageReactions(reactions: GramJs.MessageReactions): ApiReactions {
const { const {
recentReactons, results, canSeeList, recentReactions, results, canSeeList,
} = reactions; } = reactions;
return { return {
canSeeList, canSeeList,
results: results.map(buildReactionCount), results: results.map(buildReactionCount),
recentReactions: recentReactons?.map(buildMessageUserReaction), recentReactions: recentReactions?.map(buildMessagePeerReaction),
}; };
} }
@ -212,11 +212,11 @@ function buildReactionCount(reactionCount: GramJs.ReactionCount): ApiReactionCou
}; };
} }
export function buildMessageUserReaction(userReaction: GramJs.MessageUserReaction): ApiUserReaction { export function buildMessagePeerReaction(userReaction: GramJs.MessagePeerReaction): ApiUserReaction {
const { userId, reaction } = userReaction; const { peerId, reaction } = userReaction;
return { return {
userId: buildApiPeerId(userId, 'user'), userId: getApiChatIdFromMtpPeer(peerId),
reaction, reaction,
}; };
} }

View File

@ -2,12 +2,13 @@ import { Api as GramJs } from '../../../lib/gramjs';
import { import {
ApiEmojiInteraction, ApiSticker, ApiStickerSet, GramJsEmojiInteraction, ApiEmojiInteraction, ApiSticker, ApiStickerSet, GramJsEmojiInteraction,
} from '../../types'; } from '../../types';
import { MEMOJI_STICKER_ID } from '../../../config'; import { NO_STICKER_SET_ID } from '../../../config';
import { buildApiThumbnailFromCached, buildApiThumbnailFromPath } from './common'; import { buildApiThumbnailFromCached, buildApiThumbnailFromPath } from './common';
import localDb from '../localDb'; import localDb from '../localDb';
const ANIMATED_STICKER_MIME_TYPE = 'application/x-tgsticker'; const LOTTIE_STICKER_MIME_TYPE = 'application/x-tgsticker';
const GIF_STICKER_MIME_TYPE = 'video/webm';
export function buildStickerFromDocument(document: GramJs.TypeDocument): ApiSticker | undefined { export function buildStickerFromDocument(document: GramJs.TypeDocument): ApiSticker | undefined {
if (document instanceof GramJs.DocumentEmpty) { if (document instanceof GramJs.DocumentEmpty) {
@ -19,31 +20,55 @@ export function buildStickerFromDocument(document: GramJs.TypeDocument): ApiStic
attr instanceof GramJs.DocumentAttributeSticker attr instanceof GramJs.DocumentAttributeSticker
)); ));
const fileAttribute = document.mimeType === ANIMATED_STICKER_MIME_TYPE && document.attributes const fileAttribute = (document.mimeType === LOTTIE_STICKER_MIME_TYPE || document.mimeType === GIF_STICKER_MIME_TYPE)
.find((attr: any): attr is GramJs.DocumentAttributeFilename => ( && document.attributes
attr instanceof GramJs.DocumentAttributeFilename .find((attr: any): attr is GramJs.DocumentAttributeFilename => (
)); attr instanceof GramJs.DocumentAttributeFilename
));
if (!stickerAttribute && !fileAttribute) { if (!stickerAttribute && !fileAttribute) {
return undefined; return undefined;
} }
const sizeAttribute = document.attributes const isLottie = document.mimeType === LOTTIE_STICKER_MIME_TYPE;
const isGif = document.mimeType === GIF_STICKER_MIME_TYPE;
const imageSizeAttribute = document.attributes
.find((attr: any): attr is GramJs.DocumentAttributeImageSize => ( .find((attr: any): attr is GramJs.DocumentAttributeImageSize => (
attr instanceof GramJs.DocumentAttributeImageSize attr instanceof GramJs.DocumentAttributeImageSize
)); ));
const videoSizeAttribute = document.attributes
.find((attr: any): attr is GramJs.DocumentAttributeVideo => (
attr instanceof GramJs.DocumentAttributeVideo
));
const sizeAttribute = imageSizeAttribute || videoSizeAttribute;
const stickerSetInfo = stickerAttribute && stickerAttribute.stickerset instanceof GramJs.InputStickerSetID const stickerSetInfo = stickerAttribute && stickerAttribute.stickerset instanceof GramJs.InputStickerSetID
? stickerAttribute.stickerset ? stickerAttribute.stickerset
: undefined; : undefined;
const emoji = stickerAttribute?.alt; const emoji = stickerAttribute?.alt;
const isAnimated = document.mimeType === ANIMATED_STICKER_MIME_TYPE;
const cachedThumb = document.thumbs && document.thumbs.find( const cachedThumb = document.thumbs && document.thumbs.find(
(s): s is GramJs.PhotoCachedSize => s instanceof GramJs.PhotoCachedSize, (s): s is GramJs.PhotoCachedSize => s instanceof GramJs.PhotoCachedSize,
); );
// eslint-disable-next-line no-restricted-globals
if (document.mimeType === GIF_STICKER_MIME_TYPE && !(self as any).isWebmSupported && !cachedThumb) {
const staticThumb = document.thumbs && document.thumbs.find(
(s): s is GramJs.PhotoSize => s instanceof GramJs.PhotoSize,
);
if (!staticThumb) {
return undefined;
}
}
const pathThumb = document.thumbs && document.thumbs.find( const pathThumb = document.thumbs && document.thumbs.find(
(s): s is GramJs.PhotoPathSize => s instanceof GramJs.PhotoPathSize, (s): s is GramJs.PhotoPathSize => s instanceof GramJs.PhotoPathSize,
); );
const thumbnail = cachedThumb ? ( const thumbnail = cachedThumb ? (
buildApiThumbnailFromCached(cachedThumb) buildApiThumbnailFromCached(cachedThumb)
) : pathThumb && sizeAttribute ? ( ) : pathThumb && sizeAttribute ? (
@ -54,10 +79,11 @@ export function buildStickerFromDocument(document: GramJs.TypeDocument): ApiStic
return { return {
id: String(document.id), id: String(document.id),
stickerSetId: stickerSetInfo ? String(stickerSetInfo.id) : MEMOJI_STICKER_ID, stickerSetId: stickerSetInfo ? String(stickerSetInfo.id) : NO_STICKER_SET_ID,
stickerSetAccessHash: stickerSetInfo && String(stickerSetInfo.accessHash), stickerSetAccessHash: stickerSetInfo && String(stickerSetInfo.accessHash),
emoji, emoji,
isAnimated, isLottie,
isGif,
width, width,
height, height,
thumbnail, thumbnail,
@ -69,6 +95,7 @@ export function buildStickerSet(set: GramJs.StickerSet): ApiStickerSet {
archived, archived,
animated, animated,
installedDate, installedDate,
gifs,
id, id,
accessHash, accessHash,
title, title,
@ -79,7 +106,8 @@ export function buildStickerSet(set: GramJs.StickerSet): ApiStickerSet {
return { return {
archived, archived,
isAnimated: animated, isLottie: animated,
isGifs: gifs,
installedDate, installedDate,
id: String(id), id: String(id),
accessHash: String(accessHash), accessHash: String(accessHash),

View File

@ -47,12 +47,14 @@ export async function init(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs)
onUpdate = _onUpdate; onUpdate = _onUpdate;
const { const {
userAgent, platform, sessionData, isTest, isMovSupported, userAgent, platform, sessionData, isTest, isMovSupported, isWebmSupported,
} = initialArgs; } = initialArgs;
const session = new sessions.CallbackSession(sessionData, onSessionUpdate); const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
// eslint-disable-next-line no-restricted-globals // eslint-disable-next-line no-restricted-globals
(self as any).isMovSupported = isMovSupported; (self as any).isMovSupported = isMovSupported;
// eslint-disable-next-line no-restricted-globals
(self as any).isWebmSupported = isWebmSupported;
client = new TelegramClient( client = new TelegramClient(
session, session,

View File

@ -3,7 +3,7 @@ import { invokeRequest } from './client';
import { Api as GramJs } from '../../../lib/gramjs'; import { Api as GramJs } from '../../../lib/gramjs';
import { buildInputPeer } from '../gramjsBuilders'; import { buildInputPeer } from '../gramjsBuilders';
import localDb from '../localDb'; import localDb from '../localDb';
import { buildApiAvailableReaction, buildMessageUserReaction } from '../apiBuilders/messages'; import { buildApiAvailableReaction, buildMessagePeerReaction } from '../apiBuilders/messages';
import { REACTION_LIST_LIMIT } from '../../../config'; import { REACTION_LIST_LIMIT } from '../../../config';
import { addEntitiesWithPhotosToLocalDb } from '../helpers'; import { addEntitiesWithPhotosToLocalDb } from '../helpers';
import { buildApiUser } from '../apiBuilders/users'; import { buildApiUser } from '../apiBuilders/users';
@ -120,7 +120,7 @@ export async function fetchMessageReactionsList({
return { return {
users: result.users.map(buildApiUser).filter<ApiUser>(Boolean as any), users: result.users.map(buildApiUser).filter<ApiUser>(Boolean as any),
nextOffset, nextOffset,
reactions: reactions.map(buildMessageUserReaction), reactions: reactions.map(buildMessagePeerReaction),
count, count,
}; };
} }

View File

@ -25,7 +25,8 @@ export interface ApiSticker {
stickerSetId: string; stickerSetId: string;
stickerSetAccessHash?: string; stickerSetAccessHash?: string;
emoji?: string; emoji?: string;
isAnimated: boolean; isLottie: boolean;
isGif: boolean;
width?: number; width?: number;
height?: number; height?: number;
thumbnail?: ApiThumbnail; thumbnail?: ApiThumbnail;
@ -34,7 +35,8 @@ export interface ApiSticker {
export interface ApiStickerSet { export interface ApiStickerSet {
archived?: true; archived?: true;
isAnimated?: true; isLottie?: true;
isGifs?: true;
installedDate?: number; installedDate?: number;
id: string; id: string;
accessHash: string; accessHash: string;

View File

@ -6,6 +6,7 @@ export interface ApiInitialArgs {
sessionData?: ApiSessionData; sessionData?: ApiSessionData;
isTest?: boolean; isTest?: boolean;
isMovSupported?: boolean; isMovSupported?: boolean;
isWebmSupported?: boolean;
} }
export interface ApiOnProgress { export interface ApiOnProgress {

View File

@ -38,7 +38,7 @@
margin: 0; margin: 0;
} }
.AnimatedSticker, img { .AnimatedSticker, img, video {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@ -46,7 +46,7 @@
height: 100%; height: 100%;
} }
img { img, video {
object-fit: contain; object-fit: contain;
} }

View File

@ -11,6 +11,8 @@ import useShowTransition from '../../hooks/useShowTransition';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur'; import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
import safePlay from '../../util/safePlay';
import { IS_WEBM_SUPPORTED } from '../../util/environment';
import AnimatedSticker from './AnimatedSticker'; import AnimatedSticker from './AnimatedSticker';
import Button from '../ui/Button'; import Button from '../ui/Button';
@ -44,12 +46,15 @@ const StickerButton: FC<OwnProps> = ({
const previewBlobUrl = useMedia(`${localMediaHash}?size=m`, !isIntersecting, ApiMediaFormat.BlobUrl); const previewBlobUrl = useMedia(`${localMediaHash}?size=m`, !isIntersecting, ApiMediaFormat.BlobUrl);
const shouldPlay = isIntersecting && !noAnimate; const shouldPlay = isIntersecting && !noAnimate;
const lottieData = useMedia(sticker.isAnimated && localMediaHash, !shouldPlay, ApiMediaFormat.Lottie); const lottieData = useMedia(sticker.isLottie && localMediaHash, !shouldPlay, ApiMediaFormat.Lottie);
const [isAnimationLoaded, markLoaded, unmarkLoaded] = useFlag(Boolean(lottieData)); const [isLottieLoaded, markLoaded, unmarkLoaded] = useFlag(Boolean(lottieData));
const canAnimatedPlay = isAnimationLoaded && shouldPlay; const canLottiePlay = isLottieLoaded && shouldPlay;
const isGif = sticker.isGif && IS_WEBM_SUPPORTED;
const gifBlobUrl = useMedia(isGif && localMediaHash, !shouldPlay, ApiMediaFormat.BlobUrl);
const canGifPlay = Boolean(isGif && gifBlobUrl && shouldPlay);
const { transitionClassNames: previewTransitionClassNames } = useShowTransition( const { transitionClassNames: previewTransitionClassNames } = useShowTransition(
Boolean(previewBlobUrl || canAnimatedPlay), Boolean(previewBlobUrl || canLottiePlay),
undefined, undefined,
undefined, undefined,
'slow', 'slow',
@ -62,6 +67,17 @@ const StickerButton: FC<OwnProps> = ({
} }
}, [unmarkLoaded, shouldPlay]); }, [unmarkLoaded, shouldPlay]);
useEffect(() => {
if (!isGif || !ref.current) return;
const video = ref.current.querySelector('video');
if (!video) return;
if (canGifPlay) {
safePlay(video);
} else {
video.pause();
}
}, [isGif, canGifPlay]);
function handleClick() { function handleClick() {
if (onClick) { if (onClick) {
onClick(clickArg); onClick(clickArg);
@ -78,12 +94,11 @@ const StickerButton: FC<OwnProps> = ({
const fullClassName = buildClassName( const fullClassName = buildClassName(
'StickerButton', 'StickerButton',
onClick && 'interactive', onClick && 'interactive',
sticker.isAnimated && 'animated',
stickerSelector, stickerSelector,
className, className,
); );
const style = thumbDataUri && !canAnimatedPlay ? `background-image: url('${thumbDataUri}');` : ''; const style = (thumbDataUri && !canLottiePlay && !canGifPlay) ? `background-image: url('${thumbDataUri}');` : '';
return ( return (
<div <div
@ -96,10 +111,20 @@ const StickerButton: FC<OwnProps> = ({
onMouseDown={preventMessageInputBlurWithBubbling} onMouseDown={preventMessageInputBlurWithBubbling}
onClick={handleClick} onClick={handleClick}
> >
{!canAnimatedPlay && ( {!canLottiePlay && !canGifPlay && (
// eslint-disable-next-line jsx-a11y/alt-text // eslint-disable-next-line jsx-a11y/alt-text
<img src={previewBlobUrl} className={previewTransitionClassNames} /> <img src={previewBlobUrl} className={previewTransitionClassNames} />
)} )}
{isGif && (
<video
className={previewTransitionClassNames}
src={gifBlobUrl}
autoPlay={canGifPlay}
loop
playsInline
muted
/>
)}
{shouldPlay && lottieData && ( {shouldPlay && lottieData && (
<AnimatedSticker <AnimatedSticker
id={localMediaHash} id={localMediaHash}

View File

@ -47,7 +47,7 @@ const SettingsStickerSet: FC<OwnProps> = ({
color="translucent" color="translucent"
isRtl={lang.isRtl} isRtl={lang.isRtl}
> >
{stickerSet.isAnimated ? ( {stickerSet.isLottie ? (
<StickerSetCoverAnimated <StickerSetCoverAnimated
size={STICKER_SIZE_GENERAL_SETTINGS} size={STICKER_SIZE_GENERAL_SETTINGS}
stickerSet={stickerSet} stickerSet={stickerSet}

View File

@ -45,11 +45,13 @@
.sticker-set-button { .sticker-set-button {
display: inline-flex; display: inline-flex;
vertical-align: middle; vertical-align: middle;
align-items: center;
justify-content: center;
&.StickerButton { &.StickerButton {
background-size: 2rem; background-size: 2rem;
img, .AnimatedSticker { video, img, .AnimatedSticker {
top: 0.375rem; top: 0.375rem;
left: 0.375rem; left: 0.375rem;
width: 2rem; width: 2rem;
@ -65,7 +67,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
img, .AnimatedSticker { video, img, .AnimatedSticker {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;

View File

@ -201,7 +201,7 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
<i className="icon-recent" /> <i className="icon-recent" />
) : stickerSet.id === 'favorite' ? ( ) : stickerSet.id === 'favorite' ? (
<i className="icon-favorite" /> <i className="icon-favorite" />
) : stickerSet.isAnimated ? ( ) : stickerSet.isLottie ? (
<StickerSetCoverAnimated <StickerSetCoverAnimated
stickerSet={stickerSet as ApiStickerSet} stickerSet={stickerSet as ApiStickerSet}
observeIntersection={observeIntersectionForCovers} observeIntersection={observeIntersectionForCovers}

View File

@ -4,6 +4,7 @@ import React, {
import { ApiStickerSet } from '../../../api/types'; import { ApiStickerSet } from '../../../api/types';
import { IS_WEBM_SUPPORTED } from '../../../util/environment';
import { getFirstLetters } from '../../../util/textFormat'; import { getFirstLetters } from '../../../util/textFormat';
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver'; import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import useMedia from '../../../hooks/useMedia'; import useMedia from '../../../hooks/useMedia';
@ -22,17 +23,20 @@ const StickerSetCover: FC<OwnProps> = ({ stickerSet, observeIntersection }) => {
const mediaData = useMedia(stickerSet.hasThumbnail && `stickerSet${stickerSet.id}`, !isIntersecting); const mediaData = useMedia(stickerSet.hasThumbnail && `stickerSet${stickerSet.id}`, !isIntersecting);
const transitionClassNames = useMediaTransition(mediaData); const transitionClassNames = useMediaTransition(mediaData);
const isGif = stickerSet.isGifs;
const firstLetters = useMemo(() => { const firstLetters = useMemo(() => {
if (mediaData) return undefined; if ((isGif && !IS_WEBM_SUPPORTED) || !mediaData) return getFirstLetters(stickerSet.title, 2);
}, [isGif, mediaData, stickerSet.title]);
return getFirstLetters(stickerSet.title, 2);
}, [mediaData, stickerSet.title]);
return ( return (
<div ref={ref} className="sticker-set-cover"> <div ref={ref} className="sticker-set-cover">
{firstLetters} {firstLetters}
<img src={mediaData} className={transitionClassNames} alt="" /> {isGif ? (
<video src={mediaData} className={transitionClassNames} loop autoPlay />
) : (
<img src={mediaData} className={transitionClassNames} alt="" />
)}
</div> </div>
); );
}; };

View File

@ -1,8 +1,8 @@
import React, { FC, useRef } from '../../../lib/teact/teact'; import React, { FC, useEffect, useRef } from '../../../lib/teact/teact';
import { ApiMessage } from '../../../api/types'; import { ApiMessage } from '../../../api/types';
import { MEMOJI_STICKER_ID } from '../../../config'; import { NO_STICKER_SET_ID } from '../../../config';
import { getStickerDimensions } from '../../common/helpers/mediaDimensions'; import { getStickerDimensions } from '../../common/helpers/mediaDimensions';
import { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers'; import { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
@ -11,6 +11,8 @@ import useMedia from '../../../hooks/useMedia';
import useMediaTransition from '../../../hooks/useMediaTransition'; import useMediaTransition from '../../../hooks/useMediaTransition';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
import useWebpThumbnail from '../../../hooks/useWebpThumbnail'; import useWebpThumbnail from '../../../hooks/useWebpThumbnail';
import safePlay from '../../../util/safePlay';
import { IS_WEBM_SUPPORTED } from '../../../util/environment';
import AnimatedSticker from '../../common/AnimatedSticker'; import AnimatedSticker from '../../common/AnimatedSticker';
import StickerSetModal from '../../common/StickerSetModal.async'; import StickerSetModal from '../../common/StickerSetModal.async';
@ -34,14 +36,20 @@ const Sticker: FC<OwnProps> = ({
const [isModalOpen, openModal, closeModal] = useFlag(); const [isModalOpen, openModal, closeModal] = useFlag();
const sticker = message.content.sticker!; const sticker = message.content.sticker!;
const { isAnimated, stickerSetId } = sticker; const { isLottie, stickerSetId, isGif } = sticker;
const isMemojiSticker = stickerSetId === MEMOJI_STICKER_ID; const canDisplayGif = IS_WEBM_SUPPORTED;
const isMemojiSticker = stickerSetId === NO_STICKER_SET_ID;
const shouldLoad = useIsIntersecting(ref, observeIntersection); const shouldLoad = useIsIntersecting(ref, observeIntersection);
const shouldPlay = useIsIntersecting(ref, observeIntersectionForPlaying); const shouldPlay = useIsIntersecting(ref, observeIntersectionForPlaying);
const mediaHash = sticker.isPreloadedGlobally ? `sticker${sticker.id}` : getMessageMediaHash(message, 'inline')!; const mediaHash = sticker.isPreloadedGlobally ? `sticker${sticker.id}` : getMessageMediaHash(message, 'inline')!;
const previewMediaHash = isGif && !canDisplayGif && (
sticker.isPreloadedGlobally ? `sticker${sticker.id}?size=m` : getMessageMediaHash(message, 'pictogram'));
const previewBlobUrl = useMedia(previewMediaHash);
const thumbDataUri = useWebpThumbnail(message); const thumbDataUri = useWebpThumbnail(message);
const previewUrl = previewBlobUrl || thumbDataUri;
const mediaData = useMedia( const mediaData = useMedia(
mediaHash, mediaHash,
!shouldLoad, !shouldLoad,
@ -50,8 +58,8 @@ const Sticker: FC<OwnProps> = ({
); );
const isMediaLoaded = Boolean(mediaData); const isMediaLoaded = Boolean(mediaData);
const [isAnimationLoaded, markAnimationLoaded] = useFlag(isMediaLoaded); const [isLottieLoaded, markLottieLoaded] = useFlag(isMediaLoaded);
const isMediaReady = isAnimated ? isAnimationLoaded : isMediaLoaded; const isMediaReady = isLottie ? isLottieLoaded : isMediaLoaded;
const transitionClassNames = useMediaTransition(isMediaReady); const transitionClassNames = useMediaTransition(isMediaReady);
const { width, height } = getStickerDimensions(sticker); const { width, height } = getStickerDimensions(sticker);
@ -62,19 +70,30 @@ const Sticker: FC<OwnProps> = ({
isMemojiSticker && 'inactive', isMemojiSticker && 'inactive',
); );
useEffect(() => {
if (!isGif || !ref.current) return;
const video = ref.current.querySelector('video');
if (!video) return;
if (shouldPlay) {
safePlay(video);
} else {
video.pause();
}
}, [isGif, shouldPlay]);
return ( return (
<div ref={ref} className={stickerClassName} onClick={!isMemojiSticker ? openModal : undefined}> <div ref={ref} className={stickerClassName} onClick={!isMemojiSticker ? openModal : undefined}>
{!isMediaReady && ( {(!isMediaReady || (isGif && !canDisplayGif)) && (
<img <img
id={`sticker-thumb-${message.id}`} id={`sticker-thumb-${message.id}`}
src={thumbDataUri} src={previewUrl}
width={width} width={width}
height={height} height={height}
alt="" alt=""
className={thumbClassName} className={thumbClassName}
/> />
)} )}
{!isAnimated && ( {!isLottie && !isGif && (
<img <img
id={`sticker-${message.id}`} id={`sticker-${message.id}`}
src={mediaData as string} src={mediaData as string}
@ -84,7 +103,19 @@ const Sticker: FC<OwnProps> = ({
className={buildClassName('full-media', transitionClassNames)} className={buildClassName('full-media', transitionClassNames)}
/> />
)} )}
{isAnimated && isMediaLoaded && ( {isGif && canDisplayGif && isMediaReady && (
<video
id={`sticker-${message.id}`}
src={mediaData as string}
width={width}
height={height}
autoPlay={shouldPlay}
playsInline
loop={shouldLoop}
muted
/>
)}
{isLottie && isMediaLoaded && (
<AnimatedSticker <AnimatedSticker
key={mediaHash} key={mediaHash}
className={buildClassName('full-media', transitionClassNames)} className={buildClassName('full-media', transitionClassNames)}
@ -93,7 +124,7 @@ const Sticker: FC<OwnProps> = ({
size={width} size={width}
play={shouldPlay} play={shouldPlay}
noLoop={!shouldLoop} noLoop={!shouldLoop}
onLoad={markAnimationLoaded} onLoad={markLottieLoaded}
/> />
)} )}
<StickerSetModal <StickerSetModal

View File

@ -126,7 +126,7 @@ export const STICKER_SIZE_INLINE_BOT_RESULT = 100;
export const STICKER_SIZE_JOIN_REQUESTS = 140; export const STICKER_SIZE_JOIN_REQUESTS = 140;
export const STICKER_SIZE_INVITES = 140; export const STICKER_SIZE_INVITES = 140;
export const RECENT_STICKERS_LIMIT = 20; export const RECENT_STICKERS_LIMIT = 20;
export const MEMOJI_STICKER_ID = 'MEMOJI_STICKER'; export const NO_STICKER_SET_ID = 'NO_STICKER_SET';
export const BASE_EMOJI_KEYWORD_LANG = 'en'; export const BASE_EMOJI_KEYWORD_LANG = 'en';

View File

@ -1,6 +1,6 @@
const api = require('./api'); const api = require('./api');
const LAYER = 137; const LAYER = 138;
const tlobjects = {}; const tlobjects = {};
for (const tl of Object.values(api)) { for (const tl of Object.values(api)) {

View File

@ -267,8 +267,8 @@ namespace Api {
export type TypeSearchResultsPosition = SearchResultPosition; export type TypeSearchResultsPosition = SearchResultPosition;
export type TypeReactionCount = ReactionCount; export type TypeReactionCount = ReactionCount;
export type TypeMessageReactions = MessageReactions; export type TypeMessageReactions = MessageReactions;
export type TypeMessageUserReaction = MessageUserReaction;
export type TypeAvailableReaction = AvailableReaction; export type TypeAvailableReaction = AvailableReaction;
export type TypeMessagePeerReaction = MessagePeerReaction;
export type TypeResPQ = ResPQ; export type TypeResPQ = ResPQ;
export type TypeP_Q_inner_data = PQInnerData | PQInnerDataDc | PQInnerDataTemp | PQInnerDataTempDc; export type TypeP_Q_inner_data = PQInnerData | PQInnerDataDc | PQInnerDataTemp | PQInnerDataTempDc;
export type TypeServer_DH_Params = ServerDHParamsFail | ServerDHParamsOk; export type TypeServer_DH_Params = ServerDHParamsFail | ServerDHParamsOk;
@ -1655,6 +1655,7 @@ namespace Api {
readOutboxMaxId: int; readOutboxMaxId: int;
unreadCount: int; unreadCount: int;
unreadMentionsCount: int; unreadMentionsCount: int;
unreadReactionsCount: int;
notifySettings: Api.TypePeerNotifySettings; notifySettings: Api.TypePeerNotifySettings;
pts?: int; pts?: int;
draft?: Api.TypeDraftMessage; draft?: Api.TypeDraftMessage;
@ -1669,6 +1670,7 @@ namespace Api {
readOutboxMaxId: int; readOutboxMaxId: int;
unreadCount: int; unreadCount: int;
unreadMentionsCount: int; unreadMentionsCount: int;
unreadReactionsCount: int;
notifySettings: Api.TypePeerNotifySettings; notifySettings: Api.TypePeerNotifySettings;
pts?: int; pts?: int;
draft?: Api.TypeDraftMessage; draft?: Api.TypeDraftMessage;
@ -3650,6 +3652,7 @@ namespace Api {
official?: true; official?: true;
masks?: true; masks?: true;
animated?: true; animated?: true;
gifs?: true;
installedDate?: int; installedDate?: int;
id: long; id: long;
accessHash: long; accessHash: long;
@ -3666,6 +3669,7 @@ namespace Api {
official?: true; official?: true;
masks?: true; masks?: true;
animated?: true; animated?: true;
gifs?: true;
installedDate?: int; installedDate?: int;
id: long; id: long;
accessHash: long; accessHash: long;
@ -7003,20 +7007,13 @@ namespace Api {
min?: true; min?: true;
canSeeList?: true; canSeeList?: true;
results: Api.TypeReactionCount[]; results: Api.TypeReactionCount[];
recentReactons?: Api.TypeMessageUserReaction[]; recentReactions?: Api.TypeMessagePeerReaction[];
}> { }> {
// flags: undefined; // flags: undefined;
min?: true; min?: true;
canSeeList?: true; canSeeList?: true;
results: Api.TypeReactionCount[]; results: Api.TypeReactionCount[];
recentReactons?: Api.TypeMessageUserReaction[]; recentReactions?: Api.TypeMessagePeerReaction[];
};
export class MessageUserReaction extends VirtualClass<{
userId: long;
reaction: string;
}> {
userId: long;
reaction: string;
}; };
export class AvailableReaction extends VirtualClass<{ export class AvailableReaction extends VirtualClass<{
// flags: undefined; // flags: undefined;
@ -7043,6 +7040,19 @@ namespace Api {
aroundAnimation?: Api.TypeDocument; aroundAnimation?: Api.TypeDocument;
centerIcon?: Api.TypeDocument; centerIcon?: Api.TypeDocument;
}; };
export class MessagePeerReaction extends VirtualClass<{
// flags: undefined;
big?: true;
unread?: true;
peerId: Api.TypePeer;
reaction: string;
}> {
// flags: undefined;
big?: true;
unread?: true;
peerId: Api.TypePeer;
reaction: string;
};
export class ResPQ extends VirtualClass<{ export class ResPQ extends VirtualClass<{
nonce: int128; nonce: int128;
serverNonce: int128; serverNonce: int128;
@ -8075,13 +8085,15 @@ namespace Api {
export class MessageReactionsList extends VirtualClass<{ export class MessageReactionsList extends VirtualClass<{
// flags: undefined; // flags: undefined;
count: int; count: int;
reactions: Api.TypeMessageUserReaction[]; reactions: Api.TypeMessagePeerReaction[];
chats: Api.TypeChat[];
users: Api.TypeUser[]; users: Api.TypeUser[];
nextOffset?: string; nextOffset?: string;
}> { }> {
// flags: undefined; // flags: undefined;
count: int; count: int;
reactions: Api.TypeMessageUserReaction[]; reactions: Api.TypeMessagePeerReaction[];
chats: Api.TypeChat[];
users: Api.TypeUser[]; users: Api.TypeUser[];
nextOffset?: string; nextOffset?: string;
}; };
@ -11224,11 +11236,13 @@ namespace Api {
}; };
export class SendReaction extends Request<Partial<{ export class SendReaction extends Request<Partial<{
// flags: undefined; // flags: undefined;
big?: true;
peer: Api.TypeInputPeer; peer: Api.TypeInputPeer;
msgId: int; msgId: int;
reaction?: string; reaction?: string;
}>, Api.TypeUpdates> { }>, Api.TypeUpdates> {
// flags: undefined; // flags: undefined;
big?: true;
peer: Api.TypeInputPeer; peer: Api.TypeInputPeer;
msgId: int; msgId: int;
reaction?: string; reaction?: string;
@ -11287,6 +11301,26 @@ namespace Api {
fromLang?: string; fromLang?: string;
toLang: string; toLang: string;
}; };
export class GetUnreadReactions extends Request<Partial<{
peer: Api.TypeInputPeer;
offsetId: int;
addOffset: int;
limit: int;
maxId: int;
minId: int;
}>, messages.TypeMessages> {
peer: Api.TypeInputPeer;
offsetId: int;
addOffset: int;
limit: int;
maxId: int;
minId: int;
};
export class ReadReactions extends Request<Partial<{
peer: Api.TypeInputPeer;
}>, messages.TypeAffectedHistory> {
peer: Api.TypeInputPeer;
};
} }
export namespace updates { export namespace updates {
@ -12359,7 +12393,7 @@ namespace Api {
| account.RegisterDevice | account.UnregisterDevice | account.UpdateNotifySettings | account.GetNotifySettings | account.ResetNotifySettings | account.UpdateProfile | account.UpdateStatus | account.GetWallPapers | account.ReportPeer | account.CheckUsername | account.UpdateUsername | account.GetPrivacy | account.SetPrivacy | account.DeleteAccount | account.GetAccountTTL | account.SetAccountTTL | account.SendChangePhoneCode | account.ChangePhone | account.UpdateDeviceLocked | account.GetAuthorizations | account.ResetAuthorization | account.GetPassword | account.GetPasswordSettings | account.UpdatePasswordSettings | account.SendConfirmPhoneCode | account.ConfirmPhone | account.GetTmpPassword | account.GetWebAuthorizations | account.ResetWebAuthorization | account.ResetWebAuthorizations | account.GetAllSecureValues | account.GetSecureValue | account.SaveSecureValue | account.DeleteSecureValue | account.GetAuthorizationForm | account.AcceptAuthorization | account.SendVerifyPhoneCode | account.VerifyPhone | account.SendVerifyEmailCode | account.VerifyEmail | account.InitTakeoutSession | account.FinishTakeoutSession | account.ConfirmPasswordEmail | account.ResendPasswordEmail | account.CancelPasswordEmail | account.GetContactSignUpNotification | account.SetContactSignUpNotification | account.GetNotifyExceptions | account.GetWallPaper | account.UploadWallPaper | account.SaveWallPaper | account.InstallWallPaper | account.ResetWallPapers | account.GetAutoDownloadSettings | account.SaveAutoDownloadSettings | account.UploadTheme | account.CreateTheme | account.UpdateTheme | account.SaveTheme | account.InstallTheme | account.GetTheme | account.GetThemes | account.SetContentSettings | account.GetContentSettings | account.GetMultiWallPapers | account.GetGlobalPrivacySettings | account.SetGlobalPrivacySettings | account.ReportProfilePhoto | account.ResetPassword | account.DeclinePasswordReset | account.GetChatThemes | account.SetAuthorizationTTL | account.ChangeAuthorizationSettings | account.RegisterDevice | account.UnregisterDevice | account.UpdateNotifySettings | account.GetNotifySettings | account.ResetNotifySettings | account.UpdateProfile | account.UpdateStatus | account.GetWallPapers | account.ReportPeer | account.CheckUsername | account.UpdateUsername | account.GetPrivacy | account.SetPrivacy | account.DeleteAccount | account.GetAccountTTL | account.SetAccountTTL | account.SendChangePhoneCode | account.ChangePhone | account.UpdateDeviceLocked | account.GetAuthorizations | account.ResetAuthorization | account.GetPassword | account.GetPasswordSettings | account.UpdatePasswordSettings | account.SendConfirmPhoneCode | account.ConfirmPhone | account.GetTmpPassword | account.GetWebAuthorizations | account.ResetWebAuthorization | account.ResetWebAuthorizations | account.GetAllSecureValues | account.GetSecureValue | account.SaveSecureValue | account.DeleteSecureValue | account.GetAuthorizationForm | account.AcceptAuthorization | account.SendVerifyPhoneCode | account.VerifyPhone | account.SendVerifyEmailCode | account.VerifyEmail | account.InitTakeoutSession | account.FinishTakeoutSession | account.ConfirmPasswordEmail | account.ResendPasswordEmail | account.CancelPasswordEmail | account.GetContactSignUpNotification | account.SetContactSignUpNotification | account.GetNotifyExceptions | account.GetWallPaper | account.UploadWallPaper | account.SaveWallPaper | account.InstallWallPaper | account.ResetWallPapers | account.GetAutoDownloadSettings | account.SaveAutoDownloadSettings | account.UploadTheme | account.CreateTheme | account.UpdateTheme | account.SaveTheme | account.InstallTheme | account.GetTheme | account.GetThemes | account.SetContentSettings | account.GetContentSettings | account.GetMultiWallPapers | account.GetGlobalPrivacySettings | account.SetGlobalPrivacySettings | account.ReportProfilePhoto | account.ResetPassword | account.DeclinePasswordReset | account.GetChatThemes | account.SetAuthorizationTTL | account.ChangeAuthorizationSettings
| users.GetUsers | users.GetFullUser | users.SetSecureValueErrors | users.GetUsers | users.GetFullUser | users.SetSecureValueErrors
| contacts.GetContactIDs | contacts.GetStatuses | contacts.GetContacts | contacts.ImportContacts | contacts.DeleteContacts | contacts.DeleteByPhones | contacts.Block | contacts.Unblock | contacts.GetBlocked | contacts.Search | contacts.ResolveUsername | contacts.GetTopPeers | contacts.ResetTopPeerRating | contacts.ResetSaved | contacts.GetSaved | contacts.ToggleTopPeers | contacts.AddContact | contacts.AcceptContact | contacts.GetLocated | contacts.BlockFromReplies | contacts.GetContactIDs | contacts.GetStatuses | contacts.GetContacts | contacts.ImportContacts | contacts.DeleteContacts | contacts.DeleteByPhones | contacts.Block | contacts.Unblock | contacts.GetBlocked | contacts.Search | contacts.ResolveUsername | contacts.GetTopPeers | contacts.ResetTopPeerRating | contacts.ResetSaved | contacts.GetSaved | contacts.ToggleTopPeers | contacts.AddContact | contacts.AcceptContact | contacts.GetLocated | contacts.BlockFromReplies
| messages.GetMessages | messages.GetDialogs | messages.GetHistory | messages.Search | messages.ReadHistory | messages.DeleteHistory | messages.DeleteMessages | messages.ReceivedMessages | messages.SetTyping | messages.SendMessage | messages.SendMedia | messages.ForwardMessages | messages.ReportSpam | messages.GetPeerSettings | messages.Report | messages.GetChats | messages.GetFullChat | messages.EditChatTitle | messages.EditChatPhoto | messages.AddChatUser | messages.DeleteChatUser | messages.CreateChat | messages.GetDhConfig | messages.RequestEncryption | messages.AcceptEncryption | messages.DiscardEncryption | messages.SetEncryptedTyping | messages.ReadEncryptedHistory | messages.SendEncrypted | messages.SendEncryptedFile | messages.SendEncryptedService | messages.ReceivedQueue | messages.ReportEncryptedSpam | messages.ReadMessageContents | messages.GetStickers | messages.GetAllStickers | messages.GetWebPagePreview | messages.ExportChatInvite | messages.CheckChatInvite | messages.ImportChatInvite | messages.GetStickerSet | messages.InstallStickerSet | messages.UninstallStickerSet | messages.StartBot | messages.GetMessagesViews | messages.EditChatAdmin | messages.MigrateChat | messages.SearchGlobal | messages.ReorderStickerSets | messages.GetDocumentByHash | messages.GetSavedGifs | messages.SaveGif | messages.GetInlineBotResults | messages.SetInlineBotResults | messages.SendInlineBotResult | messages.GetMessageEditData | messages.EditMessage | messages.EditInlineBotMessage | messages.GetBotCallbackAnswer | messages.SetBotCallbackAnswer | messages.GetPeerDialogs | messages.SaveDraft | messages.GetAllDrafts | messages.GetFeaturedStickers | messages.ReadFeaturedStickers | messages.GetRecentStickers | messages.SaveRecentSticker | messages.ClearRecentStickers | messages.GetArchivedStickers | messages.GetMaskStickers | messages.GetAttachedStickers | messages.SetGameScore | messages.SetInlineGameScore | messages.GetGameHighScores | messages.GetInlineGameHighScores | messages.GetCommonChats | messages.GetAllChats | messages.GetWebPage | messages.ToggleDialogPin | messages.ReorderPinnedDialogs | messages.GetPinnedDialogs | messages.SetBotShippingResults | messages.SetBotPrecheckoutResults | messages.UploadMedia | messages.SendScreenshotNotification | messages.GetFavedStickers | messages.FaveSticker | messages.GetUnreadMentions | messages.ReadMentions | messages.GetRecentLocations | messages.SendMultiMedia | messages.UploadEncryptedFile | messages.SearchStickerSets | messages.GetSplitRanges | messages.MarkDialogUnread | messages.GetDialogUnreadMarks | messages.ClearAllDrafts | messages.UpdatePinnedMessage | messages.SendVote | messages.GetPollResults | messages.GetOnlines | messages.EditChatAbout | messages.EditChatDefaultBannedRights | messages.GetEmojiKeywords | messages.GetEmojiKeywordsDifference | messages.GetEmojiKeywordsLanguages | messages.GetEmojiURL | messages.GetSearchCounters | messages.RequestUrlAuth | messages.AcceptUrlAuth | messages.HidePeerSettingsBar | messages.GetScheduledHistory | messages.GetScheduledMessages | messages.SendScheduledMessages | messages.DeleteScheduledMessages | messages.GetPollVotes | messages.ToggleStickerSets | messages.GetDialogFilters | messages.GetSuggestedDialogFilters | messages.UpdateDialogFilter | messages.UpdateDialogFiltersOrder | messages.GetOldFeaturedStickers | messages.GetReplies | messages.GetDiscussionMessage | messages.ReadDiscussion | messages.UnpinAllMessages | messages.DeleteChat | messages.DeletePhoneCallHistory | messages.CheckHistoryImport | messages.InitHistoryImport | messages.UploadImportedMedia | messages.StartHistoryImport | messages.GetExportedChatInvites | messages.GetExportedChatInvite | messages.EditExportedChatInvite | messages.DeleteRevokedExportedChatInvites | messages.DeleteExportedChatInvite | messages.GetAdminsWithInvites | messages.GetChatInviteImporters | messages.SetHistoryTTL | messages.CheckHistoryImportPeer | messages.SetChatTheme | messages.GetMessageReadParticipants | messages.GetSearchResultsCalendar | messages.GetSearchResultsPositions | messages.HideChatJoinRequest | messages.HideAllChatJoinRequests | messages.ToggleNoForwards | messages.SaveDefaultSendAs | messages.SendReaction | messages.GetMessagesReactions | messages.GetMessageReactionsList | messages.SetChatAvailableReactions | messages.GetAvailableReactions | messages.SetDefaultReaction | messages.TranslateText | messages.GetMessages | messages.GetDialogs | messages.GetHistory | messages.Search | messages.ReadHistory | messages.DeleteHistory | messages.DeleteMessages | messages.ReceivedMessages | messages.SetTyping | messages.SendMessage | messages.SendMedia | messages.ForwardMessages | messages.ReportSpam | messages.GetPeerSettings | messages.Report | messages.GetChats | messages.GetFullChat | messages.EditChatTitle | messages.EditChatPhoto | messages.AddChatUser | messages.DeleteChatUser | messages.CreateChat | messages.GetDhConfig | messages.RequestEncryption | messages.AcceptEncryption | messages.DiscardEncryption | messages.SetEncryptedTyping | messages.ReadEncryptedHistory | messages.SendEncrypted | messages.SendEncryptedFile | messages.SendEncryptedService | messages.ReceivedQueue | messages.ReportEncryptedSpam | messages.ReadMessageContents | messages.GetStickers | messages.GetAllStickers | messages.GetWebPagePreview | messages.ExportChatInvite | messages.CheckChatInvite | messages.ImportChatInvite | messages.GetStickerSet | messages.InstallStickerSet | messages.UninstallStickerSet | messages.StartBot | messages.GetMessagesViews | messages.EditChatAdmin | messages.MigrateChat | messages.SearchGlobal | messages.ReorderStickerSets | messages.GetDocumentByHash | messages.GetSavedGifs | messages.SaveGif | messages.GetInlineBotResults | messages.SetInlineBotResults | messages.SendInlineBotResult | messages.GetMessageEditData | messages.EditMessage | messages.EditInlineBotMessage | messages.GetBotCallbackAnswer | messages.SetBotCallbackAnswer | messages.GetPeerDialogs | messages.SaveDraft | messages.GetAllDrafts | messages.GetFeaturedStickers | messages.ReadFeaturedStickers | messages.GetRecentStickers | messages.SaveRecentSticker | messages.ClearRecentStickers | messages.GetArchivedStickers | messages.GetMaskStickers | messages.GetAttachedStickers | messages.SetGameScore | messages.SetInlineGameScore | messages.GetGameHighScores | messages.GetInlineGameHighScores | messages.GetCommonChats | messages.GetAllChats | messages.GetWebPage | messages.ToggleDialogPin | messages.ReorderPinnedDialogs | messages.GetPinnedDialogs | messages.SetBotShippingResults | messages.SetBotPrecheckoutResults | messages.UploadMedia | messages.SendScreenshotNotification | messages.GetFavedStickers | messages.FaveSticker | messages.GetUnreadMentions | messages.ReadMentions | messages.GetRecentLocations | messages.SendMultiMedia | messages.UploadEncryptedFile | messages.SearchStickerSets | messages.GetSplitRanges | messages.MarkDialogUnread | messages.GetDialogUnreadMarks | messages.ClearAllDrafts | messages.UpdatePinnedMessage | messages.SendVote | messages.GetPollResults | messages.GetOnlines | messages.EditChatAbout | messages.EditChatDefaultBannedRights | messages.GetEmojiKeywords | messages.GetEmojiKeywordsDifference | messages.GetEmojiKeywordsLanguages | messages.GetEmojiURL | messages.GetSearchCounters | messages.RequestUrlAuth | messages.AcceptUrlAuth | messages.HidePeerSettingsBar | messages.GetScheduledHistory | messages.GetScheduledMessages | messages.SendScheduledMessages | messages.DeleteScheduledMessages | messages.GetPollVotes | messages.ToggleStickerSets | messages.GetDialogFilters | messages.GetSuggestedDialogFilters | messages.UpdateDialogFilter | messages.UpdateDialogFiltersOrder | messages.GetOldFeaturedStickers | messages.GetReplies | messages.GetDiscussionMessage | messages.ReadDiscussion | messages.UnpinAllMessages | messages.DeleteChat | messages.DeletePhoneCallHistory | messages.CheckHistoryImport | messages.InitHistoryImport | messages.UploadImportedMedia | messages.StartHistoryImport | messages.GetExportedChatInvites | messages.GetExportedChatInvite | messages.EditExportedChatInvite | messages.DeleteRevokedExportedChatInvites | messages.DeleteExportedChatInvite | messages.GetAdminsWithInvites | messages.GetChatInviteImporters | messages.SetHistoryTTL | messages.CheckHistoryImportPeer | messages.SetChatTheme | messages.GetMessageReadParticipants | messages.GetSearchResultsCalendar | messages.GetSearchResultsPositions | messages.HideChatJoinRequest | messages.HideAllChatJoinRequests | messages.ToggleNoForwards | messages.SaveDefaultSendAs | messages.SendReaction | messages.GetMessagesReactions | messages.GetMessageReactionsList | messages.SetChatAvailableReactions | messages.GetAvailableReactions | messages.SetDefaultReaction | messages.TranslateText | messages.GetUnreadReactions | messages.ReadReactions
| updates.GetState | updates.GetDifference | updates.GetChannelDifference | updates.GetState | updates.GetDifference | updates.GetChannelDifference
| photos.UpdateProfilePhoto | photos.UploadProfilePhoto | photos.DeletePhotos | photos.GetUserPhotos | photos.UpdateProfilePhoto | photos.UploadProfilePhoto | photos.DeletePhotos | photos.GetUserPhotos
| upload.SaveFilePart | upload.GetFile | upload.SaveBigFilePart | upload.GetWebFile | upload.GetCdnFile | upload.ReuploadCdnFile | upload.GetCdnFileHashes | upload.GetFileHashes | upload.SaveFilePart | upload.GetFile | upload.SaveBigFilePart | upload.GetWebFile | upload.GetCdnFile | upload.ReuploadCdnFile | upload.GetCdnFileHashes | upload.GetFileHashes

View File

@ -133,7 +133,7 @@ messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction;
messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction;
messageActionSetChatTheme#aa786345 emoticon:string = MessageAction; messageActionSetChatTheme#aa786345 emoticon:string = MessageAction;
messageActionChatJoinedByRequest#ebbca3cb = MessageAction; messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog; dialog#a8edd0f5 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
photoEmpty#2331b22d id:long = Photo; photoEmpty#2331b22d id:long = Photo;
photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> video_sizes:flags.1?Vector<VideoSize> dc_id:int = Photo; photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> video_sizes:flags.1?Vector<VideoSize> dc_id:int = Photo;
@ -436,7 +436,7 @@ inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;
stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet; stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true gifs:flags.6?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
messages.stickerSetNotModified#d3f924eb = messages.StickerSet; messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
botCommand#c27ac8c7 command:string description:string = BotCommand; botCommand#c27ac8c7 command:string description:string = BotCommand;
@ -944,14 +944,14 @@ users.userFull#3b6d152e full_user:UserFull chats:Vector<Chat> users:Vector<User>
messages.peerSettings#6880b94d settings:PeerSettings chats:Vector<Chat> users:Vector<User> = messages.PeerSettings; messages.peerSettings#6880b94d settings:PeerSettings chats:Vector<Chat> users:Vector<User> = messages.PeerSettings;
auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut;
reactionCount#6fb250d1 flags:# chosen:flags.0?true reaction:string count:int = ReactionCount; reactionCount#6fb250d1 flags:# chosen:flags.0?true reaction:string count:int = ReactionCount;
messageReactions#87b6e36 flags:# min:flags.0?true can_see_list:flags.2?true results:Vector<ReactionCount> recent_reactons:flags.1?Vector<MessageUserReaction> = MessageReactions; messageReactions#4f2b9479 flags:# min:flags.0?true can_see_list:flags.2?true results:Vector<ReactionCount> recent_reactions:flags.1?Vector<MessagePeerReaction> = MessageReactions;
messageUserReaction#932844fa user_id:long reaction:string = MessageUserReaction; messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector<MessagePeerReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.MessageReactionsList;
messages.messageReactionsList#a366923c flags:# count:int reactions:Vector<MessageUserReaction> users:Vector<User> next_offset:flags.0?string = messages.MessageReactionsList;
availableReaction#c077ec01 flags:# inactive:flags.0?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; availableReaction#c077ec01 flags:# inactive:flags.0?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction;
messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions;
messages.availableReactions#768e3aad hash:int reactions:Vector<AvailableReaction> = messages.AvailableReactions; messages.availableReactions#768e3aad hash:int reactions:Vector<AvailableReaction> = messages.AvailableReactions;
messages.translateNoResult#67ca4737 = messages.TranslatedText; messages.translateNoResult#67ca4737 = messages.TranslatedText;
messages.translateResultText#a214f7d0 text:string = messages.TranslatedText; messages.translateResultText#a214f7d0 text:string = messages.TranslatedText;
messagePeerReaction#51b67eff flags:# big:flags.0?true unread:flags.1?true peer_id:Peer reaction:string = MessagePeerReaction;
---functions--- ---functions---
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
@ -1092,7 +1092,7 @@ messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPe
messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates;
messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates; messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates;
messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool;
messages.sendReaction#25690ce4 flags:# peer:InputPeer msg_id:int reaction:flags.0?string = Updates; messages.sendReaction#25690ce4 flags:# big:flags.1?true peer:InputPeer msg_id:int reaction:flags.0?string = Updates;
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates; messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates;
messages.getMessageReactionsList#e0ee6b77 flags:# peer:InputPeer id:int reaction:flags.0?string offset:flags.1?string limit:int = messages.MessageReactionsList; messages.getMessageReactionsList#e0ee6b77 flags:# peer:InputPeer id:int reaction:flags.0?string offset:flags.1?string limit:int = messages.MessageReactionsList;
messages.setChatAvailableReactions#14050ea6 peer:InputPeer available_reactions:Vector<string> = Updates; messages.setChatAvailableReactions#14050ea6 peer:InputPeer available_reactions:Vector<string> = Updates;

View File

@ -190,7 +190,7 @@ messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int =
messageActionSetChatTheme#aa786345 emoticon:string = MessageAction; messageActionSetChatTheme#aa786345 emoticon:string = MessageAction;
messageActionChatJoinedByRequest#ebbca3cb = MessageAction; messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog; dialog#a8edd0f5 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
photoEmpty#2331b22d id:long = Photo; photoEmpty#2331b22d id:long = Photo;
@ -566,7 +566,7 @@ inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;
stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet; stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true gifs:flags.6?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
messages.stickerSetNotModified#d3f924eb = messages.StickerSet; messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
@ -1307,11 +1307,9 @@ auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut
reactionCount#6fb250d1 flags:# chosen:flags.0?true reaction:string count:int = ReactionCount; reactionCount#6fb250d1 flags:# chosen:flags.0?true reaction:string count:int = ReactionCount;
messageReactions#87b6e36 flags:# min:flags.0?true can_see_list:flags.2?true results:Vector<ReactionCount> recent_reactons:flags.1?Vector<MessageUserReaction> = MessageReactions; messageReactions#4f2b9479 flags:# min:flags.0?true can_see_list:flags.2?true results:Vector<ReactionCount> recent_reactions:flags.1?Vector<MessagePeerReaction> = MessageReactions;
messageUserReaction#932844fa user_id:long reaction:string = MessageUserReaction; messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector<MessagePeerReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.MessageReactionsList;
messages.messageReactionsList#a366923c flags:# count:int reactions:Vector<MessageUserReaction> users:Vector<User> next_offset:flags.0?string = messages.MessageReactionsList;
availableReaction#c077ec01 flags:# inactive:flags.0?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; availableReaction#c077ec01 flags:# inactive:flags.0?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction;
@ -1321,6 +1319,8 @@ messages.availableReactions#768e3aad hash:int reactions:Vector<AvailableReaction
messages.translateNoResult#67ca4737 = messages.TranslatedText; messages.translateNoResult#67ca4737 = messages.TranslatedText;
messages.translateResultText#a214f7d0 text:string = messages.TranslatedText; messages.translateResultText#a214f7d0 text:string = messages.TranslatedText;
messagePeerReaction#51b67eff flags:# big:flags.0?true unread:flags.1?true peer_id:Peer reaction:string = MessagePeerReaction;
---functions--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1599,13 +1599,15 @@ messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPe
messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates;
messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates; messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates;
messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool;
messages.sendReaction#25690ce4 flags:# peer:InputPeer msg_id:int reaction:flags.0?string = Updates; messages.sendReaction#25690ce4 flags:# big:flags.1?true peer:InputPeer msg_id:int reaction:flags.0?string = Updates;
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates; messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates;
messages.getMessageReactionsList#e0ee6b77 flags:# peer:InputPeer id:int reaction:flags.0?string offset:flags.1?string limit:int = messages.MessageReactionsList; messages.getMessageReactionsList#e0ee6b77 flags:# peer:InputPeer id:int reaction:flags.0?string offset:flags.1?string limit:int = messages.MessageReactionsList;
messages.setChatAvailableReactions#14050ea6 peer:InputPeer available_reactions:Vector<string> = Updates; messages.setChatAvailableReactions#14050ea6 peer:InputPeer available_reactions:Vector<string> = Updates;
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
messages.setDefaultReaction#d960c4d4 reaction:string = Bool; messages.setDefaultReaction#d960c4d4 reaction:string = Bool;
messages.translateText#24ce6dee flags:# peer:flags.0?InputPeer msg_id:flags.0?int text:flags.1?string from_lang:flags.2?string to_lang:string = messages.TranslatedText; messages.translateText#24ce6dee flags:# peer:flags.0?InputPeer msg_id:flags.0?int text:flags.1?string from_lang:flags.2?string to_lang:string = messages.TranslatedText;
messages.getUnreadReactions#e85bae1a peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.readReactions#82e251d7 peer:InputPeer = messages.AffectedHistory;
updates.getState#edd4882a = updates.State; updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@ -1754,4 +1756,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
// LAYER 137 // LAYER 138

View File

@ -13,7 +13,7 @@ import {
MEDIA_PROGRESSIVE_CACHE_NAME, MEDIA_PROGRESSIVE_CACHE_NAME,
IS_TEST, IS_TEST,
} from '../../../config'; } from '../../../config';
import { IS_MOV_SUPPORTED, PLATFORM_ENV } from '../../../util/environment'; import { IS_MOV_SUPPORTED, IS_WEBM_SUPPORTED, PLATFORM_ENV } from '../../../util/environment';
import { unsubscribe } from '../../../util/notifications'; import { unsubscribe } from '../../../util/notifications';
import * as cacheApi from '../../../util/cacheApi'; import * as cacheApi from '../../../util/cacheApi';
import { updateAppBadge } from '../../../util/appBadge'; import { updateAppBadge } from '../../../util/appBadge';
@ -39,6 +39,7 @@ addReducer('initApi', (global: GlobalState, actions) => {
sessionData: loadStoredSession(), sessionData: loadStoredSession(),
isTest: window.location.search.includes('test'), isTest: window.location.search.includes('test'),
isMovSupported: IS_MOV_SUPPORTED, isMovSupported: IS_MOV_SUPPORTED,
isWebmSupported: IS_WEBM_SUPPORTED,
}); });
})(); })();
}); });

View File

@ -27,13 +27,18 @@ addReducer('loadStickerSets', (global) => {
addReducer('loadAddedStickers', (global, actions) => { addReducer('loadAddedStickers', (global, actions) => {
const { setIds: addedSetIds } = global.stickers.added; const { setIds: addedSetIds } = global.stickers.added;
const cached = global.stickers.setsById;
if (!addedSetIds || !addedSetIds.length) { if (!addedSetIds || !addedSetIds.length) {
return; return;
} }
(async () => { (async () => {
for (let i = 0; i < addedSetIds.length; i++) { for (let i = 0; i < addedSetIds.length; i++) {
actions.loadStickers({ stickerSetId: addedSetIds[i] }); const id = addedSetIds[i];
if (cached[id].stickers) {
continue; // Already loaded
}
actions.loadStickers({ stickerSetId: id });
if (i % ADDED_SETS_THROTTLE_CHUNK === 0 && i > 0) { if (i % ADDED_SETS_THROTTLE_CHUNK === 0 && i > 0) {
await pause(ADDED_SETS_THROTTLE); await pause(ADDED_SETS_THROTTLE);

View File

@ -252,7 +252,7 @@ export function getMessageMediaFormat(
const fullVideo = video || getMessageWebPageVideo(message); const fullVideo = video || getMessageWebPageVideo(message);
if (sticker && target === 'inline' && sticker.isAnimated) { if (sticker && target === 'inline' && sticker.isLottie) {
return ApiMediaFormat.Lottie; return ApiMediaFormat.Lottie;
} else if (fullVideo && IS_PROGRESSIVE_SUPPORTED && ( } else if (fullVideo && IS_PROGRESSIVE_SUPPORTED && (
target === 'viewerFull' || target === 'inline' target === 'viewerFull' || target === 'inline'

View File

@ -190,7 +190,8 @@ export function getMessageContentFilename(message: ApiMessage) {
} }
if (content.sticker) { if (content.sticker) {
const extension = content.sticker.isAnimated ? 'tgs' : isWebpSupported() ? 'webp' : 'png'; const extension = content.sticker.isLottie ? 'tgs' : content.sticker.isGif
? 'webm' : isWebpSupported() ? 'webp' : 'png';
return `${content.sticker.id}.${extension}`; return `${content.sticker.id}.${extension}`;
} }

View File

@ -47,11 +47,24 @@ export function updateStickerSet(
global: GlobalState, stickerSetId: string, update: Partial<ApiStickerSet>, global: GlobalState, stickerSetId: string, update: Partial<ApiStickerSet>,
): GlobalState { ): GlobalState {
const currentStickerSet = global.stickers.setsById[stickerSetId] || {}; const currentStickerSet = global.stickers.setsById[stickerSetId] || {};
const addedSets = global.stickers.added.setIds || [];
let setIds: string[] = addedSets;
if (update.installedDate && addedSets && !addedSets.includes(stickerSetId)) {
setIds = [stickerSetId, ...setIds];
}
if (!update.installedDate && addedSets?.includes(stickerSetId)) {
setIds = setIds.filter((id) => id !== stickerSetId);
}
return { return {
...global, ...global,
stickers: { stickers: {
...global.stickers, ...global.stickers,
added: {
...global.stickers.added,
setIds,
},
setsById: { setsById: {
...global.stickers.setsById, ...global.stickers.setsById,
[stickerSetId]: { [stickerSetId]: {

View File

@ -208,7 +208,7 @@ export enum SettingsScreens {
} }
export type StickerSetOrRecent = Pick<ApiStickerSet, ( export type StickerSetOrRecent = Pick<ApiStickerSet, (
'id' | 'title' | 'count' | 'stickers' | 'hasThumbnail' | 'isAnimated' 'id' | 'title' | 'count' | 'stickers' | 'hasThumbnail' | 'isLottie' | 'isGifs'
)>; )>;
export enum LeftColumnContent { export enum LeftColumnContent {

View File

@ -73,11 +73,15 @@ export const IS_REQUEST_FULLSCREEN_SUPPORTED = 'requestFullscreen' in document.c
export const ARE_CALLS_SUPPORTED = !navigator.userAgent.includes('Firefox'); export const ARE_CALLS_SUPPORTED = !navigator.userAgent.includes('Firefox');
export const LAYERS_ANIMATION_NAME = IS_ANDROID ? 'slide-fade' : IS_IOS ? 'slide-layers' : 'push-slide'; export const LAYERS_ANIMATION_NAME = IS_ANDROID ? 'slide-fade' : IS_IOS ? 'slide-layers' : 'push-slide';
const TEST_VIDEO = document.createElement('video');
// `canPlayType(VIDEO_MOV_TYPE)` returns false negative at least for macOS Chrome and iOS Safari // `canPlayType(VIDEO_MOV_TYPE)` returns false negative at least for macOS Chrome and iOS Safari
export const IS_MOV_SUPPORTED = true; export const IS_MOV_SUPPORTED = true;
if (IS_MOV_SUPPORTED) SUPPORTED_VIDEO_CONTENT_TYPES.add(VIDEO_MOV_TYPE); if (IS_MOV_SUPPORTED) SUPPORTED_VIDEO_CONTENT_TYPES.add(VIDEO_MOV_TYPE);
export const IS_WEBM_SUPPORTED = Boolean(TEST_VIDEO.canPlayType('video/webm; codecs="vp9"').replace('no', ''))
&& !(IS_MAC_OS && IS_SAFARI); // Safari on MacOS has some issues with WebM
export const DPR = window.devicePixelRatio || 1; export const DPR = window.devicePixelRatio || 1;
export const MASK_IMAGE_DISABLED = true; export const MASK_IMAGE_DISABLED = true;

View File

@ -22,6 +22,7 @@ module.exports = (env = {}, argv = {}) => {
port: 1234, port: 1234,
host: '0.0.0.0', host: '0.0.0.0',
allowedHosts: "all", allowedHosts: "all",
hot: false,
static: [ static: [
{ {
directory: path.resolve(__dirname, 'public'), directory: path.resolve(__dirname, 'public'),