diff --git a/react/features/base/modal/components/JitsiKeyboardAvoidingView.js b/react/features/base/modal/components/JitsiKeyboardAvoidingView.js
index 740987642d..9d996d414b 100644
--- a/react/features/base/modal/components/JitsiKeyboardAvoidingView.js
+++ b/react/features/base/modal/components/JitsiKeyboardAvoidingView.js
@@ -1,8 +1,9 @@
// @flow
import { getDefaultHeaderHeight } from '@react-navigation/elements';
-import React, { useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
import {
+ Keyboard,
KeyboardAvoidingView,
Platform,
StatusBar
@@ -78,6 +79,10 @@ const JitsiKeyboardAvoidingView = (
const androidVerticalOffset = hasBottomTextInput
? deviceHeight + StatusBar.currentHeight : deviceHeight;
+ // Tells the view what to do with taps
+ const shouldSetResponse = useCallback(() => true);
+ const onRelease = useCallback(() => Keyboard.dismiss());
+
return (
{ children }
diff --git a/react/features/base/modal/components/JitsiScreen.js b/react/features/base/modal/components/JitsiScreen.js
index ff868fcab8..2678aa8208 100644
--- a/react/features/base/modal/components/JitsiScreen.js
+++ b/react/features/base/modal/components/JitsiScreen.js
@@ -74,9 +74,9 @@ const JitsiScreen = ({
- { children }
+ {children}
- { footerComponent && footerComponent() }
+ {footerComponent && footerComponent()}
);
diff --git a/react/features/conference/components/native/Conference.js b/react/features/conference/components/native/Conference.js
index 18d5bd88f2..99ed075cf7 100644
--- a/react/features/conference/components/native/Conference.js
+++ b/react/features/conference/components/native/Conference.js
@@ -22,12 +22,13 @@ import {
} from '../../../filmstrip';
import { CalleeInfoContainer } from '../../../invite';
import { LargeVideo } from '../../../large-video';
+import { startKnocking } from '../../../lobby/actions.any';
import { KnockingParticipantList } from '../../../lobby/components/native';
import { getIsLobbyVisible } from '../../../lobby/functions';
import { navigate }
from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
+import { shouldEnableAutoKnock } from '../../../mobile/navigation/functions';
import { screen } from '../../../mobile/navigation/routes';
-import { setPictureInPictureEnabled } from '../../../mobile/picture-in-picture';
import { Captions } from '../../../subtitles';
import { setToolboxVisible } from '../../../toolbox/actions';
import { Toolbox } from '../../../toolbox/components/native';
@@ -100,6 +101,11 @@ type Props = AbstractProps & {
*/
_largeVideoParticipantId: string,
+ /**
+ * Local participant's display name.
+ */
+ _localParticipantDisplayName: string,
+
/**
* Whether Picture-in-Picture is enabled.
*/
@@ -116,6 +122,11 @@ type Props = AbstractProps & {
*/
_toolboxVisible: boolean,
+ /**
+ * Indicates if we should auto-knock.
+ */
+ _shouldEnableAutoKnock: boolean,
+
/**
* Indicates whether the lobby screen should be visible.
*/
@@ -180,7 +191,6 @@ class Conference extends AbstractConference {
*/
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this._onHardwareBackPress);
- setPictureInPictureEnabled(true);
}
/**
@@ -189,10 +199,18 @@ class Conference extends AbstractConference {
* @inheritdoc
*/
componentDidUpdate(prevProps) {
- const { _showLobby } = this.props;
+ const {
+ _shouldEnableAutoKnock,
+ _showLobby,
+ dispatch
+ } = this.props;
if (!prevProps._showLobby && _showLobby) {
navigate(screen.lobby.root);
+
+ if (_shouldEnableAutoKnock) {
+ dispatch(startKnocking());
+ }
}
if (prevProps._showLobby && !_showLobby) {
@@ -213,7 +231,6 @@ class Conference extends AbstractConference {
BackHandler.removeEventListener('hardwareBackPress', this._onHardwareBackPress);
clearTimeout(this._expandedLabelTimeout.current);
- setPictureInPictureEnabled(false);
}
/**
@@ -535,6 +552,7 @@ function _mapStateToProps(state) {
_largeVideoParticipantId: state['features/large-video'].participantId,
_pictureInPictureEnabled: getFeatureFlag(state, PIP_ENABLED),
_reducedUI: reducedUI,
+ _shouldEnableAutoKnock: shouldEnableAutoKnock(state),
_showLobby: getIsLobbyVisible(state),
_toolboxVisible: isToolboxVisible(state)
};
diff --git a/react/features/lobby/components/native/LobbyScreen.js b/react/features/lobby/components/native/LobbyScreen.js
index 5c37371945..1afaf32dd2 100644
--- a/react/features/lobby/components/native/LobbyScreen.js
+++ b/react/features/lobby/components/native/LobbyScreen.js
@@ -58,6 +58,7 @@ class LobbyScreen extends AbstractLobbyScreen {
return (
diff --git a/react/features/lobby/components/native/styles.js b/react/features/lobby/components/native/styles.js
index ba90f9ddf9..11563b2e08 100644
--- a/react/features/lobby/components/native/styles.js
+++ b/react/features/lobby/components/native/styles.js
@@ -24,7 +24,8 @@ export default {
marginHorizontal: BaseTheme.spacing[3],
height: 24,
width: 24
- }
+ },
+ underlayColor: 'transparent'
},
lobbyChatWrapper: {
@@ -75,18 +76,20 @@ export default {
},
contentContainer: {
- alignItems: 'center',
+ alignSelf: 'center',
display: 'flex',
justifyContent: 'center',
- minHeight: '50%'
+ minHeight: '50%',
+ paddingHorizontal: BaseTheme.spacing[3],
+ width: 400
},
contentContainerWide: {
+ alignItems: 'center',
height: '100%',
justifyContent: 'center',
left: '50%',
- marginHorizontal: BaseTheme.spacing[6],
- marginVertical: BaseTheme.spacing[3],
+ paddingHorizontal: BaseTheme.spacing[3],
position: 'absolute',
width: '50%'
},
@@ -132,7 +135,8 @@ export default {
borderRadius: BaseTheme.shape.borderRadius,
borderWidth: 2,
height: BaseTheme.spacing[7],
- marginHorizontal: BaseTheme.spacing[3],
+ marginTop: BaseTheme.spacing[3],
+ marginHorizontal: 12,
padding: BaseTheme.spacing[2],
textAlign: 'center'
},
@@ -182,12 +186,12 @@ export default {
primaryButton: {
backgroundColor: BaseTheme.palette.action01,
- marginTop: BaseTheme.spacing[4]
+ marginTop: BaseTheme.spacing[3]
},
primaryButtonDisabled: {
backgroundColor: BaseTheme.palette.action03Disabled,
- marginTop: BaseTheme.spacing[4]
+ marginTop: BaseTheme.spacing[3]
},
primaryButtonText: {
diff --git a/react/features/mobile/navigation/functions.js b/react/features/mobile/navigation/functions.js
index df002f4475..d7c21ed45a 100644
--- a/react/features/mobile/navigation/functions.js
+++ b/react/features/mobile/navigation/functions.js
@@ -3,12 +3,14 @@ import { useTranslation } from 'react-i18next';
import { Platform } from 'react-native';
import { useDispatch } from 'react-redux';
+
import { appNavigate } from '../../app/actions';
import {
getFeatureFlag,
PREJOIN_PAGE_ENABLED
} from '../../base/flags';
import { IconClose } from '../../base/icons';
+import { toState } from '../../base/redux';
import { cancelKnocking } from '../../lobby/actions.native';
import HeaderNavigationButton from './components/HeaderNavigationButton';
@@ -48,7 +50,7 @@ export function screenHeaderCloseButton(goBack: Function) {
* {@code true}; otherwise, {@code false}.
*/
export function isPrejoinPageEnabled(stateful: Function | Object) {
- return getFeatureFlag(stateful, PREJOIN_PAGE_ENABLED, true);
+ return getFeatureFlag(toState(stateful), PREJOIN_PAGE_ENABLED, true);
}
/**
@@ -78,3 +80,23 @@ export function lobbyScreenHeaderCloseButton() {
src = { IconClose } />
);
}
+
+/**
+ * Returns true if we should auto-knock in case prejoin is enabled for the room.
+ *
+ * @param {Function|Object} stateful - The redux state or {@link getState}
+ * function.
+ * @returns {boolean}
+ */
+export function shouldEnableAutoKnock(stateful: Function | Object) {
+ const state = toState(stateful);
+ const { displayName } = state['features/base/settings'];
+
+ if (isPrejoinPageEnabled(state)) {
+ if (displayName) {
+ return true;
+ }
+ } else {
+ return false;
+ }
+}
diff --git a/react/features/prejoin/components/Prejoin.native.tsx b/react/features/prejoin/components/Prejoin.native.tsx
index ae4f4c2de6..f331d02eaa 100644
--- a/react/features/prejoin/components/Prejoin.native.tsx
+++ b/react/features/prejoin/components/Prejoin.native.tsx
@@ -1,6 +1,13 @@
import React, { useCallback, useEffect, useLayoutEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { Text, View, TouchableOpacity, TextInput, Platform, BackHandler } from 'react-native';
+import {
+ BackHandler,
+ Text,
+ View,
+ TouchableOpacity,
+ TextInput,
+ Platform
+} from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { appNavigate } from '../../app/actions.native';
@@ -12,6 +19,7 @@ import { getLocalParticipant } from '../../base/participants';
import { getFieldValue } from '../../base/react';
import { ASPECT_RATIO_NARROW } from '../../base/responsive-ui';
import { updateSettings } from '../../base/settings';
+import BaseTheme from '../../base/ui/components/BaseTheme.native';
import { BrandingImageBackground } from '../../dynamic-branding';
import { LargeVideo } from '../../large-video/components';
import HeaderNavigationButton from '../../mobile/navigation/components/HeaderNavigationButton';
@@ -19,6 +27,7 @@ import { navigateRoot } from '../../mobile/navigation/rootNavigationContainerRef
import { screen } from '../../mobile/navigation/routes';
import AudioMuteButton from '../../toolbox/components/AudioMuteButton';
import VideoMuteButton from '../../toolbox/components/VideoMuteButton';
+import { isDisplayNameRequired } from '../functions';
import styles from './styles';
@@ -34,6 +43,7 @@ const Prejoin: ({ navigation }: Props) => JSX.Element = ({ navigation }: Props)
(state: any) => state['features/base/responsive-ui']?.aspectRatio
);
const localParticipant = useSelector(state => getLocalParticipant(state));
+ const isDisplayNameMandatory = useSelector(state => isDisplayNameRequired(state));
const participantName = localParticipant?.name;
const [ displayName, setDisplayName ]
= useState(participantName || '');
@@ -58,26 +68,10 @@ const Prejoin: ({ navigation }: Props) => JSX.Element = ({ navigation }: Props)
const goBack = useCallback(() => {
dispatch(appNavigate(undefined));
+
return true;
}, [ dispatch ]);
- let contentWrapperStyles;
- let contentContainerStyles;
- let largeVideoContainerStyles;
- let toolboxContainerStyles;
-
- if (aspectRatio === ASPECT_RATIO_NARROW) {
- contentWrapperStyles = styles.contentWrapper;
- contentContainerStyles = styles.contentContainer;
- largeVideoContainerStyles = styles.largeVideoContainer;
- toolboxContainerStyles = styles.toolboxContainer;
- } else {
- contentWrapperStyles = styles.contentWrapperWide;
- contentContainerStyles = styles.contentContainerWide;
- largeVideoContainerStyles = styles.largeVideoContainerWide;
- toolboxContainerStyles = styles.toolboxContainerWide;
- }
-
const headerLeft = useCallback(() => {
if (Platform.OS === 'ios') {
return (
@@ -94,10 +88,14 @@ const Prejoin: ({ navigation }: Props) => JSX.Element = ({ navigation }: Props)
);
}, []);
+ const joinButtonDisabled = !displayName && isDisplayNameMandatory;
+ const joinButtonStyles = joinButtonDisabled
+ ? styles.primaryButtonDisabled : styles.primaryButton;
+
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', goBack);
- return () => BackHandler.removeEventListener('hardwareBackPress', goBack)
+ return () => BackHandler.removeEventListener('hardwareBackPress', goBack);
}, [ ]);
@@ -107,9 +105,26 @@ const Prejoin: ({ navigation }: Props) => JSX.Element = ({ navigation }: Props)
});
}, [ navigation ]);
+ let contentWrapperStyles;
+ let contentContainerStyles;
+ let largeVideoContainerStyles;
+ let toolboxContainerStyles;
+
+ if (aspectRatio === ASPECT_RATIO_NARROW) {
+ contentWrapperStyles = styles.contentWrapper;
+ contentContainerStyles = styles.contentContainer;
+ largeVideoContainerStyles = styles.largeVideoContainer;
+ toolboxContainerStyles = styles.toolboxContainer;
+ } else {
+ contentWrapperStyles = styles.contentWrapperWide;
+ contentContainerStyles = styles.contentContainerWide;
+ largeVideoContainerStyles = styles.largeVideoContainerWide;
+ toolboxContainerStyles = styles.toolboxContainerWide;
+ }
+
return (
@@ -120,13 +135,15 @@ const Prejoin: ({ navigation }: Props) => JSX.Element = ({ navigation }: Props)
{ t('prejoin.joinMeeting') }
diff --git a/react/features/prejoin/components/styles.js b/react/features/prejoin/components/styles.js
index 496462b0d0..3e7b28ad8a 100644
--- a/react/features/prejoin/components/styles.js
+++ b/react/features/prejoin/components/styles.js
@@ -23,6 +23,10 @@ export default {
backgroundColor: BaseTheme.palette.action01
},
+ primaryButtonDisabled: {
+ backgroundColor: BaseTheme.palette.action03Disabled,
+ marginTop: BaseTheme.spacing[4]
+ },
primaryButtonText: {
...btnText
@@ -49,7 +53,8 @@ export default {
marginHorizontal: BaseTheme.spacing[3],
height: 24,
width: 24
- }
+ },
+ underlayColor: 'transparent'
},
contentWrapper: {
@@ -73,18 +78,20 @@ export default {
},
contentContainer: {
- alignItems: 'center',
+ alignSelf: 'center',
display: 'flex',
justifyContent: 'center',
- minHeight: '50%'
+ minHeight: '50%',
+ paddingHorizontal: BaseTheme.spacing[3],
+ width: 400
},
contentContainerWide: {
+ alignItems: 'center',
height: '100%',
justifyContent: 'center',
left: '50%',
- marginHorizontal: BaseTheme.spacing[6],
- marginVertical: BaseTheme.spacing[3],
+ paddingHorizontal: BaseTheme.spacing[3],
position: 'absolute',
width: '50%'
},
@@ -115,7 +122,7 @@ export default {
borderRadius: BaseTheme.shape.borderRadius,
borderWidth: 2,
height: BaseTheme.spacing[7],
- marginTop: BaseTheme.spacing[2],
+ marginTop: BaseTheme.spacing[3],
textAlign: 'center'
}
};
diff --git a/react/features/prejoin/functions.js b/react/features/prejoin/functions.js
index 9b313b0509..001f30d527 100644
--- a/react/features/prejoin/functions.js
+++ b/react/features/prejoin/functions.js
@@ -32,8 +32,8 @@ export function isDeviceStatusVisible(state: Object): boolean {
* @returns {boolean}
*/
export function isDisplayNameRequired(state: Object): boolean {
- return state['features/prejoin'].isDisplayNameRequired
- || state['features/base/config'].requireDisplayName;
+ return state['features/prejoin']?.isDisplayNameRequired
+ || state['features/base/config']?.requireDisplayName;
}
/**