fix(rn, bottomsheet) fix not rendering above presentation sheets

Move all sheets to render in a new container which uses FullWindowOverlay, which allows rendering above presentation controllers on iOS.
This commit is contained in:
Saúl Ibarra Corretgé 2022-06-20 16:53:19 +02:00 committed by GitHub
parent 0e98f90205
commit 6ad279f029
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 210 additions and 325 deletions

View File

@ -749,4 +749,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: bef1335067eaa4e8c558b1248f8ab3948de855bc
COCOAPODS: 1.11.2
COCOAPODS: 1.11.3

View File

@ -1,10 +1,11 @@
// @flow
import React from 'react';
import React, { Fragment } from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import SplashScreen from 'react-native-splash-screen';
import { DialogContainer } from '../../base/dialog';
import BottomSheetContainer from '../../base/dialog/components/native/BottomSheetContainer';
import { updateFlags } from '../../base/flags/actions';
import { CALL_INTEGRATION_ENABLED, SERVER_URL_CHANGE_ENABLED } from '../../base/flags/constants';
import { getFeatureFlag } from '../../base/flags/functions';
@ -240,7 +241,10 @@ export class App extends AbstractApp {
*/
_renderDialogContainer() {
return (
<Fragment>
<DialogContainer />
<BottomSheetContainer />
</Fragment>
);
}
}

View File

@ -7,6 +7,15 @@
*/
export const HIDE_DIALOG = 'HIDE_DIALOG';
/**
* The type of Redux action which closes a sheet.
*
* {
* type: HIDE_SHEET
* }
*/
export const HIDE_SHEET = 'HIDE_SHEET';
/**
* The type of Redux action which begins a request to open a dialog.
*
@ -18,3 +27,15 @@ export const HIDE_DIALOG = 'HIDE_DIALOG';
*
*/
export const OPEN_DIALOG = 'OPEN_DIALOG';
/**
* The type of Redux action which begins a request to open a sheet.
*
* {
* type: OPEN_SHEET,
* component: React.Component,
* props: PropTypes
* }
*
*/
export const OPEN_SHEET = 'OPEN_SHEET';

View File

@ -2,7 +2,12 @@
import type { Dispatch } from 'redux';
import { HIDE_DIALOG, OPEN_DIALOG } from './actionTypes';
import {
HIDE_DIALOG,
HIDE_SHEET,
OPEN_DIALOG,
OPEN_SHEET
} from './actionTypes';
import { isDialogOpen } from './functions';
/**
@ -24,6 +29,19 @@ export function hideDialog(component: ?Object) {
};
}
/**
* Closes the active sheet.
*
* @returns {{
* type: HIDE_SHEET,
* }}
*/
export function hideSheet() {
return {
type: HIDE_SHEET
};
}
/**
* Signals Dialog to open dialog.
*
@ -44,6 +62,26 @@ export function openDialog(component: Object, componentProps: ?Object) {
};
}
/**
* Opens the requested sheet.
*
* @param {Object} component - The component to display as a sheet.
* @param {Object} [componentProps] - The React {@code Component} props of the
* specified {@code component}.
* @returns {{
* type: OPEN_SHEET,
* component: React.Component,
* componentProps: (Object | undefined)
* }}
*/
export function openSheet(component: Object, componentProps: ?Object) {
return {
type: OPEN_SHEET,
component,
componentProps
};
}
/**
* Signals Dialog to open a dialog with the specified component if the component
* is not already open. If it is open, then Dialog is signaled to close its

View File

@ -2,6 +2,8 @@ import React, { PureComponent, type Node } from 'react';
import { SafeAreaView, ScrollView, View } from 'react-native';
import { SlidingView } from '../../../react';
import { connect } from '../../../redux';
import { hideSheet } from '../../actions';
import { bottomSheetStyles as styles } from './styles';
@ -20,6 +22,11 @@ type Props = {
*/
children: Node,
/**
* Redux Dispatch function.
*/
dispatch: Function,
/**
* Handler for the cancel event, which happens when the user dismisses
* the sheet.
@ -61,6 +68,31 @@ class BottomSheet extends PureComponent<Props> {
showSlidingView: true
};
/**
* Initializes a new instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* the new instance with.
*/
constructor(props: Props) {
super(props);
this._onCancel = this._onCancel.bind(this);
}
/**
* Handles the cancel event, when the user dismissed the sheet. By default we close it.
*
* @returns {void}
*/
_onCancel() {
if (this.props.onCancel) {
this.props.onCancel();
} else {
this.props.dispatch(hideSheet());
}
}
/**
* Implements React's {@link Component#render()}.
*
@ -80,7 +112,7 @@ class BottomSheet extends PureComponent<Props> {
<SlidingView
accessibilityRole = 'menu'
accessibilityViewIsModal = { true }
onHide = { this.props.onCancel }
onHide = { this._onCancel }
position = 'bottom'
show = { showSlidingView }>
<View
@ -116,4 +148,4 @@ class BottomSheet extends PureComponent<Props> {
}
}
export default BottomSheet;
export default connect()(BottomSheet);

View File

@ -0,0 +1,26 @@
import React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import { FullWindowOverlay } from 'react-native-screens';
import { useSelector } from 'react-redux';
const Wrapper = Platform.select({
ios: FullWindowOverlay,
default: View
});
const BottomSheetContainer: () => JSX.Element = () => {
const { sheet, sheetProps } = useSelector(state => state['features/base/dialog']);
const { reducedUI } = useSelector(state => state['features/base/responsive-ui']);
if (!sheet || reducedUI) {
return null;
}
return (
<Wrapper style={StyleSheet.absoluteFill}>
{ React.createElement(sheet, sheetProps) }
</Wrapper>
);
}
export default BottomSheetContainer;

View File

@ -1,8 +1,11 @@
/* @flow */
import { assign, ReducerRegistry } from '../redux';
import { HIDE_DIALOG, OPEN_DIALOG } from './actionTypes';
import {
HIDE_DIALOG,
HIDE_SHEET,
OPEN_DIALOG,
OPEN_SHEET
} from './actionTypes';
/**
* Reduces redux actions which show or hide dialogs.
@ -32,6 +35,18 @@ ReducerRegistry.register('features/base/dialog', (state = {}, action) => {
component: action.component,
componentProps: action.componentProps
});
case HIDE_SHEET:
return assign(state, {
sheet: undefined,
sheetProps: undefined
});
case OPEN_SHEET:
return assign(state, {
sheet: action.component,
sheetProps: action.componentProps
});
}
return state;

View File

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Button } from 'react-native-paper';
import { useDispatch } from 'react-redux';
import { openDialog } from '../../../../base/dialog/actions';
import { openSheet } from '../../../../base/dialog/actions';
import AudioRoutePickerDialog from '../../../../mobile/audio-mode/components/AudioRoutePickerDialog';
import AudioIcon from './AudioIcon';
@ -19,7 +19,7 @@ const SelectSoundDevice = () : JSX.Element => {
const dispatch = useDispatch();
const onSelect = useCallback(() =>
dispatch(openDialog(AudioRoutePickerDialog))
dispatch(openSheet(AudioRoutePickerDialog))
, [ dispatch ]);
return (

View File

@ -1,7 +1,6 @@
// @flow
import type { Dispatch } from 'redux';
import { openDialog } from '../../../base/dialog';
import { openSheet } from '../../../base/dialog';
import { translate } from '../../../base/i18n';
import { IconVolumeEmpty } from '../../../base/icons';
import { connect } from '../../../base/redux';
@ -32,7 +31,7 @@ class AudioDeviceToggleButton extends AbstractButton<Props, *> {
* @returns {void}
*/
_handleClick() {
this.props.dispatch(openDialog(AudioRoutePickerDialog));
this.props.dispatch(openSheet(AudioRoutePickerDialog));
}
}

View File

@ -1,10 +1,8 @@
// @flow
import _ from 'lodash';
import React, { Component } from 'react';
import { NativeModules, Text, TouchableHighlight, View } from 'react-native';
import { hideDialog, BottomSheet } from '../../../base/dialog';
import { hideSheet, BottomSheet } from '../../../base/dialog';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
import { translate } from '../../../base/i18n';
import {
@ -143,11 +141,6 @@ const deviceInfoMap = {
}
};
/**
* The exported React {@code Component}.
*/
let AudioRoutePickerDialog_; // eslint-disable-line prefer-const
/**
* Implements a React {@code Component} which prompts the user when a password
* is required to join a conference.
@ -218,36 +211,10 @@ class AudioRoutePickerDialog extends Component<Props, State> {
constructor(props: Props) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onCancel = this._onCancel.bind(this);
// Trigger an initial update.
AudioMode.updateDeviceList && AudioMode.updateDeviceList();
}
/**
* Dispatches a redux action to hide this sheet.
*
* @returns {void}
*/
_hide() {
this.props.dispatch(hideDialog(AudioRoutePickerDialog_));
}
_onCancel: () => void;
/**
* Cancels the dialog by hiding it.
*
* @private
* @returns {void}
*/
_onCancel() {
this._hide();
}
_onSelectDeviceFn: (Device) => Function;
/**
* Builds and returns a function which handles the selection of a device
* on the sheet. The selected device will be used by {@code AudioMode}.
@ -258,7 +225,7 @@ class AudioRoutePickerDialog extends Component<Props, State> {
*/
_onSelectDeviceFn(device: Device) {
return () => {
this._hide();
this.props.dispatch(hideSheet());
AudioMode.setAudioDevice(device.uid || device.type);
};
}
@ -329,7 +296,7 @@ class AudioRoutePickerDialog extends Component<Props, State> {
}
return (
<BottomSheet onCancel = { this._onCancel }>
<BottomSheet>
{ content }
</BottomSheet>
);
@ -348,6 +315,4 @@ function _mapStateToProps(state) {
};
}
AudioRoutePickerDialog_ = translate(connect(_mapStateToProps)(AudioRoutePickerDialog));
export default AudioRoutePickerDialog_;
export default translate(connect(_mapStateToProps)(AudioRoutePickerDialog));

View File

@ -1,6 +1,6 @@
// @flow
import type { Dispatch } from 'redux';
import { openDialog } from '../base/dialog';
import { openSheet } from '../base/dialog';
import { SharedVideoMenu } from '../video-menu';
import { LocalVideoMenu } from '../video-menu/components/native';
import ConnectionStatusComponent
@ -20,7 +20,7 @@ export * from './actions.any';
* @returns {Function}
*/
export function showContextMenuReject(participant: Object) {
return openDialog(ContextMenuLobbyParticipantReject, { participant });
return openSheet(ContextMenuLobbyParticipantReject, { participant });
}
@ -31,7 +31,7 @@ export function showContextMenuReject(participant: Object) {
* @returns {Function}
*/
export function showConnectionStatus(participantID: string) {
return openDialog(ConnectionStatusComponent, { participantID });
return openSheet(ConnectionStatusComponent, { participantID });
}
/**
@ -46,9 +46,9 @@ export function showContextMenuDetails(participantId: string, local: boolean = f
const { remoteVideoMenu } = getState()['features/base/config'];
if (local) {
dispatch(openDialog(LocalVideoMenu));
dispatch(openSheet(LocalVideoMenu));
} else if (!remoteVideoMenu?.disabled) {
dispatch(openDialog(RemoteVideoMenu, { participantId }));
dispatch(openSheet(RemoteVideoMenu, { participantId }));
}
};
}
@ -60,7 +60,7 @@ export function showContextMenuDetails(participantId: string, local: boolean = f
* @returns {Function}
*/
export function showSharedVideoMenu(participantId: string) {
return openDialog(SharedVideoMenu, { participantId });
return openSheet(SharedVideoMenu, { participantId });
}
/**

View File

@ -1,5 +1,3 @@
// @flow
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { TouchableOpacity } from 'react-native';
@ -7,7 +5,7 @@ import { Text } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
import { createBreakoutRoomsEvent, sendAnalytics } from '../../../../../analytics';
import { hideDialog } from '../../../../../base/dialog/actions';
import { hideSheet } from '../../../../../base/dialog/actions';
import BottomSheet from '../../../../../base/dialog/components/native/BottomSheet';
import {
Icon,
@ -29,7 +27,6 @@ type Props = {
const BreakoutRoomContextMenu = ({ room }: Props) => {
const dispatch = useDispatch();
const closeDialog = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const isLocalModerator = useSelector(isLocalParticipantModerator);
const { hideJoinRoomButton } = useSelector(getBreakoutRoomsConfig);
const { t } = useTranslation();
@ -37,23 +34,22 @@ const BreakoutRoomContextMenu = ({ room }: Props) => {
const onJoinRoom = useCallback(() => {
sendAnalytics(createBreakoutRoomsEvent('join'));
dispatch(moveToRoom(room.jid));
closeDialog();
dispatch(hideSheet());
}, [ dispatch, room ]);
const onRemoveBreakoutRoom = useCallback(() => {
dispatch(removeBreakoutRoom(room.jid));
closeDialog();
dispatch(hideSheet());
}, [ dispatch, room ]);
const onCloseBreakoutRoom = useCallback(() => {
dispatch(closeBreakoutRoom(room.id));
closeDialog();
dispatch(hideSheet());
}, [ dispatch, room ]);
return (
<BottomSheet
addScrollViewPadding = { false }
onCancel = { closeDialog }
showSlidingView = { true }>
{
!hideJoinRoomButton && (

View File

@ -1,11 +1,9 @@
// @flow
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { FlatList } from 'react-native';
import { useDispatch } from 'react-redux';
import { openDialog } from '../../../../../base/dialog';
import { openSheet } from '../../../../../base/dialog';
import { participantMatchesSearch } from '../../../../functions';
import CollapsibleList from '../../../native/CollapsibleList';
import styles from '../../../native/styles';
@ -41,7 +39,7 @@ export const CollapsibleRoom = ({ room, searchString }: Props) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const _openContextMenu = useCallback(() => {
dispatch(openDialog(BreakoutRoomContextMenu, { room }));
dispatch(openSheet(BreakoutRoomContextMenu, { room }));
}, [ room ]);
const roomParticipantsNr = Object.values(room.participants || {}).length;
const title

View File

@ -1,5 +1,3 @@
// @flow
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { TouchableOpacity, View } from 'react-native';
@ -7,7 +5,6 @@ import { Text } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
import { Avatar } from '../../../base/avatar';
import { hideDialog } from '../../../base/dialog';
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
import {
Icon, IconClose
@ -16,6 +13,7 @@ import { setKnockingParticipantApproval } from '../../../lobby/actions.native';
import { getKnockingParticipantsById } from '../../../lobby/functions';
import styles from './styles';
type Props = {
/**
@ -28,7 +26,6 @@ const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) => {
const dispatch = useDispatch();
const knockParticipantsIDArr = useSelector(getKnockingParticipantsById);
const knockParticipantIsAvailable = knockParticipantsIDArr.find(knockPartId => knockPartId === p.id);
const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const displayName = p.name;
const reject = useCallback(() => dispatch(setKnockingParticipantApproval(p.id, false), [ dispatch ]));
const { t } = useTranslation();
@ -50,7 +47,6 @@ const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) => {
return (
<BottomSheet
addScrollViewPadding = { false }
onCancel = { cancel }
/* eslint-disable-next-line react/jsx-no-bind */
renderHeader = { renderMenuHeader }
showSlidingView = { Boolean(knockParticipantIsAvailable) }

View File

@ -1,5 +1,3 @@
// @flow
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { TouchableOpacity, View } from 'react-native';
@ -16,7 +14,7 @@ import {
isSupported as isAvModerationSupported,
isEnabled as isAvModerationEnabled
} from '../../../av-moderation/functions';
import { openDialog, hideDialog } from '../../../base/dialog/actions';
import { openDialog, hideSheet } from '../../../base/dialog/actions';
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
import {
Icon,
@ -32,10 +30,10 @@ import styles from './styles';
export const ContextMenuMore = () => {
const dispatch = useDispatch();
const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const muteAllVideo = useCallback(() =>
dispatch(openDialog(MuteEveryonesVideoDialog)),
[ dispatch ]);
const muteAllVideo = useCallback(() => {
dispatch(openDialog(MuteEveryonesVideoDialog));
dispatch(hideSheet());
}, [ dispatch ]);
const { t } = useTranslation();
const isModerationSupported = useSelector(isAvModerationSupported);
@ -54,7 +52,6 @@ export const ContextMenuMore = () => {
return (
<BottomSheet
addScrollViewPadding = { false }
onCancel = { cancel }
showSlidingView = { true }>
<TouchableOpacity
onPress = { muteAllVideo }

View File

@ -6,7 +6,7 @@ import { View } from 'react-native';
import { Button } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
import { openDialog } from '../../../base/dialog';
import { openDialog, openSheet } from '../../../base/dialog';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import { isLocalParticipantModerator } from '../../../base/participants';
import { equals } from '../../../base/redux';
@ -42,7 +42,7 @@ import styles from './styles';
const ParticipantsPane = () => {
const dispatch = useDispatch();
const [ searchString, setSearchString ] = useState('');
const openMoreMenu = useCallback(() => dispatch(openDialog(ContextMenuMore)), [ dispatch ]);
const openMoreMenu = useCallback(() => dispatch(openSheet(ContextMenuMore)), [ dispatch ]);
const isLocalModerator = useSelector(isLocalParticipantModerator);
const muteAll = useCallback(() => dispatch(openDialog(MuteEveryoneDialog)),
[ dispatch ]);

View File

@ -1,11 +1,9 @@
// @flow
import React from 'react';
import { TouchableWithoutFeedback, View } from 'react-native';
import type { Dispatch } from 'redux';
import { getDefaultURL } from '../../app/functions';
import { openDialog } from '../../base/dialog/actions';
import { openSheet } from '../../base/dialog/actions';
import { translate } from '../../base/i18n';
import { NavigateSectionList, type Section } from '../../base/react';
import { connect } from '../../base/redux';
@ -56,9 +54,6 @@ type Props = {
*
*/
class RecentList extends AbstractRecentList<Props> {
_getRenderListEmptyComponent: () => React$Node;
_onPress: string => {};
/**
* Initializes a new {@code RecentList} instance.
*
@ -105,8 +100,6 @@ class RecentList extends AbstractRecentList<Props> {
);
}
_onLongPress: (Object) => void;
/**
* Handles the list's navigate action.
*
@ -115,7 +108,7 @@ class RecentList extends AbstractRecentList<Props> {
* @returns {void}
*/
_onLongPress(item) {
this.props.dispatch(openDialog(RecentListItemMenu, { item }));
this.props.dispatch(openSheet(RecentListItemMenu, { item }));
}
}

View File

@ -1,9 +1,7 @@
// @flow
import React, { PureComponent } from 'react';
import { Text, View } from 'react-native';
import { BottomSheet, hideDialog, isDialogOpen } from '../../base/dialog';
import { BottomSheet, hideSheet } from '../../base/dialog';
import { bottomSheetStyles } from '../../base/dialog/components/native/styles';
import { type Item } from '../../base/react/Types';
import { connect } from '../../base/redux';
@ -22,17 +20,9 @@ type Props = {
/**
* Item being rendered in this menu.
*/
item: Item,
/**
* True if the menu is currently open, false otherwise.
*/
_isOpen: boolean
item: Item
}
// eslint-disable-next-line prefer-const
let RecentListItemMenu_;
/**
* Class to implement a popup menu that opens upon long pressing a recent list item.
*/
@ -65,7 +55,6 @@ class RecentListItemMenu extends PureComponent<Props> {
return (
<BottomSheet
onCancel = { this._onCancel }
renderHeader = { this._renderMenuHeader }>
<DeleteItemButton { ...buttonProps } />
<ShowDialInInfoButton { ...buttonProps } />
@ -73,8 +62,6 @@ class RecentListItemMenu extends PureComponent<Props> {
);
}
_onCancel: () => boolean;
/**
* Callback to hide this menu.
*
@ -82,17 +69,9 @@ class RecentListItemMenu extends PureComponent<Props> {
* @returns {boolean}
*/
_onCancel() {
if (this.props._isOpen) {
this.props.dispatch(hideDialog(RecentListItemMenu_));
return true;
this.props.dispatch(hideSheet());
}
return false;
}
_renderMenuHeader: () => React$Element<any>;
/**
* Function to render the menu's header.
*
@ -118,19 +97,4 @@ class RecentListItemMenu extends PureComponent<Props> {
}
}
/**
* Function that maps parts of Redux state tree into component props.
*
* @param {Object} state - Redux state.
* @private
* @returns {Props}
*/
function _mapStateToProps(state) {
return {
_isOpen: isDialogOpen(state, RecentListItemMenu_)
};
}
RecentListItemMenu_ = connect(_mapStateToProps)(RecentListItemMenu);
export default RecentListItemMenu_;
export default connect()(RecentListItemMenu);

View File

@ -1,6 +1,4 @@
// @flow
import { openDialog } from '../base/dialog';
import { openSheet } from '../base/dialog';
import JitsiMeetJS from '../base/lib-jitsi-meet';
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
@ -15,7 +13,7 @@ export * from './actions.any';
*/
export function openHighlightDialog() {
return (dispatch: Function) => {
dispatch(openDialog(HighlightDialog));
dispatch(openSheet(HighlightDialog));
};
}

View File

@ -1,27 +1,26 @@
// @flow
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { Text, View } from 'react-native';
import { Button } from 'react-native-paper';
import { useDispatch, batch } from 'react-redux';
import { hideDialog, BottomSheet } from '../../../../base/dialog';
import { BottomSheet, hideSheet } from '../../../../base/dialog';
import { highlightMeetingMoment } from '../../../actions.any';
import styles from '../styles.native';
const HighlightDialog = () => {
const dispatch = useDispatch();
const { t } = useTranslation();
const closeDialog = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const closeDialog = useCallback(() => dispatch(hideSheet()), [ dispatch ]);
const highlightMoment = useCallback(() => {
batch(() => {
dispatch(highlightMeetingMoment());
dispatch(hideDialog());
dispatch(hideSheet());
});
}, [ dispatch ]);
return (
<BottomSheet onCancel = { closeDialog }>
<BottomSheet>
<View style = { styles.highlightDialog }>
<Text style = { styles.highlightDialogHeading }>{ `${t('recording.highlightMoment')}?` }</Text>
<Text style = { styles.highlightDialogText }>

View File

@ -3,7 +3,7 @@
import React, { PureComponent } from 'react';
import { Divider } from 'react-native-paper';
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
import { BottomSheet, hideSheet } from '../../../base/dialog';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
import { connect } from '../../../base/redux';
import { SharedDocumentButton } from '../../../etherpad';
@ -73,15 +73,6 @@ type State = {
scrolledToTop: boolean
}
/**
* The exported React {@code Component}. We need it to execute
* {@link hideDialog}.
*
* XXX It does not break our coding style rule to not utilize globals for state,
* because it is merely another name for {@code export}'s {@code default}.
*/
let OverflowMenu_; // eslint-disable-line prefer-const
/**
* Implements a React {@code Component} with some extra actions in addition to
* those in the toolbar.
@ -139,7 +130,6 @@ class OverflowMenu extends PureComponent<Props, State> {
return (
<BottomSheet
onCancel = { this._onCancel }
renderFooter = { _reactionsEnabled && !toolbarButtons.has('raisehand')
? this._renderReactionMenu
: null }>
@ -167,26 +157,16 @@ class OverflowMenu extends PureComponent<Props, State> {
);
}
_onCancel: () => boolean;
/**
* Hides this {@code OverflowMenu}.
*
* @private
* @returns {boolean}
* @returns {void}
*/
_onCancel() {
if (this.props._isOpen) {
this.props.dispatch(hideDialog(OverflowMenu_));
return true;
this.props.dispatch(hideSheet());
}
return false;
}
_renderReactionMenu: () => React$Element<any>;
/**
* Functoin to render the reaction menu as the footer of the bottom sheet.
*
@ -210,13 +190,10 @@ function _mapStateToProps(state) {
const { disableSelfView } = state['features/base/settings'];
return {
_isOpen: isDialogOpen(state, OverflowMenu_),
_reactionsEnabled: isReactionsEnabled(state),
_selfViewHidden: Boolean(disableSelfView),
_width: state['features/base/responsive-ui'].clientWidth
};
}
OverflowMenu_ = connect(_mapStateToProps)(OverflowMenu);
export default OverflowMenu_;
export default connect(_mapStateToProps)(OverflowMenu);

View File

@ -1,6 +1,4 @@
// @flow
import { openDialog } from '../../../base/dialog';
import { openSheet } from '../../../base/dialog';
import { getFeatureFlag, OVERFLOW_MENU_ENABLED } from '../../../base/flags';
import { translate } from '../../../base/i18n';
import { IconHorizontalPoints } from '../../../base/icons';
@ -35,7 +33,7 @@ class OverflowMenuButton extends AbstractButton<Props, *> {
* @returns {void}
*/
_handleClick() {
this.props.dispatch(openDialog(OverflowMenu));
this.props.dispatch(openSheet(OverflowMenu));
}
}

View File

@ -1,33 +1 @@
// @flow
import { hideDialog } from '../base/dialog';
import { RemoteVideoMenu, SharedVideoMenu, LocalVideoMenu } from './components/native';
/**
* Hides the local video menu.
*
* @returns {Function}
*/
export function hideLocalVideoMenu() {
return hideDialog(LocalVideoMenu);
}
/**
* Hides the remote video menu.
*
* @returns {Function}
*/
export function hideRemoteVideoMenu() {
return hideDialog(RemoteVideoMenu);
}
/**
* Hides the shared video menu.
*
* @returns {Function}
*/
export function hideSharedVideoMenu() {
return hideDialog(SharedVideoMenu);
}
export * from './actions.any';

View File

@ -1,6 +1,4 @@
// @flow
import { openDialog } from '../../../base/dialog';
import { openSheet } from '../../../base/dialog';
import { translate } from '../../../base/i18n';
import { IconInfo } from '../../../base/icons';
import { connect } from '../../../base/redux';
@ -42,7 +40,7 @@ class ConnectionStatusButton extends AbstractButton<Props, *> {
_handleClick() {
const { dispatch, participantID } = this.props;
dispatch(openDialog(ConnectionStatusComponent, {
dispatch(openSheet(ConnectionStatusComponent, {
participantID
}));
}

View File

@ -1,13 +1,10 @@
// @flow
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { withTheme } from 'react-native-paper';
import { Avatar } from '../../../base/avatar';
import { getSourceNameSignalingFeatureFlag } from '../../../base/config';
import { BottomSheet, isDialogOpen, hideDialog } from '../../../base/dialog';
import { BottomSheet, hideSheet } from '../../../base/dialog';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
import { translate } from '../../../base/i18n';
import { IconArrowDownLarge, IconArrowUpLarge } from '../../../base/icons';
@ -87,9 +84,6 @@ type State = {
connectionString: string
};
// eslint-disable-next-line prefer-const
let ConnectionStatusComponent_;
/**
* Class to implement a popup menu that show the connection statistics.
*/
@ -126,9 +120,9 @@ class ConnectionStatusComponent extends Component<Props, State> {
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {React$Node}
* @returns {ReactNode}
*/
render(): React$Node {
render() {
const { t, theme } = this.props;
const { palette } = theme;
@ -402,8 +396,6 @@ class ConnectionStatusComponent extends Component<Props, State> {
}
}
_onCancel: () => boolean;
/**
* Callback to hide the {@code ConnectionStatusComponent}.
*
@ -419,17 +411,9 @@ class ConnectionStatusComponent extends Component<Props, State> {
this.props._sourceName, this._onStatsUpdated);
}
if (this.props._isOpen) {
this.props.dispatch(hideDialog(ConnectionStatusComponent_));
return true;
this.props.dispatch(hideSheet());
}
return false;
}
_renderMenuHeader: () => React$Element<any>;
/**
* Function to render the menu's header.
*
@ -466,13 +450,10 @@ function _mapStateToProps(state, ownProps) {
const { participantID } = ownProps;
return {
_isOpen: isDialogOpen(state, ConnectionStatusComponent_),
_participantDisplayName: getParticipantDisplayName(state, participantID),
_sourceNameSignalingEnabled: getSourceNameSignalingFeatureFlag(state),
_sourceName: getSourceNameByParticipantId(state, ownProps.participantId)
};
}
ConnectionStatusComponent_ = translate(connect(_mapStateToProps)(withTheme(ConnectionStatusComponent)));
export default ConnectionStatusComponent_;
export default translate(connect(_mapStateToProps)(withTheme(ConnectionStatusComponent)));

View File

@ -1,10 +1,8 @@
// @flow
import React, { PureComponent } from 'react';
import { Text, View } from 'react-native';
import { Avatar } from '../../../base/avatar';
import { BottomSheet, isDialogOpen } from '../../../base/dialog';
import { BottomSheet } from '../../../base/dialog';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
import { translate } from '../../../base/i18n';
import {
@ -13,7 +11,6 @@ import {
} from '../../../base/participants';
import { connect } from '../../../base/redux';
import ToggleSelfViewButton from '../../../toolbox/components/native/ToggleSelfViewButton';
import { hideLocalVideoMenu } from '../../actions.native';
import ConnectionStatusButton from './ConnectionStatusButton';
import styles from './styles';
@ -26,11 +23,6 @@ const AVATAR_SIZE = 24;
type Props = {
/**
* True if the menu is currently open, false otherwise.
*/
_isOpen: boolean,
/**
* The local participant.
*/
@ -52,9 +44,6 @@ type Props = {
t: Function
}
// eslint-disable-next-line prefer-const
let LocalVideoMenu_;
/**
* Class to implement a popup menu that opens upon long pressing a thumbnail.
*/
@ -67,7 +56,6 @@ class LocalVideoMenu extends PureComponent<Props> {
constructor(props: Props) {
super(props);
this._onCancel = this._onCancel.bind(this);
this._renderMenuHeader = this._renderMenuHeader.bind(this);
}
@ -79,7 +67,6 @@ class LocalVideoMenu extends PureComponent<Props> {
render() {
const { _participant } = this.props;
const buttonProps = {
afterClick: this._onCancel,
showLabel: true,
participantID: _participant.id,
styles: bottomSheetStyles.buttons
@ -87,7 +74,6 @@ class LocalVideoMenu extends PureComponent<Props> {
return (
<BottomSheet
onCancel = { this._onCancel }
renderHeader = { this._renderMenuHeader }
showSlidingView = { true }>
<ToggleSelfViewButton { ...buttonProps } />
@ -96,26 +82,6 @@ class LocalVideoMenu extends PureComponent<Props> {
);
}
_onCancel: () => boolean;
/**
* Callback to hide the {@code RemoteVideoMenu}.
*
* @private
* @returns {boolean}
*/
_onCancel() {
if (this.props._isOpen) {
this.props.dispatch(hideLocalVideoMenu());
return true;
}
return false;
}
_renderMenuHeader: () => React$Element<any>;
/**
* Function to render the menu's header.
*
@ -151,12 +117,9 @@ function _mapStateToProps(state) {
const participant = getLocalParticipant(state);
return {
_isOpen: isDialogOpen(state, LocalVideoMenu_),
_participant: participant,
_participantDisplayName: getParticipantDisplayName(state, participant.id)
};
}
LocalVideoMenu_ = translate(connect(_mapStateToProps)(LocalVideoMenu));
export default LocalVideoMenu_;
export default translate(connect(_mapStateToProps)(LocalVideoMenu));

View File

@ -1,11 +1,9 @@
// @flow
import React, { PureComponent } from 'react';
import { Text, View } from 'react-native';
import { Divider } from 'react-native-paper';
import { Avatar } from '../../../base/avatar';
import { BottomSheet, isDialogOpen } from '../../../base/dialog';
import { BottomSheet, hideSheet } from '../../../base/dialog';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
import { KICK_OUT_ENABLED, getFeatureFlag } from '../../../base/flags';
import { translate } from '../../../base/i18n';
@ -16,7 +14,6 @@ import {
import { connect } from '../../../base/redux';
import { getBreakoutRooms, getCurrentRoomId } from '../../../breakout-rooms/functions';
import PrivateMessageButton from '../../../chat/components/native/PrivateMessageButton';
import { hideRemoteVideoMenu } from '../../actions.native';
import ConnectionStatusButton from '../native/ConnectionStatusButton';
import AskUnmuteButton from './AskUnmuteButton';
@ -74,11 +71,6 @@ type Props = {
*/
_disableGrantModerator: Boolean,
/**
* True if the menu is currently open, false otherwise.
*/
_isOpen: boolean,
/**
* Whether the participant is present in the room or not.
*/
@ -100,9 +92,6 @@ type Props = {
t: Function
}
// eslint-disable-next-line prefer-const
let RemoteVideoMenu_;
/**
* Class to implement a popup menu that opens upon long pressing a thumbnail.
*/
@ -145,7 +134,6 @@ class RemoteVideoMenu extends PureComponent<Props> {
return (
<BottomSheet
onCancel = { this._onCancel }
renderHeader = { this._renderMenuHeader }
showSlidingView = { _isParticipantAvailable }>
<AskUnmuteButton { ...buttonProps } />
@ -157,7 +145,9 @@ class RemoteVideoMenu extends PureComponent<Props> {
{ !_disableGrantModerator && <GrantModeratorButton { ...buttonProps } /> }
<PinButton { ...buttonProps } />
{ !_disablePrivateChat && <PrivateMessageButton { ...buttonProps } /> }
<ConnectionStatusButton { ...buttonProps } />
<ConnectionStatusButton
{ ...buttonProps }
afterClick = { undefined } />
{_rooms.length > 1 && <>
<Divider style = { styles.divider } />
<View style = { styles.contextMenuItem }>
@ -175,8 +165,6 @@ class RemoteVideoMenu extends PureComponent<Props> {
);
}
_onCancel: () => boolean;
/**
* Callback to hide the {@code RemoteVideoMenu}.
*
@ -184,17 +172,9 @@ class RemoteVideoMenu extends PureComponent<Props> {
* @returns {boolean}
*/
_onCancel() {
if (this.props._isOpen) {
this.props.dispatch(hideRemoteVideoMenu());
return true;
this.props.dispatch(hideSheet());
}
return false;
}
_renderMenuHeader: () => React$Element<any>;
/**
* Function to render the menu's header.
*
@ -242,13 +222,10 @@ function _mapStateToProps(state, ownProps) {
_disableKick: Boolean(shouldDisableKick),
_disableRemoteMute: Boolean(disableRemoteMute),
_disablePrivateChat: Boolean(disablePrivateChat),
_isOpen: isDialogOpen(state, RemoteVideoMenu_),
_isParticipantAvailable: Boolean(isParticipantAvailable),
_participantDisplayName: getParticipantDisplayName(state, participantId),
_rooms
};
}
RemoteVideoMenu_ = translate(connect(_mapStateToProps)(RemoteVideoMenu));
export default RemoteVideoMenu_;
export default translate(connect(_mapStateToProps)(RemoteVideoMenu));

View File

@ -5,7 +5,7 @@ import { Text, View } from 'react-native';
import { Divider } from 'react-native-paper';
import { Avatar } from '../../../base/avatar';
import { BottomSheet, isDialogOpen } from '../../../base/dialog';
import { BottomSheet, hideSheet } from '../../../base/dialog';
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
import {
getParticipantById,
@ -13,7 +13,6 @@ import {
} from '../../../base/participants';
import { connect } from '../../../base/redux';
import { SharedVideoButton } from '../../../shared-video/components';
import { hideSharedVideoMenu } from '../../actions.native';
import styles from './styles';
@ -51,9 +50,6 @@ type Props = {
_participantDisplayName: string,
}
// eslint-disable-next-line prefer-const
let SharedVideoMenu_;
/**
* Class to implement a popup menu that opens upon long pressing a fake participant thumbnail.
*/
@ -90,7 +86,6 @@ class SharedVideoMenu extends PureComponent<Props> {
return (
<BottomSheet
onCancel = { this._onCancel }
renderHeader = { this._renderMenuHeader }
showSlidingView = { _isParticipantAvailable }>
<Divider style = { styles.divider } />
@ -99,8 +94,6 @@ class SharedVideoMenu extends PureComponent<Props> {
);
}
_onCancel: () => boolean;
/**
* Callback to hide the {@code SharedVideoMenu}.
*
@ -108,17 +101,9 @@ class SharedVideoMenu extends PureComponent<Props> {
* @returns {boolean}
*/
_onCancel() {
if (this.props._isOpen) {
this.props.dispatch(hideSharedVideoMenu());
return true;
this.props.dispatch(hideSheet());
}
return false;
}
_renderMenuHeader: () => React$Element<any>;
/**
* Function to render the menu's header.
*
@ -156,12 +141,9 @@ function _mapStateToProps(state, ownProps) {
const isParticipantAvailable = getParticipantById(state, participantId);
return {
_isOpen: isDialogOpen(state, SharedVideoMenu_),
_isParticipantAvailable: Boolean(isParticipantAvailable),
_participantDisplayName: getParticipantDisplayName(state, participantId)
};
}
SharedVideoMenu_ = connect(_mapStateToProps)(SharedVideoMenu);
export default SharedVideoMenu_;
export default connect(_mapStateToProps)(SharedVideoMenu);