Story: Support clickable gifts (#5477)

This commit is contained in:
zubiden 2025-01-21 18:21:33 +01:00 committed by Alexander Zinchuk
parent 4c974d982b
commit 36639f1c2a
6 changed files with 45 additions and 32 deletions

View File

@ -166,36 +166,37 @@ function buildApiMediaAreaCoordinates(coordinates: GramJs.TypeMediaAreaCoordinat
}
export function buildApiMediaArea(area: GramJs.TypeMediaArea): ApiMediaArea | undefined {
const coordinates = buildApiMediaAreaCoordinates(area.coordinates);
if (area instanceof GramJs.MediaAreaVenue) {
const { geo, title, coordinates } = area;
const { geo, title } = area;
const point = buildGeoPoint(geo);
if (!point) return undefined;
return {
type: 'venue',
coordinates: buildApiMediaAreaCoordinates(coordinates),
coordinates,
geo: point,
title,
};
}
if (area instanceof GramJs.MediaAreaGeoPoint) {
const { geo, coordinates } = area;
const { geo } = area;
const point = buildGeoPoint(geo);
if (!point) return undefined;
return {
type: 'geoPoint',
coordinates: buildApiMediaAreaCoordinates(coordinates),
coordinates,
geo: point,
};
}
if (area instanceof GramJs.MediaAreaSuggestedReaction) {
const {
coordinates, reaction, dark, flipped,
reaction, dark, flipped,
} = area;
const apiReaction = buildApiReaction(reaction);
@ -205,7 +206,7 @@ export function buildApiMediaArea(area: GramJs.TypeMediaArea): ApiMediaArea | un
return {
type: 'suggestedReaction',
coordinates: buildApiMediaAreaCoordinates(coordinates),
coordinates,
reaction: apiReaction,
...(dark && { isDark: true }),
...(flipped && { isFlipped: true }),
@ -213,40 +214,50 @@ export function buildApiMediaArea(area: GramJs.TypeMediaArea): ApiMediaArea | un
}
if (area instanceof GramJs.MediaAreaChannelPost) {
const { coordinates, channelId, msgId } = area;
const { channelId, msgId } = area;
return {
type: 'channelPost',
coordinates: buildApiMediaAreaCoordinates(coordinates),
coordinates,
channelId: buildApiPeerId(channelId, 'channel'),
messageId: msgId,
};
}
if (area instanceof GramJs.MediaAreaUrl) {
const { coordinates, url } = area;
const { url } = area;
return {
type: 'url',
coordinates: buildApiMediaAreaCoordinates(coordinates),
coordinates,
url,
};
}
if (area instanceof GramJs.MediaAreaWeather) {
const {
coordinates, emoji, temperatureC, color,
emoji, temperatureC, color,
} = area;
return {
type: 'weather',
coordinates: buildApiMediaAreaCoordinates(coordinates),
coordinates,
emoji,
temperatureC,
color,
};
}
if (area instanceof GramJs.MediaAreaStarGift) {
const { slug } = area;
return {
type: 'uniqueGift',
coordinates,
slug,
};
}
return undefined;
}

View File

@ -176,5 +176,11 @@ export type ApiMediaAreaWeather = {
color: number;
};
export type ApiMediaAreaUniqueGift = {
type: 'uniqueGift';
coordinates: ApiMediaAreaCoordinates;
slug: string;
};
export type ApiMediaArea = ApiMediaAreaVenue | ApiMediaAreaGeoPoint | ApiMediaAreaSuggestedReaction
| ApiMediaAreaChannelPost | ApiMediaAreaUrl | ApiMediaAreaWeather;
| ApiMediaAreaChannelPost | ApiMediaAreaUrl | ApiMediaAreaWeather | ApiMediaAreaUniqueGift;

View File

@ -72,8 +72,6 @@ interface OwnProps {
storyId: number;
dimensions: IDimensions;
// eslint-disable-next-line react/no-unused-prop-types
isReportModalOpen?: boolean;
// eslint-disable-next-line react/no-unused-prop-types
isDeleteModalOpen?: boolean;
isPrivateStories?: boolean;
isArchivedStories?: boolean;
@ -908,7 +906,6 @@ function Story({
export default memo(withGlobal<OwnProps>((global, {
peerId,
storyId,
isReportModalOpen,
isDeleteModalOpen,
}): StateProps => {
const { appConfig } = global;
@ -927,13 +924,15 @@ export default memo(withGlobal<OwnProps>((global, {
premiumModal,
safeLinkModalUrl,
mapModal,
reportModal,
giftInfoModal,
} = tabState;
const { isOpen: isPremiumModalOpen } = premiumModal || {};
const story = selectPeerStory(global, peerId, storyId);
const isLoadedStory = story && 'content' in story;
const shouldForcePause = Boolean(
viewModal || forwardedStoryId || tabState.reactionPicker?.storyId || isReportModalOpen || isPrivacyModalOpen
|| isPremiumModalOpen || isDeleteModalOpen || safeLinkModalUrl || isStealthModalOpen || mapModal,
viewModal || forwardedStoryId || tabState.reactionPicker?.storyId || reportModal || isPrivacyModalOpen
|| isPremiumModalOpen || isDeleteModalOpen || safeLinkModalUrl || isStealthModalOpen || mapModal || giftInfoModal,
);
const forwardInfo = isLoadedStory ? story.forwardInfo : undefined;

View File

@ -43,7 +43,6 @@ import styles from './StoryViewer.module.scss';
interface OwnProps {
isOpen?: boolean;
isReportModalOpen?: boolean;
isDeleteModalOpen?: boolean;
onDelete: (story: ApiTypeStory) => void;
onReport: NoneToVoidFunction;
@ -80,7 +79,6 @@ function StorySlides({
isPrivate,
isArchive,
byPeerId,
isReportModalOpen,
isDeleteModalOpen,
onDelete,
onClose,
@ -380,7 +378,6 @@ function StorySlides({
dimensions={slideSizes.activeSlide}
isPrivateStories={renderingIsPrivate}
isArchivedStories={renderingIsArchive}
isReportModalOpen={isReportModalOpen}
isDeleteModalOpen={isDeleteModalOpen}
isSingleStory={isSingleStory}
getIsAnimating={getIsAnimating}
@ -438,7 +435,6 @@ function StorySlides({
dimensions={slideSizes.activeSlide}
isPrivateStories={renderingIsPrivate}
isArchivedStories={renderingIsArchive}
isReportModalOpen={isReportModalOpen}
isDeleteModalOpen={isDeleteModalOpen}
isSingleStory={isSingleStory}
getIsAnimating={getIsAnimating}

View File

@ -48,7 +48,6 @@ interface StateProps {
shouldSkipHistoryAnimations?: boolean;
withAnimation?: boolean;
isPrivacyModalOpen?: boolean;
isReportModalOpen?: boolean;
}
function StoryViewer({
@ -60,7 +59,6 @@ function StoryViewer({
shouldSkipHistoryAnimations,
withAnimation,
isPrivacyModalOpen,
isReportModalOpen,
}: StateProps) {
const { closeStoryViewer, closeStoryPrivacyEditor, reportStory } = getActions();
@ -165,7 +163,6 @@ function StoryViewer({
<StorySlides
isOpen={isOpen}
isReportModalOpen={isReportModalOpen}
isDeleteModalOpen={isDeleteModalOpen}
onReport={openMessageReport}
onClose={handleClose}
@ -188,17 +185,14 @@ export default memo(withGlobal((global): StateProps => {
const {
shouldSkipHistoryAnimations, storyViewer: {
storyId, peerId, isPrivacyModalOpen, origin,
}, reportModal,
},
} = selectTabState(global);
const story = peerId && storyId ? selectPeerStory(global, peerId, storyId) : undefined;
const withAnimation = selectPerformanceSettingsValue(global, 'mediaViewerAnimations');
const isReportModalOpen = Boolean(reportModal);
return {
isOpen: selectIsStoryViewerOpen(global),
shouldSkipHistoryAnimations,
isReportModalOpen,
peerId: peerId!,
storyId,
story,

View File

@ -27,11 +27,13 @@ type OwnProps = {
const STORY_ASPECT_RATIO = 9 / 16;
const PERCENTAGE_BASE = 100;
const NO_SHINY_TYPES = new Set<ApiMediaArea['type']>(['channelPost', 'uniqueGift']);
const MediaAreaOverlay = ({
story, isActive, className, isStoryPlaying,
}: OwnProps) => {
const {
openMapModal, focusMessage, closeStoryViewer, openUrl,
openMapModal, openUniqueGiftBySlug, focusMessage, closeStoryViewer, openUrl,
} = getActions();
// eslint-disable-next-line no-null/no-null
@ -85,6 +87,10 @@ const MediaAreaOverlay = ({
openUrl({ url: mediaArea.url });
break;
}
case 'uniqueGift': {
openUniqueGiftBySlug({ slug: mediaArea.slug });
break;
}
}
};
@ -100,8 +106,9 @@ const MediaAreaOverlay = ({
case 'geoPoint':
case 'venue':
case 'channelPost':
case 'url': {
const isShiny = isActive && (mediaArea.type !== 'channelPost');
case 'url':
case 'uniqueGift': {
const isShiny = isActive && !NO_SHINY_TYPES.has(mediaArea.type);
return (
<div
className={buildClassName(styles.mediaArea, isShiny && styles.shiny)}