Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix Hide video playback controls on auto-playing videos #43349

Merged
merged 27 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
944c6ed
fix Hide video playback controls on auto-playing videos
tienifr Jun 10, 2024
fe167aa
fix lint
tienifr Jun 10, 2024
9caa203
fix update controlsStatus
tienifr Jun 10, 2024
8a7993d
fix use runOnJS
tienifr Jun 11, 2024
6bf5ec3
fix merge main
tienifr Jun 24, 2024
19c70fc
fix merge main
tienifr Jun 26, 2024
cf99a4c
fix auto hide controls after playing video 2s
tienifr Jun 26, 2024
964a0d2
fix missing condition
tienifr Jun 26, 2024
5daecf0
fix lint
tienifr Jun 26, 2024
cfe687a
fix lint
tienifr Jun 26, 2024
54fa6d5
fix merge main
tienifr Jun 27, 2024
f1f9bea
fix do not play video on tap
tienifr Jun 27, 2024
61dacf5
fix merge main
tienifr Jul 3, 2024
801707f
fix reset the debounce once click on video
tienifr Jul 3, 2024
b92b079
fix merge main
tienifr Jul 5, 2024
2fc8759
fix do not hide control if popover is opening
tienifr Jul 5, 2024
ab2d8ed
Merge branch 'Expensify:main' into fix/42323
tienifr Jul 15, 2024
6a871f3
merge main
tienifr Jul 16, 2024
80504a8
remove canToggleControlOnTap and fix lint
tienifr Jul 16, 2024
1cb1e81
fix type
tienifr Jul 16, 2024
f73f558
fix lint
tienifr Jul 16, 2024
e274b3a
merge main
tienifr Jul 22, 2024
b81117f
fix hover over video should display control in dekstop
tienifr Jul 22, 2024
dd15a3d
fix lint
tienifr Jul 22, 2024
53f69d6
do not delay hide control & hide control on tap
tienifr Jul 31, 2024
8f5c197
reduce hide delay to 1500
tienifr Aug 1, 2024
7034385
Merge branch 'main' of https://github.com/tienifr/App into fix/42323
tienifr Aug 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/FeatureTrainingModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need an early return here. Otherwise, showControl will trigger the timer to hide the controls for large screen devices.

Suggested change
togglePlayCurrentVideo();
togglePlayCurrentVideo();
return;

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
Loading