Video Player: Fix isSeeking change (#5977)
This commit is contained in:
parent
ad4e496446
commit
850daef3b0
@ -13,6 +13,7 @@ import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
|||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { captureEvents } from '../../util/captureEvents';
|
import { captureEvents } from '../../util/captureEvents';
|
||||||
import { formatMediaDuration } from '../../util/dates/dateFormat';
|
import { formatMediaDuration } from '../../util/dates/dateFormat';
|
||||||
|
import getPointerPosition from '../../util/events/getPointerPosition';
|
||||||
import { clamp, round } from '../../util/math';
|
import { clamp, round } from '../../util/math';
|
||||||
|
|
||||||
import { useThrottledSignal } from '../../hooks/useAsyncResolvers';
|
import { useThrottledSignal } from '../../hooks/useAsyncResolvers';
|
||||||
@ -151,7 +152,7 @@ const SeekLine: FC<OwnProps> = ({
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
|
|
||||||
const getPreviewProps = (e: MouseEvent | TouchEvent) => {
|
const getPreviewProps = (e: MouseEvent | TouchEvent) => {
|
||||||
const pageX = e instanceof MouseEvent ? e.pageX : e.touches[0].pageX;
|
const pageX = getPointerPosition(e).x;
|
||||||
const t = clamp(duration * ((pageX - seekerSize.left) / seekerSize.width), 0, duration);
|
const t = clamp(duration * ((pageX - seekerSize.left) / seekerSize.width), 0, duration);
|
||||||
if (isPreviewDisabled) return [t, 0];
|
if (isPreviewDisabled) return [t, 0];
|
||||||
if (!seekerSize.width) seekerSize = seeker.getBoundingClientRect();
|
if (!seekerSize.width) seekerSize = seeker.getBoundingClientRect();
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import type React from '../../lib/teact/teact';
|
import type React from '../../lib/teact/teact';
|
||||||
import {
|
import {
|
||||||
memo, useEffect, useRef, useState,
|
memo, useEffect, useRef, useSignal, useState,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
import { getActions } from '../../global';
|
import { getActions } from '../../global';
|
||||||
|
|
||||||
import type { ApiDimensions } from '../../api/types';
|
import type { ApiDimensions } from '../../api/types';
|
||||||
|
|
||||||
import { IS_IOS, IS_TOUCH_ENV, IS_YA_BROWSER } from '../../util/browser/windowEnvironment';
|
import { IS_IOS, IS_TOUCH_ENV, IS_YA_BROWSER } from '../../util/browser/windowEnvironment';
|
||||||
|
import getPointerPosition from '../../util/events/getPointerPosition';
|
||||||
import { clamp } from '../../util/math';
|
import { clamp } from '../../util/math';
|
||||||
import safePlay from '../../util/safePlay';
|
import safePlay from '../../util/safePlay';
|
||||||
import stopEvent from '../../util/stopEvent';
|
import stopEvent from '../../util/stopEvent';
|
||||||
@ -112,17 +113,47 @@ const VideoPlayer: FC<OwnProps> = ({
|
|||||||
] = usePictureInPicture(videoRef, handleEnterFullscreen, handleLeaveFullscreen);
|
] = usePictureInPicture(videoRef, handleEnterFullscreen, handleLeaveFullscreen);
|
||||||
|
|
||||||
const [, toggleControls, lockControls] = useControlsSignal();
|
const [, toggleControls, lockControls] = useControlsSignal();
|
||||||
|
const [getIsSeeking, setIsSeeking] = useSignal(false);
|
||||||
|
const lastMousePosition = useRef({ x: 0, y: 0 });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateMousePosition = (e: MouseEvent | TouchEvent) => {
|
||||||
|
lastMousePosition.current = getPointerPosition(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('mousemove', updateMousePosition);
|
||||||
|
window.addEventListener('touchmove', updateMousePosition);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('mousemove', updateMousePosition);
|
||||||
|
window.removeEventListener('touchmove', updateMousePosition);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const checkMousePositionAndToggleControls = useLastCallback((clientX: number, clientY: number) => {
|
||||||
|
const bounds = videoRef.current?.getBoundingClientRect();
|
||||||
|
if (!bounds) return;
|
||||||
|
if (clientX <= bounds.left || clientX >= bounds.right
|
||||||
|
|| clientY <= bounds.top || clientY >= bounds.bottom) {
|
||||||
|
if (!getIsSeeking()) {
|
||||||
|
toggleControls(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const handleVideoMove = useLastCallback(() => {
|
const handleVideoMove = useLastCallback(() => {
|
||||||
toggleControls(true);
|
toggleControls(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleVideoLeave = useLastCallback((e) => {
|
const handleVideoLeave = useLastCallback((e) => {
|
||||||
const bounds = videoRef.current?.getBoundingClientRect();
|
checkMousePositionAndToggleControls(e.clientX, e.clientY);
|
||||||
if (!bounds) return;
|
});
|
||||||
if (e.clientX <= bounds.left || e.clientX >= bounds.right
|
|
||||||
|| e.clientY <= bounds.top || e.clientY >= bounds.bottom) {
|
const handleSeekingChange = useLastCallback((isSeeking: boolean) => {
|
||||||
toggleControls(false);
|
setIsSeeking(isSeeking);
|
||||||
|
if (!isSeeking) {
|
||||||
|
const { x, y } = lastMousePosition.current;
|
||||||
|
checkMousePositionAndToggleControls(x, y);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -374,6 +405,7 @@ const VideoPlayer: FC<OwnProps> = ({
|
|||||||
onVolumeClick={handleVolumeMuted}
|
onVolumeClick={handleVolumeMuted}
|
||||||
onVolumeChange={handleVolumeChange}
|
onVolumeChange={handleVolumeChange}
|
||||||
onPlaybackRateChange={handlePlaybackRateChange}
|
onPlaybackRateChange={handlePlaybackRateChange}
|
||||||
|
onSeekingChange={handleSeekingChange}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -58,6 +58,7 @@ type OwnProps = {
|
|||||||
onPlaybackRateChange: (playbackRate: number) => void;
|
onPlaybackRateChange: (playbackRate: number) => void;
|
||||||
onPlayPause: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
onPlayPause: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||||
onSeek: (position: number) => void;
|
onSeek: (position: number) => void;
|
||||||
|
onSeekingChange: (isSeeking: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopEvent = (e: React.MouseEvent<HTMLElement>) => {
|
const stopEvent = (e: React.MouseEvent<HTMLElement>) => {
|
||||||
@ -98,6 +99,7 @@ const VideoPlayerControls: FC<OwnProps> = ({
|
|||||||
onPictureInPictureChange,
|
onPictureInPictureChange,
|
||||||
onPlayPause,
|
onPlayPause,
|
||||||
onSeek,
|
onSeek,
|
||||||
|
onSeekingChange,
|
||||||
}) => {
|
}) => {
|
||||||
const [isPlaybackMenuOpen, openPlaybackMenu, closePlaybackMenu] = useFlag();
|
const [isPlaybackMenuOpen, openPlaybackMenu, closePlaybackMenu] = useFlag();
|
||||||
const [getCurrentTime] = useCurrentTimeSignal();
|
const [getCurrentTime] = useCurrentTimeSignal();
|
||||||
@ -146,10 +148,12 @@ const VideoPlayerControls: FC<OwnProps> = ({
|
|||||||
const handleSeek = useLastCallback((position: number) => {
|
const handleSeek = useLastCallback((position: number) => {
|
||||||
setIsSeeking(false);
|
setIsSeeking(false);
|
||||||
onSeek(position);
|
onSeek(position);
|
||||||
|
onSeekingChange(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSeekStart = useLastCallback(() => {
|
const handleSeekStart = useLastCallback(() => {
|
||||||
setIsSeeking(true);
|
setIsSeeking(true);
|
||||||
|
onSeekingChange(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
const volumeIcon: IconName = useMemo(() => {
|
const volumeIcon: IconName = useMemo(() => {
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import type React from '../../lib/teact/teact';
|
|
||||||
import {
|
import {
|
||||||
memo, useCallback, useEffect, useMemo, useRef, useState,
|
memo, useCallback, useEffect, useMemo, useRef, useState,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
|
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import buildStyle from '../../util/buildStyle';
|
import buildStyle from '../../util/buildStyle';
|
||||||
|
import getPointerPosition from '../../util/events/getPointerPosition';
|
||||||
|
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ const Draggable: FC<OwnProps> = ({
|
|||||||
const handleMouseDown = (e: React.MouseEvent | React.TouchEvent) => {
|
const handleMouseDown = (e: React.MouseEvent | React.TouchEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { x, y } = getClientCoordinate(e);
|
const { x, y } = getPointerPosition(e);
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
@ -71,7 +71,7 @@ const Draggable: FC<OwnProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseMove = useCallback((e: MouseEvent | TouchEvent) => {
|
const handleMouseMove = useCallback((e: MouseEvent | TouchEvent) => {
|
||||||
const { x, y } = getClientCoordinate(e);
|
const { x, y } = getPointerPosition(e);
|
||||||
|
|
||||||
const translation = {
|
const translation = {
|
||||||
x: x - state.origin.x,
|
x: x - state.origin.x,
|
||||||
@ -172,18 +172,3 @@ const Draggable: FC<OwnProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(Draggable);
|
export default memo(Draggable);
|
||||||
|
|
||||||
function getClientCoordinate(e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent) {
|
|
||||||
let x;
|
|
||||||
let y;
|
|
||||||
|
|
||||||
if ('touches' in e) {
|
|
||||||
x = e.touches[0].clientX;
|
|
||||||
y = e.touches[0].clientY;
|
|
||||||
} else {
|
|
||||||
x = e.clientX;
|
|
||||||
y = e.clientY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { x, y };
|
|
||||||
}
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import type { Point, Size } from '../types';
|
|||||||
import { RESIZE_HANDLE_SELECTOR } from '../config';
|
import { RESIZE_HANDLE_SELECTOR } from '../config';
|
||||||
import buildStyle from '../util/buildStyle';
|
import buildStyle from '../util/buildStyle';
|
||||||
import { captureEvents } from '../util/captureEvents';
|
import { captureEvents } from '../util/captureEvents';
|
||||||
|
import getPointerPosition from '../util/events/getPointerPosition';
|
||||||
import useFlag from './useFlag';
|
import useFlag from './useFlag';
|
||||||
import useLastCallback from './useLastCallback';
|
import useLastCallback from './useLastCallback';
|
||||||
|
|
||||||
@ -124,11 +125,11 @@ export default function useDraggable(
|
|||||||
if (targetElement.closest('.no-drag') || !element) {
|
if (targetElement.closest('.no-drag') || !element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { pageX, pageY } = ('touches' in event) ? event.touches[0] : event;
|
const { x, y } = getPointerPosition(event);
|
||||||
|
|
||||||
const { left, top } = element.getBoundingClientRect();
|
const { left, top } = element.getBoundingClientRect();
|
||||||
setElementPositionOnStartTransform({ x: left, y: top });
|
setElementPositionOnStartTransform({ x: left, y: top });
|
||||||
setTransformStartPoint({ x: pageX, y: pageY });
|
setTransformStartPoint({ x, y });
|
||||||
|
|
||||||
startDragging();
|
startDragging();
|
||||||
});
|
});
|
||||||
@ -159,14 +160,14 @@ export default function useDraggable(
|
|||||||
if (resizeHandle === undefined) return;
|
if (resizeHandle === undefined) return;
|
||||||
setHitResizeHandle(resizeHandle);
|
setHitResizeHandle(resizeHandle);
|
||||||
|
|
||||||
const { pageX, pageY } = ('touches' in event) ? event.touches[0] : event;
|
const { x, y } = getPointerPosition(event);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
left, right, top, bottom,
|
left, right, top, bottom,
|
||||||
} = element.getBoundingClientRect();
|
} = element.getBoundingClientRect();
|
||||||
setElementPositionOnStartTransform({ x: left, y: top });
|
setElementPositionOnStartTransform({ x: left, y: top });
|
||||||
setElementSizeOnStartTransform({ width: right - left, height: bottom - top });
|
setElementSizeOnStartTransform({ width: right - left, height: bottom - top });
|
||||||
setTransformStartPoint({ x: pageX, y: pageY });
|
setTransformStartPoint({ x, y });
|
||||||
|
|
||||||
startResizing();
|
startResizing();
|
||||||
});
|
});
|
||||||
@ -269,10 +270,10 @@ export default function useDraggable(
|
|||||||
|
|
||||||
const handleDrag = useLastCallback((event: MouseEvent | TouchEvent) => {
|
const handleDrag = useLastCallback((event: MouseEvent | TouchEvent) => {
|
||||||
if (!isDragging || !element) return;
|
if (!isDragging || !element) return;
|
||||||
const { pageX, pageY } = ('touches' in event) ? event.touches[0] : event;
|
const { x, y } = getPointerPosition(event);
|
||||||
|
|
||||||
const offsetX = pageX - transformStartPoint.x;
|
const offsetX = x - transformStartPoint.x;
|
||||||
const offsetY = pageY - transformStartPoint.y;
|
const offsetY = y - transformStartPoint.y;
|
||||||
|
|
||||||
const newX = elementPositionOnStartTransform.x + offsetX;
|
const newX = elementPositionOnStartTransform.x + offsetX;
|
||||||
const newY = elementPositionOnStartTransform.y + offsetY;
|
const newY = elementPositionOnStartTransform.y + offsetY;
|
||||||
@ -282,11 +283,11 @@ export default function useDraggable(
|
|||||||
|
|
||||||
const handleResize = useLastCallback((event: MouseEvent | TouchEvent) => {
|
const handleResize = useLastCallback((event: MouseEvent | TouchEvent) => {
|
||||||
if (!isResizing || !element || hitResizeHandle === undefined) return;
|
if (!isResizing || !element || hitResizeHandle === undefined) return;
|
||||||
const { pageX, pageY } = ('touches' in event) ? event.touches[0] : event;
|
const { x, y } = getPointerPosition(event);
|
||||||
const sizeOnStartTransform = getElementSizeOnStartTransform();
|
const sizeOnStartTransform = getElementSizeOnStartTransform();
|
||||||
|
|
||||||
const pageVisibleX = Math.min(Math.max(0, pageX), getVisibleArea().width);
|
const pageVisibleX = Math.min(Math.max(0, x), getVisibleArea().width);
|
||||||
const pageVisibleY = Math.min(Math.max(0, pageY), getVisibleArea().height);
|
const pageVisibleY = Math.min(Math.max(0, y), getVisibleArea().height);
|
||||||
|
|
||||||
const offsetX = pageVisibleX - transformStartPoint.x;
|
const offsetX = pageVisibleX - transformStartPoint.x;
|
||||||
const offsetY = pageVisibleY - transformStartPoint.y;
|
const offsetY = pageVisibleY - transformStartPoint.y;
|
||||||
|
|||||||
13
src/util/events/getPointerPosition.ts
Normal file
13
src/util/events/getPointerPosition.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export default function getPointerPosition(e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent) {
|
||||||
|
if ('touches' in e) {
|
||||||
|
return {
|
||||||
|
x: e.touches[0].clientX,
|
||||||
|
y: e.touches[0].clientY,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: e.clientX,
|
||||||
|
y: e.clientY,
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user