Przeglądaj źródła

[RN] Dynamically adjust LargeView's Avatar to available size

When in PiP mode the LargeView will not be large enough to hold the avatar (for
those interested in the details, our avatar's size is 200, and in PiP mode the
app is resized to about 150).

In order to solve it, this PR refactors how the avatar style is passed along,
reducing it to a single "size" prop. With this only prop, the Avatar compononent
will compute the width, height and borderRadius, plus deal with some Android
shenanigans.

In addition, the LargeView component now uses DimensionsDetector to check its
own size and adjust the size prop passed to the Avatar component as needed.
master
Saúl Ibarra Corretgé 7 lat temu
rodzic
commit
1419247801

+ 18
- 4
react/features/base/participants/components/Avatar.native.js Wyświetl plik

6
 import { Platform } from '../../react';
6
 import { Platform } from '../../react';
7
 import { ColorPalette } from '../../styles';
7
 import { ColorPalette } from '../../styles';
8
 
8
 
9
+import styles from './styles';
10
+
9
 /**
11
 /**
10
  * The default image/source to be used in case none is specified or the
12
  * The default image/source to be used in case none is specified or the
11
  * specified one fails to load.
13
  * specified one fails to load.
32
      */
34
      */
33
     static propTypes = {
35
     static propTypes = {
34
         /**
36
         /**
35
-         * The optional style to add to the {@link Avatar} in order to customize
36
-         * its base look (and feel).
37
+         * The size for the {@link Avatar}.
37
          */
38
          */
38
-        style: PropTypes.object,
39
+        size: PropTypes.number,
39
 
40
 
40
         /**
41
         /**
41
          * The URI of the {@link Avatar}.
42
          * The URI of the {@link Avatar}.
216
 
217
 
217
             /* eslint-enable no-unused-vars */
218
             /* eslint-enable no-unused-vars */
218
 
219
 
219
-            style,
220
+            size,
220
             ...props
221
             ...props
221
         } = this.props;
222
         } = this.props;
222
         const {
223
         const {
224
             source
225
             source
225
         } = this.state;
226
         } = this.state;
226
 
227
 
228
+        // Compute the base style
229
+        const style = {
230
+            ...styles.avatar,
231
+
232
+            // XXX Workaround for Android: for radii < 80 the border radius
233
+            // doesn't work properly, but applying a radius twice as big
234
+            // seems to do the trick.
235
+            borderRadius: size / 2 < 80
236
+                ? Platform.OS === 'android' ? size * 2 : size / 2 : size / 2,
237
+            height: size,
238
+            width: size
239
+        };
240
+
227
         // If we're rendering the _DEFAULT_SOURCE, then we want to do some
241
         // If we're rendering the _DEFAULT_SOURCE, then we want to do some
228
         // additional fu like having automagical colors generated per
242
         // additional fu like having automagical colors generated per
229
         // participant, transparency to make the intermediate state while
243
         // participant, transparency to make the intermediate state while

+ 5
- 5
react/features/base/participants/components/ParticipantView.native.js Wyświetl plik

73
         _videoTrack: PropTypes.object,
73
         _videoTrack: PropTypes.object,
74
 
74
 
75
         /**
75
         /**
76
-         * The style, if any, of the avatar in addition to the default style.
76
+         * The avatar size.
77
          */
77
          */
78
-        avatarStyle: PropTypes.object,
78
+        avatarSize: PropTypes.number,
79
 
79
 
80
         /**
80
         /**
81
          * The ID of the participant (to be) depicted by ParticipantView.
81
          * The ID of the participant (to be) depicted by ParticipantView.
145
         }
145
         }
146
 
146
 
147
         const {
147
         const {
148
-            avatarStyle,
148
+            avatarSize,
149
             _participantName: displayName,
149
             _participantName: displayName,
150
             t
150
             t
151
         } = this.props;
151
         } = this.props;
154
         // view and one for the thumbnail. Some of these don't apply to both.
154
         // view and one for the thumbnail. Some of these don't apply to both.
155
         const containerStyle = {
155
         const containerStyle = {
156
             ...styles.connectionInfoContainer,
156
             ...styles.connectionInfoContainer,
157
-            width: avatarStyle.width * 1.5
157
+            width: avatarSize * 1.5
158
         };
158
         };
159
 
159
 
160
         return (
160
         return (
230
                     // rendered.
230
                     // rendered.
231
                     && _toBoolean(this.props.showAvatar, true)
231
                     && _toBoolean(this.props.showAvatar, true)
232
                     && <Avatar
232
                     && <Avatar
233
-                        style = { this.props.avatarStyle }
233
+                        size = { this.props.avatarSize }
234
                         uri = { avatar } /> }
234
                         uri = { avatar } /> }
235
 
235
 
236
                 { useTint
236
                 { useTint

+ 8
- 0
react/features/base/participants/components/styles.js Wyświetl plik

4
  * The styles of the feature base/participants.
4
  * The styles of the feature base/participants.
5
  */
5
  */
6
 export default createStyleSheet({
6
 export default createStyleSheet({
7
+    /**
8
+     * The style of the avatar of the participant.
9
+     */
10
+    avatar: {
11
+        alignSelf: 'center',
12
+        flex: 0
13
+    },
14
+
7
     /**
15
     /**
8
      * Style for the text rendered when there is a connectivity problem.
16
      * Style for the text rendered when there is a connectivity problem.
9
      */
17
      */

+ 3
- 1
react/features/filmstrip/components/Thumbnail.js Wyświetl plik

19
     VideoMutedIndicator
19
     VideoMutedIndicator
20
 } from './_';
20
 } from './_';
21
 
21
 
22
+import { AVATAR_SIZE } from './styles';
23
+
22
 /**
24
 /**
23
  * React component for video thumbnail.
25
  * React component for video thumbnail.
24
  * @extends Component
26
  * @extends Component
94
                             = { audioTrack.jitsiTrack.getOriginalStream() } /> }
96
                             = { audioTrack.jitsiTrack.getOriginalStream() } /> }
95
 
97
 
96
                 <ParticipantView
98
                 <ParticipantView
97
-                    avatarStyle = { styles.avatar }
99
+                    avatarSize = { AVATAR_SIZE }
98
                     participantId = { participantId }
100
                     participantId = { participantId }
99
                     showAvatar = { participantNotInLargeVideo }
101
                     showAvatar = { participantNotInLargeVideo }
100
                     showVideo = { participantNotInLargeVideo }
102
                     showVideo = { participantNotInLargeVideo }

+ 5
- 15
react/features/filmstrip/components/styles.js Wyświetl plik

1
-import { Platform } from '../../base/react';
2
 import { ColorPalette } from '../../base/styles';
1
 import { ColorPalette } from '../../base/styles';
3
 
2
 
3
+/**
4
+ * Size for the Avatar.
5
+ */
6
+export const AVATAR_SIZE = 50;
7
+
4
 /**
8
 /**
5
  * The base style of {@link Filmstrip} shared between narrow and wide versions.
9
  * The base style of {@link Filmstrip} shared between narrow and wide versions.
6
  */
10
  */
13
  * The styles of the feature filmstrip common to both Web and native.
17
  * The styles of the feature filmstrip common to both Web and native.
14
  */
18
  */
15
 export default {
19
 export default {
16
-    /**
17
-     * Avatar style.
18
-     */
19
-    avatar: {
20
-        alignSelf: 'center',
21
-
22
-        // XXX Workaround for Android: for images < 80 the border radius doesn't
23
-        // work properly, but applying a radius twice as big does the trick.
24
-        borderRadius: Platform.OS === 'android' ? 100 : 25,
25
-        flex: 0,
26
-        height: 50,
27
-        width: 50
28
-    },
29
-
30
     /**
20
     /**
31
      * Dominant speaker indicator style.
21
      * Dominant speaker indicator style.
32
      */
22
      */

+ 89
- 20
react/features/large-video/components/LargeVideo.native.js Wyświetl plik

1
-/* @flow */
1
+// @flow
2
 
2
 
3
-import PropTypes from 'prop-types';
4
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
5
 import { connect } from 'react-redux';
4
 import { connect } from 'react-redux';
6
 
5
 
7
 import { ParticipantView } from '../../base/participants';
6
 import { ParticipantView } from '../../base/participants';
7
+import { DimensionsDetector } from '../../base/responsive-ui';
8
 
8
 
9
-import styles from './styles';
9
+import styles, { AVATAR_SIZE } from './styles';
10
+
11
+type Props = {
12
+
13
+    /**
14
+     * The ID of the participant (to be) depicted by LargeVideo.
15
+     *
16
+     * @private
17
+     */
18
+    _participantId: string
19
+};
20
+
21
+type State = {
22
+
23
+    /**
24
+     * Size for the Avatar. It will be dynamically adjusted based on the
25
+     * available size.
26
+     */
27
+    avatarSize: number,
28
+
29
+    /**
30
+     * Whether the connectivity indicator will be shown or not. It will be true
31
+     * by default, but it may be turned off if there is not enough space.
32
+     */
33
+    useConnectivityInfoLabel: boolean
34
+};
35
+
36
+const DEFAULT_STATE = {
37
+    avatarSize: AVATAR_SIZE,
38
+    useConnectivityInfoLabel: true
39
+};
10
 
40
 
11
 /**
41
 /**
12
  * Implements a React {@link Component} which represents the large video (a.k.a.
42
  * Implements a React {@link Component} which represents the large video (a.k.a.
14
  *
44
  *
15
  * @extends Component
45
  * @extends Component
16
  */
46
  */
17
-class LargeVideo extends Component<*> {
47
+class LargeVideo extends Component<Props, State> {
48
+    state = {
49
+        ...DEFAULT_STATE
50
+    };
51
+
52
+    /** Initializes a new {@code LargeVideo} instance.
53
+     *
54
+     * @param {Object} props - The read-only properties with which the new
55
+     * instance is to be initialized.
56
+     */
57
+    constructor(props) {
58
+        super(props);
59
+
60
+        this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
61
+    }
62
+
63
+    _onDimensionsChanged: (width: number, height: number) => void;
64
+
18
     /**
65
     /**
19
-     * LargeVideo component's property types.
66
+     * Handle this component's dimension changes. In case we deem it's too
67
+     * small, the connectivity indicator won't be rendered and the avatar
68
+     * will occupy the entirety of the available screen state.
20
      *
69
      *
21
-     * @static
70
+     * @param {number} width - The component's current width.
71
+     * @param {number} height - The component's current height.
72
+     * @private
73
+     * @returns {void}
22
      */
74
      */
23
-    static propTypes = {
24
-        /**
25
-         * The ID of the participant (to be) depicted by LargeVideo.
26
-         *
27
-         * @private
28
-         */
29
-        _participantId: PropTypes.string
30
-    };
75
+    _onDimensionsChanged(width: number, height: number) {
76
+        // Get the size, rounded to the nearest even number.
77
+        const size = 2 * Math.round(Math.min(height, width) / 2);
78
+
79
+        let newState;
80
+
81
+        if (size < AVATAR_SIZE * 1.5) {
82
+            newState = {
83
+                avatarSize: size - 15, // Leave some margin.
84
+                useConnectivityInfoLabel: false
85
+            };
86
+        } else {
87
+            newState = DEFAULT_STATE;
88
+        }
89
+
90
+        this.setState(newState);
91
+    }
31
 
92
 
32
     /**
93
     /**
33
      * Implements React's {@link Component#render()}.
94
      * Implements React's {@link Component#render()}.
36
      * @returns {ReactElement}
97
      * @returns {ReactElement}
37
      */
98
      */
38
     render() {
99
     render() {
100
+        const {
101
+            avatarSize,
102
+            useConnectivityInfoLabel
103
+        } = this.state;
104
+
39
         return (
105
         return (
40
-            <ParticipantView
41
-                avatarStyle = { styles.avatar }
42
-                participantId = { this.props._participantId }
43
-                style = { styles.largeVideo }
44
-                useConnectivityInfoLabel = { true }
45
-                zOrder = { 0 } />
106
+            <DimensionsDetector
107
+                onDimensionsChanged = { this._onDimensionsChanged } >
108
+                <ParticipantView
109
+                    avatarSize = { avatarSize }
110
+                    participantId = { this.props._participantId }
111
+                    style = { styles.largeVideo }
112
+                    useConnectivityInfoLabel = { useConnectivityInfoLabel }
113
+                    zOrder = { 0 } />
114
+            </DimensionsDetector>
46
         );
115
         );
47
     }
116
     }
48
 }
117
 }

+ 5
- 12
react/features/large-video/components/styles.js Wyświetl plik

1
 import { ColorPalette, createStyleSheet } from '../../base/styles';
1
 import { ColorPalette, createStyleSheet } from '../../base/styles';
2
 
2
 
3
-export default createStyleSheet({
4
-    /**
5
-     * The style of the avatar of the participant displayed in largeVideo. It's
6
-     * an addition to the default style of Avatar.
7
-     */
8
-    avatar: {
9
-        alignSelf: 'center',
10
-        borderRadius: 100,
11
-        flex: 0,
12
-        height: 200,
13
-        width: 200
14
-    },
3
+/**
4
+ * Size for the Avatar.
5
+ */
6
+export const AVATAR_SIZE = 200;
15
 
7
 
8
+export default createStyleSheet({
16
     /**
9
     /**
17
      * Large video container style.
10
      * Large video container style.
18
      */
11
      */

Ładowanie…
Anuluj
Zapisz