Story: Support clickable gifts (#5477)
This commit is contained in:
parent
4c974d982b
commit
36639f1c2a
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user