@100mslive/roomkit-react 0.2.8-alpha.3 → 0.2.8-alpha.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/dist/{HLSView-PACDZWJN.js → HLSView-UIPDGADR.js} +509 -234
  2. package/dist/HLSView-UIPDGADR.js.map +7 -0
  3. package/dist/Prebuilt/common/hooks.d.ts +3 -0
  4. package/dist/Prebuilt/components/HMSVideo/FullscreenButton.d.ts +5 -0
  5. package/dist/Prebuilt/components/HMSVideo/HLSAutoplayBlockedPrompt.d.ts +5 -0
  6. package/dist/Prebuilt/components/HMSVideo/HLSCaptionSelector.d.ts +1 -2
  7. package/dist/Prebuilt/components/HMSVideo/HLSQualitySelector.d.ts +12 -0
  8. package/dist/Prebuilt/components/HMSVideo/MwebHLSViewTitle.d.ts +2 -0
  9. package/dist/Prebuilt/components/HMSVideo/PlayButton.d.ts +6 -0
  10. package/dist/Prebuilt/components/HMSVideo/PlayerContext.d.ts +8 -0
  11. package/dist/Prebuilt/components/HMSVideo/VideoProgress.d.ts +2 -0
  12. package/dist/Prebuilt/components/HMSVideo/VideoTime.d.ts +2 -0
  13. package/dist/Prebuilt/components/HMSVideo/VolumeControl.d.ts +2 -0
  14. package/dist/Prebuilt/components/HMSVideo/index.d.ts +17 -0
  15. package/dist/Prebuilt/components/HMSVideo/utils.d.ts +9 -0
  16. package/dist/Prebuilt/components/Leave/MwebLeaveRoom.d.ts +1 -3
  17. package/dist/Prebuilt/components/MwebLandscapePrompt.d.ts +1 -1
  18. package/dist/Prebuilt/components/RaiseHand.d.ts +2 -0
  19. package/dist/Prebuilt/components/SidePaneTabs.d.ts +1 -0
  20. package/dist/{chunk-2QHBD2VO.js → chunk-J4NOQ2YL.js} +562 -450
  21. package/dist/chunk-J4NOQ2YL.js.map +7 -0
  22. package/dist/index.cjs.js +1556 -1145
  23. package/dist/index.cjs.js.map +4 -4
  24. package/dist/index.js +1 -1
  25. package/dist/meta.cjs.json +429 -156
  26. package/dist/meta.esbuild.json +445 -164
  27. package/package.json +6 -6
  28. package/src/Prebuilt/common/hooks.ts +21 -0
  29. package/src/Prebuilt/components/Chat/ChatFooter.tsx +26 -10
  30. package/src/Prebuilt/components/ConferenceScreen.tsx +34 -2
  31. package/src/Prebuilt/components/Footer/Footer.tsx +0 -1
  32. package/src/Prebuilt/components/HMSVideo/Controls.jsx +1 -1
  33. package/src/Prebuilt/components/HMSVideo/FullscreenButton.tsx +13 -0
  34. package/src/Prebuilt/components/HMSVideo/{HLSAutoplayBlockedPrompt.jsx → HLSAutoplayBlockedPrompt.tsx} +13 -6
  35. package/src/Prebuilt/components/HMSVideo/HLSCaptionSelector.tsx +4 -2
  36. package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.tsx +241 -0
  37. package/src/Prebuilt/components/HMSVideo/HMSVideo.jsx +3 -0
  38. package/src/Prebuilt/components/HMSVideo/MwebHLSViewTitle.tsx +91 -0
  39. package/src/Prebuilt/components/HMSVideo/PlayButton.tsx +27 -0
  40. package/src/Prebuilt/components/HMSVideo/PlayerContext.tsx +15 -0
  41. package/src/Prebuilt/components/HMSVideo/VideoProgress.tsx +81 -0
  42. package/src/Prebuilt/components/HMSVideo/VideoTime.tsx +42 -0
  43. package/src/Prebuilt/components/HMSVideo/{VolumeControl.jsx → VolumeControl.tsx} +7 -5
  44. package/src/Prebuilt/components/HMSVideo/{index.js → index.ts} +2 -0
  45. package/src/Prebuilt/components/HMSVideo/utils.ts +35 -0
  46. package/src/Prebuilt/components/Leave/LeaveRoom.tsx +7 -1
  47. package/src/Prebuilt/components/Leave/MwebLeaveRoom.tsx +38 -25
  48. package/src/Prebuilt/components/MoreSettings/MoreSettings.tsx +3 -1
  49. package/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +1 -1
  50. package/src/Prebuilt/components/MwebLandscapePrompt.tsx +5 -0
  51. package/src/Prebuilt/components/{RaiseHand.jsx → RaiseHand.tsx} +3 -2
  52. package/src/Prebuilt/components/SidePaneTabs.tsx +29 -10
  53. package/src/Prebuilt/layouts/HLSView.jsx +272 -156
  54. package/src/Prebuilt/layouts/SidePane.tsx +21 -10
  55. package/src/Prebuilt/layouts/VideoStreamingSection.tsx +11 -1
  56. package/dist/HLSView-PACDZWJN.js.map +0 -7
  57. package/dist/chunk-2QHBD2VO.js.map +0 -7
  58. package/src/Prebuilt/components/HMSVideo/FullscreenButton.jsx +0 -18
  59. package/src/Prebuilt/components/HMSVideo/HLSQualitySelector.jsx +0 -127
  60. package/src/Prebuilt/components/HMSVideo/HMSVIdeoUtils.js +0 -27
  61. package/src/Prebuilt/components/HMSVideo/VideoProgress.jsx +0 -76
  62. package/src/Prebuilt/components/HMSVideo/VideoTime.jsx +0 -33
@@ -0,0 +1,91 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { selectHLSState, selectPeerCount, useHMSStore } from '@100mslive/react-sdk';
3
+ import { Flex } from '../../../Layout';
4
+ import { Text } from '../../../Text';
5
+ // @ts-ignore: No implicit any
6
+ import { Logo } from '../Header/HeaderComponents';
7
+ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
8
+ // @ts-ignore: No implicit Any
9
+ import { getFormattedCount } from '../../common/utils';
10
+ import { getTime } from './utils';
11
+
12
+ /*
13
+ player handler --> left -> go live with timer or live, right -> expand icon
14
+ inbetween -> play pause icon, double tap to go back/forward
15
+ seekbar
16
+ half page will have chat or participant view
17
+ */
18
+ export const HLSViewTitle = () => {
19
+ const peerCount = useHMSStore(selectPeerCount);
20
+ const hlsState = useHMSStore(selectHLSState);
21
+ const intervalRef = useRef<NodeJS.Timeout | null>(null);
22
+ const { screenType } = useRoomLayoutConferencingScreen();
23
+ const [liveTime, setLiveTime] = useState(0);
24
+
25
+ const startTimer = useCallback(() => {
26
+ intervalRef.current = setInterval(() => {
27
+ const timeStamp = hlsState?.variants[0]?.[screenType === 'hls_live_streaming' ? 'startedAt' : 'initialisedAt'];
28
+ if (hlsState?.running && timeStamp) {
29
+ setLiveTime(Date.now() - timeStamp.getTime());
30
+ }
31
+ }, 60000);
32
+ }, [hlsState?.running, hlsState?.variants, screenType]);
33
+
34
+ useEffect(() => {
35
+ if (hlsState?.running) {
36
+ startTimer();
37
+ const timeStamp = hlsState?.variants[0]?.[screenType === 'hls_live_streaming' ? 'startedAt' : 'initialisedAt'];
38
+ if (hlsState?.running && timeStamp) {
39
+ setLiveTime(Date.now() - timeStamp.getTime());
40
+ }
41
+ }
42
+ if (!hlsState?.running && intervalRef.current) {
43
+ clearInterval(intervalRef.current);
44
+ }
45
+ return () => {
46
+ if (intervalRef.current) {
47
+ clearInterval(intervalRef.current);
48
+ }
49
+ };
50
+ }, [hlsState?.running, hlsState?.variants, screenType, startTimer]);
51
+
52
+ return (
53
+ <Flex
54
+ gap="4"
55
+ align="center"
56
+ css={{
57
+ position: 'relative',
58
+ h: 'fit-content',
59
+ w: '100%',
60
+ borderBottom: '1px solid $border_bright',
61
+ p: '$8',
62
+ backgroundColor: '$surface_dim',
63
+ }}
64
+ >
65
+ <Logo />
66
+ <Flex direction="column">
67
+ <Text variant="sub2" css={{ fontWeight: '$semiBold' }}>
68
+ Tech Talk
69
+ </Text>
70
+ <Flex gap="1">
71
+ <Text variant="caption" css={{ color: '$on_surface_medium' }}>
72
+ {getFormattedCount(peerCount) + ' watching'}
73
+ </Text>
74
+ <Flex
75
+ direction="column"
76
+ css={{
77
+ w: '$3',
78
+ h: '$3',
79
+ backgroundColor: '$on_surface_medium',
80
+ borderRadius: '50%',
81
+ alignSelf: 'center',
82
+ }}
83
+ />
84
+ <Text variant="caption" css={{ color: '$on_surface_medium' }}>
85
+ {'Started ' + getTime(liveTime) + ' ago'}
86
+ </Text>
87
+ </Flex>
88
+ </Flex>
89
+ </Flex>
90
+ );
91
+ };
@@ -0,0 +1,27 @@
1
+ import React, { MouseEvent } from 'react';
2
+ import { PauseIcon, PlayIcon } from '@100mslive/react-icons';
3
+ import { IconButton, Tooltip } from '../../..';
4
+ import { useHMSPlayerContext } from './PlayerContext';
5
+
6
+ export const PlayButton = ({
7
+ isPaused,
8
+ width = 20,
9
+ height = 20,
10
+ }: {
11
+ isPaused: boolean;
12
+ width: number;
13
+ height: number;
14
+ }) => {
15
+ const { hlsPlayer } = useHMSPlayerContext();
16
+ const onClick = async (event: MouseEvent) => {
17
+ event?.stopPropagation();
18
+ isPaused ? await hlsPlayer?.play() : hlsPlayer?.pause();
19
+ };
20
+ return (
21
+ <Tooltip title={isPaused ? 'Play' : 'Pause'} side="top">
22
+ <IconButton onClick={onClick} data-testid="play_pause_btn">
23
+ {isPaused ? <PlayIcon width={width} height={height} /> : <PauseIcon width={width} height={height} />}
24
+ </IconButton>
25
+ </Tooltip>
26
+ );
27
+ };
@@ -0,0 +1,15 @@
1
+ import React, { useContext } from 'react';
2
+ import { HMSHLSPlayer } from '@100mslive/hls-player';
3
+
4
+ type IHMSPlayerContext = {
5
+ hlsPlayer?: HMSHLSPlayer;
6
+ };
7
+
8
+ export const HMSPlayerContext = React.createContext<IHMSPlayerContext>({
9
+ hlsPlayer: undefined,
10
+ });
11
+
12
+ export const useHMSPlayerContext = () => {
13
+ const context = useContext(HMSPlayerContext);
14
+ return context;
15
+ };
@@ -0,0 +1,81 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Box, Flex, Slider } from '../../..';
3
+ import { useHMSPlayerContext } from './PlayerContext';
4
+ import { getPercentage } from './utils';
5
+
6
+ export const VideoProgress = () => {
7
+ const { hlsPlayer } = useHMSPlayerContext();
8
+ const [videoProgress, setVideoProgress] = useState<number>(0);
9
+ const [bufferProgress, setBufferProgress] = useState(0);
10
+ const videoEl = hlsPlayer?.getVideoElement();
11
+
12
+ const onValueChange = (time: number) => {
13
+ hlsPlayer?.seekTo(time);
14
+ };
15
+ useEffect(() => {
16
+ if (!videoEl) {
17
+ return;
18
+ }
19
+ const timeupdateHandler = () => {
20
+ if (!videoEl) {
21
+ return;
22
+ }
23
+ const videoProgress = Math.floor(getPercentage(videoEl.currentTime, videoEl.duration));
24
+ let bufferProgress = 0;
25
+ if (videoEl.buffered.length > 0) {
26
+ bufferProgress = Math.floor(getPercentage(videoEl.buffered?.end(0), videoEl.duration));
27
+ }
28
+
29
+ setVideoProgress(isNaN(videoProgress) ? 0 : videoProgress);
30
+ setBufferProgress(isNaN(bufferProgress) ? 0 : bufferProgress);
31
+ };
32
+ videoEl.addEventListener('timeupdate', timeupdateHandler);
33
+ return function cleanup() {
34
+ videoEl?.removeEventListener('timeupdate', timeupdateHandler);
35
+ };
36
+ }, [videoEl]);
37
+
38
+ const onProgress = (progress: number[]) => {
39
+ const progress1 = Math.floor(getPercentage(progress[0], 100));
40
+ const videoEl = hlsPlayer?.getVideoElement();
41
+ const currentTime = (progress1 * (videoEl?.duration || 0)) / 100;
42
+ if (onValueChange) {
43
+ onValueChange(currentTime);
44
+ }
45
+ };
46
+
47
+ if (!videoEl) {
48
+ return null;
49
+ }
50
+ return (
51
+ <Flex align="center" css={{ cursor: 'pointer', h: '$2', alignSelf: 'stretch' }}>
52
+ <Slider
53
+ id="video-actual-rest"
54
+ css={{
55
+ cursor: 'pointer',
56
+ h: '$2',
57
+ zIndex: 1,
58
+ transition: `all .2s ease .5s`,
59
+ }}
60
+ min={0}
61
+ max={100}
62
+ step={1}
63
+ value={[videoProgress]}
64
+ showTooltip={false}
65
+ onValueChange={onProgress}
66
+ thumbStyles={{ w: '$6', h: '$6' }}
67
+ />
68
+ <Box
69
+ id="video-buffer"
70
+ css={{
71
+ h: '$2',
72
+ width: `${bufferProgress - videoProgress}%`,
73
+ background: '$on_surface_high',
74
+ position: 'absolute',
75
+ left: `${videoProgress}%`,
76
+ opacity: '25%',
77
+ }}
78
+ />
79
+ </Flex>
80
+ );
81
+ };
@@ -0,0 +1,42 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { HMSHLSPlayerEvents } from '@100mslive/hls-player';
3
+ import { Text } from '../../../Text';
4
+ import { useHMSPlayerContext } from './PlayerContext';
5
+ import { getDurationFromSeconds } from './utils';
6
+
7
+ export const VideoTime = () => {
8
+ const { hlsPlayer } = useHMSPlayerContext();
9
+ const [videoTime, setVideoTime] = useState('');
10
+
11
+ useEffect(() => {
12
+ const timeupdateHandler = (currentTime: number) => {
13
+ const videoEl = hlsPlayer?.getVideoElement();
14
+ if (videoEl) {
15
+ setVideoTime(getDurationFromSeconds(videoEl.duration - currentTime));
16
+ } else {
17
+ setVideoTime(getDurationFromSeconds(currentTime));
18
+ }
19
+ };
20
+ if (hlsPlayer) {
21
+ hlsPlayer.on(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler);
22
+ }
23
+ return function cleanup() {
24
+ hlsPlayer?.off(HMSHLSPlayerEvents.CURRENT_TIME, timeupdateHandler);
25
+ };
26
+ }, [hlsPlayer]);
27
+
28
+ return hlsPlayer ? (
29
+ <Text
30
+ variant="body1"
31
+ css={{
32
+ minWidth: '$16',
33
+ c: '$on_surface_medium',
34
+ display: 'flex',
35
+ justifyContent: 'center',
36
+ fontWeight: '$regular',
37
+ }}
38
+ >
39
+ -{videoTime}
40
+ </Text>
41
+ ) : null;
42
+ };
@@ -1,9 +1,11 @@
1
1
  import React, { useState } from 'react';
2
2
  import { VolumeOneIcon, VolumeTwoIcon, VolumeZeroIcon } from '@100mslive/react-icons';
3
- import { Flex, Slider } from '../../../';
3
+ import { Flex, Slider } from '../../..';
4
+ import { useHMSPlayerContext } from './PlayerContext';
4
5
 
5
- export const VolumeControl = ({ hlsPlayer }) => {
6
- const [volume, setVolume] = useState(hlsPlayer?.volume ?? 100);
6
+ export const VolumeControl = () => {
7
+ const { hlsPlayer } = useHMSPlayerContext();
8
+ const [volume, setVolume] = useState(hlsPlayer?.volume || 0);
7
9
  const [showSlider, setShowSlider] = useState(false);
8
10
 
9
11
  return (
@@ -47,7 +49,7 @@ export const VolumeControl = ({ hlsPlayer }) => {
47
49
  step={1}
48
50
  value={[volume]}
49
51
  onValueChange={volume => {
50
- hlsPlayer.setVolume(volume[0]);
52
+ hlsPlayer?.setVolume(volume[0]);
51
53
  setVolume(volume[0]);
52
54
  }}
53
55
  thumbStyles={{ w: '$6', h: '$6' }}
@@ -56,7 +58,7 @@ export const VolumeControl = ({ hlsPlayer }) => {
56
58
  );
57
59
  };
58
60
 
59
- const VolumeIcon = ({ volume, onClick }) => {
61
+ const VolumeIcon = ({ volume, onClick }: { volume: number; onClick: () => void }) => {
60
62
  if (volume === 0) {
61
63
  return <VolumeZeroIcon style={{ cursor: 'pointer', transition: 'color 0.3s' }} onClick={onClick} />;
62
64
  }
@@ -1,4 +1,6 @@
1
+ // @ts-ignore
1
2
  import { LeftControls, RightControls, VideoControls } from './Controls';
3
+ // @ts-ignore
2
4
  import { HMSVideo } from './HMSVideo';
3
5
  import { PlayButton } from './PlayButton';
4
6
  import { VideoProgress } from './VideoProgress';
@@ -0,0 +1,35 @@
1
+ export function getPercentage(a: number, b: number) {
2
+ return (a / b) * 100;
3
+ }
4
+
5
+ /**
6
+ * Take a time in seconds and return its equivalent time in hh:mm:ss format
7
+ * @param {number} timeInSeconds if given as floating point value, it is floored.
8
+ *
9
+ * @returns a string representing timeInSeconds in HH:MM:SS format.
10
+ */
11
+ export function getDurationFromSeconds(timeInSeconds: number) {
12
+ let time = Math.floor(timeInSeconds);
13
+ const hours = Math.floor(time / 3600);
14
+ time = time - hours * 3600;
15
+ const minutes = Math.floor(time / 60);
16
+ const seconds = Math.floor(time - minutes * 60);
17
+
18
+ const prefixedMinutes = `${minutes < 10 ? `0${minutes}` : minutes}`;
19
+ const prefixedSeconds = `${seconds < 10 ? `0${seconds}` : seconds}`;
20
+
21
+ let videoTimeStr = `${prefixedMinutes}:${prefixedSeconds}`;
22
+ if (hours) {
23
+ const prefixedHours = `${hours < 10 ? `0${hours}` : hours}`;
24
+ videoTimeStr = `${prefixedHours}:${prefixedMinutes}:${prefixedSeconds}`;
25
+ }
26
+ return videoTimeStr;
27
+ }
28
+
29
+ export function getTime(timeInMilles: number) {
30
+ const timeInSeconds = Math.floor(timeInMilles / 1000);
31
+ const hours = Math.floor(timeInSeconds / 3600);
32
+ const minutes = Math.floor((timeInSeconds % 3600) / 60);
33
+ const hour = hours !== 0 ? `${hours < 10 ? '0' : ''}${hours}` : '';
34
+ return hour + `${hour ? 'h:' : ''}` + minutes + 'm';
35
+ }
@@ -18,6 +18,7 @@ import { config as cssConfig } from '../../../Theme';
18
18
  import { ToastManager } from '../Toast/ToastManager';
19
19
  import { DesktopLeaveRoom } from './DesktopLeaveRoom';
20
20
  import { MwebLeaveRoom } from './MwebLeaveRoom';
21
+ import { useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
21
22
 
22
23
  export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen }) => {
23
24
  const isConnected = useHMSStore(selectIsConnectedToRoom);
@@ -33,6 +34,8 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen
33
34
  );
34
35
  const hlsState = useHMSStore(selectHLSState);
35
36
  const hmsActions = useHMSActions();
37
+ const isMobileHLSStream = useMobileHLSStream();
38
+ const isLandscapeHLSStream = useLandscapeHLSStream();
36
39
 
37
40
  const stopStream = async () => {
38
41
  try {
@@ -61,8 +64,11 @@ export const LeaveRoom = ({ screenType }: { screenType: keyof ConferencingScreen
61
64
  if (!permissions || !isConnected) {
62
65
  return null;
63
66
  }
67
+ if (isMobileHLSStream || isLandscapeHLSStream) {
68
+ return <MwebLeaveRoom leaveRoom={leaveRoom} endRoom={endRoom} />;
69
+ }
64
70
  return isMobile ? (
65
- <MwebLeaveRoom leaveRoom={leaveRoom} screenType={screenType} endRoom={endRoom} />
71
+ <MwebLeaveRoom leaveRoom={leaveRoom} endRoom={endRoom} />
66
72
  ) : (
67
73
  <DesktopLeaveRoom leaveRoom={leaveRoom} screenType={screenType} endRoom={endRoom} />
68
74
  );
@@ -1,9 +1,9 @@
1
1
  import React, { Fragment, useState } from 'react';
2
- import { ConferencingScreen } from '@100mslive/types-prebuilt';
3
2
  // @ts-ignore: No implicit Any
4
3
  import { selectIsConnectedToRoom, selectPermissions, useHMSStore, useRecordingStreaming } from '@100mslive/react-sdk';
5
4
  // @ts-ignore: No implicit Any
6
- import { ExitIcon, StopIcon } from '@100mslive/react-icons';
5
+ import { CrossIcon, ExitIcon, StopIcon } from '@100mslive/react-icons';
6
+ import { IconButton } from '../../../IconButton';
7
7
  import { Box } from '../../../Layout';
8
8
  import { Sheet } from '../../../Sheet';
9
9
  import { Tooltip } from '../../../Tooltip';
@@ -11,19 +11,20 @@ import { EndSessionContent } from './EndSessionContent';
11
11
  import { LeaveIconButton } from './LeaveAtoms';
12
12
  import { LeaveCard } from './LeaveCard';
13
13
  import { LeaveSessionContent } from './LeaveSessionContent';
14
+ import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
14
15
  // @ts-ignore: No implicit Any
15
16
  import { useDropdownList } from '../hooks/useDropdownList';
17
+ import { useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
16
18
 
17
19
  export const MwebLeaveRoom = ({
18
20
  leaveRoom,
19
- screenType,
20
21
  endRoom,
21
22
  }: {
22
23
  leaveRoom: (options?: { endStream?: boolean }) => Promise<void>;
23
- screenType: keyof ConferencingScreen;
24
24
  endRoom: () => Promise<void>;
25
25
  }) => {
26
26
  const [open, setOpen] = useState(false);
27
+ const { screenType } = useRoomLayoutConferencingScreen();
27
28
  const [showLeaveRoomAlert, setShowLeaveRoomAlert] = useState(false);
28
29
  const [showEndStreamAlert, setShowEndStreamAlert] = useState(false);
29
30
  const isConnected = useHMSStore(selectIsConnectedToRoom);
@@ -43,20 +44,7 @@ export const MwebLeaveRoom = ({
43
44
  {showLeaveOptions ? (
44
45
  <Sheet.Root open={open} onOpenChange={setOpen}>
45
46
  <Sheet.Trigger asChild>
46
- <LeaveIconButton
47
- key="LeaveRoom"
48
- data-testid="leave_room_btn"
49
- css={{
50
- borderTopRightRadius: '$1',
51
- borderBottomRightRadius: '$1',
52
- }}
53
- >
54
- <Tooltip title="Leave Room">
55
- <Box>
56
- <ExitIcon style={{ transform: 'rotate(180deg)' }} />
57
- </Box>
58
- </Tooltip>
59
- </LeaveIconButton>
47
+ <LeaveButton onClick={() => setOpen(!open)} />
60
48
  </Sheet.Trigger>
61
49
  <Sheet.Content>
62
50
  <LeaveCard
@@ -88,13 +76,7 @@ export const MwebLeaveRoom = ({
88
76
  </Sheet.Content>
89
77
  </Sheet.Root>
90
78
  ) : (
91
- <LeaveIconButton key="LeaveRoom" data-testid="leave_room_btn" onClick={() => setShowLeaveRoomAlert(true)}>
92
- <Tooltip title="Leave Room">
93
- <Box>
94
- <ExitIcon style={{ transform: 'rotate(180deg)' }} />
95
- </Box>
96
- </Tooltip>
97
- </LeaveIconButton>
79
+ <LeaveButton onClick={() => setShowLeaveRoomAlert(true)} />
98
80
  )}
99
81
  <Sheet.Root open={showEndStreamAlert} onOpenChange={setShowEndStreamAlert}>
100
82
  <Sheet.Content css={{ bg: '$surface_dim', p: '$10', pb: '$12' }}>
@@ -114,3 +96,34 @@ export const MwebLeaveRoom = ({
114
96
  </Fragment>
115
97
  );
116
98
  };
99
+
100
+ const LeaveButton = ({ onClick }: { onClick: () => void }) => {
101
+ const isMobileHLSStream = useMobileHLSStream();
102
+ const isLandscapeHLSStream = useLandscapeHLSStream();
103
+
104
+ return isMobileHLSStream || isLandscapeHLSStream ? (
105
+ <IconButton key="LeaveRoom" data-testid="leave_room_btn" onClick={() => onClick()}>
106
+ <Tooltip title="Leave Room">
107
+ <Box>
108
+ <CrossIcon />
109
+ </Box>
110
+ </Tooltip>
111
+ </IconButton>
112
+ ) : (
113
+ <LeaveIconButton
114
+ key="LeaveRoom"
115
+ data-testid="leave_room_btn"
116
+ css={{
117
+ borderTopRightRadius: '$1',
118
+ borderBottomRightRadius: '$1',
119
+ }}
120
+ onClick={() => onClick()}
121
+ >
122
+ <Tooltip title="Leave Room">
123
+ <Box>
124
+ <ExitIcon style={{ transform: 'rotate(180deg)' }} />
125
+ </Box>
126
+ </Tooltip>
127
+ </LeaveIconButton>
128
+ );
129
+ };
@@ -10,6 +10,7 @@ import { DesktopOptions } from './SplitComponents/DesktopOptions';
10
10
  // @ts-ignore: No implicit Any
11
11
  import { MwebOptions } from './SplitComponents/MwebOptions';
12
12
  import { config as cssConfig } from '../../..';
13
+ import { useLandscapeHLSStream } from '../../common/hooks';
13
14
 
14
15
  export const MoreSettings = ({
15
16
  elements,
@@ -19,7 +20,8 @@ export const MoreSettings = ({
19
20
  screenType: keyof ConferencingScreen;
20
21
  }) => {
21
22
  const isMobile = useMedia(cssConfig.media.md);
22
- return isMobile ? (
23
+ const isLandscapeHLSStream = useLandscapeHLSStream();
24
+ return isMobile || isLandscapeHLSStream ? (
23
25
  <MwebOptions elements={elements} screenType={screenType} />
24
26
  ) : (
25
27
  <DesktopOptions elements={elements} screenType={screenType} />
@@ -120,7 +120,7 @@ export const MwebOptions = ({
120
120
  <Sheet.Root open={openOptionsSheet} onOpenChange={setOpenOptionsSheet}>
121
121
  <Tooltip title="More options">
122
122
  <Sheet.Trigger asChild data-testid="more_settings_btn">
123
- <IconButton>
123
+ <IconButton css={{ '@md': { bg: screenType === 'hls_live_streaming' ? '$surface_default' : '' } }}>
124
124
  <HamburgerMenuIcon />
125
125
  </IconButton>
126
126
  </Sheet.Trigger>
@@ -6,12 +6,14 @@ import { Box, Flex } from '../../Layout';
6
6
  import { Dialog } from '../../Modal';
7
7
  import { Text } from '../../Text';
8
8
  import { config as cssConfig } from '../../Theme';
9
+ import { useLandscapeHLSStream } from '../common/hooks';
9
10
  // @ts-ignore
10
11
  import { isMobileUserAgent } from '../common/utils';
11
12
 
12
13
  export const MwebLandscapePrompt = () => {
13
14
  const [showMwebLandscapePrompt, setShowMwebLandscapePrompt] = useState(false);
14
15
  const isLandscape = useMedia(cssConfig.media.ls);
16
+ const isLandscapeHLSStream = useLandscapeHLSStream();
15
17
 
16
18
  useEffect(() => {
17
19
  if (!isMobileUserAgent) {
@@ -36,6 +38,9 @@ export const MwebLandscapePrompt = () => {
36
38
  };
37
39
  }, [isLandscape]);
38
40
 
41
+ if (isLandscapeHLSStream) {
42
+ return null;
43
+ }
39
44
  return (
40
45
  <Dialog.Root open={showMwebLandscapePrompt} onOpenChange={setShowMwebLandscapePrompt}>
41
46
  <Dialog.Portal>
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
- import { HandIcon } from '@100mslive/react-icons';
2
+ import { HandIcon, HandRaiseSlashedIcon } from '@100mslive/react-icons';
3
3
  import { Tooltip } from '../../Tooltip';
4
+ // @ts-ignore: No implicit Any
4
5
  import IconButton from '../IconButton';
5
6
  // @ts-ignore: No implicit Any
6
7
  import { useMyMetadata } from './hooks/useMetadata';
@@ -10,7 +11,7 @@ export const RaiseHand = () => {
10
11
  return (
11
12
  <Tooltip title={isHandRaised ? 'Lower hand' : 'Raise hand'}>
12
13
  <IconButton data-testid="hand_raise_btn" active={!isHandRaised} onClick={async () => await toggleHandRaise()}>
13
- <HandIcon />
14
+ {isHandRaised ? <HandRaiseSlashedIcon /> : <HandIcon />}
14
15
  </IconButton>
15
16
  </Tooltip>
16
17
  );
@@ -40,18 +40,19 @@ const ParticipantCount = ({ count }: { count: number }) => {
40
40
  export const SidePaneTabs = React.memo<{
41
41
  active: 'Participants | Chat';
42
42
  hideControls?: boolean;
43
- }>(({ active = SIDE_PANE_OPTIONS.CHAT, hideControls }) => {
43
+ hideTab?: boolean;
44
+ }>(({ active = SIDE_PANE_OPTIONS.CHAT, hideControls, hideTab = false }) => {
44
45
  const toggleChat = useSidepaneToggle(SIDE_PANE_OPTIONS.CHAT);
45
46
  const toggleParticipants = useSidepaneToggle(SIDE_PANE_OPTIONS.PARTICIPANTS);
46
47
  const resetSidePane = useSidepaneReset();
47
48
  const [activeTab, setActiveTab] = useState(active);
48
49
  const [activeRole, setActiveRole] = useState('');
49
50
  const peerCount = useHMSStore(selectPeerCount);
50
- const { elements } = useRoomLayoutConferencingScreen();
51
+ const { elements, screenType } = useRoomLayoutConferencingScreen();
51
52
  const chat_title = elements?.chat?.chat_title || 'Chat';
52
53
  const showChat = !!elements?.chat;
53
54
  const showParticipants = !!elements?.participant_list;
54
- const hideTabs = !(showChat && showParticipants);
55
+ const hideTabs = !(showChat && showParticipants) || hideTab;
55
56
  const isMobile = useMedia(cssConfig.media.md);
56
57
  const isOverlayChat = !!elements?.chat?.is_overlay && isMobile;
57
58
  const { off_stage_roles = [] } = (elements as DefaultConferencingScreen_Elements)?.on_stage_exp || {};
@@ -107,10 +108,19 @@ export const SidePaneTabs = React.memo<{
107
108
  <>
108
109
  {hideTabs ? (
109
110
  <>
110
- <Flex justify="between" css={{ w: '100%' }}>
111
- <Text variant="sm" css={{ fontWeight: '$semiBold', p: '$4', c: '$on_surface_high', pr: '$12' }}>
112
- {showChat ? (
113
- chat_title
111
+ <Flex justify="between" css={{ w: '100%', '&:empty': { display: 'none' } }}>
112
+ <Text
113
+ variant="sm"
114
+ css={{
115
+ fontWeight: '$semiBold',
116
+ p: '$4',
117
+ c: '$on_surface_high',
118
+ pr: '$12',
119
+ '&:empty': { display: 'none' },
120
+ }}
121
+ >
122
+ {activeTab === SIDE_PANE_OPTIONS.CHAT ? (
123
+ screenType !== 'hls_live_streaming' && chat_title
114
124
  ) : (
115
125
  <span>
116
126
  Participants&nbsp;
@@ -122,7 +132,12 @@ export const SidePaneTabs = React.memo<{
122
132
  {showChatSettings ? <ChatSettings /> : null}
123
133
  {isOverlayChat && isChatOpen ? null : (
124
134
  <IconButton
125
- css={{ my: '$1', color: '$on_surface_medium', '&:hover': { color: '$on_surface_high' } }}
135
+ css={{
136
+ my: '$1',
137
+ color: '$on_surface_medium',
138
+ '&:hover': { color: '$on_surface_high' },
139
+ '&:empty': { display: 'none' },
140
+ }}
126
141
  onClick={e => {
127
142
  e.stopPropagation();
128
143
  if (activeTab === SIDE_PANE_OPTIONS.CHAT) {
@@ -133,12 +148,16 @@ export const SidePaneTabs = React.memo<{
133
148
  }}
134
149
  data-testid="close_chat"
135
150
  >
136
- <CrossIcon />
151
+ {screenType === 'hls_live_streaming' && isChatOpen ? null : <CrossIcon />}
137
152
  </IconButton>
138
153
  )}
139
154
  </Flex>
140
155
  </Flex>
141
- {showChat ? <Chat /> : <ParticipantList offStageRoles={off_stage_roles} onActive={setActiveRole} />}
156
+ {activeTab === SIDE_PANE_OPTIONS.CHAT ? (
157
+ <Chat />
158
+ ) : (
159
+ <ParticipantList offStageRoles={off_stage_roles} onActive={setActiveRole} />
160
+ )}
142
161
  </>
143
162
  ) : (
144
163
  <Tabs.Root