Emoji Modal: Fix sticker set card list modal (#4764)

This commit is contained in:
Alexander Zinchuk 2024-08-06 20:06:12 +02:00
parent 527e4644e2
commit 66d54b2f63
7 changed files with 75 additions and 50 deletions

View File

@ -40,7 +40,6 @@
.sets {
position: relative;
width: 100%;
min-height: 19rem;
overflow-y: auto;
padding: 0 0.5rem;
text-align: left;

View File

@ -1,15 +1,19 @@
import type { FC } from '../../lib/teact/teact';
import React, {
memo, useCallback, useRef,
memo,
useMemo,
useRef,
} from '../../lib/teact/teact';
import { getGlobal } from '../../lib/teact/teactn';
import { getActions, withGlobal } from '../../global';
import type { ApiSticker, ApiStickerSet } from '../../api/types';
import type { ApiSticker } from '../../api/types';
import { selectCanPlayAnimatedEmojis } from '../../global/selectors';
import buildClassName from '../../util/buildClassName';
import { useIntersectionObserver } from '../../hooks/useIntersectionObserver';
import useLastCallback from '../../hooks/useLastCallback';
import useOldLang from '../../hooks/useOldLang';
import usePrevious from '../../hooks/usePrevious';
@ -24,18 +28,21 @@ export type OwnProps = {
};
type StateProps = {
customEmojiSets?: ApiStickerSet[];
canPlayAnimatedEmojis?: boolean;
};
const CustomEmojiSetsModal: FC<OwnProps & StateProps> = ({
customEmojiSets,
customEmojiSetIds,
canPlayAnimatedEmojis,
onClose,
}) => {
const { openStickerSet } = getActions();
const lang = useOldLang();
const customEmojiSets = useMemo(() => {
return customEmojiSetIds?.map((id) => getGlobal().stickers.setsById[id]);
}, [customEmojiSetIds]);
// eslint-disable-next-line no-null/no-null
const customEmojiModalRef = useRef<HTMLDivElement>(null);
const { observe: observeIntersectionForCovers } = useIntersectionObserver({
@ -45,11 +52,11 @@ const CustomEmojiSetsModal: FC<OwnProps & StateProps> = ({
const prevCustomEmojiSets = usePrevious(customEmojiSets);
const renderingCustomEmojiSets = customEmojiSets || prevCustomEmojiSets;
const handleSetClick = useCallback((sticker: ApiSticker) => {
const handleSetClick = useLastCallback((sticker: ApiSticker) => {
openStickerSet({
stickerSetInfo: sticker.stickerSetInfo,
});
}, [openStickerSet]);
});
return (
<Modal
@ -60,27 +67,26 @@ const CustomEmojiSetsModal: FC<OwnProps & StateProps> = ({
title={lang('lng_custom_emoji_used_sets')}
>
<div className={buildClassName(styles.sets, 'custom-scroll')} ref={customEmojiModalRef} teactFastList>
{renderingCustomEmojiSets?.map((customEmojiSet) => (
<StickerSetCard
key={customEmojiSet.id}
className={styles.setCard}
stickerSet={customEmojiSet}
onClick={handleSetClick}
observeIntersection={observeIntersectionForCovers}
noPlay={!canPlayAnimatedEmojis}
/>
))}
{renderingCustomEmojiSets?.map((customEmojiSet) => {
return (
<StickerSetCard
key={customEmojiSet.id}
className={styles.setCard}
stickerSet={customEmojiSet}
onClick={handleSetClick}
observeIntersection={observeIntersectionForCovers}
noPlay={!canPlayAnimatedEmojis}
/>
);
})}
</div>
</Modal>
);
};
export default memo(withGlobal<OwnProps>(
(global, { customEmojiSetIds }): StateProps => {
const customEmojiSets = customEmojiSetIds?.map((id) => global.stickers.setsById[id]);
(global): StateProps => {
return {
customEmojiSets,
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
};
},

View File

@ -1,5 +1,5 @@
import type { FC } from '../../lib/teact/teact';
import React, { memo, useCallback } from '../../lib/teact/teact';
import React, { memo } from '../../lib/teact/teact';
import type { ApiSticker, ApiStickerSet } from '../../api/types';
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
@ -7,6 +7,7 @@ import type { ObserveFn } from '../../hooks/useIntersectionObserver';
import { CHAT_HEIGHT_PX, STICKER_SIZE_GENERAL_SETTINGS } from '../../config';
import buildClassName from '../../util/buildClassName';
import useLastCallback from '../../hooks/useLastCallback';
import useOldLang from '../../hooks/useOldLang';
import StickerSetCover from '../middle/composer/StickerSetCover';
@ -35,11 +36,11 @@ const StickerSetCard: FC<OwnProps> = ({
const firstSticker = stickerSet?.stickers?.[0];
const handleCardClick = useCallback(() => {
const handleCardClick = useLastCallback(() => {
if (firstSticker) onClick(firstSticker);
}, [firstSticker, onClick]);
});
if (!stickerSet || !stickerSet.stickers) {
if (!stickerSet?.stickers) {
return undefined;
}

View File

@ -4,18 +4,17 @@ import React, {
} from '../../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../../global';
import type {
ApiAvailableReaction,
ApiChatReactions,
ApiMessage,
ApiReaction,
ApiStickerSet, ApiStickerSetInfo,
ApiThreadInfo,
} from '../../../api/types';
import type { ActiveDownloads, MessageListType } from '../../../global/types';
import type { IAlbum, IAnchorPosition, ThreadId } from '../../../types';
import {
type ApiAvailableReaction,
type ApiChatReactions,
type ApiMessage,
type ApiReaction,
type ApiStickerSet,
type ApiStickerSetInfo,
type ApiThreadInfo,
MAIN_THREAD_ID,
} from '../../../api/types';
import { MAIN_THREAD_ID } from '../../../api/types';
import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
import {
@ -45,8 +44,7 @@ import {
selectIsMessageProtected,
selectIsMessageUnread,
selectIsPremiumPurchaseBlocked,
selectIsReactionPickerOpen,
selectMessageCustomEmojiSets,
selectIsReactionPickerOpen, selectMessageCustomEmojiSets,
selectMessageTranslations,
selectRequestedChatTranslationLanguage,
selectRequestedMessageTranslationLanguage,
@ -88,8 +86,6 @@ type StateProps = {
availableReactions?: ApiAvailableReaction[];
topReactions?: ApiReaction[];
defaultTagReactions?: ApiReaction[];
customEmojiSetsInfo?: ApiStickerSetInfo[];
customEmojiSets?: ApiStickerSet[];
noOptions?: boolean;
canSendNow?: boolean;
canReschedule?: boolean;
@ -98,6 +94,8 @@ type StateProps = {
canShowReactionsCount?: boolean;
canBuyPremium?: boolean;
canShowReactionList?: boolean;
customEmojiSetsInfo?: ApiStickerSetInfo[];
customEmojiSets?: ApiStickerSet[];
canUnpin?: boolean;
canDelete?: boolean;
canReport?: boolean;
@ -694,12 +692,12 @@ export default memo(withGlobal<OwnProps>(
const isMessageUnread = selectIsMessageUnread(global, message);
const canLoadReadDate = Boolean(
isPrivate
&& isOwn
&& !isMessageUnread
&& readDateExpiresAt
&& message.date > Date.now() / 1000 - readDateExpiresAt
&& !userStatus?.isReadDateRestricted
&& messageListType !== 'scheduled',
&& isOwn
&& !isMessageUnread
&& readDateExpiresAt
&& message.date > Date.now() / 1000 - readDateExpiresAt
&& !userStatus?.isReadDateRestricted
&& messageListType !== 'scheduled',
);
const shouldRenderShowWhen = Boolean(
canLoadReadDate && isPrivate && selectUserStatus(global, chat.id)?.isReadDateRestrictedByMe,

View File

@ -214,7 +214,9 @@ const MessageContextMenu: FC<OwnProps> = ({
onShowOriginal,
onSelectLanguage,
}) => {
const { showNotification, openStickerSet, openCustomEmojiSets } = getActions();
const {
showNotification, openStickerSet, openCustomEmojiSets, loadStickers,
} = getActions();
// eslint-disable-next-line no-null/no-null
const menuRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
@ -244,6 +246,19 @@ const MessageContextMenu: FC<OwnProps> = ({
}
}, [onClose, isOpen, isReactionPickerOpen, areItemsHidden]);
useEffect(() => {
if (customEmojiSets?.length) {
customEmojiSets.map((customEmojiSet) => {
return loadStickers({
stickerSetInfo: {
id: customEmojiSet.id,
accessHash: customEmojiSet.accessHash,
},
});
});
}
}, [customEmojiSets, openCustomEmojiSets]);
const handleOpenCustomEmojiSets = useLastCallback(() => {
if (!customEmojiSets) return;
if (customEmojiSets.length === 1) {

View File

@ -1,5 +1,11 @@
import type {
ApiAttachment, ApiChat, ApiMessage, ApiMessageEntityTextUrl, ApiPeer, ApiStory, ApiUser,
ApiAttachment,
ApiChat,
ApiMessage,
ApiMessageEntityTextUrl,
ApiPeer,
ApiStory,
ApiUser,
} from '../../api/types';
import type { MediaContent } from '../../api/types/messages';
import type { LangFn } from '../../hooks/useOldLang';

View File

@ -722,7 +722,7 @@ export function selectAllowedMessageActions<T extends GlobalState>(global: T, me
const canSelect = !isLocal && !isAction;
const canDownload = Boolean(content.webPage?.document || content.webPage?.video || content.webPage?.photo
|| content.audio || content.voice || content.photo || content.video || content.document || content.sticker)
|| content.audio || content.voice || content.photo || content.video || content.document || content.sticker)
&& !hasTtl;
const canSaveGif = message.content.video?.isGif;
@ -1210,7 +1210,7 @@ export function selectLastServiceNotification<T extends GlobalState>(global: T)
export function selectIsMessageProtected<T extends GlobalState>(global: T, message?: ApiMessage) {
return Boolean(message && (
message.isProtected || selectIsChatProtected(global, message.chatId) || hasMessageTtl(message)
|| getMessagePaidMedia(message)
|| getMessagePaidMedia(message)
));
}
@ -1246,7 +1246,7 @@ export function selectCanForwardMessages<T extends GlobalState>(global: T, chatI
return messageIds
.map((id) => messages[id])
.every((message) => !hasMessageTtl(message)
&& (message.isForwardingAllowed || isServiceNotificationMessage(message)));
&& (message.isForwardingAllowed || isServiceNotificationMessage(message)));
}
export function selectSponsoredMessage<T extends GlobalState>(global: T, chatId: string) {