Fix DPR update when switching monitors (#4155)

This commit is contained in:
Alexander Zinchuk 2024-01-12 13:00:22 +01:00
parent 16c2fdbc04
commit e9dacf35f3
40 changed files with 137 additions and 98 deletions

View File

@ -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';

View File

@ -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>;

View File

@ -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) {

View File

@ -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';

View File

@ -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 (

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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}>

View File

@ -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]);

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -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;

View File

@ -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;

View File

@ -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) => {

View File

@ -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;

View File

@ -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';

View File

@ -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,

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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();

View File

@ -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';

View File

@ -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;

View File

@ -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,

View File

@ -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();

View File

@ -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);

View File

@ -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);

View 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);

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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);

View File

@ -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) {