Reactions: Support service messages (#5387)
This commit is contained in:
parent
d0ad84217d
commit
5dbb3ddea9
@ -216,6 +216,7 @@ export function buildApiMessageWithChatId(
|
||||
const senderBoosts = mtpMessage.fromBoostsApplied;
|
||||
const factCheck = mtpMessage.factcheck && buildApiFactCheck(mtpMessage.factcheck);
|
||||
const isVideoProcessingPending = mtpMessage.videoProcessingPending;
|
||||
const areReactionsPossible = mtpMessage.reactionsArePossible;
|
||||
|
||||
const isInvertedMedia = mtpMessage.invertMedia;
|
||||
|
||||
@ -242,6 +243,7 @@ export function buildApiMessageWithChatId(
|
||||
editDate: mtpMessage.editDate,
|
||||
isMediaUnread,
|
||||
hasUnreadMention: mtpMessage.mentioned && isMediaUnread,
|
||||
areReactionsPossible,
|
||||
isMentioned: mtpMessage.mentioned,
|
||||
...(groupedId && {
|
||||
groupedId,
|
||||
@ -439,6 +441,7 @@ function buildAction(
|
||||
text = 'Notification.ChangedGroupPhoto';
|
||||
translationValues.push('%action_origin%');
|
||||
}
|
||||
type = 'updateProfilePhoto';
|
||||
} else if (action instanceof GramJs.MessageActionChatDeletePhoto) {
|
||||
if (isChannelPost) {
|
||||
text = 'Channel.MessagePhotoRemoved';
|
||||
|
||||
@ -478,6 +478,7 @@ export interface ApiAction {
|
||||
| 'chatCreate'
|
||||
| 'topicCreate'
|
||||
| 'suggestProfilePhoto'
|
||||
| 'updateProfilePhoto'
|
||||
| 'joinedChannel'
|
||||
| 'chatBoost'
|
||||
| 'receipt'
|
||||
@ -755,6 +756,7 @@ export interface ApiMessage {
|
||||
effectId?: string;
|
||||
isInvertedMedia?: true;
|
||||
isVideoProcessingPending?: true;
|
||||
areReactionsPossible?: true;
|
||||
}
|
||||
|
||||
export interface ApiReactions {
|
||||
|
||||
@ -19,6 +19,7 @@ import {
|
||||
selectChatMessage,
|
||||
selectGiftStickerForDuration,
|
||||
selectGiftStickerForStars,
|
||||
selectIsCurrentUserPremium,
|
||||
selectIsMessageFocused,
|
||||
selectStarGiftSticker,
|
||||
selectTabState,
|
||||
@ -47,7 +48,9 @@ import Avatar from '../common/Avatar';
|
||||
import GiftRibbon from '../common/gift/GiftRibbon';
|
||||
import Sparkles from '../common/Sparkles';
|
||||
import ActionMessageSuggestedAvatar from './ActionMessageSuggestedAvatar';
|
||||
import ActionMessageUpdatedAvatar from './ActionMessageUpdatedAvatar';
|
||||
import ContextMenuContainer from './message/ContextMenuContainer.async';
|
||||
import Reactions from './message/reactions/Reactions';
|
||||
import SimilarChannels from './message/SimilarChannels';
|
||||
|
||||
type OwnProps = {
|
||||
@ -82,6 +85,7 @@ type StateProps = {
|
||||
starsGiftSticker?: ApiSticker;
|
||||
canPlayAnimatedEmojis?: boolean;
|
||||
patternColor?: string;
|
||||
isCurrentUserPremium?: boolean;
|
||||
};
|
||||
|
||||
const APPEARANCE_DELAY = 10;
|
||||
@ -89,6 +93,7 @@ const STAR_GIFT_STICKER_SIZE = 120;
|
||||
|
||||
const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
message,
|
||||
threadId,
|
||||
isEmbedded,
|
||||
appearanceOrder = 0,
|
||||
isJustAdded,
|
||||
@ -114,6 +119,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
observeIntersectionForLoading,
|
||||
observeIntersectionForPlaying,
|
||||
onIntersectPinnedMessage,
|
||||
isCurrentUserPremium,
|
||||
}) => {
|
||||
const {
|
||||
openPremiumModal,
|
||||
@ -156,11 +162,14 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
const isPremiumGift = message.content.action?.type === 'giftPremium';
|
||||
const isGiftCode = message.content.action?.type === 'giftCode';
|
||||
const isSuggestedAvatar = message.content.action?.type === 'suggestProfilePhoto' && message.content.action!.photo;
|
||||
const isUpdatedAvatar = message.content.action?.type === 'updateProfilePhoto' && message.content.action!.photo;
|
||||
const isJoinedMessage = isJoinedChannelMessage(message);
|
||||
const isStarsGift = message.content.action?.type === 'giftStars';
|
||||
const isStarGift = message.content.action?.type === 'starGift';
|
||||
const isPrizeStars = message.content.action?.type === 'prizeStars';
|
||||
|
||||
const withServiceReactions = Boolean(message.areReactionsPossible && message?.reactions);
|
||||
|
||||
useEffect(() => {
|
||||
if (noAppearanceAnimation) {
|
||||
return;
|
||||
@ -548,7 +557,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
const className = buildClassName(
|
||||
'ActionMessage message-list-item',
|
||||
isFocused && !noFocusHighlight && 'focused',
|
||||
(isPremiumGift || isSuggestedAvatar) && 'centered-action',
|
||||
(isPremiumGift || isSuggestedAvatar || isUpdatedAvatar) && 'centered-action',
|
||||
isContextMenuShown && 'has-menu-open',
|
||||
isLastInList && 'last-in-list',
|
||||
transitionClassNames,
|
||||
@ -564,7 +573,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
onMouseDown={handleMouseDown}
|
||||
onContextMenu={handleContextMenu}
|
||||
>
|
||||
{!isSuggestedAvatar && !isGiftCode && !isJoinedMessage && (
|
||||
{!isSuggestedAvatar && !isGiftCode && !isJoinedMessage && !isUpdatedAvatar && (
|
||||
<span className="action-message-content" onClick={handleClick}>{renderContent()}</span>
|
||||
)}
|
||||
{isPremiumGift && renderGift()}
|
||||
@ -575,6 +584,9 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
{isSuggestedAvatar && (
|
||||
<ActionMessageSuggestedAvatar message={message} renderContent={renderContent} />
|
||||
)}
|
||||
{isUpdatedAvatar && (
|
||||
<ActionMessageUpdatedAvatar message={message} renderContent={renderContent} />
|
||||
)}
|
||||
{isJoinedMessage && <SimilarChannels chatId={targetChatId!} />}
|
||||
{contextMenuAnchor && (
|
||||
<ContextMenuContainer
|
||||
@ -586,6 +598,15 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
onCloseAnimationEnd={handleContextMenuHide}
|
||||
/>
|
||||
)}
|
||||
{withServiceReactions && (
|
||||
<Reactions
|
||||
isOutside
|
||||
message={message!}
|
||||
threadId={threadId}
|
||||
observeIntersection={observeIntersectionForPlaying}
|
||||
isCurrentUserPremium={isCurrentUserPremium}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -646,6 +667,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
focusDirection,
|
||||
noFocusHighlight,
|
||||
}),
|
||||
isCurrentUserPremium: selectIsCurrentUserPremium(global),
|
||||
};
|
||||
},
|
||||
)(ActionMessage));
|
||||
|
||||
60
src/components/middle/ActionMessageUpdatedAvatar.tsx
Normal file
60
src/components/middle/ActionMessageUpdatedAvatar.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React, { memo } from '../../lib/teact/teact';
|
||||
import { getActions } from '../../global';
|
||||
|
||||
import type { ApiMessage } from '../../api/types';
|
||||
import type { TextPart } from '../../types';
|
||||
import { MAIN_THREAD_ID } from '../../api/types';
|
||||
import { MediaViewerOrigin } from '../../types';
|
||||
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
|
||||
import Avatar from '../common/Avatar';
|
||||
|
||||
type OwnProps = {
|
||||
message: ApiMessage;
|
||||
renderContent: () => TextPart | undefined;
|
||||
};
|
||||
|
||||
const ActionMessageUpdatedAvatar: FC<OwnProps> = ({
|
||||
message,
|
||||
renderContent,
|
||||
}) => {
|
||||
const {
|
||||
openMediaViewer,
|
||||
} = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const isVideo = message.content.action!.photo?.isVideo;
|
||||
|
||||
const handleViewUpdatedAvatar = () => {
|
||||
openMediaViewer({
|
||||
chatId: message.chatId,
|
||||
messageId: message.id,
|
||||
threadId: MAIN_THREAD_ID,
|
||||
origin: MediaViewerOrigin.SuggestedAvatar,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>{renderContent()}</span>
|
||||
<span
|
||||
className="action-message-updated-avatar"
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onClick={handleViewUpdatedAvatar}
|
||||
aria-label={lang('ViewPhotoAction')}
|
||||
>
|
||||
<Avatar
|
||||
photo={message.content.action!.photo}
|
||||
loopIndefinitely
|
||||
withVideo={isVideo}
|
||||
size="jumbo"
|
||||
/>
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ActionMessageUpdatedAvatar);
|
||||
@ -339,6 +339,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.action-message-updated-avatar {
|
||||
background: transparent !important;
|
||||
margin-top: 0.5rem;
|
||||
cursor: var(--custom-cursor, pointer);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.action-message-button {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
@ -232,7 +232,8 @@ const MessageContextMenu: FC<OwnProps> = ({
|
||||
const scrollableRef = useRef<HTMLDivElement>(null);
|
||||
const lang = useOldLang();
|
||||
const noReactions = !isPrivate && !enabledReactions;
|
||||
const withReactions = canShowReactionList && !noReactions;
|
||||
const areReactionsPossible = message.areReactionsPossible;
|
||||
const withReactions = (canShowReactionList && !noReactions) || areReactionsPossible;
|
||||
const isEdited = ('isEdited' in message) && message.isEdited;
|
||||
const seenByDates = message.seenByDates;
|
||||
const isPremiumGift = message.content.action?.type === 'giftPremium';
|
||||
|
||||
@ -13,6 +13,12 @@
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
&.with-service-reactions {
|
||||
justify-content: center;
|
||||
max-width: 19rem;
|
||||
margin: 0.3rem auto;
|
||||
}
|
||||
|
||||
.own &.is-outside {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
@ -64,6 +64,7 @@ const Reactions: FC<OwnProps> = ({
|
||||
const lang = useOldLang();
|
||||
|
||||
const { results, areTags, recentReactions } = message.reactions!;
|
||||
const withServiceReactions = Boolean(message.areReactionsPossible && message.reactions);
|
||||
|
||||
const totalCount = useMemo(() => (
|
||||
results.reduce((acc, reaction) => acc + reaction.count, 0)
|
||||
@ -178,7 +179,11 @@ const Reactions: FC<OwnProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName('Reactions', isOutside && 'is-outside')}
|
||||
className={buildClassName(
|
||||
'Reactions',
|
||||
isOutside && 'is-outside',
|
||||
withServiceReactions && 'with-service-reactions',
|
||||
)}
|
||||
style={maxWidth ? `max-width: ${maxWidth}px` : undefined}
|
||||
dir={lang.isRtl ? 'rtl' : 'ltr'}
|
||||
>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user