[Android] Hardware back in Conference and Dialog
This commit is contained in:
parent
46b75e5178
commit
03d337612b
|
@ -1,6 +1,6 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, TextInput } from 'react-native';
|
import { Modal, StyleSheet, TextInput } from 'react-native';
|
||||||
import Prompt from 'react-native-prompt';
|
import Prompt from 'react-native-prompt';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
@ -99,13 +99,33 @@ class Dialog extends AbstractDialog {
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
element = this._mapReactElement(element, element => {
|
element = this._mapReactElement(element, element => {
|
||||||
// * If this Dialog has children, they are to be rendered instead of
|
const { type } = element;
|
||||||
// Prompt's TextInput.
|
|
||||||
if (element.type === TextInput) {
|
if (type === Modal) {
|
||||||
|
// * Modal handles hardware button presses for back navigation.
|
||||||
|
// Firstly, we don't want Prompt's default behavior to merely
|
||||||
|
// hide the Modal - we want this Dialog to be canceled.
|
||||||
|
// Secondly, we cannot get Prompt's default behavior anyway
|
||||||
|
// because we've removed Prompt and we're preserving whatever
|
||||||
|
// it's rendered only.
|
||||||
|
return (
|
||||||
|
React.cloneElement(
|
||||||
|
element,
|
||||||
|
/* props */ {
|
||||||
|
onRequestClose: this._onCancel
|
||||||
|
},
|
||||||
|
...React.Children.toArray(element.props.children))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === TextInput) {
|
||||||
|
// * If this Dialog has children, they are to be rendered
|
||||||
|
// instead of Prompt's TextInput.
|
||||||
if (children) {
|
if (children) {
|
||||||
element = children; // eslint-disable-line no-param-reassign
|
element = children; // eslint-disable-line no-param-reassign
|
||||||
children = undefined;
|
children = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let { style } = element.props;
|
let { style } = element.props;
|
||||||
|
|
||||||
|
@ -126,14 +146,14 @@ class Dialog extends AbstractDialog {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
return (
|
||||||
element
|
React.cloneElement(
|
||||||
= React.cloneElement(
|
|
||||||
element,
|
element,
|
||||||
/* props */ {
|
/* props */ {
|
||||||
style: set(style, _TAG_KEY, undefined)
|
style: set(style, _TAG_KEY, undefined)
|
||||||
},
|
},
|
||||||
...React.Children.toArray(element.props.children));
|
...React.Children.toArray(element.props.children))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,18 +182,22 @@ class Dialog extends AbstractDialog {
|
||||||
|
|
||||||
let mapped = f(element);
|
let mapped = f(element);
|
||||||
|
|
||||||
if (mapped === element) {
|
if (mapped) {
|
||||||
mapped
|
const { children } = mapped.props;
|
||||||
= React.cloneElement(
|
|
||||||
element,
|
if (mapped === element || React.Children.count(children)) {
|
||||||
/* props */ undefined,
|
mapped
|
||||||
...React.Children.toArray(React.Children.map(
|
= React.cloneElement(
|
||||||
element.props.children,
|
mapped,
|
||||||
function(element) { // eslint-disable-line no-shadow
|
/* props */ undefined,
|
||||||
// eslint-disable-next-line no-invalid-this
|
...React.Children.toArray(React.Children.map(
|
||||||
return this._mapReactElement(element, f);
|
children,
|
||||||
},
|
function(element) { // eslint-disable-line no-shadow
|
||||||
this)));
|
// eslint-disable-next-line no-invalid-this
|
||||||
|
return this._mapReactElement(element, f);
|
||||||
|
},
|
||||||
|
this)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapped;
|
return mapped;
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { View } from 'react-native';
|
|
||||||
|
// eslint-disable-next-line react-native/split-platform-components
|
||||||
|
import { BackAndroid, BackHandler, View } from 'react-native';
|
||||||
import { connect as reactReduxConnect } from 'react-redux';
|
import { connect as reactReduxConnect } from 'react-redux';
|
||||||
|
|
||||||
|
import { appNavigate } from '../../app';
|
||||||
import { connect, disconnect } from '../../base/connection';
|
import { connect, disconnect } from '../../base/connection';
|
||||||
import { DialogContainer } from '../../base/dialog';
|
import { DialogContainer } from '../../base/dialog';
|
||||||
import { Container, LoadingIndicator } from '../../base/react';
|
import { Container, LoadingIndicator } from '../../base/react';
|
||||||
|
@ -56,6 +59,17 @@ class Conference extends Component {
|
||||||
*/
|
*/
|
||||||
_onDisconnect: PropTypes.func,
|
_onDisconnect: PropTypes.func,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a hardware button press for back navigation. Leaves the
|
||||||
|
* associated <tt>Conference</tt>.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {boolean} As the associated conference is unconditionally
|
||||||
|
* left and exiting the app while it renders a <tt>Conference</tt> is
|
||||||
|
* undesired, <tt>true</tt> is always returned.
|
||||||
|
*/
|
||||||
|
_onHardwareBackPress: PropTypes.func,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The handler which dispatches the (redux) action setToolboxVisible to
|
* The handler which dispatches the (redux) action setToolboxVisible to
|
||||||
* show/hide the Toolbox.
|
* show/hide the Toolbox.
|
||||||
|
@ -90,22 +104,36 @@ class Conference extends Component {
|
||||||
*/
|
*/
|
||||||
this._toolboxTimeout = undefined;
|
this._toolboxTimeout = undefined;
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once for every instance.
|
// Bind event handlers so they are only bound once per instance.
|
||||||
this._onClick = this._onClick.bind(this);
|
this._onClick = this._onClick.bind(this);
|
||||||
|
this._onHardwareBackPress = this._onHardwareBackPress.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inits the Toolbox timeout after the component is initially rendered.
|
* Implements {@link Component#componentDidMount()}. Invoked immediately
|
||||||
|
* after this component is mounted.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
* returns {void}
|
* returns {void}
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
// Set handling any hardware button presses for back navigation up.
|
||||||
|
const backHandler = BackHandler || BackAndroid;
|
||||||
|
|
||||||
|
if (backHandler) {
|
||||||
|
this._backHandler = backHandler;
|
||||||
|
backHandler.addEventListener(
|
||||||
|
'hardwareBackPress',
|
||||||
|
this._onHardwareBackPress);
|
||||||
|
}
|
||||||
|
|
||||||
this._setToolboxTimeout(this.props._toolboxVisible);
|
this._setToolboxTimeout(this.props._toolboxVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inits new connection and conference when conference screen is entered.
|
* Implements {@link Component#componentWillMount()}. Invoked immediately
|
||||||
|
* before mounting occurs. Connects the conference described by the redux
|
||||||
|
* store/state.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
|
@ -115,13 +143,24 @@ class Conference extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys connection, conference and local tracks when conference screen
|
* Implements {@link Component#componentWillUnmount()}. Invoked immediately
|
||||||
* is left. Clears {@link #_toolboxTimeout} before the component unmounts.
|
* before this component is unmounted and destroyed. Disconnects the
|
||||||
|
* conference described by the redux store/state.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
// Tear handling any hardware button presses for back navigation down.
|
||||||
|
const backHandler = this._backHandler;
|
||||||
|
|
||||||
|
if (backHandler) {
|
||||||
|
this._backHandler = undefined;
|
||||||
|
backHandler.removeEventListener(
|
||||||
|
'hardwareBackPress',
|
||||||
|
this._onHardwareBackPress);
|
||||||
|
}
|
||||||
|
|
||||||
this._clearToolboxTimeout();
|
this._clearToolboxTimeout();
|
||||||
|
|
||||||
this.props._onDisconnect();
|
this.props._onDisconnect();
|
||||||
|
@ -210,6 +249,17 @@ class Conference extends Component {
|
||||||
this._setToolboxTimeout(toolboxVisible);
|
this._setToolboxTimeout(toolboxVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a hardware button press for back navigation.
|
||||||
|
*
|
||||||
|
* @returns {boolean} If the hardware button press for back navigation was
|
||||||
|
* handled by this <tt>Conference</tt>, then <tt>true</tt>; otherwise,
|
||||||
|
* <tt>false</tt>.
|
||||||
|
*/
|
||||||
|
_onHardwareBackPress() {
|
||||||
|
return this._backHandler && this.props._onHardwareBackPress();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers the default Toolbox timeout.
|
* Triggers the default Toolbox timeout.
|
||||||
*
|
*
|
||||||
|
@ -263,7 +313,21 @@ function _mapDispatchToProps(dispatch) {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches an action changing the visiblity of the Toolbox.
|
* Handles a hardware button press for back navigation. Leaves the
|
||||||
|
* associated <tt>Conference</tt>.
|
||||||
|
*
|
||||||
|
* @returns {boolean} As the associated conference is unconditionally
|
||||||
|
* left and exiting the app while it renders a <tt>Conference</tt> is
|
||||||
|
* undesired, <tt>true</tt> is always returned.
|
||||||
|
*/
|
||||||
|
_onHardwareBackPress() {
|
||||||
|
dispatch(appNavigate(undefined));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches an action changing the visibility of the Toolbox.
|
||||||
*
|
*
|
||||||
* @param {boolean} visible - True to show the Toolbox or false to hide
|
* @param {boolean} visible - True to show the Toolbox or false to hide
|
||||||
* it.
|
* it.
|
||||||
|
|
Loading…
Reference in New Issue