fix(android,back-button) rework back button handling on Android
We used to have a registry which registered a single handlerwith RN. THis was registered really early in the app. When React Navigation was introduced we ddidn't realize it interacts with the back button. In a stack nagigator it will navigate to the previous screen. This meant our back button handling was broken. This commit removes our previous registry and uses the RN back button handler directly in the 2 components that use it: the conference and bottom sheets. Since these handlers are registered after navigation, our handlers are going to run first so we cna implement the behavior we need, namely to dismiss an open botom sheet or set the conference in PiP mode.
This commit is contained in:
parent
ef125968ce
commit
26b3eb34f0
|
@ -2,7 +2,6 @@
|
|||
|
||||
import '../authentication/middleware';
|
||||
import '../mobile/audio-mode/middleware';
|
||||
import '../mobile/back-button/middleware';
|
||||
import '../mobile/background/middleware';
|
||||
import '../mobile/call-integration/middleware';
|
||||
import '../mobile/external-api/middleware';
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
import React, { PureComponent, type Node } from 'react';
|
||||
import {
|
||||
Animated,
|
||||
BackHandler,
|
||||
Dimensions,
|
||||
TouchableWithoutFeedback,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import { BackButtonRegistry } from '../../../../mobile/back-button';
|
||||
import { type StyleType } from '../../../styles';
|
||||
|
||||
import styles from './slidingviewstyles';
|
||||
|
@ -121,7 +121,7 @@ export default class SlidingView extends PureComponent<Props, State> {
|
|||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
BackButtonRegistry.addListener(this._onHardwareBackPress, true);
|
||||
BackHandler.addEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
|
||||
this._mounted = true;
|
||||
this._setShow(this.props.show);
|
||||
|
@ -146,7 +146,7 @@ export default class SlidingView extends PureComponent<Props, State> {
|
|||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
BackButtonRegistry.removeListener(this._onHardwareBackPress);
|
||||
BackHandler.removeEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
|
||||
this._mounted = false;
|
||||
}
|
||||
|
@ -229,13 +229,9 @@ export default class SlidingView extends PureComponent<Props, State> {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
_onHardwareBackPress() {
|
||||
const { onHide } = this.props;
|
||||
this._onHide();
|
||||
|
||||
if (typeof onHide === 'function') {
|
||||
return onHide();
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
_onHide: () => void;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { NativeModules, SafeAreaView, StatusBar, View } from 'react-native';
|
||||
import { BackHandler, NativeModules, SafeAreaView, StatusBar, View } from 'react-native';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import { appNavigate } from '../../../app/actions';
|
||||
|
@ -22,7 +22,6 @@ import { CalleeInfoContainer } from '../../../invite';
|
|||
import { LargeVideo } from '../../../large-video';
|
||||
import { KnockingParticipantList } from '../../../lobby/components/native';
|
||||
import { getIsLobbyVisible } from '../../../lobby/functions';
|
||||
import { BackButtonRegistry } from '../../../mobile/back-button';
|
||||
import { navigate }
|
||||
from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
|
@ -166,7 +165,7 @@ class Conference extends AbstractConference<Props, State> {
|
|||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
BackButtonRegistry.addListener(this._onHardwareBackPress);
|
||||
BackHandler.addEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +195,7 @@ class Conference extends AbstractConference<Props, State> {
|
|||
*/
|
||||
componentWillUnmount() {
|
||||
// Tear handling any hardware button presses for back navigation down.
|
||||
BackButtonRegistry.removeListener(this._onHardwareBackPress);
|
||||
BackHandler.removeEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
|
||||
clearTimeout(this._expandedLabelTimeout.current);
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* An registry that dispatches hardware back button events for subscribers with a custom logic.
|
||||
*/
|
||||
class BackButtonRegistry {
|
||||
_listeners: Array<Function>;
|
||||
|
||||
/**
|
||||
* Instantiates a new instance of the registry.
|
||||
*/
|
||||
constructor() {
|
||||
this._listeners = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the registry.
|
||||
*
|
||||
* NOTE: Due to the different order of component mounts, we allow a component to register
|
||||
* its listener to the top of the list, so then that will be invoked before other, 'non-top'
|
||||
* listeners. For example a 'non-top' listener can be the one that puts the app into PiP mode,
|
||||
* while a 'top' listener is the one that closes a modal in a conference.
|
||||
*
|
||||
* @param {Function} listener - The listener function.
|
||||
* @param {boolean?} top - If true, the listener will be put on the top (eg for modal-like components).
|
||||
* @returns {void}
|
||||
*/
|
||||
addListener(listener: Function, top: boolean = false) {
|
||||
if (top) {
|
||||
this._listeners.splice(0, 0, listener);
|
||||
} else {
|
||||
this._listeners.push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the registry.
|
||||
*
|
||||
* @param {Function} listener - The listener to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
removeListener(listener: Function) {
|
||||
this._listeners = this._listeners.filter(f => f !== listener);
|
||||
}
|
||||
|
||||
onHardwareBackPress: () => boolean;
|
||||
|
||||
/**
|
||||
* Callback for the back button press event.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
onHardwareBackPress() {
|
||||
for (const listener of this._listeners) {
|
||||
const result = listener();
|
||||
|
||||
if (result === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default new BackButtonRegistry();
|
|
@ -1,3 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export { default as BackButtonRegistry } from './BackButtonRegistry';
|
|
@ -1,36 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { BackHandler } from 'react-native';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../../base/app';
|
||||
import { MiddlewareRegistry } from '../../base/redux';
|
||||
|
||||
import BackButtonRegistry from './BackButtonRegistry';
|
||||
|
||||
// Binding function to the proper instance, so then the event emitter won't replace the
|
||||
// underlying instance.
|
||||
BackButtonRegistry.onHardwareBackPress = BackButtonRegistry.onHardwareBackPress.bind(BackButtonRegistry);
|
||||
|
||||
/**
|
||||
* Middleware that captures App lifetime actions and subscribes to application
|
||||
* state changes. When the application state changes it will fire the action
|
||||
* required to mute or unmute the local video in case the application goes to
|
||||
* the background or comes back from it.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @returns {Function}
|
||||
* @see {@link https://facebook.github.io/react-native/docs/appstate.html}
|
||||
*/
|
||||
MiddlewareRegistry.register(() => next => action => {
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT:
|
||||
BackHandler.addEventListener('hardwareBackPress', BackButtonRegistry.onHardwareBackPress);
|
||||
break;
|
||||
|
||||
case APP_WILL_UNMOUNT:
|
||||
BackHandler.removeEventListener('hardwareBackPress', BackButtonRegistry.onHardwareBackPress);
|
||||
break;
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
Loading…
Reference in New Issue