Bladeren bron

[RN] LoadingIndicator on WelcomePage

It will replace the "Join" text button while appNavigate lasts.

Note about the implementation: when appNavigate completes the component
may have been unmounted and thus we cannot touch its state. In order to
avoid this problem I added a 'mounted' instance variable which gets set
and reset in componentWillMount / Unmount respectively. This is to avoid
using isMounted, which is highly discouraged.
j8
Saúl Ibarra Corretgé 8 jaren geleden
bovenliggende
commit
ca13a9b914

+ 29
- 4
react/features/welcome/components/AbstractWelcomePage.js Bestand weergeven

@@ -48,6 +48,7 @@ export class AbstractWelcomePage extends Component {
48 48
         this.state = {
49 49
             animateTimeoutId: null,
50 50
             generatedRoomname: '',
51
+            joining: false,
51 52
             room: '',
52 53
             roomPlaceholder: '',
53 54
             updateTimeoutId: null
@@ -62,7 +63,18 @@ export class AbstractWelcomePage extends Component {
62 63
     }
63 64
 
64 65
     /**
65
-     * This method is executed when component receives new properties.
66
+     * Implements React's {@link Component#componentWillMount()}. Invoked
67
+     * immediately before mounting occurs.
68
+     *
69
+     * @inheritdoc
70
+     */
71
+    componentWillMount() {
72
+        this._mounted = true;
73
+    }
74
+
75
+    /**
76
+     * Implements React's {@link Component#componentWillReceiveProps()}. Invoked
77
+     * before this mounted component receives new props.
66 78
      *
67 79
      * @inheritdoc
68 80
      * @param {Object} nextProps - New props component will receive.
@@ -72,12 +84,14 @@ export class AbstractWelcomePage extends Component {
72 84
     }
73 85
 
74 86
     /**
75
-     * This method is executed when method will be unmounted from DOM.
87
+     * Implements React's {@link Component#componentWillUnmount()}. Invoked
88
+     * immediately before this component is unmounted and destroyed.
76 89
      *
77 90
      * @inheritdoc
78 91
      */
79 92
     componentWillUnmount() {
80 93
         this._clearTimeouts();
94
+        this._mounted = false;
81 95
     }
82 96
 
83 97
     /**
@@ -128,7 +142,7 @@ export class AbstractWelcomePage extends Component {
128 142
      * otherwise, false.
129 143
      */
130 144
     _isJoinDisabled() {
131
-        return !isRoomValid(this.state.room);
145
+        return this.state.joining || !isRoomValid(this.state.room);
132 146
     }
133 147
 
134 148
     /**
@@ -141,7 +155,18 @@ export class AbstractWelcomePage extends Component {
141 155
     _onJoin() {
142 156
         const room = this.state.room || this.state.generatedRoomname;
143 157
 
144
-        room && this.props.dispatch(appNavigate(room));
158
+        if (room) {
159
+            this.setState({ joining: true });
160
+
161
+            // By the time the Promise of appNavigate settles, this component
162
+            // may have already been unmounted.
163
+            const onAppNavigateSettled = () => {
164
+                this._mounted && this.setState({ joining: false });
165
+            };
166
+
167
+            this.props.dispatch(appNavigate(room))
168
+                .then(onAppNavigateSettled, onAppNavigateSettled);
169
+        }
145 170
     }
146 171
 
147 172
     /**

+ 56
- 13
react/features/welcome/components/WelcomePage.native.js Bestand weergeven

@@ -4,7 +4,7 @@ import { connect } from 'react-redux';
4 4
 
5 5
 import { translate } from '../../base/i18n';
6 6
 import { MEDIA_TYPE } from '../../base/media';
7
-import { Link, Text } from '../../base/react';
7
+import { Link, LoadingIndicator, Text } from '../../base/react';
8 8
 import { ColorPalette } from '../../base/styles';
9 9
 import { createDesiredLocalTracks } from '../../base/tracks';
10 10
 
@@ -41,18 +41,24 @@ class WelcomePage extends AbstractWelcomePage {
41 41
     static propTypes = AbstractWelcomePage.propTypes;
42 42
 
43 43
     /**
44
-     * Creates a video track if not already available.
44
+     * Implements React's {@link Component#componentWillMount()}. Invoked
45
+     * immediately before mounting occurs. Creates a local video track if none
46
+     * is available.
45 47
      *
46 48
      * @inheritdoc
47 49
      * @returns {void}
48 50
      */
49 51
     componentWillMount() {
52
+        super.componentWillMount();
53
+
50 54
         this.props.dispatch(createDesiredLocalTracks(MEDIA_TYPE.VIDEO));
51 55
     }
52 56
 
53 57
     /**
54
-     * Renders a prompt for entering a room name.
58
+     * Implements React's {@link Component#render()}. Renders a prompt for
59
+     * entering a room name.
55 60
      *
61
+     * @inheritdoc
56 62
      * @returns {ReactElement}
57 63
      */
58 64
     render() {
@@ -75,16 +81,9 @@ class WelcomePage extends AbstractWelcomePage {
75 81
                         style = { styles.textInput }
76 82
                         underlineColorAndroid = 'transparent'
77 83
                         value = { this.state.room } />
78
-                    <TouchableHighlight
79
-                        accessibilityLabel = { 'Tap to Join.' }
80
-                        disabled = { this._isJoinDisabled() }
81
-                        onPress = { this._onJoin }
82
-                        style = { styles.button }
83
-                        underlayColor = { ColorPalette.white }>
84
-                        <Text style = { styles.buttonText }>
85
-                            { t('welcomepage.join') }
86
-                        </Text>
87
-                    </TouchableHighlight>
84
+                    {
85
+                        this._renderJoinButton()
86
+                    }
88 87
                 </View>
89 88
                 {
90 89
                     this._renderLegalese()
@@ -93,6 +92,50 @@ class WelcomePage extends AbstractWelcomePage {
93 92
         );
94 93
     }
95 94
 
95
+    /**
96
+     * Renders the join button.
97
+     *
98
+     * @private
99
+     * @returns {ReactElement}
100
+     */
101
+    _renderJoinButton() {
102
+        let children;
103
+
104
+        /* eslint-disable no-extra-parens */
105
+
106
+        if (this.state.joining) {
107
+            // TouchableHighlight is picky about what its children can be, so
108
+            // wrap it in a native component, i.e. View to avoid having to
109
+            // modify non-native children.
110
+            children = (
111
+                <View>
112
+                    <LoadingIndicator />
113
+                </View>
114
+            );
115
+        } else {
116
+            children = (
117
+                <Text style = { styles.buttonText }>
118
+                    { this.props.t('welcomepage.join') }
119
+                </Text>
120
+            );
121
+        }
122
+
123
+        /* eslint-enable no-extra-parens */
124
+
125
+        return (
126
+            <TouchableHighlight
127
+                accessibilityLabel = { 'Tap to Join.' }
128
+                disabled = { this._isJoinDisabled() }
129
+                onPress = { this._onJoin }
130
+                style = { styles.button }
131
+                underlayColor = { ColorPalette.white }>
132
+                {
133
+                    children
134
+                }
135
+            </TouchableHighlight>
136
+        );
137
+    }
138
+
96 139
     /**
97 140
      * Renders legal-related content such as Terms of service/use, Privacy
98 141
      * policy, etc.

+ 2
- 1
react/features/welcome/components/WelcomePage.web.js Bestand weergeven

@@ -38,7 +38,8 @@ class WelcomePage extends AbstractWelcomePage {
38 38
     }
39 39
 
40 40
     /**
41
-     * This method is executed when comonent is mounted.
41
+     * Implements React's {@link Component#componentDidMount()}. Invoked
42
+     * immediately after this component is mounted.
42 43
      *
43 44
      * @inheritdoc
44 45
      * @returns {void}

Laden…
Annuleren
Opslaan