Compare commits

...

4 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé c8309ffe05 chore(rn,version) bump app version 2022-03-04 13:44:42 +01:00
Saúl Ibarra Corretgé 4a98782cec fix(rn,dialogs,auth) fix not showing authentication dialogs
1) Fix not being able to show multiple dialogs at once in iOS
2) Fix cancelling the login dialog when XMPP auth is enabled without
   guest support
2022-03-04 13:44:42 +01:00
Calinteodor ce5f2b269d feat(filmstrip/toolbox) mobile ui updates (#11051) 2022-03-01 17:48:45 +02:00
Calin Chitu f35a9176ec feat(filmstrip/toolbox) mobile ui undo changes 2022-02-28 18:04:38 +02:00
13 changed files with 156 additions and 125 deletions

View File

@ -26,5 +26,5 @@ android.useAndroidX=true
android.enableJetifier=true
android.bundle.enableUncompressedNativeLibs=false
appVersion=22.0.0
appVersion=22.0.1
sdkVersion=5.0.0

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>22.0.0</string>
<string>22.0.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>22.0.0</string>
<string>22.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>22.0.0</string>
<string>22.0.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UISupportedInterfaceOrientations</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>22.0.0</string>
<string>22.0.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>

View File

@ -44,6 +44,11 @@ type Props = {
*/
_error: Object,
/**
* Extra handler for cancel functionality.
*/
_onCancel: Function,
/**
* The progress in the floating range between 0 and 1 of the authenticating
* and upgrading the role of the local participant/user.
@ -63,7 +68,12 @@ type Props = {
/**
* Invoked to obtain translated strings.
*/
t: Function
t: Function,
/**
* Override the default visibility.
*/
visible: boolean
};
/**
@ -110,6 +120,10 @@ type State = {
* of the configuration parameters.
*/
class LoginDialog extends Component<Props, State> {
static defaultProps = {
visible: true
};
/**
* Initializes a new LoginDialog instance.
*
@ -140,13 +154,14 @@ class LoginDialog extends Component<Props, State> {
render() {
const {
_connecting: connecting,
t
t,
visible
} = this.props;
return (
<View>
<Dialog.Container
visible = { true }>
visible = { visible }>
<Dialog.Title>
{ t('dialog.login') }
</Dialog.Title>
@ -280,7 +295,10 @@ class LoginDialog extends Component<Props, State> {
* @returns {void}
*/
_onCancel() {
this.props.dispatch(cancelLogin());
const { _onCancel, dispatch } = this.props;
_onCancel && _onCancel();
dispatch(cancelLogin());
}
_onLogin: () => void;

View File

@ -6,7 +6,9 @@ import type { Dispatch } from 'redux';
import { ConfirmDialog } from '../../../base/dialog';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import { openLoginDialog, cancelWaitForOwner } from '../../actions.native';
import { cancelWaitForOwner } from '../../actions.native';
import LoginDialog from './LoginDialog';
/**
* The type of the React {@code Component} props of {@link WaitForOwnerDialog}.
@ -45,9 +47,14 @@ class WaitForOwnerDialog extends Component<Props> {
constructor(props) {
super(props);
this.state = {
showLoginDialog: false
};
// Bind event handlers so they are only bound once per instance.
this._onCancel = this._onCancel.bind(this);
this._onLogin = this._onLogin.bind(this);
this._onLoginDialogCancel = this._onLoginDialogCancel.bind(this);
}
/**
@ -72,7 +79,12 @@ class WaitForOwnerDialog extends Component<Props> {
}
}
onCancel = { this._onCancel }
onSubmit = { this._onLogin } />
onSubmit = { this._onLogin }>
<LoginDialog
// eslint-disable-next-line react/jsx-handler-names
_onCancel = { this._onLoginDialogCancel }
visible = { this.state.showLoginDialog } />
</ConfirmDialog>
);
}
@ -97,7 +109,17 @@ class WaitForOwnerDialog extends Component<Props> {
* @returns {void}
*/
_onLogin() {
this.props.dispatch(openLoginDialog());
this.setState({ showLoginDialog: true });
}
/**
* Called when the nested login dialog is cancelled.
*
* @private
* @returns {void}
*/
_onLoginDialogCancel() {
this.setState({ showLoginDialog: false });
}
}

View File

@ -62,13 +62,14 @@ MiddlewareRegistry.register(store => next => action => {
// Go back to the app's entry point.
_hideLoginDialog(store);
const { authRequired, conference } = getState()['features/base/conference'];
const state = getState();
const { authRequired, conference } = state['features/base/conference'];
const { passwordRequired } = state['features/base/connection'];
// Only end the meeting if we are not already inside and trying to upgrade.
if (authRequired && !conference) {
// FIXME Like cancelWaitForOwner, dispatch conferenceLeft to notify
// the external-api.
// NOTE: Despite it's confusing name, `passwordRequired` implies an XMPP
// connection auth error.
if ((passwordRequired || authRequired) && !conference) {
dispatch(appNavigate(undefined));
}
}

View File

@ -42,7 +42,7 @@ type Props = {
/**
* Whether or not the toolbox is displayed.
*/
_isToolboxVisible: Boolean,
_toolboxVisible: Boolean,
_localParticipantId: string,
@ -97,7 +97,7 @@ class Filmstrip extends PureComponent<Props> {
// layer #0 sits behind the window, creates a hole in the window, and
// there we render the LargeVideo; layer #1 is known as media overlay in
// EGL terms, renders on top of layer #0, and, consequently, is for the
// Filmstrip. With the separate LocalThumnail, we should have left the
// Filmstrip. With the separate LocalThumbnail, we should have left the
// remote participants' Thumbnails in layer #1 and utilized layer #2 for
// LocalThumbnail. Unfortunately, layer #2 is not practical (that's why
// I said we had two practical layers only) because it renders on top of
@ -233,7 +233,7 @@ class Filmstrip extends PureComponent<Props> {
const {
_aspectRatio,
_disableSelfView,
_isToolboxVisible,
_toolboxVisible,
_localParticipantId,
_participants,
_visible
@ -243,6 +243,7 @@ class Filmstrip extends PureComponent<Props> {
return null;
}
const bottomEdge = Platform.OS === 'ios' && !_toolboxVisible;
const isNarrowAspectRatio = _aspectRatio === ASPECT_RATIO_NARROW;
const filmstripStyle = isNarrowAspectRatio ? styles.filmstripNarrow : styles.filmstripWide;
const { height, width } = this._getDimensions();
@ -263,12 +264,7 @@ class Filmstrip extends PureComponent<Props> {
return (
<SafeAreaView
edges = { [
!_isToolboxVisible && 'bottom',
'top',
'left',
'right'
].filter(Boolean) }
edges = { [ bottomEdge && 'bottom', 'left', 'right' ].filter(Boolean) }
style = { filmstripStyle }>
{
this._separateLocalThumbnail
@ -320,9 +316,9 @@ function _mapStateToProps(state) {
_clientHeight: responsiveUI.clientHeight,
_clientWidth: responsiveUI.clientWidth,
_disableSelfView: disableSelfView,
_isToolboxVisible: isToolboxVisible(state),
_localParticipantId: getLocalParticipant(state)?.id,
_participants: showRemoteVideos ? remoteParticipants : NO_REMOTE_VIDEOS,
_toolboxVisible: isToolboxVisible(state),
_visible: enabled && isFilmstripVisible(state)
};
}

View File

@ -45,7 +45,7 @@ export default {
flexDirection: 'row',
flexGrow: 0,
justifyContent: 'flex-end',
marginBottom: BaseTheme.spacing[1]
margin: 6
},
/**

View File

@ -4,7 +4,6 @@ import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';
import { Chat } from '../../../../../chat';
@ -63,81 +62,79 @@ const ConferenceNavigationContainer = () => {
const { t } = useTranslation();
return (
<SafeAreaProvider>
<NavigationContainer
independent = { true }
ref = { conferenceNavigationRef }
theme = { navigationContainerTheme }>
<ConferenceStack.Navigator
initialRouteName = { screen.conference.main }
screenOptions = {{
presentation: 'modal'
}}>
<ConferenceStack.Screen
component = { Conference }
name = { screen.conference.main }
options = { conferenceScreenOptions } />
<ConferenceStack.Screen
component = { ChatScreen }
name = { chatScreenName }
options = {{
...chatScreenOptions,
title: t(chatTitleString)
}} />
<ConferenceStack.Screen
component = { ParticipantsPane }
name = { screen.conference.participants }
options = {{
...participantsScreenOptions,
title: t('participantsPane.header')
}} />
<ConferenceStack.Screen
component = { SecurityDialog }
name = { screen.conference.security }
options = {{
...securityScreenOptions,
title: t('security.header')
}} />
<ConferenceStack.Screen
component = { StartRecordingDialog }
name = { screen.conference.recording }
options = {{
...recordingScreenOptions
}} />
<ConferenceStack.Screen
component = { StartLiveStreamDialog }
name = { screen.conference.liveStream }
options = {{
...liveStreamScreenOptions
}} />
<ConferenceStack.Screen
component = { SpeakerStats }
name = { screen.conference.speakerStats }
options = {{
...speakerStatsScreenOptions,
title: t('speakerStats.speakerStats')
}} />
<ConferenceStack.Screen
component = { LobbyScreen }
name = { screen.lobby }
options = { lobbyScreenOptions } />
<ConferenceStack.Screen
component = { AddPeopleDialog }
name = { screen.conference.invite }
options = {{
...inviteScreenOptions,
title: t('addPeople.add')
}} />
<ConferenceStack.Screen
component = { SharedDocument }
name = { screen.conference.sharedDocument }
options = {{
...sharedDocumentScreenOptions,
title: t('documentSharing.title')
}} />
</ConferenceStack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
<NavigationContainer
independent = { true }
ref = { conferenceNavigationRef }
theme = { navigationContainerTheme }>
<ConferenceStack.Navigator
initialRouteName = { screen.conference.main }
screenOptions = {{
presentation: 'modal'
}}>
<ConferenceStack.Screen
component = { Conference }
name = { screen.conference.main }
options = { conferenceScreenOptions } />
<ConferenceStack.Screen
component = { ChatScreen }
name = { chatScreenName }
options = {{
...chatScreenOptions,
title: t(chatTitleString)
}} />
<ConferenceStack.Screen
component = { ParticipantsPane }
name = { screen.conference.participants }
options = {{
...participantsScreenOptions,
title: t('participantsPane.header')
}} />
<ConferenceStack.Screen
component = { SecurityDialog }
name = { screen.conference.security }
options = {{
...securityScreenOptions,
title: t('security.header')
}} />
<ConferenceStack.Screen
component = { StartRecordingDialog }
name = { screen.conference.recording }
options = {{
...recordingScreenOptions
}} />
<ConferenceStack.Screen
component = { StartLiveStreamDialog }
name = { screen.conference.liveStream }
options = {{
...liveStreamScreenOptions
}} />
<ConferenceStack.Screen
component = { SpeakerStats }
name = { screen.conference.speakerStats }
options = {{
...speakerStatsScreenOptions,
title: t('speakerStats.speakerStats')
}} />
<ConferenceStack.Screen
component = { LobbyScreen }
name = { screen.lobby }
options = { lobbyScreenOptions } />
<ConferenceStack.Screen
component = { AddPeopleDialog }
name = { screen.conference.invite }
options = {{
...inviteScreenOptions,
title: t('addPeople.add')
}} />
<ConferenceStack.Screen
component = { SharedDocument }
name = { screen.conference.sharedDocument }
options = {{
...sharedDocumentScreenOptions,
title: t('documentSharing.title')
}} />
</ConferenceStack.Navigator>
</NavigationContainer>
);
};

View File

@ -1,9 +1,11 @@
// @flow
import React from 'react';
import { SafeAreaView, View } from 'react-native';
import { View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { Platform } from '../../../base/react';
import { connect } from '../../../base/redux';
import { StyleType } from '../../../base/styles';
import { ChatButton } from '../../../chat';
@ -26,6 +28,11 @@ import styles from './styles';
*/
type Props = {
/**
* Whether or not the reactions feature is enabled.
*/
_reactionsEnabled: boolean,
/**
* The color-schemed stylesheet of the feature.
*/
@ -39,12 +46,7 @@ type Props = {
/**
* The width of the screen.
*/
_width: number,
/**
* Whether or not the reactions feature is enabled.
*/
_reactionsEnabled: boolean
_width: number
};
/**
@ -54,11 +56,13 @@ type Props = {
* @returns {React$Element}.
*/
function Toolbox(props: Props) {
if (!props._visible) {
const { _reactionsEnabled, _styles, _visible, _width } = props;
if (!_visible) {
return null;
}
const { _styles, _width, _reactionsEnabled } = props;
const bottomEdge = Platform.OS === 'ios' && _visible;
const { buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
const additionalButtons = getMovableButtons(_width);
const backgroundToggledStyle = {
@ -75,6 +79,7 @@ function Toolbox(props: Props) {
style = { styles.toolboxContainer }>
<SafeAreaView
accessibilityRole = 'toolbar'
edges = { [ bottomEdge && 'bottom' ].filter(Boolean) }
pointerEvents = 'box-none'
style = { styles.toolbox }>
<AudioMuteButton

View File

@ -18,7 +18,7 @@ const toolbarButton = {
height: BUTTON_SIZE,
justifyContent: 'center',
marginHorizontal: 6,
marginTop: 6,
marginVertical: 6,
width: BUTTON_SIZE
};
@ -86,9 +86,7 @@ const styles = {
borderTopLeftRadius: 3,
borderTopRightRadius: 3,
flexDirection: 'row',
flexGrow: 0,
justifyContent: 'space-between',
margin: BaseTheme.spacing[2]
justifyContent: 'space-between'
},
/**
@ -97,16 +95,10 @@ const styles = {
toolboxContainer: {
backgroundColor: BaseTheme.palette.uiBackground,
flexDirection: 'column',
flexGrow: 0,
height: '100%',
width: '100%',
// TODO revisit this
maxHeight: 76,
maxWidth: 580,
marginLeft: 'auto',
marginRight: 'auto'
marginRight: 'auto',
width: '100%'
}
};