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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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