Explorar el Código

[Android] Hardware back in Conference and Dialog

j8
Lyubo Marinov hace 8 años
padre
commit
03d337612b

+ 44
- 20
react/features/base/dialog/components/Dialog.native.js Ver fichero

@@ -1,6 +1,6 @@
1 1
 import PropTypes from 'prop-types';
2 2
 import React from 'react';
3
-import { StyleSheet, TextInput } from 'react-native';
3
+import { Modal, StyleSheet, TextInput } from 'react-native';
4 4
 import Prompt from 'react-native-prompt';
5 5
 import { connect } from 'react-redux';
6 6
 
@@ -99,13 +99,33 @@ class Dialog extends AbstractDialog {
99 99
 
100 100
         // eslint-disable-next-line no-shadow
101 101
         element = this._mapReactElement(element, element => {
102
-            // * If this Dialog has children, they are to be rendered instead of
103
-            //   Prompt's TextInput.
104
-            if (element.type === TextInput) {
102
+            const { type } = element;
103
+
104
+            if (type === Modal) {
105
+                // * Modal handles hardware button presses for back navigation.
106
+                //   Firstly, we don't want Prompt's default behavior to merely
107
+                //   hide the Modal - we want this Dialog to be canceled.
108
+                //   Secondly, we cannot get Prompt's default behavior anyway
109
+                //   because we've removed Prompt and we're preserving whatever
110
+                //   it's rendered only.
111
+                return (
112
+                    React.cloneElement(
113
+                        element,
114
+                        /* props */ {
115
+                            onRequestClose: this._onCancel
116
+                        },
117
+                        ...React.Children.toArray(element.props.children))
118
+                );
119
+            }
120
+
121
+            if (type === TextInput) {
122
+                // * If this Dialog has children, they are to be rendered
123
+                //   instead of Prompt's TextInput.
105 124
                 if (children) {
106 125
                     element = children; // eslint-disable-line no-param-reassign
107 126
                     children = undefined;
108 127
                 }
128
+
109 129
             } else {
110 130
                 let { style } = element.props;
111 131
 
@@ -126,14 +146,14 @@ class Dialog extends AbstractDialog {
126 146
                         break;
127 147
                     }
128 148
 
129
-                    // eslint-disable-next-line no-param-reassign
130
-                    element
131
-                        = React.cloneElement(
149
+                    return (
150
+                        React.cloneElement(
132 151
                             element,
133 152
                             /* props */ {
134 153
                                 style: set(style, _TAG_KEY, undefined)
135 154
                             },
136
-                            ...React.Children.toArray(element.props.children));
155
+                            ...React.Children.toArray(element.props.children))
156
+                    );
137 157
                 }
138 158
             }
139 159
 
@@ -162,18 +182,22 @@ class Dialog extends AbstractDialog {
162 182
 
163 183
         let mapped = f(element);
164 184
 
165
-        if (mapped === element) {
166
-            mapped
167
-                = React.cloneElement(
168
-                    element,
169
-                    /* props */ undefined,
170
-                    ...React.Children.toArray(React.Children.map(
171
-                        element.props.children,
172
-                        function(element) { // eslint-disable-line no-shadow
173
-                            // eslint-disable-next-line no-invalid-this
174
-                            return this._mapReactElement(element, f);
175
-                        },
176
-                        this)));
185
+        if (mapped) {
186
+            const { children } = mapped.props;
187
+
188
+            if (mapped === element || React.Children.count(children)) {
189
+                mapped
190
+                    = React.cloneElement(
191
+                        mapped,
192
+                        /* props */ undefined,
193
+                        ...React.Children.toArray(React.Children.map(
194
+                            children,
195
+                            function(element) { // eslint-disable-line no-shadow
196
+                                // eslint-disable-next-line no-invalid-this
197
+                                return this._mapReactElement(element, f);
198
+                            },
199
+                            this)));
200
+            }
177 201
         }
178 202
 
179 203
         return mapped;

+ 71
- 7
react/features/conference/components/Conference.native.js Ver fichero

@@ -1,8 +1,11 @@
1 1
 import PropTypes from 'prop-types';
2 2
 import React, { Component } from 'react';
3
-import { View } from 'react-native';
3
+
4
+// eslint-disable-next-line react-native/split-platform-components
5
+import { BackAndroid, BackHandler, View } from 'react-native';
4 6
 import { connect as reactReduxConnect } from 'react-redux';
5 7
 
8
+import { appNavigate } from '../../app';
6 9
 import { connect, disconnect } from '../../base/connection';
7 10
 import { DialogContainer } from '../../base/dialog';
8 11
 import { Container, LoadingIndicator } from '../../base/react';
@@ -56,6 +59,17 @@ class Conference extends Component {
56 59
          */
57 60
         _onDisconnect: PropTypes.func,
58 61
 
62
+        /**
63
+         * Handles a hardware button press for back navigation. Leaves the
64
+         * associated <tt>Conference</tt>.
65
+         *
66
+         * @private
67
+         * @returns {boolean} As the associated conference is unconditionally
68
+         * left and exiting the app while it renders a <tt>Conference</tt> is
69
+         * undesired, <tt>true</tt> is always returned.
70
+         */
71
+        _onHardwareBackPress: PropTypes.func,
72
+
59 73
         /**
60 74
          * The handler which dispatches the (redux) action setToolboxVisible to
61 75
          * show/hide the Toolbox.
@@ -90,22 +104,36 @@ class Conference extends Component {
90 104
          */
91 105
         this._toolboxTimeout = undefined;
92 106
 
93
-        // Bind event handlers so they are only bound once for every instance.
107
+        // Bind event handlers so they are only bound once per instance.
94 108
         this._onClick = this._onClick.bind(this);
109
+        this._onHardwareBackPress = this._onHardwareBackPress.bind(this);
95 110
     }
96 111
 
97 112
     /**
98
-     * Inits the Toolbox timeout after the component is initially rendered.
113
+     * Implements {@link Component#componentDidMount()}. Invoked immediately
114
+     * after this component is mounted.
99 115
      *
100 116
      * @inheritdoc
101 117
      * returns {void}
102 118
      */
103 119
     componentDidMount() {
120
+        // Set handling any hardware button presses for back navigation up.
121
+        const backHandler = BackHandler || BackAndroid;
122
+
123
+        if (backHandler) {
124
+            this._backHandler = backHandler;
125
+            backHandler.addEventListener(
126
+                'hardwareBackPress',
127
+                this._onHardwareBackPress);
128
+        }
129
+
104 130
         this._setToolboxTimeout(this.props._toolboxVisible);
105 131
     }
106 132
 
107 133
     /**
108
-     * Inits new connection and conference when conference screen is entered.
134
+     * Implements {@link Component#componentWillMount()}. Invoked immediately
135
+     * before mounting occurs. Connects the conference described by the redux
136
+     * store/state.
109 137
      *
110 138
      * @inheritdoc
111 139
      * @returns {void}
@@ -115,13 +143,24 @@ class Conference extends Component {
115 143
     }
116 144
 
117 145
     /**
118
-     * Destroys connection, conference and local tracks when conference screen
119
-     * is left. Clears {@link #_toolboxTimeout} before the component unmounts.
146
+     * Implements {@link Component#componentWillUnmount()}. Invoked immediately
147
+     * before this component is unmounted and destroyed. Disconnects the
148
+     * conference described by the redux store/state.
120 149
      *
121 150
      * @inheritdoc
122 151
      * @returns {void}
123 152
      */
124 153
     componentWillUnmount() {
154
+        // Tear handling any hardware button presses for back navigation down.
155
+        const backHandler = this._backHandler;
156
+
157
+        if (backHandler) {
158
+            this._backHandler = undefined;
159
+            backHandler.removeEventListener(
160
+                'hardwareBackPress',
161
+                this._onHardwareBackPress);
162
+        }
163
+
125 164
         this._clearToolboxTimeout();
126 165
 
127 166
         this.props._onDisconnect();
@@ -210,6 +249,17 @@ class Conference extends Component {
210 249
         this._setToolboxTimeout(toolboxVisible);
211 250
     }
212 251
 
252
+    /**
253
+     * Handles a hardware button press for back navigation.
254
+     *
255
+     * @returns {boolean} If the hardware button press for back navigation was
256
+     * handled by this <tt>Conference</tt>, then <tt>true</tt>; otherwise,
257
+     * <tt>false</tt>.
258
+     */
259
+    _onHardwareBackPress() {
260
+        return this._backHandler && this.props._onHardwareBackPress();
261
+    }
262
+
213 263
     /**
214 264
      * Triggers the default Toolbox timeout.
215 265
      *
@@ -263,7 +313,21 @@ function _mapDispatchToProps(dispatch) {
263 313
         },
264 314
 
265 315
         /**
266
-         * Dispatches an action changing the visiblity of the Toolbox.
316
+         * Handles a hardware button press for back navigation. Leaves the
317
+         * associated <tt>Conference</tt>.
318
+         *
319
+         * @returns {boolean} As the associated conference is unconditionally
320
+         * left and exiting the app while it renders a <tt>Conference</tt> is
321
+         * undesired, <tt>true</tt> is always returned.
322
+         */
323
+        _onHardwareBackPress() {
324
+            dispatch(appNavigate(undefined));
325
+
326
+            return true;
327
+        },
328
+
329
+        /**
330
+         * Dispatches an action changing the visibility of the Toolbox.
267 331
          *
268 332
          * @param {boolean} visible - True to show the Toolbox or false to hide
269 333
          * it.

Loading…
Cancelar
Guardar