Skip to content

Commit

Permalink
Merge pull request #43349 from tienifr/fix/42323
Browse files Browse the repository at this point in the history
fix Hide video playback controls on auto-playing videos
  • Loading branch information
MariaHCD authored Aug 8, 2024
2 parents 13bed5c + 7034385 commit 4f45424
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/components/FeatureTrainingModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ function FeatureTrainingModal({
url={videoURL}
videoPlayerStyle={[styles.onboardingVideoPlayer, {aspectRatio}]}
onVideoLoaded={setAspectRatio}
controlsStatus={CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW}
controlsStatus={CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE}
shouldUseControlsBottomMargin={false}
shouldPlay
isLooping
Expand Down
61 changes: 56 additions & 5 deletions src/components/VideoPlayer/BaseVideoPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* eslint-disable no-underscore-dangle */
import type {AVPlaybackStatus, VideoFullscreenUpdateEvent} from 'expo-av';
import {ResizeMode, Video, VideoFullscreenUpdate} from 'expo-av';
import {debounce} from 'lodash';
import type {MutableRefObject} from 'react';
import React, {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react';
import React, {useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react';
import type {GestureResponderEvent} from 'react-native';
import {View} from 'react-native';
import {runOnJS, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import AttachmentOfflineIndicator from '@components/AttachmentOfflineIndicator';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import Hoverable from '@components/Hoverable';
Expand Down Expand Up @@ -73,6 +75,11 @@ function BaseVideoPlayer({
const [sourceURL] = useState(VideoUtils.addSkipTimeTagToURL(url.includes('blob:') || url.includes('file:///') ? url : addEncryptedAuthTokenToURL(url), 0.001));
const [isPopoverVisible, setIsPopoverVisible] = useState(false);
const [popoverAnchorPosition, setPopoverAnchorPosition] = useState({horizontal: 0, vertical: 0});
const [controlStatusState, setControlStatusState] = useState(controlsStatus);
const controlsOpacity = useSharedValue(1);
const controlsAnimatedStyle = useAnimatedStyle(() => ({
opacity: controlsOpacity.value,
}));

const videoPlayerRef = useRef<VideoWithOnFullScreenUpdate | null>(null);
const videoPlayerElementParentRef = useRef<View | HTMLDivElement | null>(null);
Expand All @@ -96,6 +103,46 @@ function BaseVideoPlayer({
}
}, [isCurrentlyURLSet, isPlaying, pauseVideo, playVideo, updateCurrentlyPlayingURL, url, videoResumeTryNumberRef]);

const hideControl = useCallback(() => {
// eslint-disable-next-line react-compiler/react-compiler
controlsOpacity.value = withTiming(0, {duration: 500}, () => runOnJS(setControlStatusState)(CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE));
}, [controlsOpacity]);
const debouncedHideControl = useMemo(() => debounce(hideControl, 1500), [hideControl]);

useEffect(() => {
if (canUseTouchScreen) {
return;
}
// If the device cannot use touch screen, always set the control status as 'show'.
// Then if user hover over the video, controls is shown.
setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW);
}, [canUseTouchScreen]);

useEffect(() => {
// We only auto hide the control if the device can use touch screen.
if (!canUseTouchScreen) {
return;
}
if (controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) {
return;
}
if (!isPlaying || isPopoverVisible) {
debouncedHideControl.cancel();
return;
}

debouncedHideControl();
}, [isPlaying, debouncedHideControl, controlStatusState, isPopoverVisible, canUseTouchScreen]);

const toggleControl = useCallback(() => {
if (controlStatusState === CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW) {
hideControl();
return;
}
setControlStatusState(CONST.VIDEO_PLAYER.CONTROLS_STATUS.SHOW);
controlsOpacity.value = 1;
}, [controlStatusState, controlsOpacity, hideControl]);

const showPopoverMenu = (event?: GestureResponderEvent | KeyboardEvent) => {
videoPopoverMenuPlayerRef.current = videoPlayerRef.current;
videoPlayerRef.current?.getStatusAsync().then((status) => {
Expand Down Expand Up @@ -311,7 +358,11 @@ function BaseVideoPlayer({
if (isFullScreenRef.current) {
return;
}
togglePlayCurrentVideo();
if (!canUseTouchScreen) {
togglePlayCurrentVideo();
return;
}
toggleControl();
}}
style={[styles.flex1, styles.noSelect]}
>
Expand Down Expand Up @@ -373,17 +424,17 @@ function BaseVideoPlayer({
</PressableWithoutFeedback>
{((isLoading && !isOffline) || isBuffering) && <FullScreenLoadingIndicator style={[styles.opacity1, styles.bgTransparent]} />}
{isLoading && !isBuffering && <AttachmentOfflineIndicator isPreview={isPreview} />}
{controlsStatus !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE && !isLoading && (isPopoverVisible || isHovered || canUseTouchScreen) && (
{controlStatusState !== CONST.VIDEO_PLAYER.CONTROLS_STATUS.HIDE && !isLoading && (isPopoverVisible || isHovered || canUseTouchScreen) && (
<VideoPlayerControls
duration={duration}
position={position}
url={url}
videoPlayerRef={videoPlayerRef}
isPlaying={isPlaying}
small={shouldUseSmallVideoControls}
style={videoControlsStyle}
style={[videoControlsStyle, controlsAnimatedStyle]}
togglePlayCurrentVideo={togglePlayCurrentVideo}
controlsStatus={controlsStatus}
controlsStatus={controlStatusState}
showPopoverMenu={showPopoverMenu}
/>
)}
Expand Down

0 comments on commit 4f45424

Please sign in to comment.