Media Viewer: Fix document real size (#6177)
This commit is contained in:
parent
eb7dff433c
commit
c7bf1ebd72
@ -136,6 +136,7 @@ export default tseslint.config(
|
||||
disallowTypeAnnotations: false,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
|
||||
@ -153,7 +153,7 @@ export interface ApiDocument {
|
||||
previewPhotoSizes?: ApiPhotoSize[];
|
||||
previewBlobUrl?: string;
|
||||
innerMediaType?: 'photo' | 'video';
|
||||
mediaSize?: ApiDimensions & { fromDocumentAttribute?: boolean };
|
||||
mediaSize?: ApiDimensions & { fromDocumentAttribute?: boolean; fromPreload?: true };
|
||||
}
|
||||
|
||||
export interface ApiContact {
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
} from '../../global/helpers';
|
||||
import { isIpRevealingMedia } from '../../util/media/ipRevealingMedia';
|
||||
import { getDocumentExtension, getDocumentHasPreview } from './helpers/documentInfo';
|
||||
import { preloadDocumentMedia } from './helpers/preloadDocumentMedia';
|
||||
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import { useIsIntersecting } from '../../hooks/useIntersectionObserver';
|
||||
@ -119,10 +120,26 @@ const Document = ({
|
||||
const localBlobUrl = hasPreview ? document.previewBlobUrl : undefined;
|
||||
const previewData = useMedia(getDocumentMediaHash(document, 'pictogram'), !isIntersecting);
|
||||
|
||||
const shouldForceDownload = document.innerMediaType === 'photo' && !document.mediaSize?.fromDocumentAttribute;
|
||||
const shouldForceDownload = document.innerMediaType === 'photo' && document.mediaSize
|
||||
&& !document.mediaSize.fromDocumentAttribute && !document.mediaSize.fromPreload;
|
||||
|
||||
const withMediaViewer = onMediaClick && document.innerMediaType && !shouldForceDownload;
|
||||
|
||||
useEffect(() => {
|
||||
const fileEl = ref.current;
|
||||
if (!withMediaViewer || !fileEl || !message) return;
|
||||
|
||||
const onHover = () => {
|
||||
preloadDocumentMedia(message);
|
||||
};
|
||||
|
||||
fileEl.addEventListener('mouseenter', onHover);
|
||||
|
||||
return () => {
|
||||
fileEl.removeEventListener('mouseenter', onHover);
|
||||
};
|
||||
}, [withMediaViewer, message]);
|
||||
|
||||
const handleDownload = useLastCallback(() => {
|
||||
downloadMedia({ media: document, originMessage: message });
|
||||
});
|
||||
|
||||
@ -225,21 +225,21 @@ const PremiumProgress: FC<OwnProps> = ({
|
||||
|
||||
const renderProgressLayer = (
|
||||
isPositive: boolean,
|
||||
layerProgress: number,
|
||||
currentProgress: number,
|
||||
layerClassName?: string,
|
||||
disableTransition?: boolean,
|
||||
) => {
|
||||
const className = isPositive ? styles.positiveProgress : styles.negativeProgress;
|
||||
const typeClass = isPositive ? styles.positiveProgress : styles.negativeProgress;
|
||||
const progressVar = '--layer-progress';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName(
|
||||
className,
|
||||
typeClass,
|
||||
layerClassName,
|
||||
disableTransition && styles.noTransition,
|
||||
)}
|
||||
style={`${progressVar}: ${layerProgress}`}
|
||||
style={`${progressVar}: ${currentProgress}`}
|
||||
>
|
||||
<div className={styles.left}>
|
||||
<span>{displayLeftText}</span>
|
||||
|
||||
70
src/components/common/helpers/preloadDocumentMedia.ts
Normal file
70
src/components/common/helpers/preloadDocumentMedia.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { getGlobal, setGlobal } from '../../../global';
|
||||
|
||||
import type { ApiDocument, ApiMessage } from '../../../api/types';
|
||||
|
||||
import {
|
||||
getDocumentMediaHash, getMediaFormat, getMessageDocumentPhoto, getMessageDocumentVideo,
|
||||
} from '../../../global/helpers';
|
||||
import { updateChatMessage } from '../../../global/reducers';
|
||||
import { selectChatMessage } from '../../../global/selectors';
|
||||
import { IS_PROGRESSIVE_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||
import { preloadImage, preloadVideo } from '../../../util/files';
|
||||
import { fetch } from '../../../util/mediaLoader';
|
||||
import LimitedMap from '../../../util/primitives/LimitedMap';
|
||||
|
||||
const preloadedHashes = new LimitedMap<string, void>(100);
|
||||
|
||||
export async function preloadDocumentMedia(mediaContainer: ApiMessage) {
|
||||
const video = getMessageDocumentVideo(mediaContainer);
|
||||
const photo = getMessageDocumentPhoto(mediaContainer);
|
||||
|
||||
const media = video || photo;
|
||||
|
||||
// Skip large photos that were not processed by the server
|
||||
const shouldSkipPhoto = photo && photo.mediaSize && !photo.mediaSize.fromDocumentAttribute;
|
||||
if (!media || media.previewBlobUrl || shouldSkipPhoto) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = getDocumentMediaHash(media, 'full');
|
||||
if (!hash || preloadedHashes.has(hash)) {
|
||||
return;
|
||||
}
|
||||
|
||||
preloadedHashes.set(hash, undefined);
|
||||
|
||||
const url = await fetch(hash, getMediaFormat(media, 'full'));
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
let dimensions: ApiDocument['mediaSize'] | undefined;
|
||||
|
||||
if (video && IS_PROGRESSIVE_SUPPORTED) {
|
||||
const videoEl = await preloadVideo(url);
|
||||
dimensions = { width: videoEl.videoWidth, height: videoEl.videoHeight, fromPreload: true };
|
||||
}
|
||||
|
||||
if (photo) {
|
||||
const img = await preloadImage(url);
|
||||
dimensions = { width: img.naturalWidth, height: img.naturalHeight, fromPreload: true };
|
||||
}
|
||||
|
||||
if (!dimensions || dimensions.width <= 0 || dimensions.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let global = getGlobal();
|
||||
const message = selectChatMessage(global, mediaContainer.chatId, mediaContainer.id);
|
||||
if (!message || !message.content.document) return;
|
||||
global = updateChatMessage(global, mediaContainer.chatId, mediaContainer.id, {
|
||||
content: {
|
||||
...message.content,
|
||||
document: {
|
||||
...message.content.document,
|
||||
mediaSize: dimensions,
|
||||
},
|
||||
},
|
||||
});
|
||||
setGlobal(global);
|
||||
}
|
||||
@ -64,6 +64,7 @@ type StateProps = {
|
||||
enum ContentType {
|
||||
Main,
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
Settings,
|
||||
Archived,
|
||||
|
||||
|
||||
@ -257,14 +257,14 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
|
||||
}, [globalSearchChatId, selectedSearchDate]);
|
||||
|
||||
const version = useMemo(() => {
|
||||
let version = '';
|
||||
let fullVersion = '';
|
||||
if (IS_TAURI && window.tauri.version) {
|
||||
version = `Tauri ${window.tauri.version} | `;
|
||||
fullVersion = `Tauri ${window.tauri.version} | `;
|
||||
}
|
||||
|
||||
version += `${APP_NAME} ${versionString}`;
|
||||
fullVersion += `${APP_NAME} ${versionString}`;
|
||||
|
||||
return version;
|
||||
return fullVersion;
|
||||
}, [versionString]);
|
||||
|
||||
return (
|
||||
|
||||
@ -109,7 +109,7 @@ export const useMediaProps = ({
|
||||
}
|
||||
|
||||
if (isDocument) {
|
||||
return media.mediaSize!;
|
||||
return media.mediaSize || FALLBACK_DIMENSIONS;
|
||||
}
|
||||
|
||||
if (isPhoto) {
|
||||
|
||||
@ -145,12 +145,15 @@ type StateProps = {
|
||||
};
|
||||
|
||||
enum Content {
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
Loading,
|
||||
Restricted,
|
||||
StarsRequired,
|
||||
PremiumRequired,
|
||||
AccountInfo,
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
ContactGreeting,
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
NoMessages,
|
||||
MessageList,
|
||||
}
|
||||
@ -180,6 +183,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
|
||||
isChannelWithAvatars,
|
||||
canPost,
|
||||
isSynced,
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
isChatMonoforum,
|
||||
isReady,
|
||||
isChatWithSelf,
|
||||
|
||||
@ -478,8 +478,8 @@ const AttachmentModal: FC<OwnProps & StateProps> = ({
|
||||
const everyPhoto = renderingAttachments.every((a) => SUPPORTED_PHOTO_CONTENT_TYPES.has(a.mimeType));
|
||||
const everyVideo = renderingAttachments.every((a) => SUPPORTED_VIDEO_CONTENT_TYPES.has(a.mimeType));
|
||||
const everyAudio = renderingAttachments.every((a) => SUPPORTED_AUDIO_CONTENT_TYPES.has(a.mimeType));
|
||||
const hasAnyPhoto = renderingAttachments.some((a) => SUPPORTED_PHOTO_CONTENT_TYPES.has(a.mimeType));
|
||||
return [everyPhoto, everyVideo, everyAudio, hasAnyPhoto];
|
||||
const anyPhoto = renderingAttachments.some((a) => SUPPORTED_PHOTO_CONTENT_TYPES.has(a.mimeType));
|
||||
return [everyPhoto, everyVideo, everyAudio, anyPhoto];
|
||||
}, [renderingAttachments, isQuickGallery]);
|
||||
|
||||
const hasAnySpoilerable = useMemo(() => {
|
||||
|
||||
@ -287,13 +287,14 @@ const ToDoListModal = ({
|
||||
});
|
||||
|
||||
function renderHeader() {
|
||||
const title = isAddTaskMode ? 'TitleAppendToDoList' : editingMessage ? 'TitleEditToDoList' : 'TitleNewToDoList';
|
||||
const modalTitle = isAddTaskMode ? 'TitleAppendToDoList'
|
||||
: editingMessage ? 'TitleEditToDoList' : 'TitleNewToDoList';
|
||||
return (
|
||||
<div className="modal-header-condensed">
|
||||
<Button round color="translucent" size="smaller" ariaLabel={lang('AriaToDoCancel')} onClick={onClear}>
|
||||
<Icon name="close" />
|
||||
</Button>
|
||||
<div className="modal-title">{lang(title)}</div>
|
||||
<div className="modal-title">{lang(modalTitle)}</div>
|
||||
<Button
|
||||
color="primary"
|
||||
size="smaller"
|
||||
|
||||
@ -784,10 +784,6 @@ const ActionMessageText = ({
|
||||
case 'suggestedPostRefund': {
|
||||
const { payerInitiated } = action;
|
||||
|
||||
const replyMessage = message.replyInfo?.type === 'message' && message.replyInfo.replyToMsgId
|
||||
? selectChatMessage(global, chatId, message.replyInfo.replyToMsgId)
|
||||
: undefined;
|
||||
|
||||
const postSender = replyMessage ? selectSender(global, replyMessage) : sender;
|
||||
const postSenderTitle = postSender && getPeerTitle(lang, postSender);
|
||||
const postSenderLink = renderPeerLink(postSender?.id, postSenderTitle || userFallbackText, asPreview);
|
||||
@ -822,9 +818,6 @@ const ActionMessageText = ({
|
||||
const { isRejected, isBalanceTooLow, rejectComment } = action;
|
||||
|
||||
if (isRejected) {
|
||||
const senderTitle = sender && getPeerTitle(lang, sender);
|
||||
const senderLink = renderPeerLink(sender?.id, senderTitle || userFallbackText, asPreview);
|
||||
|
||||
return translateWithYou(
|
||||
lang,
|
||||
rejectComment ? 'SuggestedPostRejectedWithReason' : 'SuggestedPostRejected',
|
||||
@ -835,10 +828,6 @@ const ActionMessageText = ({
|
||||
}
|
||||
|
||||
if (isBalanceTooLow) {
|
||||
const replyMessage = message.replyInfo?.type === 'message' && message.replyInfo.replyToMsgId
|
||||
? selectChatMessage(global, chatId, message.replyInfo.replyToMsgId)
|
||||
: undefined;
|
||||
|
||||
const replyMessageSender = replyMessage ? selectSender(global, replyMessage) : sender;
|
||||
const replyPeerTitle = replyMessageSender && getPeerTitle(lang, replyMessageSender);
|
||||
const userLink = renderPeerLink(replyMessageSender?.id, replyPeerTitle || userFallbackText, asPreview);
|
||||
|
||||
@ -42,11 +42,11 @@ function SpeedingDiamond({ onMouseMove }: OwnProps) {
|
||||
if (!isAnimating) return false;
|
||||
|
||||
const t = Math.min((Date.now() - startAt) / SLOWDOWN_DURATION, 1);
|
||||
const speed = (MAX_SPEED - MIN_SPEED) * (1 - transition(t));
|
||||
const newSpeed = (MAX_SPEED - MIN_SPEED) * (1 - transition(t));
|
||||
|
||||
setSpeed(speed);
|
||||
setSpeed(newSpeed);
|
||||
|
||||
isAnimating = t < 1 && speed > 1;
|
||||
isAnimating = t < 1 && newSpeed > 1;
|
||||
|
||||
return isAnimating;
|
||||
}, requestMutation);
|
||||
|
||||
@ -136,10 +136,10 @@ const GiftModalResaleScreen: FC<OwnProps & StateProps> = ({
|
||||
preloadBackwards={RESALE_GIFTS_LIMIT}
|
||||
scrollContainerClosest={`.${styles.resaleScreenRoot}`}
|
||||
>
|
||||
{resellGifts?.map((gift) => (
|
||||
{resellGifts?.map((g) => (
|
||||
<GiftItemStar
|
||||
key={gift.id}
|
||||
gift={gift}
|
||||
key={g.id}
|
||||
gift={g}
|
||||
observeIntersection={observe}
|
||||
isResale
|
||||
onClick={onGiftClick}
|
||||
|
||||
@ -276,7 +276,7 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
|
||||
|
||||
const handleModelMenuItemClick = useLastCallback((attribute: ApiStarGiftAttributeModel) => {
|
||||
if (!counters) return;
|
||||
const attributes = filter.modelAttributes || [];
|
||||
const modelAttributes = filter.modelAttributes || [];
|
||||
const modelAttribute
|
||||
= counters.find((counter): counter is ApiStarGiftAttributeCounter<StarGiftAttributeIdModel> =>
|
||||
counter.attribute.type === 'model' && counter.attribute.documentId === attribute.sticker.id,
|
||||
@ -284,10 +284,10 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
|
||||
|
||||
if (!modelAttribute) return;
|
||||
|
||||
const isActive = attributes.some((item) => item.documentId === modelAttribute.documentId);
|
||||
const isActive = modelAttributes.some((item) => item.documentId === modelAttribute.documentId);
|
||||
const updatedAttributes = isActive
|
||||
? attributes.filter((item) => item.documentId !== modelAttribute.documentId)
|
||||
: [...attributes, modelAttribute];
|
||||
? modelAttributes.filter((item) => item.documentId !== modelAttribute.documentId)
|
||||
: [...modelAttributes, modelAttribute];
|
||||
updateResaleGiftsFilter({ filter: {
|
||||
...filter,
|
||||
modelAttributes: updatedAttributes,
|
||||
@ -296,7 +296,7 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
|
||||
|
||||
const handlePatternMenuItemClick = useLastCallback((attribute: ApiStarGiftAttributePattern) => {
|
||||
if (!counters) return;
|
||||
const attributes = filter.patternAttributes || [];
|
||||
const patternAttributes = filter.patternAttributes || [];
|
||||
const patternAttribute = counters.find(
|
||||
(counter): counter is ApiStarGiftAttributeCounter<ApiStarGiftAttributeIdPattern> =>
|
||||
counter.attribute.type === 'pattern' && counter.attribute.documentId === attribute.sticker.id,
|
||||
@ -304,10 +304,10 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
|
||||
|
||||
if (!patternAttribute) return;
|
||||
|
||||
const isActive = attributes.some((item) => item.documentId === patternAttribute.documentId);
|
||||
const isActive = patternAttributes.some((item) => item.documentId === patternAttribute.documentId);
|
||||
const updatedAttributes = isActive
|
||||
? attributes.filter((item) => item.documentId !== patternAttribute.documentId)
|
||||
: [...attributes, patternAttribute];
|
||||
? patternAttributes.filter((item) => item.documentId !== patternAttribute.documentId)
|
||||
: [...patternAttributes, patternAttribute];
|
||||
updateResaleGiftsFilter({ filter: {
|
||||
...filter,
|
||||
patternAttributes: updatedAttributes,
|
||||
@ -316,7 +316,7 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
|
||||
|
||||
const handleBackdropMenuItemClick = useLastCallback((attribute: ApiStarGiftAttributeBackdrop) => {
|
||||
if (!counters) return;
|
||||
const attributes = filter.backdropAttributes || [];
|
||||
const backdropAttributes = filter.backdropAttributes || [];
|
||||
const backdropAttribute = counters.find(
|
||||
(counter): counter is ApiStarGiftAttributeCounter<ApiStarGiftAttributeIdBackdrop> =>
|
||||
counter.attribute.type === 'backdrop' && counter.attribute.backdropId === attribute.backdropId,
|
||||
@ -324,10 +324,10 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
|
||||
|
||||
if (!backdropAttribute) return;
|
||||
|
||||
const isActive = attributes.some((item) => item.backdropId === backdropAttribute.backdropId);
|
||||
const isActive = backdropAttributes.some((item) => item.backdropId === backdropAttribute.backdropId);
|
||||
const updatedAttributes = isActive
|
||||
? attributes.filter((item) => item.backdropId !== backdropAttribute.backdropId)
|
||||
: [...attributes, backdropAttribute];
|
||||
? backdropAttributes.filter((item) => item.backdropId !== backdropAttribute.backdropId)
|
||||
: [...backdropAttributes, backdropAttribute];
|
||||
updateResaleGiftsFilter({ filter: {
|
||||
...filter,
|
||||
backdropAttributes: updatedAttributes,
|
||||
|
||||
@ -218,12 +218,12 @@ const GiftInfoModal = ({
|
||||
: gift?.ownerId === currentUserId || isSelfUnique
|
||||
);
|
||||
|
||||
function getResalePrice(shouldPayInTon?: boolean) {
|
||||
function getResalePrice(isInTon?: boolean) {
|
||||
if (!isGiftUnique) return undefined;
|
||||
const amounts = gift.resellPrice;
|
||||
if (!amounts) return undefined;
|
||||
|
||||
if (gift?.resaleTonOnly || shouldPayInTon) {
|
||||
if (gift?.resaleTonOnly || isInTon) {
|
||||
return amounts.find((amount) => amount.currency === TON_CURRENCY_CODE);
|
||||
}
|
||||
|
||||
|
||||
@ -180,9 +180,9 @@ function MessageStatistics({
|
||||
|
||||
<div ref={containerRef}>
|
||||
{GRAPHS.map((graph) => {
|
||||
const isReady = loadedCharts.current.has(graph) && !errorCharts.current.has(graph);
|
||||
const isGraphReady = loadedCharts.current.has(graph) && !errorCharts.current.has(graph);
|
||||
return (
|
||||
<div className={buildClassName(styles.graph, !isReady && styles.hidden)} />
|
||||
<div className={buildClassName(styles.graph, !isGraphReady && styles.hidden)} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@ -211,9 +211,9 @@ const Statistics = ({
|
||||
|
||||
<div ref={containerRef}>
|
||||
{graphs.map((graph) => {
|
||||
const isReady = loadedCharts.current.has(graph) && !errorCharts.current.has(graph);
|
||||
const isGraphReady = loadedCharts.current.has(graph) && !errorCharts.current.has(graph);
|
||||
return (
|
||||
<div className={buildClassName(styles.graph, !isReady && styles.hidden)} />
|
||||
<div className={buildClassName(styles.graph, !isGraphReady && styles.hidden)} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@ -185,9 +185,9 @@ function StoryStatistics({
|
||||
|
||||
<div ref={containerRef}>
|
||||
{GRAPHS.map((graph) => {
|
||||
const isReady = loadedCharts.current.has(graph) && !errorCharts.current.has(graph);
|
||||
const isGraphReady = loadedCharts.current.has(graph) && !errorCharts.current.has(graph);
|
||||
return (
|
||||
<div className={buildClassName(styles.graph, !isReady && styles.hidden)} />
|
||||
<div className={buildClassName(styles.graph, !isGraphReady && styles.hidden)} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@ -9,7 +9,7 @@ import type {
|
||||
} from '../../types';
|
||||
import { PaymentStep } from '../../../types';
|
||||
|
||||
import { DEBUG_PAYMENT_SMART_GLOCAL } from '../../../config';
|
||||
import { DEBUG_PAYMENT_SMART_GLOCAL, STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../../config';
|
||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
import * as langProvider from '../../../util/oldLangProvider';
|
||||
import { getStripeError } from '../../../util/payments/stripe';
|
||||
@ -1085,13 +1085,14 @@ async function payInputStarInvoice<T extends GlobalState>(
|
||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
) {
|
||||
const actions = getActions();
|
||||
const isTon = inputInvoice.type === 'stargiftResale' && inputInvoice.currency === 'TON';
|
||||
const isTon = inputInvoice.type === 'stargiftResale' && inputInvoice.currency === TON_CURRENCY_CODE;
|
||||
const balance = isTon ? global.ton?.balance : global.stars?.balance;
|
||||
const currency = isTon ? TON_CURRENCY_CODE : STARS_CURRENCY_CODE;
|
||||
|
||||
if (balance === undefined) return;
|
||||
|
||||
if (balance.amount < price) {
|
||||
actions.openStarsBalanceModal({ currency: isTon ? 'TON' : 'XTR', tabId });
|
||||
actions.openStarsBalanceModal({ currency, tabId });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1126,12 +1127,10 @@ async function payInputStarInvoice<T extends GlobalState>(
|
||||
|
||||
const formPrice = form.invoice.totalAmount;
|
||||
if (formPrice !== price) {
|
||||
const isTon = inputInvoice.type === 'stargiftResale' && inputInvoice.currency === 'TON';
|
||||
|
||||
actions.openPriceConfirmModal({
|
||||
originalAmount: price,
|
||||
newAmount: formPrice,
|
||||
currency: isTon ? 'TON' : 'XTR',
|
||||
currency,
|
||||
directInfo: {
|
||||
inputInvoice,
|
||||
formId: form.formId,
|
||||
|
||||
@ -3,6 +3,7 @@ import { useEffect } from '../lib/teact/teact';
|
||||
import { ApiMediaFormat } from '../api/types';
|
||||
|
||||
import { selectIsSynced } from '../global/selectors';
|
||||
import { IS_PROGRESSIVE_SUPPORTED } from '../util/browser/windowEnvironment';
|
||||
import * as mediaLoader from '../util/mediaLoader';
|
||||
import useSelector from './data/useSelector';
|
||||
import useForceUpdate from './useForceUpdate';
|
||||
@ -13,7 +14,11 @@ const useMedia = (
|
||||
mediaFormat = ApiMediaFormat.BlobUrl,
|
||||
delay?: number | false,
|
||||
) => {
|
||||
const mediaData = mediaHash ? mediaLoader.getFromMemory(mediaHash) : undefined;
|
||||
const isStreaming = IS_PROGRESSIVE_SUPPORTED && mediaFormat === ApiMediaFormat.Progressive;
|
||||
const mediaData = mediaHash
|
||||
? (isStreaming ? mediaLoader.getProgressiveUrl(mediaHash)
|
||||
: mediaLoader.getFromMemory(mediaHash)) : undefined;
|
||||
|
||||
const forceUpdate = useForceUpdate();
|
||||
const isSynced = useSelector(selectIsSynced);
|
||||
|
||||
|
||||
@ -23,8 +23,11 @@ export default function useMediaWithLoadProgress(
|
||||
delay?: number | false,
|
||||
isHtmlAllowed = false,
|
||||
) {
|
||||
const mediaData = mediaHash ? mediaLoader.getFromMemory(mediaHash) : undefined;
|
||||
const isStreaming = IS_PROGRESSIVE_SUPPORTED && mediaFormat === ApiMediaFormat.Progressive;
|
||||
const mediaData = mediaHash
|
||||
? (isStreaming ? mediaLoader.getProgressiveUrl(mediaHash)
|
||||
: mediaLoader.getFromMemory(mediaHash)) : undefined;
|
||||
|
||||
const forceUpdate = useForceUpdate();
|
||||
const isSynced = useSelector(selectIsSynced);
|
||||
const id = useUniqueId();
|
||||
|
||||
@ -9,7 +9,7 @@ import createMockedChatBannedRights from './createMockedChatBannedRights';
|
||||
import { MOCK_STARTING_DATE } from './MockTypes';
|
||||
|
||||
export default function createMockedChannel(id: string, mockData: MockTypes): Api.Channel {
|
||||
const channel = mockData.channels.find((channel) => channel.id === id);
|
||||
const channel = mockData.channels.find((c) => c.id === id);
|
||||
|
||||
if (!channel) throw Error('No such channel ' + id);
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import Api from '../../tl/api';
|
||||
import { MOCK_STARTING_DATE } from './MockTypes';
|
||||
|
||||
export default function createMockedChat(id: string, mockData: MockTypes): Api.Chat {
|
||||
const chat = mockData.chats.find((chat) => chat.id === id);
|
||||
const chat = mockData.chats.find((c) => c.id === id);
|
||||
|
||||
if (!chat) throw Error('No such chat ' + id);
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import type { MockTypes } from './MockTypes';
|
||||
import Api from '../../tl/api';
|
||||
|
||||
export default function createMockedChatAdminRights(chatId: string, mockData: MockTypes) {
|
||||
const channel = mockData.channels.find((channel) => channel.id === chatId);
|
||||
const channel = mockData.channels.find((c) => c.id === chatId);
|
||||
|
||||
if (!channel) throw Error('No such channel ' + chatId);
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import type { MockTypes } from './MockTypes';
|
||||
import Api from '../../tl/api';
|
||||
|
||||
export default function createMockedChatBannedRights(chatId: string, mockData: MockTypes) {
|
||||
const channel = mockData.channels.find((channel) => channel.id === chatId);
|
||||
const channel = mockData.channels.find((c) => c.id === chatId);
|
||||
|
||||
if (!channel) throw Error('No such channel ' + chatId);
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import Api from '../../tl/api';
|
||||
import createMockedTypeInputPeer from './createMockedTypeInputPeer';
|
||||
|
||||
export default function createMockedDialogFilter(id: number, mockData: MockTypes) {
|
||||
const dialogFilter = mockData.dialogFilters.find((dialogFilter) => dialogFilter.id === id);
|
||||
const dialogFilter = mockData.dialogFilters.find((f) => f.id === id);
|
||||
|
||||
if (!dialogFilter) throw Error('No such dialog filter ' + id);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import type { MockTypes } from './MockTypes';
|
||||
import Api from '../../tl/api';
|
||||
|
||||
export default function createMockedTypeInputPeer(id: string, mockData: MockTypes): Api.TypeInputPeer {
|
||||
const user = mockData.users.find((user) => user.id === id);
|
||||
const user = mockData.users.find((u) => u.id === id);
|
||||
if (user) {
|
||||
return new Api.InputPeerUser({
|
||||
userId: BigInt(id),
|
||||
@ -13,14 +13,14 @@ export default function createMockedTypeInputPeer(id: string, mockData: MockType
|
||||
});
|
||||
}
|
||||
|
||||
const chat = mockData.chats.find((chat) => chat.id === id);
|
||||
const chat = mockData.chats.find((c) => c.id === id);
|
||||
if (chat) {
|
||||
return new Api.InputPeerChat({
|
||||
chatId: BigInt(id),
|
||||
});
|
||||
}
|
||||
|
||||
const channel = mockData.channels.find((channel) => channel.id === id);
|
||||
const channel = mockData.channels.find((c) => c.id === id);
|
||||
if (channel) {
|
||||
return new Api.InputPeerChannel({
|
||||
channelId: BigInt(Number(id) + 1000000000),
|
||||
|
||||
@ -5,21 +5,21 @@ import type { MockTypes } from './MockTypes';
|
||||
import Api from '../../tl/api';
|
||||
|
||||
export default function createMockedTypePeer(id: string, mockData: MockTypes): Api.TypePeer {
|
||||
const user = mockData.users.find((user) => user.id === id);
|
||||
const user = mockData.users.find((u) => u.id === id);
|
||||
if (user) {
|
||||
return new Api.PeerUser({
|
||||
userId: BigInt(id),
|
||||
});
|
||||
}
|
||||
|
||||
const chat = mockData.chats.find((chat) => chat.id === id);
|
||||
const chat = mockData.chats.find((c) => c.id === id);
|
||||
if (chat) {
|
||||
return new Api.PeerChat({
|
||||
chatId: BigInt(id),
|
||||
});
|
||||
}
|
||||
|
||||
const channel = mockData.channels.find((channel) => channel.id === id);
|
||||
const channel = mockData.channels.find((c) => c.id === id);
|
||||
if (channel) {
|
||||
return new Api.PeerChannel({
|
||||
channelId: BigInt(Number(id) + 1000000000),
|
||||
|
||||
@ -5,7 +5,7 @@ import type { MockTypes } from './MockTypes';
|
||||
import Api from '../../tl/api';
|
||||
|
||||
export default function createMockedUser(id: string, mockData: MockTypes): Api.User {
|
||||
const user = mockData.users.find((user) => user.id === id);
|
||||
const user = mockData.users.find((u) => u.id === id);
|
||||
|
||||
if (!user) throw Error('No such user ' + id);
|
||||
|
||||
|
||||
@ -118,7 +118,6 @@ export function removeCallback(url: string, callbackUniqueId: string) {
|
||||
export function getProgressiveUrl(url: string) {
|
||||
const base = new URL(`${PROGRESSIVE_URL_PREFIX}${url}`, window.location.href);
|
||||
if (ACCOUNT_SLOT) base.searchParams.set('account', ACCOUNT_SLOT.toString());
|
||||
memoryCache.set(url, base.href); // Needed for hooks to detect document as already loaded and apply URL
|
||||
return base.href;
|
||||
}
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ export function fastRaf(callback: NoneToVoidFunction, withTimeoutFallback = fals
|
||||
|
||||
if (fastRafCallbacks) {
|
||||
const currentCallbacks = fastRafCallbacks;
|
||||
currentTimeoutCallbacks.forEach((callback) => currentCallbacks.delete(callback));
|
||||
currentTimeoutCallbacks.forEach((c) => currentCallbacks.delete(c));
|
||||
}
|
||||
fastRafFallbackCallbacks = undefined;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user