Fix DPR update when switching monitors (#4155)
This commit is contained in:
parent
16c2fdbc04
commit
e9dacf35f3
@ -24,10 +24,10 @@ import { compact } from '../../../util/iteratees';
|
||||
|
||||
import useAppLayout from '../../../hooks/useAppLayout';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import { useFullscreenStatus } from '../../../hooks/useFullscreen';
|
||||
import { useIntersectionObserver, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import { useFullscreenStatus } from '../../../hooks/window/useFullscreen';
|
||||
import useGroupCallVideoLayout from './hooks/useGroupCallVideoLayout';
|
||||
|
||||
import Button from '../../ui/Button';
|
||||
|
||||
@ -15,7 +15,6 @@ import { hexToRgb } from '../../util/switchTheme';
|
||||
import { IS_ELECTRON } from '../../util/windowEnvironment';
|
||||
|
||||
import useColorFilter from '../../hooks/stickers/useColorFilter';
|
||||
import useBackgroundMode, { isBackgroundModeActive } from '../../hooks/useBackgroundMode';
|
||||
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
||||
import useHeavyAnimationCheck, { isHeavyAnimating } from '../../hooks/useHeavyAnimationCheck';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
@ -25,6 +24,7 @@ import { useStateRef } from '../../hooks/useStateRef';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
import useThrottledCallback from '../../hooks/useThrottledCallback';
|
||||
import useUniqueId from '../../hooks/useUniqueId';
|
||||
import useBackgroundMode, { isBackgroundModeActive } from '../../hooks/window/useBackgroundMode';
|
||||
|
||||
export type OwnProps = {
|
||||
ref?: RefObject<HTMLDivElement>;
|
||||
|
||||
@ -8,9 +8,10 @@ import type { AvatarSize } from './Avatar';
|
||||
|
||||
import { selectPeerStories, selectTheme, selectUser } from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { DPR } from '../../util/windowEnvironment';
|
||||
import { REM } from './helpers/mediaDimensions';
|
||||
|
||||
import useDevicePixelRatio from '../../hooks/window/useDevicePixelRatio';
|
||||
|
||||
interface OwnProps {
|
||||
// eslint-disable-next-line react/no-unused-prop-types
|
||||
peerId: string;
|
||||
@ -27,15 +28,15 @@ interface StateProps {
|
||||
}
|
||||
|
||||
const SIZES: Record<AvatarSize, number> = {
|
||||
micro: 1.125 * DPR * REM,
|
||||
tiny: 2.125 * DPR * REM,
|
||||
mini: 1.625 * DPR * REM,
|
||||
small: 2.25 * DPR * REM,
|
||||
'small-mobile': 2.625 * DPR * REM,
|
||||
medium: 2.875 * DPR * REM,
|
||||
large: 3.5 * DPR * REM,
|
||||
giant: 5.125 * DPR * REM,
|
||||
jumbo: 7.625 * DPR * REM,
|
||||
micro: 1.125 * REM,
|
||||
tiny: 2.125 * REM,
|
||||
mini: 1.625 * REM,
|
||||
small: 2.25 * REM,
|
||||
'small-mobile': 2.625 * REM,
|
||||
medium: 2.875 * REM,
|
||||
large: 3.5 * REM,
|
||||
giant: 5.125 * REM,
|
||||
jumbo: 7.625 * REM,
|
||||
};
|
||||
|
||||
const BLUE = ['#34C578', '#3CA3F3'];
|
||||
@ -43,8 +44,8 @@ const GREEN = ['#C9EB38', '#09C167'];
|
||||
const PURPLE = ['#A667FF', '#55A5FF'];
|
||||
const GRAY = '#C4C9CC';
|
||||
const DARK_GRAY = '#737373';
|
||||
const STROKE_WIDTH = 0.125 * DPR * REM;
|
||||
const STROKE_WIDTH_READ = 0.0625 * DPR * REM;
|
||||
const STROKE_WIDTH = 0.125 * REM;
|
||||
const STROKE_WIDTH_READ = 0.0625 * REM;
|
||||
const GAP_PERCENT = 2;
|
||||
const SEGMENTS_MAX = 45; // More than this breaks rendering in Safari and Chrome
|
||||
|
||||
@ -66,6 +67,8 @@ function AvatarStoryCircle({
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const ref = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
const dpr = useDevicePixelRatio();
|
||||
|
||||
const values = useMemo(() => {
|
||||
return (storyIds || []).reduce((acc, id) => {
|
||||
acc.total += 1;
|
||||
@ -84,20 +87,21 @@ function AvatarStoryCircle({
|
||||
|
||||
drawGradientCircle({
|
||||
canvas: ref.current,
|
||||
size: SIZES[size],
|
||||
size: SIZES[size] * dpr,
|
||||
segmentsCount: values.total,
|
||||
color: isCloseFriend ? 'green' : 'blue',
|
||||
readSegmentsCount: values.read,
|
||||
withExtraGap,
|
||||
readSegmentColor: appTheme === 'dark' ? DARK_GRAY : GRAY,
|
||||
dpr,
|
||||
});
|
||||
}, [appTheme, isCloseFriend, size, values.read, values.total, withExtraGap]);
|
||||
}, [appTheme, isCloseFriend, size, values.read, values.total, withExtraGap, dpr]);
|
||||
|
||||
if (!values.total) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const maxSize = SIZES[size] / DPR;
|
||||
const maxSize = SIZES[size];
|
||||
|
||||
return (
|
||||
<canvas
|
||||
@ -129,6 +133,7 @@ export function drawGradientCircle({
|
||||
readSegmentsCount = 0,
|
||||
withExtraGap = false,
|
||||
readSegmentColor,
|
||||
dpr,
|
||||
}: {
|
||||
canvas: HTMLCanvasElement;
|
||||
size: number;
|
||||
@ -137,6 +142,7 @@ export function drawGradientCircle({
|
||||
readSegmentsCount?: number;
|
||||
withExtraGap?: boolean;
|
||||
readSegmentColor: string;
|
||||
dpr: number;
|
||||
}) {
|
||||
if (segmentsCount > SEGMENTS_MAX) {
|
||||
readSegmentsCount = Math.round(readSegmentsCount * (SEGMENTS_MAX / segmentsCount));
|
||||
@ -144,7 +150,7 @@ export function drawGradientCircle({
|
||||
segmentsCount = SEGMENTS_MAX;
|
||||
}
|
||||
|
||||
const strokeModifier = Math.max(Math.max(size - SIZES.large, 0) / DPR / REM / 1.5, 1);
|
||||
const strokeModifier = Math.max(Math.max(size - SIZES.large * dpr, 0) / REM / 1.5, 1);
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) {
|
||||
|
||||
@ -28,7 +28,7 @@ import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useMediaTransition from '../../hooks/useMediaTransition';
|
||||
import useResizeObserver from '../../hooks/useResizeObserver';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../hooks/window/useWindowSize';
|
||||
|
||||
import Button from '../ui/Button';
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
|
||||
@ -20,6 +20,7 @@ import useMedia from '../../hooks/useMedia';
|
||||
import useMediaTransition from '../../hooks/useMediaTransition';
|
||||
import useThumbnail from '../../hooks/useThumbnail';
|
||||
import useUniqueId from '../../hooks/useUniqueId';
|
||||
import useDevicePixelRatio from '../../hooks/window/useDevicePixelRatio';
|
||||
|
||||
import OptimizedVideo from '../ui/OptimizedVideo';
|
||||
import AnimatedSticker from './AnimatedSticker';
|
||||
@ -87,6 +88,8 @@ const StickerView: FC<OwnProps> = ({
|
||||
const isStatic = !isLottie && !isVideo;
|
||||
const previewMediaHash = getStickerPreviewHash(sticker.id);
|
||||
|
||||
const dpr = useDevicePixelRatio();
|
||||
|
||||
const filterStyle = useColorFilter(customColor);
|
||||
|
||||
const isIntersectingForLoading = useIsIntersecting(containerRef, observeIntersectionForLoading);
|
||||
@ -133,6 +136,7 @@ const StickerView: FC<OwnProps> = ({
|
||||
id,
|
||||
size,
|
||||
(withSharedAnimation ? customColor : undefined),
|
||||
dpr,
|
||||
].filter(Boolean).join('_');
|
||||
|
||||
return (
|
||||
|
||||
@ -9,7 +9,7 @@ import { copyTextToClipboard } from '../../../util/clipboard';
|
||||
import { areLinesWrapping } from '../helpers/renderText';
|
||||
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../../hooks/window/useWindowSize';
|
||||
|
||||
import styles from './CodeOverlay.module.scss';
|
||||
|
||||
|
||||
@ -29,10 +29,10 @@ import useAppLayout from '../../../hooks/useAppLayout';
|
||||
import useConnectionStatus from '../../../hooks/useConnectionStatus';
|
||||
import useElectronDrag from '../../../hooks/useElectronDrag';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import { useFullscreenStatus } from '../../../hooks/useFullscreen';
|
||||
import { useHotkeys } from '../../../hooks/useHotkeys';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import { useFullscreenStatus } from '../../../hooks/window/useFullscreen';
|
||||
import useLeftHeaderButtonRtlForumTransition from './hooks/useLeftHeaderButtonRtlForumTransition';
|
||||
|
||||
import PickerSelectedItem from '../../common/PickerSelectedItem';
|
||||
|
||||
@ -12,7 +12,7 @@ import { pick } from '../../util/iteratees';
|
||||
import useAppLayout from '../../hooks/useAppLayout';
|
||||
import useForceUpdate from '../../hooks/useForceUpdate';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../hooks/window/useWindowSize';
|
||||
|
||||
import styles from './ConfettiContainer.module.scss';
|
||||
|
||||
|
||||
@ -50,10 +50,7 @@ import updateIcon from '../../util/updateIcon';
|
||||
import { IS_ANDROID, IS_ELECTRON } from '../../util/windowEnvironment';
|
||||
|
||||
import useAppLayout from '../../hooks/useAppLayout';
|
||||
import useBackgroundMode from '../../hooks/useBackgroundMode';
|
||||
import useBeforeUnload from '../../hooks/useBeforeUnload';
|
||||
import useForceUpdate from '../../hooks/useForceUpdate';
|
||||
import { useFullscreenStatus } from '../../hooks/useFullscreen';
|
||||
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
|
||||
import useInterval from '../../hooks/useInterval';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
@ -61,6 +58,9 @@ import usePreventPinchZoomGesture from '../../hooks/usePreventPinchZoomGesture';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
import useTimeout from '../../hooks/useTimeout';
|
||||
import useBackgroundMode from '../../hooks/window/useBackgroundMode';
|
||||
import useBeforeUnload from '../../hooks/window/useBeforeUnload';
|
||||
import { useFullscreenStatus } from '../../hooks/window/useFullscreen';
|
||||
|
||||
import ActiveCallHeader from '../calls/ActiveCallHeader.async';
|
||||
import GroupCall from '../calls/group/GroupCall.async';
|
||||
|
||||
@ -5,11 +5,11 @@ import type { ApiUser } from '../../../../api/types';
|
||||
|
||||
import { selectUser } from '../../../../global/selectors';
|
||||
import buildClassName from '../../../../util/buildClassName';
|
||||
import { DPR } from '../../../../util/windowEnvironment';
|
||||
import { REM } from '../../../common/helpers/mediaDimensions';
|
||||
|
||||
import useLang from '../../../../hooks/useLang';
|
||||
import useScrolledState from '../../../../hooks/useScrolledState';
|
||||
import useDevicePixelRatio from '../../../../hooks/window/useDevicePixelRatio';
|
||||
|
||||
import Avatar from '../../../common/Avatar';
|
||||
import { drawGradientCircle } from '../../../common/AvatarStoryCircle';
|
||||
@ -53,7 +53,7 @@ const STORY_FEATURE_ICONS = {
|
||||
|
||||
const STORY_FEATURE_ORDER = Object.keys(STORY_FEATURE_TITLES) as (keyof typeof STORY_FEATURE_TITLES)[];
|
||||
|
||||
const CIRCLE_SIZE = 5.25 * DPR * REM;
|
||||
const CIRCLE_SIZE = 5.25 * REM;
|
||||
const CIRCLE_SEGMENTS = 8;
|
||||
const CIRCLE_READ_SEGMENTS = 0;
|
||||
|
||||
@ -65,6 +65,8 @@ const PremiumFeaturePreviewVideo = ({
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const dpr = useDevicePixelRatio();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!circleRef.current) {
|
||||
return;
|
||||
@ -72,17 +74,18 @@ const PremiumFeaturePreviewVideo = ({
|
||||
|
||||
drawGradientCircle({
|
||||
canvas: circleRef.current,
|
||||
size: CIRCLE_SIZE,
|
||||
size: CIRCLE_SIZE * dpr,
|
||||
segmentsCount: CIRCLE_SEGMENTS,
|
||||
color: 'purple',
|
||||
readSegmentsCount: CIRCLE_READ_SEGMENTS,
|
||||
readSegmentColor: 'transparent',
|
||||
dpr,
|
||||
});
|
||||
}, []);
|
||||
}, [dpr]);
|
||||
|
||||
const { handleScroll, isAtBeginning } = useScrolledState();
|
||||
|
||||
const maxSize = CIRCLE_SIZE / DPR;
|
||||
const maxSize = CIRCLE_SIZE;
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
|
||||
@ -186,18 +186,10 @@ const MediaViewer: FC<StateProps> = ({
|
||||
const forceUpdate = useForceUpdate();
|
||||
useEffect(() => {
|
||||
const mql = window.matchMedia(MEDIA_VIEWER_MEDIA_QUERY);
|
||||
if (typeof mql.addEventListener === 'function') {
|
||||
mql.addEventListener('change', forceUpdate);
|
||||
} else if (typeof mql.addListener === 'function') {
|
||||
mql.addListener(forceUpdate);
|
||||
}
|
||||
mql.addEventListener('change', forceUpdate);
|
||||
|
||||
return () => {
|
||||
if (typeof mql.removeEventListener === 'function') {
|
||||
mql.removeEventListener('change', forceUpdate);
|
||||
} else if (typeof mql.removeListener === 'function') {
|
||||
mql.removeListener(forceUpdate);
|
||||
}
|
||||
mql.removeEventListener('change', forceUpdate);
|
||||
};
|
||||
}, [forceUpdate]);
|
||||
|
||||
|
||||
@ -20,14 +20,14 @@ import { IS_IOS, IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
||||
|
||||
import useDebouncedCallback from '../../hooks/useDebouncedCallback';
|
||||
import useDerivedState from '../../hooks/useDerivedState';
|
||||
import { useFullscreenStatus } from '../../hooks/useFullscreen';
|
||||
import useHistoryBack from '../../hooks/useHistoryBack';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useSignal from '../../hooks/useSignal';
|
||||
import { useSignalRef } from '../../hooks/useSignalRef';
|
||||
import useTimeout from '../../hooks/useTimeout';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import { useFullscreenStatus } from '../../hooks/window/useFullscreen';
|
||||
import useWindowSize from '../../hooks/window/useWindowSize';
|
||||
import useControlsSignal from './hooks/useControlsSignal';
|
||||
import useZoomChange from './hooks/useZoomChangeSignal';
|
||||
|
||||
|
||||
@ -15,11 +15,11 @@ import useUnsupportedMedia from '../../hooks/media/useUnsupportedMedia';
|
||||
import useAppLayout from '../../hooks/useAppLayout';
|
||||
import useBuffering from '../../hooks/useBuffering';
|
||||
import useCurrentTimeSignal from '../../hooks/useCurrentTimeSignal';
|
||||
import useFullscreen from '../../hooks/useFullscreen';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import usePictureInPicture from '../../hooks/usePictureInPicture';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import useVideoCleanup from '../../hooks/useVideoCleanup';
|
||||
import useFullscreen from '../../hooks/window/useFullscreen';
|
||||
import useControlsSignal from './hooks/useControlsSignal';
|
||||
import useVideoWaitingSignal from './hooks/useVideoWaitingSignal';
|
||||
|
||||
|
||||
@ -58,7 +58,6 @@ import { debounce, onTickEnd } from '../../util/schedulers';
|
||||
import { groupMessages } from './helpers/groupMessages';
|
||||
import { preventMessageInputBlur } from './helpers/preventMessageInputBlur';
|
||||
|
||||
import { isBackgroundModeActive } from '../../hooks/useBackgroundMode';
|
||||
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
||||
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
|
||||
import useInterval from '../../hooks/useInterval';
|
||||
@ -67,6 +66,7 @@ import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps
|
||||
import useNativeCopySelectedMessages from '../../hooks/useNativeCopySelectedMessages';
|
||||
import { useStateRef } from '../../hooks/useStateRef';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
import { isBackgroundModeActive } from '../../hooks/window/useBackgroundMode';
|
||||
import useContainerHeight from './hooks/useContainerHeight';
|
||||
import useStickyDates from './hooks/useStickyDates';
|
||||
|
||||
|
||||
@ -13,11 +13,11 @@ import {
|
||||
import { selectBot, selectUserFullInfo } from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import buildStyle from '../../util/buildStyle';
|
||||
import { DPR } from '../../util/windowEnvironment';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useMedia from '../../hooks/useMedia';
|
||||
import useDevicePixelRatio from '../../hooks/window/useDevicePixelRatio';
|
||||
|
||||
import OptimizedVideo from '../ui/OptimizedVideo';
|
||||
import Skeleton from '../ui/placeholder/Skeleton';
|
||||
@ -40,14 +40,15 @@ const MessageListBotInfo: FC<OwnProps & StateProps> = ({
|
||||
isInMessageList,
|
||||
}) => {
|
||||
const lang = useLang();
|
||||
const dpr = useDevicePixelRatio();
|
||||
|
||||
const botInfoPhotoUrl = useMedia(botInfo?.photo ? getBotCoverMediaHash(botInfo.photo) : undefined);
|
||||
const botInfoGifUrl = useMedia(botInfo?.gif ? getDocumentMediaHash(botInfo.gif) : undefined);
|
||||
const botInfoDimensions = botInfo?.photo ? getPhotoFullDimensions(botInfo.photo) : botInfo?.gif
|
||||
? getVideoDimensions(botInfo.gif) : undefined;
|
||||
const botInfoRealDimensions = botInfoDimensions && {
|
||||
width: botInfoDimensions.width / DPR,
|
||||
height: botInfoDimensions.height / DPR,
|
||||
width: botInfoDimensions.width / dpr,
|
||||
height: botInfoDimensions.height / dpr,
|
||||
};
|
||||
const isBotInfoEmpty = botInfo && !botInfo.description && !botInfo.gif && !botInfo.photo;
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ import usePrevDuringAnimation from '../../hooks/usePrevDuringAnimation';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import { useResize } from '../../hooks/useResize';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../hooks/window/useWindowSize';
|
||||
import usePinnedMessage from './hooks/usePinnedMessage';
|
||||
|
||||
import Composer from '../common/Composer';
|
||||
|
||||
@ -62,7 +62,7 @@ import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../hooks/window/useWindowSize';
|
||||
|
||||
import GroupCallTopPane from '../calls/group/GroupCallTopPane';
|
||||
import GroupChatInfo from '../common/GroupChatInfo';
|
||||
|
||||
@ -15,12 +15,12 @@ import parseHtmlAsFormattedText from '../../../../util/parseHtmlAsFormattedText'
|
||||
import { IS_TOUCH_ENV } from '../../../../util/windowEnvironment';
|
||||
import { getTextWithEntitiesAsHtml } from '../../../common/helpers/renderTextWithEntities';
|
||||
|
||||
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
|
||||
import useBeforeUnload from '../../../../hooks/useBeforeUnload';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import useLayoutEffectWithPrevDeps from '../../../../hooks/useLayoutEffectWithPrevDeps';
|
||||
import useRunDebounced from '../../../../hooks/useRunDebounced';
|
||||
import { useStateRef } from '../../../../hooks/useStateRef';
|
||||
import useBackgroundMode from '../../../../hooks/window/useBackgroundMode';
|
||||
import useBeforeUnload from '../../../../hooks/window/useBeforeUnload';
|
||||
|
||||
let isFrozen = false;
|
||||
|
||||
|
||||
@ -14,11 +14,11 @@ import parseHtmlAsFormattedText from '../../../../util/parseHtmlAsFormattedText'
|
||||
import { getTextWithEntitiesAsHtml } from '../../../common/helpers/renderTextWithEntities';
|
||||
|
||||
import { useDebouncedResolver } from '../../../../hooks/useAsyncResolvers';
|
||||
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
|
||||
import useBeforeUnload from '../../../../hooks/useBeforeUnload';
|
||||
import useDerivedSignal from '../../../../hooks/useDerivedSignal';
|
||||
import useEffectWithPrevDeps from '../../../../hooks/useEffectWithPrevDeps';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import useBackgroundMode from '../../../../hooks/window/useBackgroundMode';
|
||||
import useBeforeUnload from '../../../../hooks/window/useBeforeUnload';
|
||||
|
||||
const URL_ENTITIES = new Set<string>([ApiMessageEntityTypes.TextUrl, ApiMessageEntityTypes.Url]);
|
||||
const DEBOUNCE_MS = 300;
|
||||
|
||||
@ -20,11 +20,12 @@ import { REM } from '../../../common/helpers/mediaDimensions';
|
||||
|
||||
import useColorFilter from '../../../../hooks/stickers/useColorFilter';
|
||||
import useDynamicColorListener from '../../../../hooks/stickers/useDynamicColorListener';
|
||||
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
|
||||
import useEffectWithPrevDeps from '../../../../hooks/useEffectWithPrevDeps';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import useResizeObserver from '../../../../hooks/useResizeObserver';
|
||||
import useThrottledCallback from '../../../../hooks/useThrottledCallback';
|
||||
import useBackgroundMode from '../../../../hooks/window/useBackgroundMode';
|
||||
import useDevicePixelRatio from '../../../../hooks/window/useDevicePixelRatio';
|
||||
|
||||
const SIZE = 1.25 * REM;
|
||||
const THROTTLE_MS = 300;
|
||||
@ -49,6 +50,7 @@ export default function useInputCustomEmojis(
|
||||
) {
|
||||
const customColor = useDynamicColorListener(inputRef, !isReady);
|
||||
const colorFilter = useColorFilter(customColor, true);
|
||||
const dpr = useDevicePixelRatio();
|
||||
const playersById = useRef<Map<string, CustomEmojiPlayer>>(new Map());
|
||||
|
||||
const clearPlayers = useLastCallback((ids: string[]) => {
|
||||
@ -99,7 +101,7 @@ export default function useInputCustomEmojis(
|
||||
}
|
||||
const isHq = customEmoji?.stickerSetInfo && selectIsAlwaysHighPriorityEmoji(global, customEmoji.stickerSetInfo);
|
||||
const renderId = [
|
||||
prefixId, documentId, customColor,
|
||||
prefixId, documentId, customColor, dpr,
|
||||
].filter(Boolean).join('_');
|
||||
|
||||
createPlayer({
|
||||
@ -159,6 +161,12 @@ export default function useInputCustomEmojis(
|
||||
false,
|
||||
);
|
||||
useResizeObserver(sharedCanvasRef, throttledSynchronizeElements);
|
||||
useEffectWithPrevDeps(([prevDpr]) => {
|
||||
if (dpr !== prevDpr) {
|
||||
clearPlayers(Array.from(playersById.current.keys()));
|
||||
synchronizeElements();
|
||||
}
|
||||
}, [dpr, synchronizeElements]);
|
||||
|
||||
const freezeAnimation = useLastCallback(() => {
|
||||
playersById.current.forEach((player) => {
|
||||
|
||||
@ -7,8 +7,8 @@ import type { PinnedIntersectionChangedCallback } from './usePinnedMessage';
|
||||
import { IS_ANDROID } from '../../../util/windowEnvironment';
|
||||
|
||||
import useAppLayout from '../../../hooks/useAppLayout';
|
||||
import useBackgroundMode, { isBackgroundModeActive } from '../../../hooks/useBackgroundMode';
|
||||
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
||||
import useBackgroundMode, { isBackgroundModeActive } from '../../../hooks/window/useBackgroundMode';
|
||||
|
||||
const INTERSECTION_THROTTLE_FOR_READING = 150;
|
||||
const INTERSECTION_THROTTLE_FOR_MEDIA = IS_ANDROID ? 1000 : 350;
|
||||
|
||||
@ -10,7 +10,7 @@ import buildClassName from '../../../util/buildClassName';
|
||||
import { REM } from '../../common/helpers/mediaDimensions';
|
||||
|
||||
import useAppLayout from '../../../hooks/useAppLayout';
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../../hooks/window/useWindowSize';
|
||||
|
||||
import ReactionEmoji from '../../common/ReactionEmoji';
|
||||
|
||||
|
||||
@ -2,10 +2,10 @@ import { useEffect, useRef } from '../../../../lib/teact/teact';
|
||||
|
||||
import { requestMeasure } from '../../../../lib/fasterdom/fasterdom';
|
||||
|
||||
import useBackgroundMode, { isBackgroundModeActive } from '../../../../hooks/useBackgroundMode';
|
||||
import useHeavyAnimationCheck, { isHeavyAnimating } from '../../../../hooks/useHeavyAnimationCheck';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import usePriorityPlaybackCheck, { isPriorityPlaybackActive } from '../../../../hooks/usePriorityPlaybackCheck';
|
||||
import useBackgroundMode, { isBackgroundModeActive } from '../../../../hooks/window/useBackgroundMode';
|
||||
|
||||
export default function useVideoAutoPause(
|
||||
playerRef: { current: HTMLVideoElement | null }, canPlay: boolean, isPriority?: boolean,
|
||||
|
||||
@ -6,7 +6,7 @@ import type { WebAppInboundEvent, WebAppOutboundEvent } from '../../../../types/
|
||||
import { extractCurrentThemeParams } from '../../../../util/themeStyle';
|
||||
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import useWindowSize from '../../../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../../../hooks/window/useWindowSize';
|
||||
|
||||
const SCROLLBAR_STYLE = `* {
|
||||
scrollbar-width: thin;
|
||||
|
||||
@ -18,7 +18,7 @@ import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||
import useHistoryBack from '../../hooks/useHistoryBack';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../hooks/window/useWindowSize';
|
||||
|
||||
import Transition from '../ui/Transition';
|
||||
import AddChatMembers from './AddChatMembers';
|
||||
|
||||
@ -34,7 +34,6 @@ import { PRIMARY_VIDEO_MIME, SECONDARY_VIDEO_MIME } from './helpers/videoFormats
|
||||
|
||||
import useUnsupportedMedia from '../../hooks/media/useUnsupportedMedia';
|
||||
import useAppLayout, { getIsMobile } from '../../hooks/useAppLayout';
|
||||
import useBackgroundMode from '../../hooks/useBackgroundMode';
|
||||
import useCanvasBlur from '../../hooks/useCanvasBlur';
|
||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
||||
@ -45,6 +44,7 @@ import useLongPress from '../../hooks/useLongPress';
|
||||
import useMediaTransition from '../../hooks/useMediaTransition';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import { useStreaming } from '../../hooks/useStreaming';
|
||||
import useBackgroundMode from '../../hooks/window/useBackgroundMode';
|
||||
import useStoryPreloader from './hooks/useStoryPreloader';
|
||||
import useStoryProps from './hooks/useStoryProps';
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ import useHistoryBack from '../../hooks/useHistoryBack';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import useSignal from '../../hooks/useSignal';
|
||||
import useWindowSize from '../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../hooks/window/useWindowSize';
|
||||
import useSlideSizes from './hooks/useSlideSizes';
|
||||
|
||||
import Story from './Story';
|
||||
|
||||
@ -2,7 +2,7 @@ import { useMemo } from '../../../lib/teact/teact';
|
||||
|
||||
import { calculateSlideSizes } from '../helpers/dimensions';
|
||||
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../../hooks/window/useWindowSize';
|
||||
|
||||
export default function useSlideSizes() {
|
||||
const { width: windowWidth, height: windowHeight } = useWindowSize();
|
||||
|
||||
@ -8,7 +8,7 @@ import { requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import buildStyle from '../../../util/buildStyle';
|
||||
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
import useWindowSize from '../../../hooks/window/useWindowSize';
|
||||
|
||||
import MediaAreaSuggestedReaction from './MediaAreaSuggestedReaction';
|
||||
|
||||
|
||||
@ -4,18 +4,18 @@ import React, { memo, useEffect, useRef } from '../../lib/teact/teact';
|
||||
import { requestMutation } from '../../lib/fasterdom/fasterdom';
|
||||
import { animate, timingFunctions } from '../../util/animation';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { DPR } from '../../util/windowEnvironment';
|
||||
|
||||
import { useStateRef } from '../../hooks/useStateRef';
|
||||
import useDevicePixelRatio from '../../hooks/window/useDevicePixelRatio';
|
||||
|
||||
import './ProgressSpinner.scss';
|
||||
|
||||
const SIZES = {
|
||||
s: 42, m: 48, l: 54, xl: 52,
|
||||
};
|
||||
const STROKE_WIDTH = 2 * DPR;
|
||||
const STROKE_WIDTH_XL = 3 * DPR;
|
||||
const PADDING = 2 * DPR;
|
||||
const STROKE_WIDTH = 2;
|
||||
const STROKE_WIDTH_XL = 3;
|
||||
const PADDING = 2;
|
||||
const MIN_PROGRESS = 0.05;
|
||||
const MAX_PROGRESS = 1;
|
||||
const GROW_DURATION = 600; // 0.6 s
|
||||
@ -41,6 +41,8 @@ const ProgressSpinner: FC<{
|
||||
const width = SIZES[size];
|
||||
const progressRef = useStateRef(progress);
|
||||
|
||||
const dpr = useDevicePixelRatio();
|
||||
|
||||
useEffect(() => {
|
||||
let isFirst = true;
|
||||
let growFrom = MIN_PROGRESS;
|
||||
@ -65,10 +67,11 @@ const ProgressSpinner: FC<{
|
||||
|
||||
drawSpinnerArc(
|
||||
canvasRef.current,
|
||||
width * DPR,
|
||||
size === 'xl' ? STROKE_WIDTH_XL : STROKE_WIDTH,
|
||||
width * dpr,
|
||||
(size === 'xl' ? STROKE_WIDTH_XL : STROKE_WIDTH) * dpr,
|
||||
'white',
|
||||
currentProgress,
|
||||
dpr,
|
||||
isFirst,
|
||||
);
|
||||
|
||||
@ -76,7 +79,7 @@ const ProgressSpinner: FC<{
|
||||
|
||||
return currentProgress < 1;
|
||||
}, requestMutation);
|
||||
}, [progressRef, size, width]);
|
||||
}, [progressRef, size, width, dpr]);
|
||||
|
||||
const className = buildClassName(
|
||||
`ProgressSpinner size-${size}`,
|
||||
@ -101,10 +104,11 @@ function drawSpinnerArc(
|
||||
strokeWidth: number,
|
||||
color: string,
|
||||
progress: number,
|
||||
dpr: number,
|
||||
shouldInit = false,
|
||||
) {
|
||||
const centerCoordinate = size / 2;
|
||||
const radius = (size - strokeWidth) / 2 - PADDING;
|
||||
const radius = (size - strokeWidth) / 2 - PADDING * dpr;
|
||||
const rotationOffset = (Date.now() % ROTATE_DURATION) / ROTATE_DURATION;
|
||||
const startAngle = (2 * Math.PI) * rotationOffset;
|
||||
const endAngle = startAngle + (2 * Math.PI) * progress;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { GlobalState } from '../global/types';
|
||||
import type { LangFn } from './useLang';
|
||||
|
||||
import useBrowserOnline from './useBrowserOnline';
|
||||
import useBrowserOnline from './window/useBrowserOnline';
|
||||
|
||||
export enum ConnectionStatus {
|
||||
waitingForNetwork,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useEffect } from '../lib/teact/teact';
|
||||
import { useEffect } from '../../lib/teact/teact';
|
||||
|
||||
import { createCallbackManager } from '../util/callbacks';
|
||||
import useLastCallback from './useLastCallback';
|
||||
import { createCallbackManager } from '../../util/callbacks';
|
||||
import useLastCallback from '../useLastCallback';
|
||||
|
||||
const blurCallbacks = createCallbackManager();
|
||||
const focusCallbacks = createCallbackManager();
|
||||
@ -1,7 +1,7 @@
|
||||
import { useEffect } from '../lib/teact/teact';
|
||||
import { useEffect } from '../../lib/teact/teact';
|
||||
|
||||
import { onBeforeUnload } from '../util/schedulers';
|
||||
import useLastCallback from './useLastCallback';
|
||||
import { onBeforeUnload } from '../../util/schedulers';
|
||||
import useLastCallback from '../useLastCallback';
|
||||
|
||||
export default function useBeforeUnload(callback: AnyToVoidFunction) {
|
||||
const lastCallback = useLastCallback(callback);
|
||||
@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from '../lib/teact/teact';
|
||||
import { useEffect, useState } from '../../lib/teact/teact';
|
||||
|
||||
export default function useBrowserOnline() {
|
||||
const [isOnline, setIsOnline] = useState(window.navigator.onLine);
|
||||
28
src/hooks/window/useDevicePixelRatio.ts
Normal file
28
src/hooks/window/useDevicePixelRatio.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { useState } from '../../lib/teact/teact';
|
||||
|
||||
import { createCallbackManager } from '../../util/callbacks';
|
||||
import useEffectOnce from '../useEffectOnce';
|
||||
|
||||
const callbacks = createCallbackManager();
|
||||
|
||||
function createListener() {
|
||||
window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`)
|
||||
.addEventListener('change', callbacks.runCallbacks, { once: true });
|
||||
}
|
||||
|
||||
export default function useDevicePixelRatio() {
|
||||
const [dpr, setDpr] = useState(window.devicePixelRatio);
|
||||
|
||||
useEffectOnce(() => {
|
||||
callbacks.addCallback(() => {
|
||||
setDpr(window.devicePixelRatio);
|
||||
});
|
||||
});
|
||||
|
||||
return dpr;
|
||||
}
|
||||
|
||||
createListener();
|
||||
|
||||
// Set up new listener for the next `devicePixelRatio` change
|
||||
callbacks.addCallback(createListener);
|
||||
@ -1,8 +1,8 @@
|
||||
import { useEffect, useLayoutEffect, useState } from '../lib/teact/teact';
|
||||
import { useEffect, useLayoutEffect, useState } from '../../lib/teact/teact';
|
||||
|
||||
import { ElectronEvent } from '../types/electron';
|
||||
import { ElectronEvent } from '../../types/electron';
|
||||
|
||||
import { IS_IOS } from '../util/windowEnvironment';
|
||||
import { IS_IOS } from '../../util/windowEnvironment';
|
||||
|
||||
type RefType = {
|
||||
current: HTMLVideoElement | null;
|
||||
@ -1,8 +1,8 @@
|
||||
import { useEffect, useMemo, useState } from '../lib/teact/teact';
|
||||
import { useEffect, useMemo, useState } from '../../lib/teact/teact';
|
||||
|
||||
import { throttle } from '../util/schedulers';
|
||||
import windowSize from '../util/windowSize';
|
||||
import useDebouncedCallback from './useDebouncedCallback';
|
||||
import { throttle } from '../../util/schedulers';
|
||||
import windowSize from '../../util/windowSize';
|
||||
import useDebouncedCallback from '../useDebouncedCallback';
|
||||
|
||||
const THROTTLE = 250;
|
||||
|
||||
@ -4,8 +4,7 @@ import Deferred from '../../util/Deferred';
|
||||
import generateUniqueId from '../../util/generateUniqueId';
|
||||
import launchMediaWorkers, { MAX_WORKERS } from '../../util/launchMediaWorkers';
|
||||
import {
|
||||
DPR, IS_ANDROID, IS_IOS,
|
||||
IS_SAFARI,
|
||||
IS_ANDROID, IS_IOS, IS_SAFARI,
|
||||
} from '../../util/windowEnvironment';
|
||||
import { requestMeasure, requestMutation } from '../fasterdom/fasterdom';
|
||||
|
||||
@ -338,7 +337,7 @@ class RLottie {
|
||||
} = this.params;
|
||||
|
||||
// Reduced quality only looks acceptable on high DPR screens
|
||||
return Math.max(DPR * quality, 1);
|
||||
return Math.max(window.devicePixelRatio * quality, 1);
|
||||
}
|
||||
|
||||
private destroy() {
|
||||
|
||||
@ -20,9 +20,5 @@ export function setSystemThemeChangeCallback(callback: (newTheme: ThemeKey) => v
|
||||
themeChangeCallback = callback;
|
||||
}
|
||||
|
||||
const mql = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
if (typeof mql.addEventListener === 'function') {
|
||||
mql.addEventListener('change', handleSystemThemeChange);
|
||||
} else if (typeof mql.addListener === 'function') {
|
||||
mql.addListener(handleSystemThemeChange);
|
||||
}
|
||||
window.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', handleSystemThemeChange);
|
||||
|
||||
@ -80,8 +80,6 @@ export const IS_WEBM_SUPPORTED = Boolean(TEST_VIDEO.canPlayType('video/webm; cod
|
||||
|
||||
export const ARE_WEBCODECS_SUPPORTED = 'VideoDecoder' in window;
|
||||
|
||||
export const DPR = window.devicePixelRatio || 1;
|
||||
|
||||
export const MASK_IMAGE_DISABLED = true;
|
||||
export const IS_OPFS_SUPPORTED = Boolean(navigator.storage?.getDirectory);
|
||||
if (IS_OPFS_SUPPORTED) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user