From 4f7581f97504b9ba6f06caa59e167c1fd48869fc Mon Sep 17 00:00:00 2001 From: amar-1995 Date: Sun, 21 Jan 2024 21:58:54 +0530 Subject: [PATCH 01/25] feat: hls player ui for mweb --- .../prebuilt-react-integration/src/App.jsx | 16 +- .../HMSVideo/HLSQualitySelector.jsx | 100 +++++++- .../Prebuilt/components/HMSVideo/HMSVideo.jsx | 1 + .../components/HMSVideo/PlayerContext.tsx | 22 ++ .../Prebuilt/components/Leave/LeaveRoom.tsx | 2 +- .../components/Leave/MwebLeaveRoom.tsx | 5 +- .../src/Prebuilt/layouts/HLSView.jsx | 225 ++++++++++++++++-- .../src/Prebuilt/layouts/SidePane.tsx | 5 +- .../layouts/VideoStreamingSection.tsx | 30 ++- 9 files changed, 366 insertions(+), 40 deletions(-) create mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayerContext.tsx diff --git a/examples/prebuilt-react-integration/src/App.jsx b/examples/prebuilt-react-integration/src/App.jsx index 36892410ef..c51b279885 100644 --- a/examples/prebuilt-react-integration/src/App.jsx +++ b/examples/prebuilt-react-integration/src/App.jsx @@ -5,8 +5,16 @@ export default function App() { const roomCode = getRoomCodeFromUrl(); return ( - - ) + + ); } - - diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx index 73ef77fb69..7842cef295 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx @@ -1,8 +1,106 @@ import React from 'react'; -import { CheckIcon, SettingsIcon } from '@100mslive/react-icons'; +import { useMedia } from 'react-use'; +import { CheckIcon, CrossIcon, SettingsIcon } from '@100mslive/react-icons'; import { Box, Dropdown, Flex, Text, Tooltip } from '../../../'; +import { Sheet } from '../../../Sheet'; +import { config } from '../../../Theme'; export function HLSQualitySelector({ open, onOpen, layers, onQualityChange, selection, isAuto }) { + const isMobile = useMedia(config.media.md); + if (isMobile) { + return ( + + + + + + + + {layers.length > 0 && ( + onOpen(false)}> + + Quality + onOpen(false)}> + + + + {layers.map(layer => { + return ( + onQualityChange(layer)} + > + + {getQualityText(layer)} + + + {getBitrateText(layer)} + + {!isAuto && layer.width === selection?.width && layer.height === selection?.height && ( + + )} + + ); + })} + onQualityChange({ height: 'auto' })} + > + + Auto + + {isAuto && } + + + )} + + ); + } return ( onOpen(value)}> diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx index fcd68de388..ba05365e56 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVideo.jsx @@ -33,6 +33,7 @@ export const HMSVideo = forwardRef(({ children, ...props }, videoRef) => { flex: '1 1 0', margin: '0 auto', minHeight: '0', + objectFit: 'cover', }} ref={videoRef} playsInline diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayerContext.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayerContext.tsx new file mode 100644 index 0000000000..38c7687bf0 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/PlayerContext.tsx @@ -0,0 +1,22 @@ +import React, { Dispatch, SetStateAction, useContext } from 'react'; +import { HMSHLSPlayer } from '@100mslive/hls-player'; + +type HMSPlayeContext = { + hlsPlayer?: HMSHLSPlayer; + setHlsPlayer: Dispatch>; +}; + +export const HMSPlayerContext = React.createContext({ + hlsPlayer: undefined, + setHlsPlayer: () => null, +}); + +export const useHMSPlayerContext = () => { + const context = useContext(HMSPlayerContext); + return context.hlsPlayer; +}; + +export const useSetHMSPlayerContext = () => { + const context = useContext(HMSPlayerContext); + return [context.hlsPlayer, context.setHlsPlayer]; +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx b/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx index 681057a310..46d79e359d 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Leave/LeaveRoom.tsx @@ -62,7 +62,7 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen return null; } return isMobile ? ( - + ) : ( ); diff --git a/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx b/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx index 952a9feef5..2a322d2f2a 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx @@ -1,5 +1,4 @@ import React, { Fragment, useState } from 'react'; -import { ConferencingScreen } from '@100mslive/types-prebuilt'; // @ts-ignore: No implicit Any import { selectIsConnectedToRoom, selectPermissions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk'; // @ts-ignore: No implicit Any @@ -11,19 +10,19 @@ import { EndSessionContent } from './EndSessionContent'; import { LeaveIconButton } from './LeaveAtoms'; import { LeaveCard } from './LeaveCard'; import { LeaveSessionContent } from './LeaveSessionContent'; +import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; // @ts-ignore: No implicit Any import { useDropdownList } from '../hooks/useDropdownList'; export const MwebLeaveRoom = ({ leaveRoom, - screenType, endRoom, }: { leaveRoom: (options?: { endStream?: boolean }) => Promise; - screenType: keyof ConferencingScreen; endRoom: () => Promise; }) => { const [open, setOpen] = useState(false); + const { screenType } = useRoomLayoutConferencingScreen(); const [showLeaveRoomAlert, setShowLeaveRoomAlert] = useState(false); const [showEndStreamAlert, setShowEndStreamAlert] = useState(false); const isConnected = useHMSStore(selectIsConnectedToRoom); diff --git a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx index 9a0a6e0c3b..6e08572b10 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx @@ -11,7 +11,7 @@ import { useHMSStore, useHMSVanillaStore, } from '@100mslive/react-sdk'; -import { ColoredHandIcon, ExpandIcon, PlayIcon, RadioIcon, ShrinkIcon } from '@100mslive/react-icons'; +import { CloseIcon, ColoredHandIcon, ExpandIcon, PlayIcon, RadioIcon, ShrinkIcon } from '@100mslive/react-icons'; import { HlsStatsOverlay } from '../components/HlsStatsOverlay'; import { HMSVideoPlayer } from '../components/HMSVideo'; import { FullScreenButton } from '../components/HMSVideo/FullscreenButton'; @@ -275,6 +275,209 @@ const HLSView = () => { [controlsVisible, isFullScreen, qualityDropDownOpen], ); + if (isMobile) { + return ( + + {hlsUrl && !streamEnded ? ( + + + {showLoader && ( + + + + )} + + + await hlsPlayer?.play()} data-testid="play_btn"> + + + + + + + console.log('TOOD')}> + + + + + + {hasCaptions && ( + hlsPlayer?.toggleCaption()} isEnabled={isCaptionEnabled} /> + )} + {availableLayers.length > 0 ? ( + + ) : null} + + + + + + + { + await hlsPlayer.seekToLivePosition(); + setIsVideoLive(true); + }} + key="jump-to-live_btn" + data-testid="jump-to-live_btn" + > + + + + + {isVideoLive ? 'LIVE' : 'GO LIVE'} + + + + + + + + + {isFullScreenSupported ? ( + : } + /> + ) : null} + + + + + {hlsPlayer && ( + { + hlsPlayer.seekTo(time); + }} + /> + )} + + + + ) : ( + + + {streamEnded ? : } + + + {streamEnded ? 'Stream has ended' : 'Stream yet to start'} + + + {streamEnded ? 'Have a nice day!' : 'Sit back and relax'} + + + )} + {/** player handler --> left -> go live with timer or live, right -> expand icon */} + {/** inbetween -> play pause icon, double tap to go back/forward */} + {/** seekbar */} + {/** half page will have chat or participant view */} + + ); + } return ( { onMouseMove={onHoverHandler} onMouseLeave={onHoverHandler} > - {isMobile && isPaused && ( - - await hlsPlayer?.play()} data-testid="play_btn"> - - - - )} { @@ -106,14 +109,25 @@ export const VideoStreamingSection = ({ }} > {ViewComponent} - - - + {screenType === 'hls_live_streaming' && isMobile ? ( + + + + ) : ( + + + + )} ); From cc4c046962980db7a0f2e34ec1e1fc4b270e72e2 Mon Sep 17 00:00:00 2001 From: amar-1995 Date: Mon, 5 Feb 2024 12:17:57 +0530 Subject: [PATCH 02/25] fix: added leave icon --- .../prebuilt-react-integration/src/App.jsx | 1 - .../Prebuilt/components/Leave/LeaveRoom.tsx | 4 ++ .../components/Leave/MwebLeaveRoom.tsx | 60 ++++++++++++------- .../src/Prebuilt/layouts/HLSView.jsx | 22 ++++--- .../src/Prebuilt/layouts/SidePane.tsx | 5 +- 5 files changed, 60 insertions(+), 32 deletions(-) diff --git a/examples/prebuilt-react-integration/src/App.jsx b/examples/prebuilt-react-integration/src/App.jsx index c51b279885..062f3f4739 100644 --- a/examples/prebuilt-react-integration/src/App.jsx +++ b/examples/prebuilt-react-integration/src/App.jsx @@ -8,7 +8,6 @@ export default function App() { = useHMSStore(selectRolesMap); const streamingPermissionRoles = Object.keys(rolesMap).filter(roleName => { const roleObj = rolesMap[roleName]; @@ -61,6 +62,9 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen if (!permissions || !isConnected) { return null; } + if ((isMobile || isLandscape) && screenType === 'hls_live_streaming') { + return ; + } return isMobile ? ( ) : ( diff --git a/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx b/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx index 2a322d2f2a..a586d5449d 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx @@ -1,10 +1,13 @@ import React, { Fragment, useState } from 'react'; +import { useMedia } from 'react-use'; // @ts-ignore: No implicit Any import { selectIsConnectedToRoom, selectPermissions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk'; // @ts-ignore: No implicit Any -import { ExitIcon, StopIcon } from '@100mslive/react-icons'; +import { CloseIcon, ExitIcon, StopIcon } from '@100mslive/react-icons'; +import { IconButton } from '../../../IconButton'; import { Box } from '../../../Layout'; import { Sheet } from '../../../Sheet'; +import { config as cssConfig } from '../../../Theme'; import { Tooltip } from '../../../Tooltip'; import { EndSessionContent } from './EndSessionContent'; import { LeaveIconButton } from './LeaveAtoms'; @@ -42,20 +45,7 @@ export const MwebLeaveRoom = ({ {showLeaveOptions ? ( - - - - - - - + setOpen(!open)} /> ) : ( - setShowLeaveRoomAlert(true)}> - - - - - - + setShowLeaveRoomAlert(true)} /> )} @@ -113,3 +97,35 @@ export const MwebLeaveRoom = ({ ); }; + +const LeaveIcon = ({ onClick }: { onClick: () => void }) => { + const isMobile = useMedia(cssConfig.media.md); + const isLandscape = useMedia(cssConfig.media.ls); + const { screenType } = useRoomLayoutConferencingScreen(); + + return (isMobile || isLandscape) && screenType === 'hls_live_streaming' ? ( + onClick()}> + + + + + + + ) : ( + onClick()} + > + + + + + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx index 6e08572b10..553622f171 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx @@ -11,13 +11,14 @@ import { useHMSStore, useHMSVanillaStore, } from '@100mslive/react-sdk'; -import { CloseIcon, ColoredHandIcon, ExpandIcon, PlayIcon, RadioIcon, ShrinkIcon } from '@100mslive/react-icons'; +import { ColoredHandIcon, ExpandIcon, PlayIcon, RadioIcon, ShrinkIcon } from '@100mslive/react-icons'; import { HlsStatsOverlay } from '../components/HlsStatsOverlay'; import { HMSVideoPlayer } from '../components/HMSVideo'; import { FullScreenButton } from '../components/HMSVideo/FullscreenButton'; import { HLSAutoplayBlockedPrompt } from '../components/HMSVideo/HLSAutoplayBlockedPrompt'; import { HLSCaptionSelector } from '../components/HMSVideo/HLSCaptionSelector'; import { HLSQualitySelector } from '../components/HMSVideo/HLSQualitySelector'; +import { LeaveRoom } from '../components/Leave/LeaveRoom'; import { ToastManager } from '../components/Toast/ToastManager'; import { Button } from '../../Button'; import { IconButton } from '../../IconButton'; @@ -27,7 +28,7 @@ import { Text } from '../../Text'; import { config, useTheme } from '../../Theme'; import { Tooltip } from '../../Tooltip'; import { usePollViewToggle } from '../components/AppData/useSidepane'; -import { APP_DATA, EMOJI_REACTION_TYPE } from '../common/constants'; +import { APP_DATA, EMOJI_REACTION_TYPE, SIDE_PANE_OPTIONS } from '../common/constants'; let hlsPlayer; @@ -60,6 +61,8 @@ const HLSView = () => { const vanillaStore = useHMSVanillaStore(); const isMobile = useMedia(config.media.md); + const isLandscape = useMedia(config.media.ls); + const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane)); const isFullScreen = useFullscreen(hlsViewRef, show, { onClose: () => toggle(false), }); @@ -275,14 +278,21 @@ const HLSView = () => { [controlsVisible, isFullScreen, qualityDropDownOpen], ); - if (isMobile) { + if (isMobile || isLandscape) { return ( {hlsUrl && !streamEnded ? ( @@ -353,9 +363,7 @@ const HLSView = () => { }} > - console.log('TOOD')}> - - + diff --git a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx index 1017278696..3403ff800f 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx @@ -76,7 +76,7 @@ const SidePane = ({ justify="center" css={{ w: '$100', - h: '100%', + h: mwebHLSStream ? '50%' : '100%', flexShrink: 0, gap: '$4', position: 'relative', @@ -97,7 +97,7 @@ const SidePane = ({ Date: Tue, 6 Feb 2024 10:34:26 +0530 Subject: [PATCH 03/25] fix: added hls mweb file structure --- .../prebuilt-react-integration/vite.config.js | 3 + .../Prebuilt/components/HMSVideo/Controls.jsx | 2 +- .../components/HMSVideo/DesktopHLSView.tsx | 182 +++++++ .../components/HMSVideo/FullscreenButton.jsx | 18 - .../components/HMSVideo/FullscreenButton.tsx | 20 + ...rompt.jsx => HLSAutoplayBlockedPrompt.tsx} | 5 +- .../HMSVideo/HLSCaptionSelector.tsx | 6 +- .../HMSVideo/HLSQualitySelector.jsx | 5 +- .../{HMSVIdeoUtils.js => HMSVIdeoUtils.ts} | 20 +- .../components/HMSVideo/MwebHLSView.tsx | 307 ++++++++++++ .../components/HMSVideo/VideoProgress.jsx | 76 --- .../components/HMSVideo/VideoProgress.tsx | 88 ++++ .../components/HMSVideo/VideoTime.jsx | 33 -- .../components/HMSVideo/VideoTime.tsx | 35 ++ .../{VolumeControl.jsx => VolumeControl.tsx} | 16 +- .../HMSVideo/{index.js => index.ts} | 3 + .../src/Prebuilt/layouts/HLSView.jsx | 447 ++++-------------- 17 files changed, 760 insertions(+), 506 deletions(-) create mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/DesktopHLSView.tsx delete mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.jsx create mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.tsx rename packages/roomkit-react/src/Prebuilt/components/HMSVideo/{HLSAutoplayBlockedPrompt.jsx => HLSAutoplayBlockedPrompt.tsx} (88%) rename packages/roomkit-react/src/Prebuilt/components/HMSVideo/{HMSVIdeoUtils.js => HMSVIdeoUtils.ts} (57%) create mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/MwebHLSView.tsx delete mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.jsx create mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx delete mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.jsx create mode 100644 packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.tsx rename packages/roomkit-react/src/Prebuilt/components/HMSVideo/{VolumeControl.jsx => VolumeControl.tsx} (76%) rename packages/roomkit-react/src/Prebuilt/components/HMSVideo/{index.js => index.ts} (92%) diff --git a/examples/prebuilt-react-integration/vite.config.js b/examples/prebuilt-react-integration/vite.config.js index 14d7d98e40..4625094b14 100644 --- a/examples/prebuilt-react-integration/vite.config.js +++ b/examples/prebuilt-react-integration/vite.config.js @@ -7,4 +7,7 @@ export default defineConfig({ define: { 'process.env': {}, }, + optimizeDeps: { + exclude: ['lodash'], + }, }); diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/Controls.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/Controls.jsx index d6ff7a9752..9e1b57e335 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/Controls.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/Controls.jsx @@ -1,4 +1,4 @@ -import { Flex, styled } from '../../../'; +import { Flex, styled } from '../../..'; export const VideoControls = styled(Flex, { justifyContent: 'center', diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/DesktopHLSView.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/DesktopHLSView.tsx new file mode 100644 index 0000000000..03615fb447 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/DesktopHLSView.tsx @@ -0,0 +1,182 @@ +import React, { useCallback, useRef, useState } from 'react'; +import { HMSHLSLayer } from '@100mslive/hls-player'; +import screenfull from 'screenfull'; +import { ExpandIcon, ShrinkIcon } from '@100mslive/react-icons'; +import { IconButton } from '../../../IconButton'; +import { Box, Flex } from '../../../Layout'; +import { Text } from '../../../Text'; +import { theme } from '../../../Theme'; +import { Tooltip } from '../../../Tooltip'; +import { FullScreenButton } from './FullscreenButton'; +import { HLSCaptionSelector } from './HLSCaptionSelector'; +// @ts-ignore +import { HLSQualitySelector } from './HLSQualitySelector'; +// @ts-ignore +import { HMSVideoPlayer } from './index'; +import { useHMSPlayerContext } from './PlayerContext'; + +export const DesktopHLSView = React.forwardRef< + HTMLDivElement, + { + isFullScreen: boolean; + isPaused: boolean; + hasCaptions: boolean; + isCaptionEnabled: boolean; + isVideoLive: boolean; + availableLayers: HMSHLSLayer[]; + currentSelectedQuality: HMSHLSLayer; + setIsVideoLive: (value: boolean) => void; + toggle: () => void; + } +>( + ( + { + isFullScreen, + isPaused, + hasCaptions, + isCaptionEnabled, + isVideoLive, + availableLayers, + currentSelectedQuality, + setIsVideoLive, + toggle, + }, + videoRef, + ) => { + const hlsPlayerContext = useHMSPlayerContext(); + const [controlsVisible, setControlsVisible] = useState(true); + const [isUserSelectedAuto, setIsUserSelectedAuto] = useState(true); + const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false); + const controlsRef: React.RefObject = useRef(null); + const controlsTimerRef = useRef(); + + const isFullScreenSupported = screenfull.isEnabled; + + const handleQuality = useCallback( + (quality: HMSHLSLayer) => { + if (hlsPlayerContext) { + setIsUserSelectedAuto(quality.height?.toString().toLowerCase() === 'auto'); + hlsPlayerContext?.setLayer(quality); + } + }, + [availableLayers], //eslint-disable-line + ); + const onHoverHandler = useCallback( + (event: any) => { + if (event.type === 'mouseenter' || event.type === 'touchenter' || qualityDropDownOpen) { + setControlsVisible(true); + return; + } + if (event.type === 'mouseleave' || event.type === 'touchleave') { + setControlsVisible(false); + } else if (isFullScreen && !controlsVisible && event.type === 'mousemove') { + setControlsVisible(true); + if (controlsTimerRef.current) { + clearTimeout(controlsTimerRef.current); + } + } + }, + [controlsVisible, isFullScreen, qualityDropDownOpen], + ); + return ( + + + + + + + + { + isPaused ? await hlsPlayerContext?.play() : hlsPlayerContext?.pause(); + }} + isPaused={isPaused} + /> + + + { + await hlsPlayerContext?.seekToLivePosition(); + setIsVideoLive(true); + }} + key="jump-to-live_btn" + data-testid="jump-to-live_btn" + > + + + + + {isVideoLive ? 'LIVE' : 'GO LIVE'} + + + + + + + + {hasCaptions && } + {availableLayers.length > 0 ? ( + + ) : null} + {isFullScreenSupported ? ( + : } + /> + ) : null} + + + + + ); + }, +); diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.jsx deleted file mode 100644 index 6fc0d40344..0000000000 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { Flex, IconButton, Tooltip } from '../../../'; - -export const FullScreenButton = ({ isFullScreen, icon, onToggle }) => { - return ( - - - {icon} - - - ); -}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.tsx new file mode 100644 index 0000000000..07d8f34676 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/FullscreenButton.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { Flex, IconButton, Tooltip } from '../../..'; + +export const FullScreenButton = ({ + isFullScreen, + icon, + onToggle, +}: { + isFullScreen: boolean; + icon: any; + onToggle: () => void; +}) => { + return ( + + + {icon} + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.tsx similarity index 88% rename from packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.jsx rename to packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.tsx index 7d30488671..fa191daf49 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.tsx @@ -1,8 +1,9 @@ import React from 'react'; -import { Button, Dialog, Text } from '../../../'; +import { Button, Dialog, Text } from '../../..'; +// @ts-ignore import { DialogContent, DialogRow } from '../../primitives/DialogContent'; -export function HLSAutoplayBlockedPrompt({ open, unblockAutoPlay }) { +export function HLSAutoplayBlockedPrompt({ open, unblockAutoPlay }: { open: boolean; unblockAutoPlay: () => void }) { return ( void }) { +export function HLSCaptionSelector({ isEnabled }: { isEnabled: boolean }) { + const hlsPlayerContext = useHMSPlayerContext(); return ( - onClick()}> + hlsPlayerContext?.toggleCaption()}> {isEnabled ? : } diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx index 7842cef295..cd3692e888 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx @@ -1,13 +1,14 @@ import React from 'react'; import { useMedia } from 'react-use'; import { CheckIcon, CrossIcon, SettingsIcon } from '@100mslive/react-icons'; -import { Box, Dropdown, Flex, Text, Tooltip } from '../../../'; +import { Box, Dropdown, Flex, Text, Tooltip } from '../../..'; import { Sheet } from '../../../Sheet'; import { config } from '../../../Theme'; export function HLSQualitySelector({ open, onOpen, layers, onQualityChange, selection, isAuto }) { const isMobile = useMedia(config.media.md); - if (isMobile) { + const isLandscape = useMedia(config.media.ls); + if (isMobile || isLandscape) { return ( diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.js b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.ts similarity index 57% rename from packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.js rename to packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.ts index 2bf07c9d37..b04ca54ae0 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.js +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.ts @@ -1,4 +1,4 @@ -export function getPercentage(a, b) { +export function getPercentage(a: number, b: number) { return (a / b) * 100; } @@ -8,7 +8,7 @@ export function getPercentage(a, b) { * @returns a string representing timeInSeconds in HH:MM:SS format. * (e.g) getDurationFromSeconds(3910) returns "1:05:10" */ -export function getDurationFromSeconds(timeInSeconds) { +export function getDurationFromSeconds(timeInSeconds: number) { let time = Math.floor(timeInSeconds); const hours = Math.floor(time / 3600); time = time - hours * 3600; @@ -25,3 +25,19 @@ export function getDurationFromSeconds(timeInSeconds) { } return videoTimeStr; } + +export function getWatchCount(viewer: number) { + if (viewer < 1000) { + return viewer; + } + const output = (viewer / 1000).toFixed(2); + return output + 'K'; +} + +export function getTime(timeInMilles: number) { + const timeInSeconds = Math.floor(timeInMilles / 1000); + const hours = Math.floor(timeInSeconds / 3600); + const minutes = Math.floor((timeInSeconds % 3600) / 60); + const hour = hours !== 0 ? `${hours < 10 ? '0' : ''}${hours}:` : ''; + return hour + `${hour ? 'h:' : ''}` + minutes + 'm'; +} diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/MwebHLSView.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/MwebHLSView.tsx new file mode 100644 index 0000000000..6b6a5efbe6 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/MwebHLSView.tsx @@ -0,0 +1,307 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { HMSHLSLayer } from '@100mslive/hls-player'; +import screenfull from 'screenfull'; +import { selectHLSState, selectPeerCount, useHMSStore } from '@100mslive/react-sdk'; +import { ExpandIcon, PauseIcon, PlayIcon, ShrinkIcon } from '@100mslive/react-icons'; +import { IconButton } from '../../../IconButton'; +import { Box, Flex } from '../../../Layout'; +import { Text } from '../../../Text'; +import { Tooltip } from '../../../Tooltip'; +// @ts-ignore: No implicit any +import { Logo } from '../Header/HeaderComponents'; +import { LeaveRoom } from '../Leave/LeaveRoom'; +import { FullScreenButton } from './FullscreenButton'; +import { HLSCaptionSelector } from './HLSCaptionSelector'; +// @ts-ignore +import { HLSQualitySelector } from './HLSQualitySelector'; +import { getTime, getWatchCount } from './HMSVIdeoUtils'; +// @ts-ignore +import { HMSVideoPlayer } from './index'; +import { useHMSPlayerContext } from './PlayerContext'; +import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; + +export const MwebHLSView = React.forwardRef< + HTMLDivElement, + { + isFullScreen: boolean; + isPaused: boolean; + hasCaptions: boolean; + isCaptionEnabled: boolean; + isVideoLive: boolean; + availableLayers: HMSHLSLayer[]; + currentSelectedQuality: HMSHLSLayer; + setIsVideoLive: (value: boolean) => void; + toggle: () => void; + } +>( + ( + { + isFullScreen, + isPaused, + hasCaptions, + isCaptionEnabled, + isVideoLive, + availableLayers, + currentSelectedQuality, + setIsVideoLive, + toggle, + }, + videoRef, + ) => { + const hlsPlayerContext = useHMSPlayerContext(); + const [controlsVisible, setControlsVisible] = useState(true); + const [isUserSelectedAuto, setIsUserSelectedAuto] = useState(true); + const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false); + const controlsRef: React.RefObject = useRef(null); + const controlsTimerRef = useRef(); + + const { screenType } = useRoomLayoutConferencingScreen(); + + const isFullScreenSupported = screenfull.isEnabled; + + const handleQuality = useCallback( + (quality: HMSHLSLayer) => { + if (hlsPlayerContext) { + setIsUserSelectedAuto(quality.height?.toString().toLowerCase() === 'auto'); + hlsPlayerContext?.setLayer(quality); + } + }, + [availableLayers], //eslint-disable-line + ); + const onHoverHandler = useCallback( + (event: React.MouseEvent) => { + if (event.type === 'mouseenter' || event.type === 'touchenter' || qualityDropDownOpen) { + setControlsVisible(true); + return; + } + if (event.type === 'mouseleave' || event.type === 'touchleave') { + setControlsVisible(false); + } else if (isFullScreen && !controlsVisible && event.type === 'mousemove') { + setControlsVisible(true); + if (controlsTimerRef.current) { + clearTimeout(controlsTimerRef.current); + } + } + }, + [controlsVisible, isFullScreen, qualityDropDownOpen], + ); + return ( + <> + + + {isPaused ? ( + await hlsPlayerContext?.play()} data-testid="play_btn"> + + + ) : ( + hlsPlayerContext?.pause()} data-testid="pause_btn"> + + + )} + + + + + + + + + {hasCaptions && } + {availableLayers.length > 0 ? ( + + ) : null} + + + + + + + { + await hlsPlayerContext?.seekToLivePosition(); + setIsVideoLive(true); + }} + key="jump-to-live_btn" + data-testid="jump-to-live_btn" + > + + + + + {isVideoLive ? 'LIVE' : 'GO LIVE'} + + + + + + + + + {isFullScreenSupported ? ( + : } + /> + ) : null} + + + + + + + + + + ); + }, +); +/* + player handler --> left -> go live with timer or live, right -> expand icon + inbetween -> play pause icon, double tap to go back/forward + seekbar + half page will have chat or participant view +*/ +const HLSViewTitle = () => { + const peerCount = useHMSStore(selectPeerCount); + const hlsState = useHMSStore(selectHLSState); + const intervalRef = useRef(null); + const { screenType } = useRoomLayoutConferencingScreen(); + const [liveTime, setLiveTime] = useState(0); + + const startTimer = useCallback(() => { + intervalRef.current = setInterval(() => { + const timeStamp = hlsState?.variants[0]?.[screenType === 'hls_live_streaming' ? 'startedAt' : 'initialisedAt']; + if (hlsState?.running && timeStamp) { + setLiveTime(Date.now() - timeStamp.getTime()); + } + }, 60000); + }, [hlsState?.running, hlsState?.variants]); + + useEffect(() => { + if (hlsState?.running) { + startTimer(); + } + if (!hlsState?.running && intervalRef.current) { + clearInterval(intervalRef.current); + } + return () => { + if (intervalRef.current) { + clearInterval(intervalRef.current); + } + }; + }, [hlsState.running, startTimer]); + + return ( + + + + Tech Talk + + {getWatchCount(peerCount)} + + . + + {getTime(liveTime)} + + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.jsx deleted file mode 100644 index 3a4cfc22a1..0000000000 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { Box, Flex } from '../../../'; -import { getPercentage } from './HMSVIdeoUtils'; - -export const VideoProgress = ({ onValueChange, hlsPlayer }) => { - const [videoProgress, setVideoProgress] = useState(0); - const [bufferProgress, setBufferProgress] = useState(0); - const progressRootRef = useRef(); - - useEffect(() => { - const videoEl = hlsPlayer.getVideoElement(); - const timeupdateHandler = () => { - const videoProgress = Math.floor(getPercentage(videoEl.currentTime, videoEl.duration)); - let bufferProgress = 0; - if (videoEl.buffered.length > 0) { - bufferProgress = Math.floor(getPercentage(videoEl.buffered?.end(0), videoEl.duration)); - } - - setVideoProgress(isNaN(videoProgress) ? 0 : videoProgress); - setBufferProgress(isNaN(bufferProgress) ? 0 : bufferProgress); - }; - if (videoEl) { - videoEl.addEventListener('timeupdate', timeupdateHandler); - } - return function cleanup() { - if (videoEl) { - videoEl.removeEventListener('timeupdate', timeupdateHandler); - } - }; - }, [hlsPlayer]); - - const onProgressChangeHandler = e => { - const userClickedX = e.clientX - progressRootRef.current.offsetLeft; - const progressBarWidth = progressRootRef.current.offsetWidth; - const progress = Math.floor(getPercentage(userClickedX, progressBarWidth)); - const videoEl = hlsPlayer.getVideoElement(); - const currentTime = (progress * videoEl.duration) / 100; - - if (onValueChange) { - onValueChange(currentTime); - } - }; - - return hlsPlayer.getVideoElement() ? ( - - - - - - ) : null; -}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx new file mode 100644 index 0000000000..c6b715a2ae --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoProgress.tsx @@ -0,0 +1,88 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Box, Flex } from '../../..'; +import { getPercentage } from './HMSVIdeoUtils'; +import { useHMSPlayerContext } from './PlayerContext'; + +export const VideoProgress = () => { + const hlsPlayerContext = useHMSPlayerContext(); + const [videoProgress, setVideoProgress] = useState(0); + const [bufferProgress, setBufferProgress] = useState(0); + const progressRootRef = useRef(null); + const videoRef = useRef(null); + + const onValueChange = (time: number) => { + hlsPlayerContext?.seekTo(time); + }; + useEffect(() => { + if (!hlsPlayerContext) { + return; + } + videoRef.current = hlsPlayerContext.getVideoElement(); + const timeupdateHandler = () => { + if (!videoRef.current) { + return; + } + const videoProgress = Math.floor(getPercentage(videoRef.current.currentTime, videoRef.current.duration)); + let bufferProgress = 0; + if (videoRef.current.buffered.length > 0) { + bufferProgress = Math.floor(getPercentage(videoRef.current.buffered?.end(0), videoRef.current.duration)); + } + + setVideoProgress(isNaN(videoProgress) ? 0 : videoProgress); + setBufferProgress(isNaN(bufferProgress) ? 0 : bufferProgress); + }; + if (videoRef.current) { + videoRef.current.addEventListener('timeupdate', timeupdateHandler); + } + return function cleanup() { + if (videoRef.current) { + videoRef.current.removeEventListener('timeupdate', timeupdateHandler); + } + }; + }, [hlsPlayerContext]); + + const onProgressChangeHandler = (e: React.MouseEvent) => { + const userClickedX = e.clientX - (progressRootRef.current?.offsetLeft || 0); + const progressBarWidth = progressRootRef.current?.offsetWidth || 0; + const progress = Math.floor(getPercentage(userClickedX, progressBarWidth)); + const videoEl = hlsPlayerContext?.getVideoElement(); + const currentTime = (progress * (videoEl?.duration || 0)) / 100; + console.log('current time ', currentTime); + if (onValueChange) { + onValueChange(currentTime); + } + }; + + return videoRef.current ? ( + + + + + + ) : null; +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.jsx deleted file mode 100644 index 7bc5d71d12..0000000000 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.jsx +++ /dev/null @@ -1,33 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { HMSHLSPlayerEvents } from '@100mslive/hls-player'; -import { Text } from '../../../'; -import { getDurationFromSeconds } from './HMSVIdeoUtils'; - -export const VideoTime = ({ hlsPlayer }) => { - const [videoTime, setVideoTime] = useState(''); - - useEffect(() => { - const timeupdateHandler = currentTime => setVideoTime(getDurationFromSeconds(currentTime)); - if (hlsPlayer) { - hlsPlayer.on(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler); - } - return function cleanup() { - if (hlsPlayer) { - hlsPlayer.off(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler); - } - }; - }, [hlsPlayer]); - - return hlsPlayer ? ( - - {videoTime} - - ) : null; -}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.tsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.tsx new file mode 100644 index 0000000000..7839baee47 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VideoTime.tsx @@ -0,0 +1,35 @@ +import React, { useEffect, useState } from 'react'; +import { HMSHLSPlayerEvents } from '@100mslive/hls-player'; +import { Text } from '../../..'; +import { getDurationFromSeconds } from './HMSVIdeoUtils'; +import { useHMSPlayerContext } from './PlayerContext'; + +export const VideoTime = () => { + const hlsPlayerContext = useHMSPlayerContext(); + const [videoTime, setVideoTime] = useState(''); + + useEffect(() => { + const timeupdateHandler = (currentTime: number) => setVideoTime(getDurationFromSeconds(currentTime)); + if (hlsPlayerContext) { + hlsPlayerContext.on(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler); + } + return function cleanup() { + if (hlsPlayerContext) { + hlsPlayerContext.off(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler); + } + }; + }, [hlsPlayerContext]); + + return hlsPlayerContext ? ( + + {videoTime} + + ) : null; +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VolumeControl.jsx b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VolumeControl.tsx similarity index 76% rename from packages/roomkit-react/src/Prebuilt/components/HMSVideo/VolumeControl.jsx rename to packages/roomkit-react/src/Prebuilt/components/HMSVideo/VolumeControl.tsx index f9d3875186..72ed2e0266 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VolumeControl.jsx +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/VolumeControl.tsx @@ -1,9 +1,11 @@ import React, { useState } from 'react'; import { VolumeOneIcon, VolumeTwoIcon, VolumeZeroIcon } from '@100mslive/react-icons'; -import { Flex, Slider } from '../../../'; +import { Flex, Slider } from '../../..'; +import { useHMSPlayerContext } from './PlayerContext'; -export const VolumeControl = ({ hlsPlayer }) => { - const [volume, setVolume] = useState(hlsPlayer?.volume ?? 100); +export const VolumeControl = () => { + const hlsPlayerContext = useHMSPlayerContext(); + const [volume, setVolume] = useState(hlsPlayerContext?.volume || 100); const [showSlider, setShowSlider] = useState(false); return ( @@ -24,10 +26,10 @@ export const VolumeControl = ({ hlsPlayer }) => { onClick={() => { if (volume > 0) { setVolume(0); - hlsPlayer?.setVolume(0); + hlsPlayerContext?.setVolume(0); } else { setVolume(100); - hlsPlayer?.setVolume(100); + hlsPlayerContext?.setVolume(100); } }} /> @@ -47,7 +49,7 @@ export const VolumeControl = ({ hlsPlayer }) => { step={1} value={[volume]} onValueChange={volume => { - hlsPlayer.setVolume(volume[0]); + hlsPlayerContext?.setVolume(volume[0]); setVolume(volume[0]); }} thumbStyles={{ w: '$6', h: '$6' }} @@ -56,7 +58,7 @@ export const VolumeControl = ({ hlsPlayer }) => { ); }; -const VolumeIcon = ({ volume, onClick }) => { +const VolumeIcon = ({ volume, onClick }: { volume: number; onClick: () => void }) => { if (volume === 0) { return ; } diff --git a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.js b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.ts similarity index 92% rename from packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.js rename to packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.ts index 067d519920..ae75a2a01d 100644 --- a/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.js +++ b/packages/roomkit-react/src/Prebuilt/components/HMSVideo/index.ts @@ -1,5 +1,8 @@ +// @ts-ignore import { LeftControls, RightControls, VideoControls } from './Controls'; +// @ts-ignore import { HMSVideo } from './HMSVideo'; +// @ts-ignore import { PlayButton } from './PlayButton'; import { VideoProgress } from './VideoProgress'; import { VideoTime } from './VideoTime'; diff --git a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx index 553622f171..6bff39ae59 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx @@ -1,7 +1,6 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { useFullscreen, useMedia, usePrevious, useToggle } from 'react-use'; import { HLSPlaybackState, HMSHLSPlayer, HMSHLSPlayerEvents } from '@100mslive/hls-player'; -import screenfull from 'screenfull'; import { selectAppData, selectHLSState, @@ -11,22 +10,18 @@ import { useHMSStore, useHMSVanillaStore, } from '@100mslive/react-sdk'; -import { ColoredHandIcon, ExpandIcon, PlayIcon, RadioIcon, ShrinkIcon } from '@100mslive/react-icons'; +import { ColoredHandIcon, RadioIcon } from '@100mslive/react-icons'; import { HlsStatsOverlay } from '../components/HlsStatsOverlay'; -import { HMSVideoPlayer } from '../components/HMSVideo'; -import { FullScreenButton } from '../components/HMSVideo/FullscreenButton'; +import { DesktopHLSView } from '../components/HMSVideo/DesktopHLSView'; import { HLSAutoplayBlockedPrompt } from '../components/HMSVideo/HLSAutoplayBlockedPrompt'; -import { HLSCaptionSelector } from '../components/HMSVideo/HLSCaptionSelector'; -import { HLSQualitySelector } from '../components/HMSVideo/HLSQualitySelector'; -import { LeaveRoom } from '../components/Leave/LeaveRoom'; +import { MwebHLSView } from '../components/HMSVideo/MwebHLSView'; +import { HMSPlayerContext, useSetHMSPlayerContext } from '../components/HMSVideo/PlayerContext'; import { ToastManager } from '../components/Toast/ToastManager'; import { Button } from '../../Button'; -import { IconButton } from '../../IconButton'; -import { Box, Flex } from '../../Layout'; +import { Flex } from '../../Layout'; import { Loading } from '../../Loading'; import { Text } from '../../Text'; import { config, useTheme } from '../../Theme'; -import { Tooltip } from '../../Tooltip'; import { usePollViewToggle } from '../components/AppData/useSidepane'; import { APP_DATA, EMOJI_REACTION_TYPE, SIDE_PANE_OPTIONS } from '../common/constants'; @@ -38,27 +33,22 @@ const HLSView = () => { const hlsState = useHMSStore(selectHLSState); const enablHlsStats = useHMSStore(selectAppData(APP_DATA.hlsStats)); const hmsActions = useHMSActions(); - const { themeType, theme } = useTheme(); + const { themeType } = useTheme(); const [streamEnded, setStreamEnded] = useState(false); let [hlsStatsState, setHlsStatsState] = useState(null); const hlsUrl = hlsState.variants[0]?.url; const [availableLayers, setAvailableLayers] = useState([]); const [isVideoLive, setIsVideoLive] = useState(true); - const [isUserSelectedAuto, setIsUserSelectedAuto] = useState(true); const [isCaptionEnabled, setIsCaptionEnabled] = useState(true); const [hasCaptions, setHasCaptions] = useState(false); const [currentSelectedQuality, setCurrentSelectedQuality] = useState(null); const [isHlsAutoplayBlocked, setIsHlsAutoplayBlocked] = useState(false); const [isPaused, setIsPaused] = useState(false); - const isFullScreenSupported = screenfull.isEnabled; const [show, toggle] = useToggle(false); - const [controlsVisible, setControlsVisible] = useState(true); - const controlsRef = useRef(); - const controlsTimerRef = useRef(); - const [qualityDropDownOpen, setQualityDropDownOpen] = useState(false); const lastHlsUrl = usePrevious(hlsUrl); const togglePollView = usePollViewToggle(); const vanillaStore = useHMSVanillaStore(); + const [hlsPlayerContext, setHLSPlayerContext] = useSetHMSPlayerContext(); const isMobile = useMedia(config.media.md); const isLandscape = useMedia(config.media.ls); @@ -108,7 +98,7 @@ const HLSView = () => { let videoEl = videoRef.current; const manifestLoadedHandler = ({ layers }) => { setAvailableLayers(layers); - setHasCaptions(hlsPlayer?.hasCaptions()); + setHasCaptions(hlsPlayerContext?.hasCaptions()); }; const layerUpdatedHandler = ({ layer }) => { setCurrentSelectedQuality(layer); @@ -178,6 +168,7 @@ const HLSView = () => { const handleAutoplayBlock = data => setIsHlsAutoplayBlocked(!!data); if (videoEl && hlsUrl) { hlsPlayer = new HMSHLSPlayer(hlsUrl, videoEl); + setHLSPlayerContext(hlsPlayer); hlsPlayer.on(HMSHLSPlayerEvents.SEEK_POS_BEHIND_LIVE_EDGE, handleNoLongerLive); hlsPlayer.on(HMSHLSPlayerEvents.TIMED_METADATA_LOADED, metadataLoadedHandler); hlsPlayer.on(HMSHLSPlayerEvents.ERROR, handleError); @@ -198,7 +189,7 @@ const HLSView = () => { hlsPlayer.off(HMSHLSPlayerEvents.MANIFEST_LOADED, manifestLoadedHandler); hlsPlayer.off(HMSHLSPlayerEvents.LAYER_UPDATED, layerUpdatedHandler); hlsPlayer.reset(); - hlsPlayer = null; + setHLSPlayerContext(undefined); }; } }, [hlsUrl]); @@ -209,75 +200,28 @@ const HLSView = () => { useEffect(() => { const onHLSStats = state => setHlsStatsState(state); if (enablHlsStats) { - hlsPlayer?.on(HMSHLSPlayerEvents.STATS, onHLSStats); + hlsPlayerContext?.on(HMSHLSPlayerEvents.STATS, onHLSStats); } else { - hlsPlayer?.off(HMSHLSPlayerEvents.STATS, onHLSStats); + hlsPlayerContext?.off(HMSHLSPlayerEvents.STATS, onHLSStats); } return () => { - hlsPlayer?.off(HMSHLSPlayerEvents.STATS, onHLSStats); + hlsPlayerContext?.off(HMSHLSPlayerEvents.STATS, onHLSStats); }; }, [enablHlsStats]); const unblockAutoPlay = async () => { try { - await hlsPlayer.play(); + await hlsPlayerContext.play(); setIsHlsAutoplayBlocked(false); } catch (error) { console.error('Tried to unblock Autoplay failed with', error.message); } }; - const handleQuality = useCallback( - quality => { - if (hlsPlayer) { - setIsUserSelectedAuto(quality.height.toString().toLowerCase() === 'auto'); - hlsPlayer.setLayer(quality); - } - }, - [availableLayers], //eslint-disable-line - ); - const sfnOverlayClose = () => { hmsActions.setAppData(APP_DATA.hlsStats, !enablHlsStats); }; - useEffect(() => { - if (controlsVisible && isFullScreen && !qualityDropDownOpen) { - if (controlsTimerRef.current) { - clearTimeout(controlsTimerRef.current); - } - controlsTimerRef.current = setTimeout(() => { - setControlsVisible(false); - }, 5000); - } - if (!isFullScreen && controlsTimerRef.current) { - clearTimeout(controlsTimerRef.current); - } - return () => { - if (controlsTimerRef.current) { - clearTimeout(controlsTimerRef.current); - } - }; - }, [controlsVisible, isFullScreen, qualityDropDownOpen]); - - const onHoverHandler = useCallback( - event => { - if (event.type === 'mouseenter' || qualityDropDownOpen) { - setControlsVisible(true); - return; - } - if (event.type === 'mouseleave') { - setControlsVisible(false); - } else if (isFullScreen && !controlsVisible && event.type === 'mousemove') { - setControlsVisible(true); - if (controlsTimerRef.current) { - clearTimeout(controlsTimerRef.current); - } - } - }, - [controlsVisible, isFullScreen, qualityDropDownOpen], - ); - if (isMobile || isLandscape) { return ( { }} > {hlsUrl && !streamEnded ? ( - - - {showLoader && ( - - - - )} - + - - await hlsPlayer?.play()} data-testid="play_btn"> - - - - - - - - - - - {hasCaptions && ( - hlsPlayer?.toggleCaption()} isEnabled={isCaptionEnabled} /> - )} - {availableLayers.length > 0 ? ( - - ) : null} - - - - - + {showLoader && ( + - - { - await hlsPlayer.seekToLivePosition(); - setIsVideoLive(true); - }} - key="jump-to-live_btn" - data-testid="jump-to-live_btn" - > - - - - - {isVideoLive ? 'LIVE' : 'GO LIVE'} - - - - - - - - - {isFullScreenSupported ? ( - : } - /> - ) : null} - - - - - {hlsPlayer && ( - { - hlsPlayer.seekTo(time); - }} - /> - )} - - - + + + )} + + + ) : ( @@ -479,10 +290,6 @@ const HLSView = () => { )} - {/** player handler --> left -> go live with timer or live, right -> expand icon */} - {/** inbetween -> play pause icon, double tap to go back/forward */} - {/** seekbar */} - {/** half page will have chat or participant view */} ); } @@ -499,129 +306,43 @@ const HLSView = () => { ) : null} {hlsUrl && !streamEnded ? ( - - - {showLoader && ( - - - - )} - + - - {!isMobile && ( - - - { - isPaused ? await hlsPlayer?.play() : hlsPlayer?.pause(); - }} - isPaused={isPaused} - /> - - - { - await hlsPlayer.seekToLivePosition(); - setIsVideoLive(true); - }} - key="jump-to-live_btn" - data-testid="jump-to-live_btn" - > - - - - - {isVideoLive ? 'LIVE' : 'GO LIVE'} - - - - - - - - {hasCaptions && ( - hlsPlayer?.toggleCaption()} isEnabled={isCaptionEnabled} /> - )} - {availableLayers.length > 0 ? ( - - ) : null} - {isFullScreenSupported ? ( - : } - /> - ) : null} - - - )} - - - + + {showLoader && ( + + + + )} + + + ) : ( From 8c0b209d2931b12893a6ef45997bc9c3b2c32ccc Mon Sep 17 00:00:00 2001 From: amar-1995 Date: Wed, 7 Feb 2024 05:24:50 +0530 Subject: [PATCH 04/25] fix: remove footer and added chat open for portrait mode --- .../Prebuilt/components/Chat/ChatFooter.tsx | 24 +++++++++-- .../Prebuilt/components/ConferenceScreen.tsx | 15 ++++++- .../components/HMSVideo/MwebHLSView.tsx | 43 +++++++++---------- .../src/Prebuilt/layouts/HLSView.jsx | 24 +++++++++-- 4 files changed, 75 insertions(+), 31 deletions(-) diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx index cf77c843f8..3e6a8e49c9 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx @@ -2,10 +2,13 @@ import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'reac import { useMedia } from 'react-use'; import data from '@emoji-mart/data'; import Picker from '@emoji-mart/react'; -import { HMSException, selectLocalPeer, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; +import { HMSException, selectLocalPeer, useAVToggle, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; import { EmojiIcon, PauseCircleIcon, SendIcon, VerticalMenuIcon } from '@100mslive/react-icons'; import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, styled, Text } from '../../..'; import { IconButton } from '../../../IconButton'; +import { MoreSettings } from '../MoreSettings/MoreSettings'; +// @ts-ignore: No implicit Any +import { RaiseHand } from '../RaiseHand'; // @ts-ignore import { ToastManager } from '../Toast/ToastManager'; import { ChatSelectorContainer } from './ChatSelectorContainer'; @@ -77,7 +80,8 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo const inputRef = useRef(null); const [draftMessage, setDraftMessage] = useChatDraftMessage(); const isMobile = useMedia(cssConfig.media.md); - const { elements } = useRoomLayoutConferencingScreen(); + const isLandscape = useMedia(cssConfig.media.ls); + const { elements, screenType } = useRoomLayoutConferencingScreen(); const message_placeholder = elements?.chat?.message_placeholder || 'Send a message'; const localPeer = useHMSStore(selectLocalPeer); const isOverlayChat = elements?.chat?.is_overlay; @@ -87,6 +91,9 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo const defaultSelection = useDefaultChatSelection(); const selection = selectedPeer.name || selectedRole || defaultSelection; const isLocalPeerBlacklisted = useIsPeerBlacklisted({ local: true }); + const { toggleAudio, toggleVideo } = useAVToggle(); + const noAVPermissions = !(toggleAudio || toggleVideo); + const isMwebHLSStream = screenType === 'hls_live_streaming' && (isMobile || isLandscape); useEffect(() => { if (!selectedPeer.id && !selectedRole && !['Everyone', ''].includes(defaultSelection)) { @@ -198,7 +205,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo position: 'relative', py: '$6', pl: '$8', - flexGrow: 1, + flexGrow: `${isMwebHLSStream ? 1 : 0}`, r: '$1', '@md': { minHeight: 'unset', @@ -257,6 +264,17 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo + {isMwebHLSStream && ( + + {noAVPermissions ? : null} + + + )} )} diff --git a/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx b/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx index 2b1f2ed9d3..c62b7a6277 100644 --- a/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useRef, useState } from 'react'; +import { useMedia } from 'react-use'; import { DefaultConferencingScreen_Elements } from '@100mslive/types-prebuilt'; import { HMSRoomState, @@ -9,6 +10,7 @@ import { useHMSStore, } from '@100mslive/react-sdk'; import { Footer } from './Footer/Footer'; +import { LeaveRoom } from './Leave/LeaveRoom'; import { HLSFailureModal } from './Notifications/HLSFailureModal'; // @ts-ignore: No implicit Any import { ActivatedPIP } from './PIP/PIPComponent'; @@ -16,6 +18,7 @@ import { ActivatedPIP } from './PIP/PIPComponent'; import { PictureInPicture } from './PIP/PIPManager'; import { RoleChangeRequestModal } from './RoleChangeRequest/RoleChangeRequestModal'; import { Box, Flex } from '../../Layout'; +import { config } from '../../Theme'; import { useHMSPrebuiltContext } from '../AppContext'; import { VideoStreamingSection } from '../layouts/VideoStreamingSection'; // @ts-ignore: No implicit Any @@ -52,6 +55,9 @@ export const ConferenceScreen = () => { } }; const autoRoomJoined = useRef(isPreviewScreenEnabled); + const isMobile = useMedia(config.media.md); + const isLandscape = useMedia(config.media.ls); + const isMwebHLSStream = screenProps.screenType === 'hls_live_streaming' && (isMobile || isLandscape); useEffect(() => { let timeout: undefined | ReturnType; @@ -112,7 +118,7 @@ export const ConferenceScreen = () => { ) : null} - {!screenProps.hideSections.includes('header') && ( + {!screenProps.hideSections.includes('header') && !isMwebHLSStream && ( {
)} + {isMwebHLSStream && ( + + + + )} { /> ) : null} - {!screenProps.hideSections.includes('footer') && screenProps.elements && ( + {!screenProps.hideSections.includes('footer') && screenProps.elements && !isMwebHLSStream && ( = useRef(null); const controlsTimerRef = useRef(); - const { screenType } = useRoomLayoutConferencingScreen(); - const isFullScreenSupported = screenfull.isEnabled; + const isLandscape = useMedia(config.media.ls); + const handleQuality = useCallback( (quality: HMSHLSLayer) => { if (hlsPlayerContext) { @@ -106,7 +108,7 @@ export const MwebHLSView = React.forwardRef< r: '$round', gap: '$1', bg: 'rgba(0, 0, 0, 0.6)', - zIndex: 21, + zIndex: 1, visibility: controlsVisible ? `` : `hidden`, opacity: controlsVisible ? `1` : '0', }} @@ -141,11 +143,8 @@ export const MwebHLSView = React.forwardRef< p: '$4 $8', }} > - - - - + {isLandscape && } {hasCaptions && } {availableLayers.length > 0 ? ( + + + {/* */} + - - - - ); }, @@ -253,7 +252,7 @@ export const MwebHLSView = React.forwardRef< seekbar half page will have chat or participant view */ -const HLSViewTitle = () => { +export const HLSViewTitle = () => { const peerCount = useHMSStore(selectPeerCount); const hlsState = useHMSStore(selectHLSState); const intervalRef = useRef(null); diff --git a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx index 6bff39ae59..e5800305be 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx @@ -22,7 +22,8 @@ import { Flex } from '../../Layout'; import { Loading } from '../../Loading'; import { Text } from '../../Text'; import { config, useTheme } from '../../Theme'; -import { usePollViewToggle } from '../components/AppData/useSidepane'; +import { useIsSidepaneTypeOpen, usePollViewToggle, useSidepaneToggle } from '../components/AppData/useSidepane'; +import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; import { APP_DATA, EMOJI_REACTION_TYPE, SIDE_PANE_OPTIONS } from '../common/constants'; let hlsPlayer; @@ -49,14 +50,28 @@ const HLSView = () => { const togglePollView = usePollViewToggle(); const vanillaStore = useHMSVanillaStore(); const [hlsPlayerContext, setHLSPlayerContext] = useSetHMSPlayerContext(); + const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT); + const isParticipantOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.PARTICIPANTS); + const isPollOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.POLLS); const isMobile = useMedia(config.media.md); const isLandscape = useMedia(config.media.ls); const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane)); + + const { screenType } = useRoomLayoutConferencingScreen(); const isFullScreen = useFullscreen(hlsViewRef, show, { onClose: () => toggle(false), }); const [showLoader, setShowLoader] = useState(false); + + const isMwebHLSStream = screenType === 'hls_live_streaming' && isMobile; + const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT); + + useEffect(() => { + if (!isChatOpen && isMwebHLSStream) { + toggleChat(); + } + }, [isChatOpen, isMwebHLSStream, toggleChat]); // FIXME: move this logic to player controller in next release useEffect(() => { /** @@ -228,6 +243,8 @@ const HLSView = () => { key="hls-viewer" id={`hls-viewer-${themeType}`} ref={hlsViewRef} + direction="column" + justify="center" css={{ w: '100%', h: @@ -248,7 +265,7 @@ const HLSView = () => { css={{ width: '100%', margin: '0 auto', - height: '100%', + height: isFullScreen || isChatOpen || isParticipantOpen || isPollOpen || isLandscape ? '100%' : '50%', }} > @@ -312,9 +329,8 @@ const HLSView = () => { align="center" justify="center" css={{ - width: '100%', + size: '100%', margin: '0 auto', - height: '100%', }} > From b103a924b5e69233b7919d63c13cc29d2fd832d7 Mon Sep 17 00:00:00 2001 From: amar-1995 Date: Wed, 7 Feb 2024 10:56:21 +0530 Subject: [PATCH 05/25] fix: size of portrait chat box --- .../src/Prebuilt/layouts/HLSView.jsx | 4 ++-- .../src/Prebuilt/layouts/SidePane.tsx | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx index e5800305be..c7171244af 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/HLSView.jsx @@ -252,7 +252,7 @@ const HLSView = () => { sidepane === SIDE_PANE_OPTIONS.CHAT || sidepane === SIDE_PANE_OPTIONS.PARTICIPANTS) && isMobile - ? '50%' + ? '32%' : '100%', }} > @@ -265,7 +265,7 @@ const HLSView = () => { css={{ width: '100%', margin: '0 auto', - height: isFullScreen || isChatOpen || isParticipantOpen || isPollOpen || isLandscape ? '100%' : '50%', + height: isFullScreen || isChatOpen || isParticipantOpen || isPollOpen || isLandscape ? '100%' : '32%', }} > diff --git a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx index 3403ff800f..0d23e870bc 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx @@ -27,6 +27,7 @@ const SidePane = ({ hideControls?: boolean; }) => { const isMobile = useMedia(cssConfig.media.md); + const isLandscape = useMedia(cssConfig.media.lg); const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane)); const activeScreensharePeerId = useHMSStore(selectAppData(APP_DATA.activeScreensharePeerId)); const trackId = useHMSStore(selectVideoTrackByPeerID(activeScreensharePeerId))?.id; @@ -76,11 +77,11 @@ const SidePane = ({ justify="center" css={{ w: '$100', - h: mwebHLSStream ? '50%' : '100%', + h: mwebHLSStream ? '68%' : '100%', flexShrink: 0, gap: '$4', position: 'relative', - '@md': { position: mwebStreamingChat ? 'absolute' : '', zIndex: 12 }, + '@md': { position: mwebStreamingChat || isLandscape ? 'absolute' : '', zIndex: 12 }, }} > {trackId && ( @@ -97,14 +98,15 @@ const SidePane = ({ Date: Mon, 12 Feb 2024 01:51:49 +0530 Subject: [PATCH 06/25] fix: added proper chat view --- .../src/Prebuilt/common/hooks.ts | 14 +++++++++++ .../Prebuilt/components/Chat/ChatFooter.tsx | 5 ++-- .../components/MoreSettings/MoreSettings.tsx | 4 ++- .../components/MwebLandscapePrompt.tsx | 5 ++++ .../src/Prebuilt/components/SidePaneTabs.tsx | 19 ++++++++------ .../src/Prebuilt/layouts/HLSView.jsx | 25 ++++++------------- .../src/Prebuilt/layouts/SidePane.tsx | 21 ++++++++++------ 7 files changed, 59 insertions(+), 34 deletions(-) diff --git a/packages/roomkit-react/src/Prebuilt/common/hooks.ts b/packages/roomkit-react/src/Prebuilt/common/hooks.ts index 4b68ba15bc..881a247aad 100644 --- a/packages/roomkit-react/src/Prebuilt/common/hooks.ts +++ b/packages/roomkit-react/src/Prebuilt/common/hooks.ts @@ -1,4 +1,5 @@ import { useEffect, useRef, useState } from 'react'; +import { useMedia } from 'react-use'; import { JoinForm_JoinBtnType } from '@100mslive/types-prebuilt/elements/join_form'; import { selectAvailableRoleNames, @@ -10,6 +11,7 @@ import { useHMSStore, useHMSVanillaStore, } from '@100mslive/react-sdk'; +import { config } from '../../Theme'; import { useRoomLayout } from '../provider/roomLayoutProvider'; import { useRoomLayoutConferencingScreen } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; import { CHAT_SELECTOR } from './constants'; @@ -100,3 +102,15 @@ export const useParticipants = (params?: { metadata?: { isHandRaised?: boolean } } return { participants: participantList, isConnected, peerCount, rolesWithParticipants }; }; + +export const useLandscapeHLSStream = () => { + const isLandscape = useMedia(config.media.ls); + const { screenType } = useRoomLayoutConferencingScreen(); + return isLandscape && screenType === 'hls_live_streaming'; +}; + +export const useMobileHLSStream = () => { + const isMobile = useMedia(config.media.md); + const { screenType } = useRoomLayoutConferencingScreen(); + return isMobile && screenType === 'hls_live_streaming'; +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx index 3e6a8e49c9..9f99eaba1a 100644 --- a/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/Chat/ChatFooter.tsx @@ -20,7 +20,7 @@ import { useSetSubscribedChatSelector, useSubscribeChatSelector } from '../AppDa import { useIsPeerBlacklisted } from '../hooks/useChatBlacklist'; // @ts-ignore import { useEmojiPickerStyles } from './useEmojiPickerStyles'; -import { useDefaultChatSelection } from '../../common/hooks'; +import { useDefaultChatSelection, useLandscapeHLSStream } from '../../common/hooks'; import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants'; const TextArea = styled('textarea', { @@ -94,6 +94,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo const { toggleAudio, toggleVideo } = useAVToggle(); const noAVPermissions = !(toggleAudio || toggleVideo); const isMwebHLSStream = screenType === 'hls_live_streaming' && (isMobile || isLandscape); + const isLandscapeHLSStream = useLandscapeHLSStream(); useEffect(() => { if (!selectedPeer.id && !selectedRole && !['Everyone', ''].includes(defaultSelection)) { @@ -241,7 +242,7 @@ export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => vo onCut={e => e.stopPropagation()} onCopy={e => e.stopPropagation()} /> - {!isMobile ? ( + {!isMobile && !isLandscapeHLSStream ? ( { if (inputRef.current) { diff --git a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/MoreSettings.tsx b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/MoreSettings.tsx index 2195a2e802..637319418d 100644 --- a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/MoreSettings.tsx @@ -19,7 +19,9 @@ export const MoreSettings = ({ screenType: keyof ConferencingScreen; }) => { const isMobile = useMedia(cssConfig.media.md); - return isMobile ? ( + const isLandscape = useMedia(cssConfig.media.lg); + const isLandscapeHLSStream = screenType === 'hls_live_streaming' || isLandscape; + return isMobile || isLandscapeHLSStream ? ( ) : ( diff --git a/packages/roomkit-react/src/Prebuilt/components/MwebLandscapePrompt.tsx b/packages/roomkit-react/src/Prebuilt/components/MwebLandscapePrompt.tsx index 33996cc46e..e49c779a94 100644 --- a/packages/roomkit-react/src/Prebuilt/components/MwebLandscapePrompt.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/MwebLandscapePrompt.tsx @@ -6,12 +6,14 @@ import { Box, Flex } from '../../Layout'; import { Dialog } from '../../Modal'; import { Text } from '../../Text'; import { config as cssConfig } from '../../Theme'; +import { useLandscapeHLSStream } from '../common/hooks'; // @ts-ignore import { isMobileUserAgent } from '../common/utils'; export const MwebLandscapePrompt = () => { const [showMwebLandscapePrompt, setShowMwebLandscapePrompt] = useState(false); const isLandscape = useMedia(cssConfig.media.ls); + const isLandscapeHLSStream = useLandscapeHLSStream(); useEffect(() => { if (!isMobileUserAgent) { @@ -36,6 +38,9 @@ export const MwebLandscapePrompt = () => { }; }, [isLandscape]); + if (isLandscapeHLSStream) { + return null; + } return ( diff --git a/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx b/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx index 8d5273e086..057a0bcb56 100644 --- a/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/SidePaneTabs.tsx @@ -40,18 +40,19 @@ const ParticipantCount = ({ count }: { count: number }) => { export const SidePaneTabs = React.memo<{ active: 'Participants | Chat'; hideControls?: boolean; -}>(({ active = SIDE_PANE_OPTIONS.CHAT, hideControls }) => { + hideTab?: boolean; +}>(({ active = SIDE_PANE_OPTIONS.CHAT, hideControls, hideTab = false }) => { const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT); const toggleParticipants = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS); const resetSidePane = useSidepaneReset(); const [activeTab, setActiveTab] = useState(active); const [activeRole, setActiveRole] = useState(''); const peerCount = useHMSStore(selectPeerCount); - const { elements } = useRoomLayoutConferencingScreen(); + const { elements, screenType } = useRoomLayoutConferencingScreen(); const chat_title = elements?.chat?.chat_title || 'Chat'; const showChat = !!elements?.chat; const showParticipants = !!elements?.participant_list; - const hideTabs = !(showChat && showParticipants); + const hideTabs = !(showChat && showParticipants) || hideTab; const isMobile = useMedia(cssConfig.media.md); const isOverlayChat = !!elements?.chat?.is_overlay && isMobile; const { off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {}; @@ -109,8 +110,8 @@ export const SidePaneTabs = React.memo<{ <> - {showChat ? ( - chat_title + {activeTab === SIDE_PANE_OPTIONS.CHAT ? ( + screenType !== 'hls_live_streaming' && chat_title ) : ( Participants  @@ -133,12 +134,16 @@ export const SidePaneTabs = React.memo<{ }} data-testid="close_chat" > - + {screenType === 'hls_live_streaming' && isChatOpen ? null : } )} - {showChat ? : } + {activeTab === SIDE_PANE_OPTIONS.CHAT ? ( + + ) : ( + + )} ) : ( { const togglePollView = usePollViewToggle(); const vanillaStore = useHMSVanillaStore(); const [hlsPlayerContext, setHLSPlayerContext] = useSetHMSPlayerContext(); - const isChatOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.CHAT); - const isParticipantOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.PARTICIPANTS); - const isPollOpen = useIsSidepaneTypeOpen(SIDE_PANE_OPTIONS.POLLS); + const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane)); + const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT); const isMobile = useMedia(config.media.md); const isLandscape = useMedia(config.media.ls); - const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane)); const { screenType } = useRoomLayoutConferencingScreen(); const isFullScreen = useFullscreen(hlsViewRef, show, { @@ -65,13 +63,12 @@ const HLSView = () => { const [showLoader, setShowLoader] = useState(false); const isMwebHLSStream = screenType === 'hls_live_streaming' && isMobile; - const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT); useEffect(() => { - if (!isChatOpen && isMwebHLSStream) { + if (sidepane === '' && isMwebHLSStream) { toggleChat(); } - }, [isChatOpen, isMwebHLSStream, toggleChat]); + }, [sidepane, isMwebHLSStream, toggleChat]); // FIXME: move this logic to player controller in next release useEffect(() => { /** @@ -246,14 +243,8 @@ const HLSView = () => { direction="column" justify="center" css={{ - w: '100%', - h: - (sidepane === SIDE_PANE_OPTIONS.POLLS || - sidepane === SIDE_PANE_OPTIONS.CHAT || - sidepane === SIDE_PANE_OPTIONS.PARTICIPANTS) && - isMobile - ? '32%' - : '100%', + w: sidepane !== '' && isLandscape ? '55%' : '100%', + h: sidepane !== '' && isMobile ? '32%' : '100%', }} > {hlsUrl && !streamEnded ? ( @@ -265,7 +256,7 @@ const HLSView = () => { css={{ width: '100%', margin: '0 auto', - height: isFullScreen || isChatOpen || isParticipantOpen || isPollOpen || isLandscape ? '100%' : '32%', + height: isFullScreen || sidepane !== '' || isLandscape ? '100%' : '32%', }} > diff --git a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx index 0d23e870bc..35976b9bb3 100644 --- a/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx +++ b/packages/roomkit-react/src/Prebuilt/layouts/SidePane.tsx @@ -16,6 +16,7 @@ import { useRoomLayoutConferencingScreen, useRoomLayoutPreviewScreen, } from '../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; +import { useLandscapeHLSStream, useMobileHLSStream } from '../common/hooks'; import { translateAcross } from '../../utils'; import { APP_DATA, SIDE_PANE_OPTIONS } from '../common/constants'; @@ -31,9 +32,12 @@ const SidePane = ({ const sidepane = useHMSStore(selectAppData(APP_DATA.sidePane)); const activeScreensharePeerId = useHMSStore(selectAppData(APP_DATA.activeScreensharePeerId)); const trackId = useHMSStore(selectVideoTrackByPeerID(activeScreensharePeerId))?.id; - const { elements, screenType } = useRoomLayoutConferencingScreen(); + const { elements } = useRoomLayoutConferencingScreen(); const { elements: preview_elements } = useRoomLayoutPreviewScreen(); + const isLandscapeHLSStream = useLandscapeHLSStream(); + const isMobileHLSStream = useMobileHLSStream(); + const backgroundMedia = preview_elements?.virtual_background?.background_media?.length ? preview_elements?.virtual_background?.background_media : elements?.virtual_background?.background_media || []; @@ -44,7 +48,9 @@ const SidePane = ({ ViewComponent = ; } if (sidepane === SIDE_PANE_OPTIONS.PARTICIPANTS || sidepane === SIDE_PANE_OPTIONS.CHAT) { - ViewComponent = ; + ViewComponent = ( + + ); } if (sidepane === SIDE_PANE_OPTIONS.VB) { ViewComponent = ; @@ -69,7 +75,6 @@ const SidePane = ({ }; const VB = sidepane === SIDE_PANE_OPTIONS.VB; const mwebStreamingChat = isMobile && sidepane === SIDE_PANE_OPTIONS.CHAT && elements?.chat?.is_overlay; - const mwebHLSStream = isMobile && screenType === 'hls_live_streaming'; return ( Date: Mon, 12 Feb 2024 04:40:33 +0530 Subject: [PATCH 07/25] fix: add no chat view --- .../Prebuilt/components/ConferenceScreen.tsx | 22 +++++ .../components/HMSVideo/MwebHLSView.tsx | 96 +++++++++++-------- .../src/Prebuilt/layouts/HLSView.jsx | 89 +++++++++-------- .../src/Prebuilt/layouts/SidePane.tsx | 6 +- 4 files changed, 126 insertions(+), 87 deletions(-) diff --git a/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx b/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx index c62b7a6277..f5d7629a10 100644 --- a/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/ConferenceScreen.tsx @@ -6,11 +6,13 @@ import { selectAppData, selectIsConnectedToRoom, selectRoomState, + useAVToggle, useHMSActions, useHMSStore, } from '@100mslive/react-sdk'; import { Footer } from './Footer/Footer'; import { LeaveRoom } from './Leave/LeaveRoom'; +import { MoreSettings } from './MoreSettings/MoreSettings'; import { HLSFailureModal } from './Notifications/HLSFailureModal'; // @ts-ignore: No implicit Any import { ActivatedPIP } from './PIP/PIPComponent'; @@ -25,6 +27,8 @@ import { VideoStreamingSection } from '../layouts/VideoStreamingSection'; import FullPageProgress from './FullPageProgress'; import { Header } from './Header'; import { PreviousRoleInMetadata } from './PreviousRoleInMetadata'; +// @ts-ignore: No implicit Any +import { RaiseHand } from './RaiseHand'; import { useRoomLayoutConferencingScreen, useRoomLayoutPreviewScreen, @@ -49,6 +53,10 @@ export const ConferenceScreen = () => { const isMobileDevice = isAndroid || isIOS || isIPadOS; const dropdownListRef = useRef(); const [isHLSStarted] = useSetAppDataByKey(APP_DATA.hlsStarted); + + const { toggleAudio, toggleVideo } = useAVToggle(); + const noAVPermissions = !(toggleAudio || toggleVideo); + const showChat = !!screenProps.elements?.chat; const toggleControls = () => { if (dropdownListRef.current?.length === 0 && isMobileDevice) { setHideControls(value => !value); @@ -184,6 +192,20 @@ export const ConferenceScreen = () => {