import { Route } from '@react-navigation/native'; import React, { PureComponent } from 'react'; import { WithTranslation } from 'react-i18next'; import { Platform, View, ViewStyle } from 'react-native'; import { WebView } from 'react-native-webview'; import { connect } from 'react-redux'; import { IReduxState, IStore } from '../../../app/types'; import { getCurrentConference } from '../../../base/conference/functions'; import { IJitsiConference } from '../../../base/conference/reducer'; import { openDialog } from '../../../base/dialog/actions'; import { translate } from '../../../base/i18n/functions'; import { IconCloseLarge } from '../../../base/icons/svg'; import JitsiScreen from '../../../base/modal/components/JitsiScreen'; import LoadingIndicator from '../../../base/react/components/native/LoadingIndicator'; import { safeDecodeURIComponent } from '../../../base/util/uri'; import HeaderNavigationButton from '../../../mobile/navigation/components/HeaderNavigationButton'; import { goBack } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef'; import { setupWhiteboard } from '../../actions.native'; import { WHITEBOARD_ID } from '../../constants'; import { getWhiteboardInfoForURIString } from '../../functions'; import logger from '../../logger'; import WhiteboardErrorDialog from './WhiteboardErrorDialog'; import styles, { INDICATOR_COLOR } from './styles'; interface IProps extends WithTranslation { /** * The current Jitsi conference. */ conference?: IJitsiConference; /** * Redux store dispatch method. */ dispatch: IStore['dispatch']; /** * Window location href. */ locationHref: string; /** * Default prop for navigating between screen components(React Navigation). */ navigation: any; /** * Default prop for navigating between screen components(React Navigation). */ route: Route<'', { collabDetails: { roomId: string; roomKey: string; }; collabServerUrl: string; localParticipantName: string; }>; } /** * Implements a React native component that displays the whiteboard page for a specific room. */ class Whiteboard extends PureComponent { /** * Initializes a new instance. * * @inheritdoc */ constructor(props: IProps) { super(props); this._onError = this._onError.bind(this); this._onNavigate = this._onNavigate.bind(this); this._onMessage = this._onMessage.bind(this); this._renderLoading = this._renderLoading.bind(this); } /** * Implements React's {@link Component#componentDidMount()}. Invoked * immediately after mounting occurs. * * @inheritdoc * @returns {void} */ override componentDidMount() { const { navigation, t } = this.props; const headerLeft = () => { if (Platform.OS === 'ios') { return ( ); } return ( ); }; navigation.setOptions({ headerLeft }); } /** * Implements React's {@link Component#render()}. * * @inheritdoc */ override render() { const { locationHref, route } = this.props; const collabServerUrl = safeDecodeURIComponent(route.params?.collabServerUrl); const localParticipantName = safeDecodeURIComponent(route.params?.localParticipantName); const collabDetails = route.params?.collabDetails; const uri = getWhiteboardInfoForURIString( locationHref, collabServerUrl, collabDetails, localParticipantName ) ?? ''; return ( ); } /** * Callback to handle the error if the page fails to load. * * @returns {void} */ _onError() { this.props.dispatch(openDialog(WhiteboardErrorDialog)); } /** * Callback to intercept navigation inside the webview and make the native app handle the whiteboard requests. * * NOTE: We don't navigate to anywhere else from that view. * * @param {any} request - The request object. * @returns {boolean} */ _onNavigate(request: { url: string; }) { const { url } = request; const { locationHref, route } = this.props; const collabServerUrl = route.params?.collabServerUrl; const collabDetails = route.params?.collabDetails; const localParticipantName = route.params?.localParticipantName; return url === getWhiteboardInfoForURIString( locationHref, collabServerUrl, collabDetails, localParticipantName ); } /** * Callback to handle the message events. * * @param {any} event - The event. * @returns {void} */ _onMessage(event: any) { const { conference, dispatch } = this.props; const collabData = JSON.parse(event.nativeEvent.data); if (!collabData) { logger.error('Message payload is missing whiteboard collaboration data'); return; } const { collabDetails, collabServerUrl } = collabData; if (collabDetails?.roomId && collabDetails?.roomKey && collabServerUrl) { dispatch(setupWhiteboard({ collabDetails, collabServerUrl })); // Broadcast the collab details. conference?.getMetadataHandler().setMetadata(WHITEBOARD_ID, { collabServerUrl, collabDetails }); } } /** * Renders the loading indicator. * * @returns {React$Component} */ _renderLoading() { return ( ); } } /** * Maps (parts of) the redux state to the associated * {@code WaitForOwnerDialog}'s props. * * @param {Object} state - The redux state. * @private * @returns {IProps} */ function mapStateToProps(state: IReduxState) { const { locationURL } = state['features/base/connection']; const { href = '' } = locationURL ?? {}; return { conference: getCurrentConference(state), locationHref: href }; } export default translate(connect(mapStateToProps)(Whiteboard));