diff --git a/examples/prebuilt-react-integration/src/App.jsx b/examples/prebuilt-react-integration/src/App.jsx index e49ddcb9b1..47560de72b 100644 --- a/examples/prebuilt-react-integration/src/App.jsx +++ b/examples/prebuilt-react-integration/src/App.jsx @@ -4,5 +4,7 @@ import { getRoomCodeFromUrl } from './utils'; export default function App() { const roomCode = getRoomCodeFromUrl(); - return ; + return ( + + ); } diff --git a/packages/hms-video-store/src/selectors/selectors.ts b/packages/hms-video-store/src/selectors/selectors.ts index ce91647ea6..fb276ff10c 100644 --- a/packages/hms-video-store/src/selectors/selectors.ts +++ b/packages/hms-video-store/src/selectors/selectors.ts @@ -452,6 +452,7 @@ export const selectPermissions = createSelector(selectLocalPeerRole, role => rol export const selectRecordingState = createSelector(selectRoom, room => room.recording); export const selectRTMPState = createSelector(selectRoom, room => room.rtmp); export const selectHLSState = createSelector(selectRoom, room => room.hls); +export const selectTranscriptionsState = createSelector(selectRoom, room => room.transcriptions); export const selectSessionId = createSelector(selectRoom, room => room.sessionId); export const selectRoomStartTime = createSelector(selectRoom, room => room.startedAt); export const selectIsLargeRoom = createSelector(selectRoom, room => !!room.isLargeRoom); diff --git a/packages/hms-video-store/src/utils/constants.ts b/packages/hms-video-store/src/utils/constants.ts index 07f78bc0ee..5372663c7b 100644 --- a/packages/hms-video-store/src/utils/constants.ts +++ b/packages/hms-video-store/src/utils/constants.ts @@ -59,7 +59,7 @@ export const HMSEvents = { export const PROTOCOL_VERSION = '2.5'; -export const PROTOCOL_SPEC = '20240417'; +export const PROTOCOL_SPEC = '20240521'; export const HAND_RAISE_GROUP_NAME = '_handraise'; diff --git a/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.tsx b/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.tsx index d781feebc8..35d3e0bf1c 100644 --- a/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/AppData/AppData.tsx @@ -66,8 +66,8 @@ const initialAppData = { [POLL_STATE.pollInView]: '', [POLL_STATE.view]: '', }, - // by default off, so it will not appear in beam bots - [APP_DATA.caption]: false, + // by default on because of on demand now + [APP_DATA.caption]: true, }; export const AppData = React.memo(() => { diff --git a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/CaptionContent.tsx b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/CaptionContent.tsx new file mode 100644 index 0000000000..5a60f1ac38 --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/CaptionContent.tsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { HMSTranscriptionMode, selectIsTranscriptionEnabled, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; +import { AlertTriangleIcon, CrossIcon } from '@100mslive/react-icons'; +import { Button } from '../../../Button'; +import { Box, Flex } from '../../../Layout'; +import { Loading } from '../../../Loading'; +import { Text } from '../../../Text'; +// @ts-ignore: No implicit Any +import { ToastManager } from '../Toast/ToastManager'; +// @ts-ignore: No implicit Any +import { useSetIsCaptionEnabled } from '../AppData/useUISettings'; + +export const CaptionContent = ({ isMobile, onExit }: { isMobile: boolean; onExit: () => void }) => { + const DURATION = 2000; + const actions = useHMSActions(); + const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled); + + const [isCaptionEnabled, setIsCaptionEnabled] = useSetIsCaptionEnabled(); + return ( + <> + + {isTranscriptionEnabled ? 'Disable' : 'Enable'} Closed Caption (CC) for this session? + + + + + {!isMobile ? ( + + This will {isTranscriptionEnabled ? 'disable' : 'enable'} Closed Captions for everyone in this room. You can + {isTranscriptionEnabled ? 'enable' : 'disable'} it later. + + ) : null} + + + {isMobile ? null : ( + + )} + + {isMobile && isTranscriptionEnabled ? ( + + ) : null} + + + + {isMobile && ( + + This will {isTranscriptionEnabled ? 'disable' : 'enable'} Closed Captions for everyone in this room. You can + {isTranscriptionEnabled ? 'enable' : 'disable'} it later. + + )} + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/CaptionModal.tsx b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/CaptionModal.tsx new file mode 100644 index 0000000000..37684c6b0a --- /dev/null +++ b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/CaptionModal.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { useMedia } from 'react-use'; +import { config as cssConfig, Dialog } from '../../..'; +import { Sheet } from '../../../Sheet'; +import { CaptionContent } from './CaptionContent'; + +export const CaptionModal = ({ onOpenChange }: { onOpenChange: (value: boolean) => void }) => { + const isMobile = useMedia(cssConfig.media.md); + + const props = { + isMobile, + onExit: () => { + onOpenChange(false); + }, + }; + + if (isMobile) { + return ( + + + + + + ); + } + + return ( + + + + + + + + + ); +}; diff --git a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx index 49ea2c01de..f9f321849b 100644 --- a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/DesktopOptions.tsx @@ -6,9 +6,23 @@ import { HLSLiveStreamingScreen_Elements, } from '@100mslive/types-prebuilt'; import { match } from 'ts-pattern'; -import { selectAppData, selectLocalPeerID, useHMSActions, useHMSStore } from '@100mslive/react-sdk'; -import { BrbIcon, CheckIcon, HamburgerMenuIcon, InfoIcon, PipIcon, SettingsIcon } from '@100mslive/react-icons'; -import { Checkbox, Dropdown, Flex, Text, Tooltip } from '../../../..'; +import { + selectAppData, + selectIsTranscriptionEnabled, + selectLocalPeerID, + useHMSActions, + useHMSStore, +} from '@100mslive/react-sdk'; +import { + BrbIcon, + CheckIcon, + HamburgerMenuIcon, + InfoIcon, + OpenCaptionIcon, + PipIcon, + SettingsIcon, +} from '@100mslive/react-icons'; +import { Checkbox, Dropdown, Flex, Switch, Text, Tooltip } from '../../../..'; import IconButton from '../../../IconButton'; // @ts-ignore: No implicit any import { PIP } from '../../PIP'; @@ -24,6 +38,7 @@ import StartRecording from '../../Settings/StartRecording'; import { StatsForNerds } from '../../StatsForNerds'; // @ts-ignore: No implicit any import { BulkRoleChangeModal } from '../BulkRoleChangeModal'; +import { CaptionModal } from '../CaptionModal'; // @ts-ignore: No implicit any import { FullScreenItem } from '../FullScreenItem'; import { MuteAllModal } from '../MuteAllModal'; @@ -43,6 +58,7 @@ const MODALS = { BULK_ROLE_CHANGE: 'bulkRoleChange', MUTE_ALL: 'muteAll', EMBED_URL: 'embedUrl', + CAPTION: 'caption', }; export const DesktopOptions = ({ @@ -59,6 +75,7 @@ export const DesktopOptions = ({ const { isBRBOn, toggleBRB } = useMyMetadata(); const isPipOn = PictureInPicture.isOn(); const isBRBEnabled = !!elements?.brb; + const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled); useDropdownList({ open: openModals.size > 0, name: 'MoreSettings' }); @@ -115,6 +132,23 @@ export const DesktopOptions = ({ ) : null} + { + updateState(MODALS.CAPTION, true); + }} + > + + + + Closed Captions + + + {isTranscriptionEnabled ? 'Enabled' : 'Disabled'} + + + + {screenType !== 'hls_live_streaming' ? ( updateState(MODALS.SELF_ROLE_CHANGE, value)} /> )} + {openModals.has(MODALS.CAPTION) && ( + updateState(MODALS.CAPTION, value)} /> + )} {/* {openModals.has(MODALS.EMBED_URL) && ( updateState(MODALS.EMBED_URL, value)} /> )} */} diff --git a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx index bf13d19d50..bb43a68ab4 100644 --- a/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx +++ b/packages/roomkit-react/src/Prebuilt/components/MoreSettings/SplitComponents/MwebOptions.tsx @@ -29,7 +29,7 @@ import { SettingsIcon, VirtualBackgroundIcon, } from '@100mslive/react-icons'; -import { Box, Loading, Tooltip } from '../../../..'; +import { Box, Loading, Text, Tooltip } from '../../../..'; import { Sheet } from '../../../../Sheet'; // @ts-ignore: No implicit any import IconButton from '../../../IconButton'; @@ -43,6 +43,7 @@ import SettingsModal from '../../Settings/SettingsModal'; import { ToastManager } from '../../Toast/ToastManager'; // @ts-ignore: No implicit any import { ActionTile } from '../ActionTile'; +import { CaptionModal } from '../CaptionModal'; // @ts-ignore: No implicit any import { ChangeNameModal } from '../ChangeNameModal'; // @ts-ignore: No implicit any @@ -73,6 +74,7 @@ const MODALS = { BULK_ROLE_CHANGE: 'bulkRoleChange', MUTE_ALL: 'muteAll', EMBED_URL: 'embedUrl', + CAPTION: 'caption', }; export const MwebOptions = ({ @@ -106,9 +108,9 @@ export const MwebOptions = ({ const isLocalVideoEnabled = useHMSStore(selectIsLocalVideoEnabled); const { startRecording, isRecordingLoading } = useRecordingHandler(); - const isCaptionPresent = useHMSStore(selectIsTranscriptionEnabled); + const isTranscriptionEnabled = useHMSStore(selectIsTranscriptionEnabled); - const [isCaptionEnabled, setIsCaptionEnabled] = useSetIsCaptionEnabled(); + const [isCaptionEnabled] = useSetIsCaptionEnabled(); useDropdownList({ open: openModals.size > 0 || openOptionsSheet || openSettingsSheet, name: 'MoreSettings' }); const updateState = (modalName: string, value: boolean) => { @@ -193,21 +195,17 @@ export const MwebOptions = ({ {isHandRaised ? 'Lower' : 'Raise'} Hand ) : null} - {isCaptionPresent && screenType !== 'hls_live_streaming' ? ( - { - setIsCaptionEnabled(!isCaptionEnabled); - }} - > - {isCaptionEnabled ? ( - - ) : ( - - )} - {isCaptionEnabled ? 'Hide Captions' : 'Captions Disabled'} - - ) : null} - + { + setOpenOptionsSheet(false); + updateState(MODALS.CAPTION, true); + }} + > + {isTranscriptionEnabled && isCaptionEnabled ? : } + + Closed Caption + + {isLocalVideoEnabled && !!elements?.virtual_background ? ( { @@ -323,7 +321,9 @@ export const MwebOptions = ({ openParentSheet={() => setOpenOptionsSheet(true)} /> )} - + {openModals.has(MODALS.CAPTION) && ( + updateState(MODALS.CAPTION, value)} /> + )} {showEmojiCard && ( { + if (transcriptionStates && transcriptionStates.length > 0 && transcriptionStates[0].error) { + ToastManager.addToast({ + title: `Failed to enable Closed Caption`, + variant: 'error', + icon: , + }); + } + }, [transcriptionStates]); + useEffect(() => { if (mainPage !== 0) { return;