Paid Media: Follow-up (#4805)

This commit is contained in:
zubiden 2024-08-06 20:06:23 +02:00 committed by Alexander Zinchuk
parent 9ad622e416
commit 3bd0f7130c
11 changed files with 34 additions and 19 deletions

View File

@ -180,7 +180,7 @@ export function buildVideoFromDocument(document: GramJs.Document, isSpoiler?: bo
}
const {
id, mimeType, thumbs, size, attributes,
id, mimeType, thumbs, size, videoThumbs, attributes,
} = document;
// eslint-disable-next-line no-restricted-globals
@ -189,14 +189,16 @@ export function buildVideoFromDocument(document: GramJs.Document, isSpoiler?: bo
}
const videoAttr = attributes
.find((a: any): a is GramJs.DocumentAttributeVideo => a instanceof GramJs.DocumentAttributeVideo);
.find((a): a is GramJs.DocumentAttributeVideo => a instanceof GramJs.DocumentAttributeVideo);
if (!videoAttr) {
return undefined;
}
const gifAttr = attributes
.find((a: any): a is GramJs.DocumentAttributeAnimated => a instanceof GramJs.DocumentAttributeAnimated);
.find((a): a is GramJs.DocumentAttributeAnimated => a instanceof GramJs.DocumentAttributeAnimated);
const hasVideoPreview = videoThumbs?.some((thumb) => thumb instanceof GramJs.VideoSize && thumb.type === 'v');
const {
duration,
@ -221,6 +223,7 @@ export function buildVideoFromDocument(document: GramJs.Document, isSpoiler?: bo
thumbnail: buildApiThumbnailFromStripped(thumbs),
size: size.toJSNumber(),
isSpoiler,
hasVideoPreview,
...(nosound && { noSound: true }),
};
}

View File

@ -98,6 +98,7 @@ export interface ApiVideo {
supportsStreaming?: boolean;
isRound?: boolean;
isGif?: boolean;
hasVideoPreview?: boolean;
isSpoiler?: boolean;
thumbnail?: ApiThumbnail;
blobUrl?: string;

View File

@ -5,9 +5,8 @@ import React, {
import type { ApiVideo } from '../../api/types';
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
import { ApiMediaFormat } from '../../api/types';
import { getVideoMediaHash } from '../../global/helpers';
import { getVideoMediaHash, getVideoPreviewMediaHash } from '../../global/helpers';
import buildClassName from '../../util/buildClassName';
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
@ -55,10 +54,15 @@ const GifButton: FC<OwnProps> = ({
const isIntersecting = useIsIntersecting(ref, observeIntersection);
const loadAndPlay = isIntersecting && !isDisabled;
const previewBlobUrl = useMedia(getVideoMediaHash(gif, 'preview'), !loadAndPlay, ApiMediaFormat.BlobUrl);
const previewHash = !gif.hasVideoPreview && gif.thumbnail && getVideoMediaHash(gif, 'pictogram');
const previewBlobUrl = useMedia(previewHash, !loadAndPlay);
const [withThumb] = useState(gif.thumbnail?.dataUri && !previewBlobUrl);
const thumbRef = useCanvasBlur(gif.thumbnail?.dataUri, !withThumb);
const videoData = useMedia(getVideoMediaHash(gif, 'full'), !loadAndPlay, ApiMediaFormat.BlobUrl);
const videoHash = getVideoPreviewMediaHash(gif) || getVideoMediaHash(gif, 'full');
const videoData = useMedia(videoHash, !loadAndPlay);
const shouldRenderVideo = Boolean(loadAndPlay && videoData);
const { isBuffered, bufferingHandlers } = useBuffering(true);
const shouldRenderSpinner = loadAndPlay && !isBuffered;
@ -154,8 +158,6 @@ const GifButton: FC<OwnProps> = ({
<canvas
ref={thumbRef}
className="thumbnail canvas-blur-setup"
// We need to always render to avoid blur re-calculation
style={isVideoReady ? 'display: none;' : undefined}
/>
)}
{previewBlobUrl && !isVideoReady && (

View File

@ -124,6 +124,7 @@ const Album: FC<OwnProps & StateProps> = ({
onCancelUpload={handleCancelUpload}
isDownloading={photo.mediaType !== 'extendedMediaPreview' && getIsDownloading(activeDownloads, photo)}
theme={theme}
noSelectControls={album.isPaidMedia}
/>
);
} else if (video) {
@ -142,6 +143,7 @@ const Album: FC<OwnProps & StateProps> = ({
onCancelUpload={handleCancelUpload}
isDownloading={video.mediaType !== 'extendedMediaPreview' && getIsDownloading(activeDownloads, video)}
theme={theme}
noSelectControls={album.isPaidMedia}
/>
);
}

View File

@ -919,7 +919,7 @@
--border-bottom-left-radius: var(--border-radius-messages-small);
--border-bottom-right-radius: var(--border-radius-messages-small);
> .media-inner {
.media-inner {
margin: 0 !important;
margin-bottom: 0.25rem !important;
}

View File

@ -17,6 +17,7 @@ import useLastCallback from '../../../../hooks/useLastCallback';
type OwnProps<T> =
(PhotoProps<T> | VideoProps<T>) & {
clickArg: number;
noSelectControls?: boolean;
};
type StateProps = {
@ -76,10 +77,10 @@ export default function withSelectControl(WrappedComponent: FC) {
return memo(withGlobal<OwnProps<unknown>>(
(global, ownProps) => {
const { clickArg } = ownProps;
const { clickArg, noSelectControls } = ownProps;
return {
isInSelectMode: selectIsInSelectMode(global),
isSelected: selectIsMessageSelected(global, clickArg),
isInSelectMode: !noSelectControls && selectIsInSelectMode(global),
isSelected: !noSelectControls && selectIsMessageSelected(global, clickArg),
};
},
)(ComponentWithSelectControl)) as typeof ComponentWithSelectControl;

View File

@ -104,7 +104,6 @@ export default function useInnerHandlers(
});
const openMediaViewerWithPhotoOrVideo = useLastCallback((withDynamicLoading: boolean): void => {
if (paidMedia && !paidMedia.isBought) return;
if (paidMedia) return; // TODO: Implement MV and remove this line
if (withDynamicLoading) {
searchChatMediaMessages({ chatId, threadId, currentMediaMessageId: messageId });
}
@ -117,12 +116,12 @@ export default function useInnerHandlers(
});
});
const handlePhotoMediaClick = useLastCallback((): void => {
const withDynamicLoading = !isScheduled;
const withDynamicLoading = !isScheduled && !paidMedia;
openMediaViewerWithPhotoOrVideo(withDynamicLoading);
});
const handleVideoMediaClick = useLastCallback(() => {
const isGif = message.content?.video?.isGif;
const withDynamicLoading = !isGif && !isScheduled;
const withDynamicLoading = !isGif && !isScheduled && !paidMedia;
openMediaViewerWithPhotoOrVideo(withDynamicLoading);
});

View File

@ -10,6 +10,7 @@ import { getUserFullName } from '../../../global/helpers';
import { selectUser } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { formatCurrency } from '../../../util/formatCurrency';
import { formatInteger } from '../../../util/textFormat';
import renderText from '../../common/helpers/renderText';
import useFlag from '../../../hooks/useFlag';
@ -233,7 +234,7 @@ function StarTopupOption({
return (
<div className={styles.option} key={option.stars} onClick={() => onClick?.(option)}>
<div className={styles.optionTop}>
+{option.stars}
+{formatInteger(option.stars)}
{/* Switch directionality for correct order. Can't use flex because https://issues.chromium.org/issues/40249030 */}
<div className={styles.stackedStars} dir={lang.isRtl ? 'ltr' : 'rtl'}>
{Array.from({ length: starsCount }).map(() => (

View File

@ -699,7 +699,9 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
} else {
const content = media as MediaContent;
global = updateChatMessage(global, chatId, id, {
content,
content: {
...content,
},
});
setGlobal(global);
}

View File

@ -319,6 +319,10 @@ export function getVideoMediaHash(video: ApiVideo | ApiDocument, target: Target)
}
}
export function getVideoPreviewMediaHash(video: ApiVideo) {
return video.hasVideoPreview ? `document${video.id}?size=v` : undefined;
}
export function getDocumentMediaHash(document: ApiDocument, target: Target) {
const base = `document${document.id}`;

View File

@ -1245,7 +1245,7 @@ export function selectCanForwardMessages<T extends GlobalState>(global: T, chatI
return messageIds
.map((id) => messages[id])
.every((message) => !hasMessageTtl(message)
.every((message) => message && !hasMessageTtl(message)
&& (message.isForwardingAllowed || isServiceNotificationMessage(message)));
}