Media Viewer: Fix volume control for narrow video (#2837)
This commit is contained in:
parent
1ad2e816a2
commit
aa1cd0a3b9
@ -57,6 +57,7 @@ type StateProps = {
|
||||
};
|
||||
|
||||
const ANIMATION_DURATION = 350;
|
||||
const MOBILE_VERSION_CONTROL_WIDTH = 350;
|
||||
|
||||
const MediaViewerContent: FC<OwnProps & StateProps> = (props) => {
|
||||
const {
|
||||
@ -105,6 +106,10 @@ const MediaViewerContent: FC<OwnProps & StateProps> = (props) => {
|
||||
setControlsVisible?.(isVisible);
|
||||
}, [setControlsVisible]);
|
||||
|
||||
const toggleControlsOnMove = useCallback(() => {
|
||||
toggleControls(true);
|
||||
}, [toggleControls]);
|
||||
|
||||
if (avatarOwner || actionPhoto) {
|
||||
if (!isVideoAvatar) {
|
||||
return (
|
||||
@ -149,21 +154,25 @@ const MediaViewerContent: FC<OwnProps & StateProps> = (props) => {
|
||||
const textParts = message.content.action?.type === 'suggestProfilePhoto'
|
||||
? lang('Conversation.SuggestedPhotoTitle')
|
||||
: renderMessageText(message);
|
||||
|
||||
const hasFooter = Boolean(textParts);
|
||||
const posterSize = message && calculateMediaViewerDimensions(dimensions!, hasFooter, isVideo);
|
||||
const isForceMobileVersion = isMobile || shouldForceMobileVersion(posterSize);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName('MediaViewerContent', hasFooter && 'has-footer')}
|
||||
onMouseMove={isForceMobileVersion && !IS_TOUCH_ENV ? toggleControlsOnMove : undefined}
|
||||
>
|
||||
{isPhoto && renderPhoto(
|
||||
bestData,
|
||||
message && calculateMediaViewerDimensions(dimensions!, hasFooter),
|
||||
posterSize,
|
||||
!isMobile && !isProtected,
|
||||
isProtected,
|
||||
)}
|
||||
{isVideo && (!isActive ? renderVideoPreview(
|
||||
bestImageData,
|
||||
message && calculateMediaViewerDimensions(dimensions!, hasFooter, true),
|
||||
posterSize,
|
||||
!isMobile && !isProtected,
|
||||
isProtected,
|
||||
) : (
|
||||
@ -172,7 +181,7 @@ const MediaViewerContent: FC<OwnProps & StateProps> = (props) => {
|
||||
url={bestData}
|
||||
isGif={isGif}
|
||||
posterData={bestImageData}
|
||||
posterSize={message && calculateMediaViewerDimensions(dimensions!, hasFooter, true)}
|
||||
posterSize={posterSize}
|
||||
loadProgress={loadProgress}
|
||||
fileSize={videoSize!}
|
||||
areControlsVisible={areControlsVisible}
|
||||
@ -182,6 +191,7 @@ const MediaViewerContent: FC<OwnProps & StateProps> = (props) => {
|
||||
onClose={onClose}
|
||||
isMuted={isMuted}
|
||||
isHidden={isHidden}
|
||||
isForceMobileVersion={isForceMobileVersion}
|
||||
isProtected={isProtected}
|
||||
volume={volume}
|
||||
isClickDisabled={isMoving}
|
||||
@ -193,6 +203,7 @@ const MediaViewerContent: FC<OwnProps & StateProps> = (props) => {
|
||||
text={textParts}
|
||||
onClick={onFooterClick}
|
||||
isProtected={isProtected}
|
||||
isForceMobileVersion={isForceMobileVersion}
|
||||
isHidden={IS_TOUCH_ENV ? !areControlsVisible : false}
|
||||
isForVideo={isVideo && !isGif}
|
||||
/>
|
||||
@ -342,3 +353,8 @@ function renderVideoPreview(blobUrl?: string, imageSize?: ApiDimensions, canDrag
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function shouldForceMobileVersion(posterSize?: { width: number; height: number }) {
|
||||
if (!posterSize) return false;
|
||||
return posterSize.width < MOBILE_VERSION_CONTROL_WIDTH;
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
padding: 0.5rem 0 0;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
&.mobile {
|
||||
background: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0) 100%);
|
||||
|
||||
&.is-for-video {
|
||||
@ -26,6 +26,14 @@
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
.media-viewer-footer-content {
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
.media-text.multiline::before {
|
||||
display: none;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
body.ghost-animating & {
|
||||
@ -43,10 +51,6 @@
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-hidden {
|
||||
@ -84,11 +88,6 @@
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
border-radius: var(--border-radius-default);
|
||||
z-index: var(--z-below);
|
||||
|
||||
@media (max-width: 600px) {
|
||||
display: none;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,11 +17,12 @@ type OwnProps = {
|
||||
onClick: () => void;
|
||||
isHidden?: boolean;
|
||||
isForVideo: boolean;
|
||||
isForceMobileVersion?: boolean;
|
||||
isProtected?: boolean;
|
||||
};
|
||||
|
||||
const MediaViewerFooter: FC<OwnProps> = ({
|
||||
text = '', isHidden, isForVideo, onClick, isProtected,
|
||||
text = '', isHidden, isForVideo, onClick, isProtected, isForceMobileVersion,
|
||||
}) => {
|
||||
const [isMultiline, setIsMultiline] = useState(false);
|
||||
const { isMobile } = useAppLayout();
|
||||
@ -58,6 +59,7 @@ const MediaViewerFooter: FC<OwnProps> = ({
|
||||
isForVideo && 'is-for-video',
|
||||
isHidden && 'is-hidden',
|
||||
isProtected && 'is-protected',
|
||||
isForceMobileVersion && 'mobile',
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@ -38,12 +38,12 @@ type OwnProps = {
|
||||
isProtected?: boolean;
|
||||
areControlsVisible: boolean;
|
||||
shouldCloseOnClick?: boolean;
|
||||
isForceMobileVersion?: boolean;
|
||||
toggleControls: (isVisible: boolean) => void;
|
||||
onClose: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
||||
isClickDisabled?: boolean;
|
||||
};
|
||||
|
||||
const MOBILE_VERSION_CONTROL_WIDTH = 400;
|
||||
const MAX_LOOP_DURATION = 30; // Seconds
|
||||
|
||||
const VideoPlayer: FC<OwnProps> = ({
|
||||
@ -59,6 +59,7 @@ const VideoPlayer: FC<OwnProps> = ({
|
||||
isMuted,
|
||||
playbackRate,
|
||||
onClose,
|
||||
isForceMobileVersion,
|
||||
toggleControls,
|
||||
areControlsVisible,
|
||||
shouldCloseOnClick,
|
||||
@ -226,13 +227,15 @@ const VideoPlayer: FC<OwnProps> = ({
|
||||
|
||||
const wrapperStyle = posterSize && `width: ${posterSize.width}px; height: ${posterSize.height}px`;
|
||||
const videoStyle = `background-image: url(${posterData})`;
|
||||
const shouldToggleControls = !IS_TOUCH_ENV && !isForceMobileVersion;
|
||||
const duration = videoRef.current?.duration || 0;
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
|
||||
<div
|
||||
className="VideoPlayer"
|
||||
onMouseMove={!IS_TOUCH_ENV ? handleVideoMove : undefined}
|
||||
onMouseOut={!IS_TOUCH_ENV ? handleVideoLeave : undefined}
|
||||
onMouseMove={shouldToggleControls ? handleVideoMove : undefined}
|
||||
onMouseOut={shouldToggleControls ? handleVideoLeave : undefined}
|
||||
>
|
||||
<div
|
||||
style={wrapperStyle}
|
||||
@ -301,7 +304,7 @@ const VideoPlayer: FC<OwnProps> = ({
|
||||
duration={duration}
|
||||
isVisible={areControlsVisible}
|
||||
setVisibility={toggleControls}
|
||||
isForceMobileVersion={posterSize && posterSize.width < MOBILE_VERSION_CONTROL_WIDTH}
|
||||
isForceMobileVersion={isForceMobileVersion}
|
||||
onSeek={handleSeek}
|
||||
onChangeFullscreen={handleFullscreenChange}
|
||||
onPictureInPictureChange={enterPictureInPicture}
|
||||
|
||||
@ -18,10 +18,16 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
&.mobile {
|
||||
position: fixed;
|
||||
padding: 2.25rem 0.5rem 0.75rem;
|
||||
background: none;
|
||||
.player-seekline {
|
||||
top: 1rem;
|
||||
}
|
||||
.playback-rate-menu .bubble {
|
||||
bottom: 4.6875rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
@ -44,6 +50,9 @@
|
||||
padding: 0;
|
||||
margin: 0.25rem;
|
||||
height: 2rem;
|
||||
@media (max-width: 320px) {
|
||||
margin: 0.125rem;
|
||||
}
|
||||
}
|
||||
|
||||
.volume-slider {
|
||||
@ -91,6 +100,9 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-left: 0.5rem;
|
||||
@media (max-width: 320px) {
|
||||
margin: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.player-seekline {
|
||||
@ -102,10 +114,6 @@
|
||||
touch-action: none;
|
||||
cursor: pointer;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
top: 1rem;
|
||||
}
|
||||
|
||||
&-track {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@ -155,9 +163,6 @@
|
||||
min-width: 3.5rem;
|
||||
margin-right: 5.8125rem;
|
||||
bottom: 4.1875rem;
|
||||
@media (max-width: 600px) {
|
||||
bottom: 4.6875rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.no-fullscreen, &.no-pip {
|
||||
|
||||
@ -94,7 +94,7 @@ const VideoPlayerControls: FC<OwnProps> = ({
|
||||
const { isMobile } = useAppLayout();
|
||||
|
||||
useEffect(() => {
|
||||
if (!IS_TOUCH_ENV) return undefined;
|
||||
if (!IS_TOUCH_ENV && !isForceMobileVersion) return undefined;
|
||||
let timeout: number | undefined;
|
||||
if (!isVisible || !isPlaying || isSeeking || isPlaybackMenuOpen) {
|
||||
if (timeout) window.clearTimeout(timeout);
|
||||
@ -106,7 +106,7 @@ const VideoPlayerControls: FC<OwnProps> = ({
|
||||
return () => {
|
||||
if (timeout) window.clearTimeout(timeout);
|
||||
};
|
||||
}, [isPlaying, isVisible, isSeeking, setVisibility, isPlaybackMenuOpen]);
|
||||
}, [isPlaying, isVisible, isSeeking, setVisibility, isPlaybackMenuOpen, isForceMobileVersion]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisible) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user