UNPKG

mediasfu-reactnative-expo

Version:

mediasfu-reactnative-expo – Expo-managed React Native WebRTC SDK for video conferencing, webinars, live streaming, broadcast, screen sharing, whiteboard, chat, recording, live subtitles, translation, and AI agent rooms on iOS, Android, and web. Prebuilt r

325 lines (321 loc) 11.6 kB
// RecordingModal.tsx import React from 'react'; import { Modal, View, StyleSheet, ScrollView, Dimensions, Pressable, Text, } from 'react-native'; import { FontAwesome } from '@expo/vector-icons'; import StandardPanelComponent from './StandardPanelComponent'; import AdvancedPanelComponent from './AdvancedPanelComponent'; import { getModalPosition } from '../../methods/utils/getModalPosition'; const getRecordingDisplayAdvice = (parameters) => { if (!parameters) { return null; } const normalizedRecordingMediaOptions = parameters.recordingMediaOptions === 'all' ? 'video' : parameters.recordingMediaOptions; if (!parameters.recordingVideoParticipantsFullRoomSupport && parameters.recordingVideoOptions === 'all' && normalizedRecordingMediaOptions === 'video' && parameters.meetingDisplayType === 'all' && !(parameters.breakOutRoomStarted && !parameters.breakOutRoomEnded)) { return 'Meeting display is set to All. This recording setup may be blocked. Switch the meeting display to Media before confirming so only participants with active media are included.'; } return null; }; /** * RecordingModal - Comprehensive recording settings with standard and advanced options * * RecordingModal is a feature-rich React Native modal for configuring and managing * session recordings. It provides both standard (quick start) and advanced (detailed) * panels for customizing video layout, background, text overlays, media options, and more. * * **Key Features:** * - Tabbed interface (Standard / Advanced settings) * - Video type selection (fullDisplay, mainScreen, custom layouts) * - Display type options (video, media, all) * - Background color customization * - Participant name tags with color options * - Custom text overlays with positioning * - Video orientation control * - Media/audio/video encoding options * - HLS streaming enablement * - Real-time preview of settings * * **UI Customization:** * This component can be replaced via `uiOverrides.recordingModalComponent` to * provide a completely custom recording modal implementation. * * @component * @param {RecordingModalOptions} props - Configuration options for the RecordingModal component * * @returns {JSX.Element} Rendered recording modal with configuration panels * * @example * // Basic usage - Display recording modal with default settings * import React, { useState } from 'react'; * import { RecordingModal, confirmRecording, startRecording } from 'mediasfu-reactnative-expo'; * * function RecordingControls() { * const [showModal, setShowModal] = useState(false); * const [recordingParams, setRecordingParams] = useState({ * recordPaused: false, * recordingVideoType: 'fullDisplay', * recordingDisplayType: 'video' as const, * recordingBackgroundColor: '#ffffff', * recordingNameTagsColor: '#000000', * recordingOrientationVideo: 'landscape', * recordingNameTags: true, * recordingAddText: false, * recordingCustomText: '', * recordingCustomTextPosition: 'top', * recordingCustomTextColor: '#000000', * recordingMediaOptions: 'default', * recordingAudioOptions: 'default', * recordingVideoOptions: 'default', * recordingAddHLS: false, * eventType: 'conference' as const, * updateRecordingVideoType: (value: string) => setRecordingParams({...recordingParams, recordingVideoType: value}), * updateRecordingDisplayType: (value: 'video' | 'media' | 'all') => setRecordingParams({...recordingParams, recordingDisplayType: value}), * // ... other update functions * getUpdatedAllParams: () => recordingParams, * }); * * return ( * <> * <Button title="Recording Settings" onPress={() => setShowModal(true)} /> * <RecordingModal * isRecordingModalVisible={showModal} * onClose={() => setShowModal(false)} * confirmRecording={confirmRecording} * startRecording={startRecording} * parameters={recordingParams} * /> * </> * ); * } * * @example * // With custom styling and positioning * <RecordingModal * isRecordingModalVisible={showRecordingModal} * onClose={() => setShowRecordingModal(false)} * backgroundColor="#1a1a2e" * position="center" * confirmRecording={async (options) => { * console.log('Confirming recording settings'); * await confirmRecording(options); * }} * startRecording={async (options) => { * console.log('Starting recording with settings:', options.parameters); * await startRecording(options); * }} * parameters={{ * ...recordingParams, * recordingBackgroundColor: '#0f3460', * recordingNameTagsColor: '#e94560', * recordingAddText: true, * recordingCustomText: 'Company Webinar', * recordingAddHLS: true, * }} * /> * * @example * // Using uiOverrides for complete modal replacement * import { MyCustomRecordingModal } from './MyCustomRecordingModal'; * * const sessionConfig = { * credentials: { apiKey: 'your-api-key' }, * uiOverrides: { * recordingModalComponent: { * component: MyCustomRecordingModal, * injectedProps: { * theme: 'professional', * presets: ['meeting', 'webinar', 'presentation'], * }, * }, * }, * }; * * // MyCustomRecordingModal.tsx * export const MyCustomRecordingModal = (props: RecordingModalOptions & { theme: string; presets: string[] }) => { * return ( * <Modal visible={props.isRecordingModalVisible} onRequestClose={props.onClose}> * <View style={{ backgroundColor: props.theme === 'professional' ? '#2c3e50' : '#fff' }}> * <Text>Recording Settings</Text> * {props.presets.map(preset => ( * <Button key={preset} title={preset} onPress={() => applyPreset(preset)} /> * ))} * <Button title="Start" onPress={() => props.startRecording({ parameters: props.parameters })} /> * </View> * </Modal> * ); * }; * ); * } * * export default App; * ``` */ const RecordingModal = ({ isRecordingModalVisible, onClose, backgroundColor = '#83c0e9', position = 'bottomRight', isDarkMode, confirmRecording, startRecording, parameters, style, renderContent, renderContainer, }) => { if (!isRecordingModalVisible) { return null; } const { recordPaused } = parameters; const recordingDisplayAdvice = getRecordingDisplayAdvice(parameters); const screenWidth = Dimensions.get('window').width; let modalWidth = 0.75 * screenWidth; if (modalWidth > 400) { modalWidth = 400; } const dimensions = { width: modalWidth, height: 0 }; const themed = typeof isDarkMode === 'boolean'; const textColor = themed ? (isDarkMode ? '#f8fafc' : '#0f172a') : 'black'; const borderColor = themed ? (isDarkMode ? 'rgba(226, 232, 240, 0.18)' : 'rgba(71, 85, 105, 0.22)') : '#000000'; const defaultContent = (<> {/* Header */} <View style={styles.modalHeader}> <Text style={[styles.modalTitle, { color: textColor }]}> <FontAwesome name="bars" size={24} color={textColor}/> {' Recording Settings'} </Text> <Pressable onPress={onClose} style={styles.closeButton}> <FontAwesome name="times" size={24} color={textColor}/> </Pressable> </View> <View style={[styles.separator, { backgroundColor: borderColor }]}/> {/* Modal Body */} <View style={styles.modalBody}> <ScrollView style={styles.scrollView}> <View style={styles.listGroup}> <StandardPanelComponent parameters={{ ...parameters, isDarkMode }}/> <AdvancedPanelComponent parameters={{ ...parameters, isDarkMode }}/> </View> </ScrollView> </View> <View style={[styles.separator, { backgroundColor: borderColor }]}/> {/* Action Buttons */} {recordingDisplayAdvice && (<View style={styles.adviceBox}> <Text style={[styles.adviceText, { color: textColor }]}>{recordingDisplayAdvice}</Text> </View>)} <View style={styles.buttonRow}> <Pressable style={[styles.button, styles.confirmButton]} onPress={() => confirmRecording({ parameters })}> <Text style={styles.buttonText}>Confirm</Text> </Pressable> {!recordPaused && (<Pressable style={[styles.button, styles.startButton]} onPress={() => startRecording({ parameters })}> <Text style={styles.buttonText}> Start <FontAwesome name="play" size={16} color="#ffffff"/> </Text> </Pressable>)} </View> </>); const content = renderContent ? renderContent({ defaultContent, dimensions }) : defaultContent; const defaultContainer = (<Modal transparent animationType="slide" visible={isRecordingModalVisible} onRequestClose={onClose}> <View style={[styles.modalContainer, getModalPosition({ position })]}> <View style={[styles.modalContent, { backgroundColor, width: modalWidth }, style]}> {content} </View> </View> </Modal>); return renderContainer ? renderContainer({ defaultContainer, dimensions }) : defaultContainer; }; export default RecordingModal; /** * Stylesheet for the RecordingModal component. */ const styles = StyleSheet.create({ modalContainer: { flex: 1, ...StyleSheet.absoluteFillObject, justifyContent: 'flex-end', alignItems: 'flex-end', zIndex: 9, elevation: 9, }, modalContent: { height: '75%', backgroundColor: '#ffffff', // Default background color borderRadius: 10, padding: 15, maxHeight: '80%', maxWidth: '75%', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 4, elevation: 9, zIndex: 9, }, scrollView: { flex: 1, maxHeight: '100%', maxWidth: '100%', }, modalHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 15, }, modalTitle: { fontSize: 16, fontWeight: 'bold', color: 'black', flexDirection: 'row', alignItems: 'center', }, closeButton: { padding: 5, }, separator: { height: 1, backgroundColor: '#000000', marginVertical: 10, }, modalBody: { flex: 1, }, buttonRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 20, }, adviceBox: { marginTop: 12, paddingHorizontal: 14, paddingVertical: 12, borderRadius: 10, borderWidth: 1, borderColor: 'rgba(245, 158, 11, 0.35)', backgroundColor: 'rgba(245, 158, 11, 0.18)', }, adviceText: { color: 'black', fontSize: 13, fontWeight: '600', lineHeight: 19, }, button: { flex: 1, paddingVertical: 10, borderRadius: 5, justifyContent: 'center', alignItems: 'center', marginHorizontal: 5, }, confirmButton: { backgroundColor: '#4CAF50', }, startButton: { backgroundColor: '#f44336', }, buttonText: { color: 'black', fontSize: 14, }, listGroup: { margin: 0, padding: 0, }, }); //# sourceMappingURL=RecordingModal.js.map