@@ -20,6 +20,9 @@ import {
2020 Box ,
2121 Chip ,
2222 Typography ,
23+ Collapse ,
24+ RadioGroup ,
25+ Radio ,
2326} from '@mui/material' ;
2427import { useTranslation } from 'react-i18next' ;
2528import GeneralSettingsDialog from './GeneralSettingsDialog.tsx' ;
@@ -138,9 +141,6 @@ function OptionButton(props: OptionButtonProps) {
138141 const [ diagnosticDialogOpen , setDiagnosticDialogOpen ] = React . useState < boolean > ( false ) ;
139142 const [ generalSettingsDialogOpen , setGeneralSettingsDialogOpen ] = React . useState < boolean > ( false ) ;
140143 const [ recordingModalOpen , setRecordingModalOpen ] = React . useState < boolean > ( false ) ;
141- const [ recordSeparately , setRecordSeparately ] = React . useState < boolean > ( ( ) => {
142- return localStorage . getItem ( 'recordSeparately' ) === 'true' ;
143- } ) ;
144144 const [ localRecordingChecked , setLocalRecordingChecked ] = React . useState < boolean > ( ( ) => {
145145 return localStorage . getItem ( 'localRecordingChecked' ) === 'true' ;
146146 } ) ;
@@ -149,10 +149,9 @@ function OptionButton(props: OptionButtonProps) {
149149 return localStorage . getItem ( 'serverSideRecordingChecked' ) === 'true' ;
150150 } ,
151151 ) ;
152-
153- React . useEffect ( ( ) => {
154- localStorage . setItem ( 'recordSeparately' , String ( recordSeparately ) ) ;
155- } , [ recordSeparately ] ) ;
152+ const [ serverRecordingMode , setServerRecordingMode ] = React . useState < 'grid' | 'separate' > ( ( ) => {
153+ return localStorage . getItem ( 'serverRecordingMode' ) === 'separate' ? 'separate' : 'grid' ;
154+ } ) ;
156155
157156 React . useEffect ( ( ) => {
158157 localStorage . setItem ( 'localRecordingChecked' , String ( localRecordingChecked ) ) ;
@@ -161,6 +160,10 @@ function OptionButton(props: OptionButtonProps) {
161160 React . useEffect ( ( ) => {
162161 localStorage . setItem ( 'serverSideRecordingChecked' , String ( serverSideRecordingChecked ) ) ;
163162 } , [ serverSideRecordingChecked ] ) ;
163+
164+ React . useEffect ( ( ) => {
165+ localStorage . setItem ( 'serverRecordingMode' , serverRecordingMode ) ;
166+ } , [ serverRecordingMode ] ) ;
164167 const [ _hovered , setHovered ] = React . useState < boolean > ( false ) ;
165168 const theme = useTheme ( ) ;
166169 const themeContext = React . useContext ( ThemeContext ) ;
@@ -294,13 +297,8 @@ function OptionButton(props: OptionButtonProps) {
294297 } ;
295298
296299 const handleRecordingConfirm = ( ) : void => {
297- // Recording each participant separately is itself a server-side capability,
298- // so it must enable server recording even if "Cloud recording" wasn't checked.
299- props ?. startRecord ?.(
300- recordSeparately ,
301- serverSideRecordingChecked || recordSeparately ,
302- localRecordingChecked ,
303- ) ;
300+ const recordSeparately = serverSideRecordingChecked && serverRecordingMode === 'separate' ;
301+ props ?. startRecord ?.( recordSeparately , serverSideRecordingChecked , localRecordingChecked ) ;
304302 if ( localRecordingChecked && props . startLocalRecording ) {
305303 props . startLocalRecording ( ) ;
306304 }
@@ -423,49 +421,55 @@ function OptionButton(props: OptionButtonProps) {
423421 label = {
424422 < Box sx = { { pt : 1 } } >
425423 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
426- < Typography fontWeight = { 600 } > { t ( 'Grid recording' ) } </ Typography >
424+ < Typography fontWeight = { 600 } > { t ( 'Server-side recording' ) } </ Typography >
427425 < Chip label = { t ( 'SERVER-SIDE' ) } size = "small" />
428426 </ Box >
429427 < Typography variant = "body2" color = "text.secondary" >
430428 { t (
431- 'Records the meeting grid view as a single MP4 file, stored on Red5 Cloud . Best for sharing, long sessions, and high quality regardless of your connection .' ,
429+ 'Recorded on Red5 Cloud as an MP4 file, independent of your device and connection . Best for sharing and long sessions .' ,
432430 ) }
433431 </ Typography >
434432 </ Box >
435433 }
436434 />
437- </ Box >
438- < Box
439- sx = { {
440- border : '1px solid' ,
441- borderColor : recordSeparately ? 'error.main' : 'divider' ,
442- borderRadius : 2 ,
443- p : 1 ,
444- mb : 1.5 ,
445- } }
446- >
447- < FormControlLabel
448- sx = { { alignItems : 'flex-start' , width : '100%' , m : 0 } }
449- control = {
450- < Checkbox
451- checked = { recordSeparately }
452- onChange = { ( e ) => setRecordSeparately ( e . target . checked ) }
435+ < Collapse in = { serverSideRecordingChecked } >
436+ < RadioGroup
437+ value = { serverRecordingMode }
438+ onChange = { ( e ) => setServerRecordingMode ( e . target . value as 'grid' | 'separate' ) }
439+ sx = { { pl : 4 , pr : 1 , pb : 0.5 } }
440+ >
441+ < FormControlLabel
442+ value = "grid"
443+ control = { < Radio size = "small" /> }
444+ sx = { { alignItems : 'flex-start' , width : '100%' , m : 0 , mt : 1 } }
445+ label = {
446+ < Box >
447+ < Typography fontWeight = { 500 } > { t ( 'Grid recording' ) } </ Typography >
448+ < Typography variant = "body2" color = "text.secondary" >
449+ { t ( 'Records the meeting grid view as a single MP4 file.' ) }
450+ </ Typography >
451+ </ Box >
452+ }
453453 />
454- }
455- label = {
456- < Box sx = { { pt : 1 } } >
457- < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
458- < Typography fontWeight = { 600 } > { t ( 'Record participants separately' ) } </ Typography >
459- < Chip label = { t ( 'SERVER-SIDE' ) } size = "small" />
460- </ Box >
461- < Typography variant = "body2" color = "text.secondary" >
462- { t (
463- "Records each participant's audio and video as an independent MP4 file, stored on Red5 Cloud." ,
464- ) }
465- </ Typography >
466- </ Box >
467- }
468- />
454+ < FormControlLabel
455+ value = "separate"
456+ control = { < Radio size = "small" /> }
457+ sx = { { alignItems : 'flex-start' , width : '100%' , m : 0 , mt : 1.5 } }
458+ label = {
459+ < Box >
460+ < Typography fontWeight = { 500 } >
461+ { t ( 'Record participants separately' ) }
462+ </ Typography >
463+ < Typography variant = "body2" color = "text.secondary" >
464+ { t (
465+ "Records each participant's audio and video as an independent MP4 file." ,
466+ ) }
467+ </ Typography >
468+ </ Box >
469+ }
470+ />
471+ </ RadioGroup >
472+ </ Collapse >
469473 </ Box >
470474 < Box
471475 sx = { {
@@ -504,7 +508,7 @@ function OptionButton(props: OptionButtonProps) {
504508 < Button
505509 onClick = { handleRecordingConfirm }
506510 variant = "contained"
507- disabled = { ! serverSideRecordingChecked && ! recordSeparately && ! localRecordingChecked }
511+ disabled = { ! serverSideRecordingChecked && ! localRecordingChecked }
508512 >
509513 { t ( 'Start Recording' ) }
510514 </ Button >
0 commit comments