feat(lobby/native) LobbyScreen and LobbyChatScreen

This commit is contained in:
Calin Chitu 2022-04-26 13:15:31 +03:00 committed by Calinteodor
parent 037b9202a6
commit 3e004811e0
15 changed files with 485 additions and 225 deletions

View File

@ -37,6 +37,11 @@ type Props = {
*/
hasTabNavigator?: boolean,
/**
* Insets for the SafeAreaView.
*/
safeAreaInsets?: Array,
/**
* Additional style to be appended to the KeyboardAvoidingView containing the content of the modal.
*/
@ -49,6 +54,7 @@ const JitsiScreen = ({
footerComponent,
hasTabNavigator = false,
hasBottomTextInput = false,
safeAreaInsets = [ 'bottom', 'left', 'right' ],
style
}: Props) => (
<View
@ -59,11 +65,7 @@ const JitsiScreen = ({
hasTabNavigator = { hasTabNavigator }
style = { style }>
<SafeAreaView
edges = { [
'bottom',
'left',
'right'
] }
edges = { safeAreaInsets }
style = { styles.safeArea }>
{ children }
</SafeAreaView>

View File

@ -183,7 +183,7 @@ class Conference extends AbstractConference<Props, State> {
const { _showLobby } = this.props;
if (!prevProps._showLobby && _showLobby) {
navigate(screen.lobby);
navigate(screen.lobby.root);
}
if (prevProps._showLobby && !_showLobby) {

View File

@ -0,0 +1,42 @@
import React from 'react';
import { translate } from '../../../base/i18n';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import { connect } from '../../../base/redux';
import ChatInputBar from '../../../chat/components/native/ChatInputBar';
import MessageContainer from '../../../chat/components/native/MessageContainer';
import AbstractLobbyScreen, {
Props as AbstractProps,
_mapStateToProps as abstractMapStateToProps
} from '../AbstractLobbyScreen';
import styles from './styles';
/**
* Implements a chat screen that appears when communication is started
* between the moderator and the participant being in the lobby.
*/
class LobbyChatScreen extends
AbstractLobbyScreen<AbstractProps> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { _lobbyChatMessages } = this.props;
return (
<JitsiScreen style = { styles.lobbyChatWrapper }>
<MessageContainer messages = { _lobbyChatMessages } />
<ChatInputBar onSend = { this._onSendMessage } />
</JitsiScreen>
);
}
_onSendMessage: () => void;
}
export default translate(connect(abstractMapStateToProps)(LobbyChatScreen));

View File

@ -2,50 +2,50 @@
import React from 'react';
import { Text, View, TouchableOpacity, TextInput } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Avatar } from '../../../base/avatar';
import { translate } from '../../../base/i18n';
import { Icon, IconClose, IconEdit } from '../../../base/icons';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import { LoadingIndicator } from '../../../base/react';
import { connect } from '../../../base/redux';
import ChatInputBar from '../../../chat/components/native/ChatInputBar';
import MessageContainer from '../../../chat/components/native/MessageContainer';
import AbstractLobbyScreen, { _mapStateToProps } from '../AbstractLobbyScreen';
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui';
import BaseTheme from '../../../base/ui/components/BaseTheme';
import InviteButton
from '../../../invite/components/add-people-dialog/native/InviteButton';
import { LargeVideo } from '../../../large-video/components';
import { navigate }
from '../../../mobile/navigation/components/lobby/LobbyNavigationContainerRef';
import { screen } from '../../../mobile/navigation/routes';
import AudioMuteButton from '../../../toolbox/components/AudioMuteButton';
import VideoMuteButton from '../../../toolbox/components/VideoMuteButton';
import AbstractLobbyScreen, {
Props as AbstractProps,
_mapStateToProps as abstractMapStateToProps } from '../AbstractLobbyScreen';
import styles from './styles';
type Props = AbstractProps & {
/**
* The current aspect ratio of the screen.
*/
_aspectRatio: Symbol
}
/**
* Implements a waiting screen that represents the participant being in the lobby.
*/
class LobbyScreen extends AbstractLobbyScreen {
class LobbyScreen extends AbstractLobbyScreen<Props> {
/**
* Implements {@code PureComponent#render}.
*
* @inheritdoc
*/
render() {
const { _meetingName, t } = this.props;
return (
<JitsiScreen
style = { this.props._isLobbyChatActive && this.state.isChatOpen
? styles.lobbyChatWrapper
: styles.contentWrapper }>
{this.props._isLobbyChatActive && this.state.isChatOpen
? this._renderLobbyChat()
: <SafeAreaView>
<Text style = { styles.dialogTitle }>
{ t(this._getScreenTitleKey(), { moderator: this.props._lobbyMessageRecipient }) }
</Text>
<Text style = { styles.secondaryText }>
{ _meetingName }
</Text>
{ this._renderContent()}
</SafeAreaView> }
</JitsiScreen>
<>
{ this._renderLobby() }
</>
);
}
@ -69,35 +69,58 @@ class LobbyScreen extends AbstractLobbyScreen {
_onSwitchToPasswordMode: () => void;
_onSendMessage: () => void;
_onToggleChat: () => void;
_renderContent: () => React$Element<*>;
_renderToolbarButtons: () => React$Element<*>;
_renderLobby: () => React$Element<*>;
_onNavigateToLobbyChat: () => void;
/**
* Renders the lobby chat.
* Navigates to the lobby chat screen.
*
* @private
* @returns {void}
*/
_onNavigateToLobbyChat() {
navigate(screen.lobby.chat);
}
/**
* Renders the lobby.
*
* @inheritdoc
*/
_renderLobbyChat() {
const { t } = this.props;
_renderLobby() {
const { _aspectRatio } = this.props;
let contentStyles;
let largeVideoContainerStyles;
let contentContainerStyles;
if (_aspectRatio === ASPECT_RATIO_NARROW) {
largeVideoContainerStyles = styles.largeVideoContainer;
contentContainerStyles = styles.contentContainer;
} else {
contentStyles = styles.contentWide;
largeVideoContainerStyles = styles.largeVideoContainerWide;
contentContainerStyles = styles.contentContainerWide;
}
return (
<>
<View style = { styles.lobbyChatHeader }>
<Text style = { styles.lobbyChatTitle }>
{ t(this._getScreenTitleKey(), { moderator: this.props._lobbyMessageRecipient }) }
</Text>
<TouchableOpacity onPress = { this._onToggleChat }>
<Icon
src = { IconClose }
style = { styles.lobbyChatCloseButton } />
</TouchableOpacity>
<JitsiScreen
safeAreaInsets = { [ 'right' ] }
style = { styles.contentWrapper }>
<View style = { contentStyles }>
<View style = { largeVideoContainerStyles }>
<LargeVideo />
</View>
<View style = { contentContainerStyles }>
{ this._renderContent() }
{ this._renderToolbarButtons() }
</View>
</View>
<MessageContainer messages = { this.props._lobbyChatMessages } />
<ChatInputBar onSend = { this._onSendMessage } />
</>
</JitsiScreen>
);
}
@ -108,15 +131,15 @@ class LobbyScreen extends AbstractLobbyScreen {
*/
_renderJoining() {
return (
<>
<View style = { styles.formWrapper }>
<LoadingIndicator
color = 'black'
color = { BaseTheme.palette.icon01 }
style = { styles.loadingIndicator } />
<Text style = { styles.joiningMessage }>
{ this.props.t('lobby.joiningMessage') }
</Text>
{ this._renderStandardButtons() }
</>
</View>
);
}
@ -127,7 +150,7 @@ class LobbyScreen extends AbstractLobbyScreen {
*/
_renderParticipantForm() {
const { t } = this.props;
const { displayName, email } = this.state;
const { displayName } = this.state;
return (
<View style = { styles.formWrapper }>
@ -138,13 +161,6 @@ class LobbyScreen extends AbstractLobbyScreen {
onChangeText = { this._onChangeDisplayName }
style = { styles.field }
value = { displayName } />
<Text style = { styles.fieldLabel }>
{ t('lobby.emailField') }
</Text>
<TextInput
onChangeText = { this._onChangeEmail }
style = { styles.field }
value = { email } />
</View>
);
}
@ -155,28 +171,7 @@ class LobbyScreen extends AbstractLobbyScreen {
* @inheritdoc
*/
_renderParticipantInfo() {
const { displayName, email } = this.state;
return (
<View style = { styles.participantBox }>
<TouchableOpacity
onPress = { this._onEnableEdit }
style = { styles.editButton }>
<Icon
src = { IconEdit }
style = { styles.editIcon } />
</TouchableOpacity>
<Avatar
participantId = { this.props._participantId }
size = { 64 } />
<Text style = { styles.displayNameText }>
{ displayName }
</Text>
{ Boolean(email) && <Text style = { styles.secondaryText }>
{ email }
</Text> }
</View>
);
return this._renderParticipantForm();
}
/**
@ -215,7 +210,17 @@ class LobbyScreen extends AbstractLobbyScreen {
const { t } = this.props;
return (
<>
<View style = { styles.passwordJoinButtonsWrapper }>
<TouchableOpacity
onPress = { this._onSwitchToKnockMode }
style = { [
styles.button,
styles.primaryButton
] }>
<Text style = { styles.primaryButtonText }>
{ t('lobby.backToKnockModeButton') }
</Text>
</TouchableOpacity>
<TouchableOpacity
disabled = { !this.state.password }
onPress = { this._onJoinWithPassword }
@ -227,17 +232,34 @@ class LobbyScreen extends AbstractLobbyScreen {
{ t('lobby.passwordJoinButton') }
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress = { this._onSwitchToKnockMode }
style = { [
styles.button,
styles.secondaryButton
] }>
<Text>
{ t('lobby.backToKnockModeButton') }
</Text>
</TouchableOpacity>
</>
</View>
);
}
/**
* Renders the toolbar buttons menu.
*
* @inheritdoc
*/
_renderToolbarButtons() {
const { _aspectRatio } = this.props;
let toolboxContainerStyles;
if (_aspectRatio === ASPECT_RATIO_NARROW) {
toolboxContainerStyles = styles.toolboxContainer;
} else {
toolboxContainerStyles = styles.toolboxContainerWide;
}
return (
<View style = { toolboxContainerStyles }>
<AudioMuteButton
styles = { styles.buttonStylesBorderless } />
<VideoMuteButton
styles = { styles.buttonStylesBorderless } />
<InviteButton
styles = { styles.buttonStylesBorderless } />
</View>
);
}
@ -248,50 +270,72 @@ class LobbyScreen extends AbstractLobbyScreen {
*/
_renderStandardButtons() {
const { _knocking, _renderPassword, _isLobbyChatActive, t } = this.props;
const { displayName } = this.state;
const askToJoinButtonStyles
= displayName ? styles.primaryButton : styles.primaryButtonDisabled;
return (
<>
{ _knocking || <TouchableOpacity
disabled = { !this.state.displayName }
onPress = { this._onAskToJoin }
<View style = { styles.standardButtonWrapper }>
{ _knocking && _isLobbyChatActive && <TouchableOpacity
onPress = { this._onNavigateToLobbyChat }
style = { [
styles.button,
styles.primaryButton
] }>
<Text style = { styles.primaryButtonText }>
{ t('lobby.knockButton') }
</Text>
</TouchableOpacity> }
{ _knocking && _isLobbyChatActive && <TouchableOpacity
onPress = { this._onToggleChat }
style = { [
styles.button,
styles.secondaryButton
] }>
<Text>
{ t('toolbar.openChat') }
</Text>
</TouchableOpacity>}
{ _knocking || <TouchableOpacity
disabled = { !displayName }
onPress = { this._onAskToJoin }
style = { [
styles.button,
askToJoinButtonStyles
] }>
<Text style = { styles.primaryButtonText }>
{ t('lobby.knockButton') }
</Text>
</TouchableOpacity> }
{ _renderPassword && <TouchableOpacity
onPress = { this._onSwitchToPasswordMode }
style = { [
styles.button,
styles.secondaryButton
styles.primaryButton
] }>
<Text>
<Text style = { styles.primaryButtonText }>
{ t('lobby.enterPasswordButton') }
</Text>
</TouchableOpacity> }
<TouchableOpacity
onPress = { this._onCancel }
style = { styles.cancelButton }>
<Text>
style = { [
styles.button,
styles.cancelButton
] }>
<Text style = { styles.cancelButtonText }>
{ t('dialog.Cancel') }
</Text>
</TouchableOpacity>
</>
</View>
);
}
}
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @param {Props} ownProps - The own props of the component.
* @returns {{
* _aspectRatio: Symbol
* }}
*/
function _mapStateToProps(state: Object, ownProps: Props) {
return {
...abstractMapStateToProps(state, ownProps),
_aspectRatio: state['features/base/responsive-ui'].aspectRatio
};
}
export default translate(connect(_mapStateToProps)(LobbyScreen));

View File

@ -2,3 +2,4 @@
export { default as KnockingParticipantList } from './KnockingParticipantList';
export { default as LobbyScreen } from './LobbyScreen';
export { default as LobbyChatScreen } from './LobbyChatScreen';

View File

@ -1,6 +1,6 @@
// @flow
import BaseTheme from '../../../base/ui/components/BaseTheme';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
const SECONDARY_COLOR = BaseTheme.palette.border04;
@ -8,8 +8,24 @@ export default {
button: {
alignItems: 'center',
borderRadius: 4,
marginVertical: BaseTheme.spacing[1],
paddingVertical: BaseTheme.spacing[2]
padding: BaseTheme.spacing[2],
width: '100%'
},
buttonStylesBorderless: {
iconStyle: {
backgroundColor: BaseTheme.palette.action02Active,
color: BaseTheme.palette.icon01,
fontSize: 24
},
style: {
backgroundColor: BaseTheme.palette.action02Active,
flexDirection: 'row',
justifyContent: 'center',
marginHorizontal: BaseTheme.spacing[3],
height: 24,
width: 24
}
},
lobbyChatWrapper: {
@ -26,29 +42,66 @@ export default {
},
lobbyChatTitle: {
color: '#fff',
color: BaseTheme.palette.text01,
fontSize: 20,
fontWeight: 'bold',
flexShrink: 1
},
lobbyChatCloseButton: {
fontSize: 20,
marginLeft: 20,
color: '#fff'
fontSize: 24,
marginLeft: BaseTheme.spacing[3],
marginTop: BaseTheme.spacing[1],
color: BaseTheme.palette.icon01
},
contentWrapper: {
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
justifyItems: 'center',
height: '100%'
backgroundColor: BaseTheme.palette.ui02,
flex: 1
},
closeIcon: {
color: 'red',
fontSize: 20
contentWide: {
backgroundColor: BaseTheme.palette.ui02,
flex: 1,
flexDirection: 'row'
},
largeVideoContainer: {
alignItems: 'center',
display: 'flex',
justifyContent: 'center',
minHeight: '50%'
},
largeVideoContainerWide: {
height: '100%',
width: '50%'
},
contentContainer: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
contentContainerWide: {
justifyContent: 'center',
marginHorizontal: BaseTheme.spacing[2],
width: '50%'
},
toolboxContainer: {
alignItems: 'center',
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
marginTop: BaseTheme.spacing[4]
},
toolboxContainerWide: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: BaseTheme.spacing[4]
},
dialogTitle: {
@ -75,40 +128,55 @@ export default {
},
field: {
backgroundColor: BaseTheme.palette.field02,
borderColor: SECONDARY_COLOR,
borderRadius: 4,
borderWidth: 1,
marginVertical: 8,
padding: 8
borderRadius: BaseTheme.shape.borderRadius,
borderWidth: 2,
marginHorizontal: BaseTheme.spacing[3],
padding: BaseTheme.spacing[2]
},
fieldError: {
color: BaseTheme.palette.warning07,
fontSize: 10
},
fieldRow: {
paddingTop: 16
color: BaseTheme.palette.warning03,
marginLeft: BaseTheme.spacing[3],
fontSize: 16
},
fieldLabel: {
color: BaseTheme.palette.text01,
marginVertical: BaseTheme.spacing[4],
textAlign: 'center'
},
formWrapper: {
alignItems: 'stretch',
alignSelf: 'stretch'
},
standardButtonWrapper: {
alignSelf: 'stretch',
paddingVertical: 16
marginHorizontal: BaseTheme.spacing[3]
},
joiningContainer: {
alignItems: 'center',
display: 'flex',
justifyContent: 'center'
},
joiningMessage: {
color: 'rgba(0, 0, 0, .7)',
paddingBottom: 36,
color: BaseTheme.palette.text01,
marginBottom: BaseTheme.spacing[2],
textAlign: 'center'
},
passwordJoinButtonsWrapper: {
alignItems: 'stretch',
alignSelf: 'stretch',
marginHorizontal: BaseTheme.spacing[3]
},
loadingIndicator: {
marginVertical: 36
marginVertical: BaseTheme.spacing[4]
},
participantBox: {
@ -122,29 +190,33 @@ export default {
},
primaryButton: {
alignSelf: 'stretch',
backgroundColor: 'rgb(3, 118, 218)'
backgroundColor: BaseTheme.palette.action01,
marginTop: BaseTheme.spacing[4]
},
primaryButtonDisabled: {
backgroundColor: BaseTheme.palette.action03Disabled,
marginTop: BaseTheme.spacing[4]
},
primaryButtonText: {
color: 'white'
color: BaseTheme.palette.text01
},
secondaryButton: {
alignSelf: 'stretch',
backgroundColor: 'transparent'
},
secondaryText: {
color: 'rgba(0, 0, 0, .7)',
primaryText: {
color: BaseTheme.palette.text01,
margin: 'auto',
textAlign: 'center'
},
cancelButton: {
alignItems: 'center',
backgroundColor: 'transparent',
marginVertical: 4
backgroundColor: BaseTheme.palette.action02Disabled,
marginTop: BaseTheme.spacing[4]
},
cancelButtonText: {
color: BaseTheme.palette.text01
},
// KnockingParticipantList

View File

@ -1,5 +1,3 @@
// @flow
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';

View File

@ -1,8 +1,5 @@
// @flow
import React from 'react';
// $FlowExpectedError
export const conferenceNavigationRef = React.createRef();
/**
@ -13,7 +10,6 @@ export const conferenceNavigationRef = React.createRef();
* @returns {Function}
*/
export function navigate(name: string, params: Object) {
// $FlowExpectedError
return conferenceNavigationRef.current?.navigate(name, params);
}
@ -23,7 +19,6 @@ export function navigate(name: string, params: Object) {
* @returns {Function}
*/
export function goBack() {
// $FlowExpectedError
return conferenceNavigationRef.current?.goBack();
}
@ -34,7 +29,6 @@ export function goBack() {
* @returns {Function}
*/
export function setParams(params: Object) {
// $FlowExpectedError
return conferenceNavigationRef.current?.setParams(params);
}

View File

@ -1,5 +1,3 @@
// @flow
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
@ -13,7 +11,6 @@ import { SharedDocument } from '../../../../../etherpad';
import { GifsMenu } from '../../../../../gifs/components';
import AddPeopleDialog
from '../../../../../invite/components/add-people-dialog/native/AddPeopleDialog';
import LobbyScreen from '../../../../../lobby/components/native/LobbyScreen';
import { ParticipantsPane } from '../../../../../participants-pane/components/native';
import { StartLiveStreamDialog } from '../../../../../recording';
import { StartRecordingDialog }
@ -31,7 +28,6 @@ import {
gifsMenuOptions,
inviteScreenOptions,
liveStreamScreenOptions,
lobbyScreenOptions,
navigationContainerTheme,
participantsScreenOptions,
recordingScreenOptions,
@ -42,6 +38,8 @@ import {
} from '../../../screenOptions';
import ChatAndPollsNavigationContainer
from '../../chat/components/ChatAndPollsNavigationContainer';
import LobbyNavigationContainer
from '../../lobby/components/LobbyNavigationContainer';
import {
conferenceNavigationRef
} from '../ConferenceNavigationContainerRef';
@ -134,9 +132,12 @@ const ConferenceNavigationContainer = () => {
title: t('notify.gifsMenu')
}} />
<ConferenceStack.Screen
component = { LobbyScreen }
name = { screen.lobby }
options = { lobbyScreenOptions } />
component = { LobbyNavigationContainer }
name = { screen.lobby.root }
options = {{
gestureEnabled: false,
headerShown: false
}} />
<ConferenceStack.Screen
component = { AddPeopleDialog }
name = { screen.conference.invite }

View File

@ -0,0 +1,23 @@
import React from 'react';
export const lobbyNavigationContainerRef = React.createRef();
/**
* User defined navigation action included inside the reference to the container.
*
* @param {string} name - Destination name of the route that has been defined somewhere.
* @param {Object} params - Params to pass to the destination route.
* @returns {Function}
*/
export function navigate(name: string, params: Object) {
return lobbyNavigationContainerRef.current?.navigate(name, params);
}
/**
* User defined navigation action included inside the reference to the container.
*
* @returns {Function}
*/
export function goBack() {
return lobbyNavigationContainerRef.current?.goBack();
}

View File

@ -0,0 +1,47 @@
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import { useSelector } from 'react-redux';
import { LobbyChatScreen, LobbyScreen } from '../../../../../lobby';
import { screen } from '../../../routes';
import {
lobbyChatScreenOptions,
lobbyScreenOptions, navigationContainerTheme
} from '../../../screenOptions';
import { lobbyNavigationContainerRef } from '../LobbyNavigationContainerRef';
const LobbyStack = createStackNavigator();
const LobbyNavigationContainer = () => {
const { isLobbyChatActive }
= useSelector(state => state['features/chat']);
return (
<NavigationContainer
independent = { true }
ref = { lobbyNavigationContainerRef }
theme = { navigationContainerTheme }>
<LobbyStack.Navigator
screenOptions = {{
presentation: 'modal'
}}>
<LobbyStack.Screen
component = { LobbyScreen }
name = { screen.lobby.main }
options = { lobbyScreenOptions } />
{
isLobbyChatActive
&& <LobbyStack.Screen
component = { LobbyChatScreen }
name = { screen.lobby.chat }
options = { lobbyChatScreenOptions } />
}
</LobbyStack.Navigator>
</NavigationContainer>
);
};
export default LobbyNavigationContainer;

View File

@ -0,0 +1,31 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Platform } from 'react-native';
import { IconClose } from '../../base/icons';
import HeaderNavigationButton from './components/HeaderNavigationButton';
/**
* Close icon/text button based on platform.
*
* @param {Function} goBack - Goes back to the previous screen function.
* @returns {React.Component}
*/
export function screenHeaderCloseButton(goBack: Function) {
const { t } = useTranslation();
if (Platform.OS === 'ios') {
return (
<HeaderNavigationButton
label = { t('dialog.close') }
onPress = { goBack } />
);
}
return (
<HeaderNavigationButton
onPress = { goBack }
src = { IconClose } />
);
}

View File

@ -1,8 +1,7 @@
// @flow
import debounce from 'lodash/debounce';
import { SET_ROOM } from '../../base/conference/actionTypes';
import { CONFERENCE_FAILED, SET_ROOM } from '../../base/conference/actionTypes';
import { JitsiConferenceErrors } from '../../base/lib-jitsi-meet';
import { MiddlewareRegistry } from '../../base/redux';
import { readyToClose } from '../external-api/actions';
@ -16,6 +15,9 @@ MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case SET_ROOM:
return _setRoom(store, next, action);
case CONFERENCE_FAILED:
return _conferenceFailed(store, next, action);
}
return next(action);
@ -61,3 +63,31 @@ function _setRoom({ dispatch, getState }, next, action) {
return result;
}
/**
* Function to handle the conference failed event and navigate the user to the lobby screen
* based on the failure reason.
*
* @param {Object} store - The Redux store.
* @param {Function} next - The Redux next function.
* @param {Object} action - The Redux action.
* @returns {Object}
*/
function _conferenceFailed({ dispatch, getState }, next, action) {
const state = getState();
const isWelcomePageEnabled = isWelcomePageAppEnabled(state);
const { error } = action;
// We need to cover the case where knocking participant
// is rejected from entering the conference
if (error.name === JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED) {
if (isWelcomePageEnabled) {
navigateRoot(screen.root);
} else {
// For JitsiSDK, WelcomePage is not available
_sendReadyToClose(dispatch);
}
}
return next(action);
}

View File

@ -34,5 +34,9 @@ export const screen = {
invite: 'Invite',
sharedDocument: 'Shared document'
},
lobby: 'Lobby'
lobby: {
root: 'Lobby root',
main: 'Lobby',
chat: 'Lobby chat'
}
};

View File

@ -1,13 +1,9 @@
// @flow
import { TransitionPresets } from '@react-navigation/stack';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Platform } from 'react-native';
import {
Icon,
IconClose,
IconHelp,
IconHome,
IconInfo,
@ -15,8 +11,9 @@ import {
} from '../../base/icons';
import BaseTheme from '../../base/ui/components/BaseTheme.native';
import HeaderNavigationButton from './components/HeaderNavigationButton';
import { goBack } from './components/conference/ConferenceNavigationContainerRef';
import { goBack as goBackToLobbyScreen } from './components/lobby/LobbyNavigationContainerRef';
import { screenHeaderCloseButton } from './functions';
/**
@ -167,16 +164,12 @@ export const helpScreenOptions = {
/**
* Screen options for conference.
*/
export const conferenceScreenOptions = {
...fullScreenOptions
};
export const conferenceScreenOptions = fullScreenOptions;
/**
* Screen options for lobby modal.
*/
export const lobbyScreenOptions = {
...fullScreenOptions
};
export const lobbyScreenOptions = fullScreenOptions;
/**
* Tab bar options for chat screen.
@ -198,23 +191,7 @@ export const chatTabBarOptions = {
export const presentationScreenOptions = {
...conferenceModalPresentation,
headerBackTitleVisible: false,
headerLeft: () => {
const { t } = useTranslation();
if (Platform.OS === 'ios') {
return (
<HeaderNavigationButton
label = { t('dialog.close') }
onPress = { goBack } />
);
}
return (
<HeaderNavigationButton
onPress = { goBack }
src = { IconClose } />
);
},
headerLeft: () => screenHeaderCloseButton(goBack),
headerStatusBarHeight: 0,
headerStyle: {
backgroundColor: BaseTheme.palette.screen01Header
@ -227,50 +204,44 @@ export const presentationScreenOptions = {
/**
* Screen options for chat.
*/
export const chatScreenOptions = {
...presentationScreenOptions
};
export const chatScreenOptions = presentationScreenOptions;
/**
* Screen options for invite modal.
*/
export const inviteScreenOptions = {
...presentationScreenOptions
};
export const inviteScreenOptions = presentationScreenOptions;
/**
* Screen options for participants modal.
*/
export const participantsScreenOptions = {
...presentationScreenOptions
};
export const participantsScreenOptions = presentationScreenOptions;
/**
* Screen options for speaker stats modal.
*/
export const speakerStatsScreenOptions = {
...presentationScreenOptions
};
export const speakerStatsScreenOptions = presentationScreenOptions;
/**
* Screen options for security options modal.
*/
export const securityScreenOptions = {
...presentationScreenOptions
};
export const securityScreenOptions = presentationScreenOptions;
/**
* Screen options for recording modal.
*/
export const recordingScreenOptions = {
...presentationScreenOptions
};
export const recordingScreenOptions = presentationScreenOptions;
/**
* Screen options for live stream modal.
*/
export const liveStreamScreenOptions = {
...presentationScreenOptions
export const liveStreamScreenOptions = presentationScreenOptions;
/**
* Screen options for lobby chat modal.
*/
export const lobbyChatScreenOptions = {
...presentationScreenOptions,
headerLeft: () => screenHeaderCloseButton(goBackToLobbyScreen)
};
/**