Browse Source

rn,flags: add more feature flags to toggle specific behavior

- Invite funcionality (altogether)
- Recording
- Live streaming
- Meeting name
- Meeting password
master
Saúl Ibarra Corretgé 5 years ago
parent
commit
e5b563ba46

+ 32
- 0
react/features/base/flags/constants.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
+/**
4
+ * Flag indicating if add-people functionality should be enabled.
5
+ * Default: enabled (true).
6
+ */
7
+export const ADD_PEOPLE_ENABLED = 'add-people.enabled';
8
+
3
 /**
9
 /**
4
  * Flag indicating if calendar integration should be enabled.
10
  * Flag indicating if calendar integration should be enabled.
5
  * Default: enabled (true) on Android, auto-detected on iOS.
11
  * Default: enabled (true) on Android, auto-detected on iOS.
37
  */
43
  */
38
 export const IOS_RECORDING_ENABLED = 'ios.recording.enabled';
44
 export const IOS_RECORDING_ENABLED = 'ios.recording.enabled';
39
 
45
 
46
+/**
47
+ * Flag indicating if live-streaming should be enabled.
48
+ * Default: auto-detected.
49
+ */
50
+export const LIVE_STREAMING_ENABLED = 'live-streaming.enabled';
51
+
52
+/**
53
+ * Flag indicating if displaying the meeting name should be enabled.
54
+ * Default: enabled (true).
55
+ */
56
+export const MEETING_NAME_ENABLED = 'meeting-name.enabled';
57
+
58
+/**
59
+ * Flag indicating if the meeting password button should be enabled.
60
+ * Note that this flag just decides on the buttton, if a meeting has a password
61
+ * set, the password ddialog will still show up.
62
+ * Default: enabled (true).
63
+ */
64
+export const MEETING_PASSWORD_ENABLED = 'meeting-password.enabled';
65
+
40
 /**
66
 /**
41
  * Flag indicating if Picture-in-Picture should be enabled.
67
  * Flag indicating if Picture-in-Picture should be enabled.
42
  * Default: auto-detected.
68
  * Default: auto-detected.
43
  */
69
  */
44
 export const PIP_ENABLED = 'pip.enabled';
70
 export const PIP_ENABLED = 'pip.enabled';
45
 
71
 
72
+/**
73
+ * Flag indicating if recording should be enabled.
74
+ * Default: auto-detected.
75
+ */
76
+export const RECORDING_ENABLED = 'recording.enabled';
77
+
46
 /**
78
 /**
47
  * Flag indicating if the welcome page should be enabled.
79
  * Flag indicating if the welcome page should be enabled.
48
  * Default: disabled (false).
80
  * Default: disabled (false).

+ 8
- 5
react/features/chat/components/native/ChatButton.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
+import { CHAT_ENABLED, getFeatureFlag } from '../../../base/flags';
3
 import { IconChat, IconChatUnread } from '../../../base/icons';
4
 import { IconChat, IconChatUnread } from '../../../base/icons';
4
 import { setActiveModalId } from '../../../base/modal';
5
 import { setActiveModalId } from '../../../base/modal';
5
 import { getLocalParticipant } from '../../../base/participants';
6
 import { getLocalParticipant } from '../../../base/participants';
114
  * Maps part of the redux state to the component's props.
115
  * Maps part of the redux state to the component's props.
115
  *
116
  *
116
  * @param {Object} state - The Redux state.
117
  * @param {Object} state - The Redux state.
117
- * @returns {{
118
- *     _unreadMessageCount
119
- * }}
118
+ * @param {Object} ownProps - The properties explicitly passed to the component instance.
119
+ * @returns {Props}
120
  */
120
  */
121
-function _mapStateToProps(state) {
121
+function _mapStateToProps(state, ownProps) {
122
     const localParticipant = getLocalParticipant(state);
122
     const localParticipant = getLocalParticipant(state);
123
+    const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
124
+    const { visible = enabled } = ownProps;
123
 
125
 
124
     return {
126
     return {
125
         _showNamePrompt: !localParticipant.name,
127
         _showNamePrompt: !localParticipant.name,
126
-        _unreadMessageCount: getUnreadCount(state)
128
+        _unreadMessageCount: getUnreadCount(state),
129
+        visible
127
     };
130
     };
128
 }
131
 }
129
 
132
 

+ 4
- 2
react/features/conference/components/native/LonelyMeetingExperience.js View File

4
 import { Text, TouchableOpacity, View } from 'react-native';
4
 import { Text, TouchableOpacity, View } from 'react-native';
5
 
5
 
6
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
6
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
7
+import { getFeatureFlag, INVITE_ENABLED } from '../../../base/flags';
8
+import { translate } from '../../../base/i18n';
7
 import { connect } from '../../../base/redux';
9
 import { connect } from '../../../base/redux';
8
 import { StyleType } from '../../../base/styles';
10
 import { StyleType } from '../../../base/styles';
9
-import { translate } from '../../../base/i18n';
10
 import { getParticipantCount } from '../../../base/participants';
11
 import { getParticipantCount } from '../../../base/participants';
11
 import { doInvitePeople } from '../../../invite/actions.native';
12
 import { doInvitePeople } from '../../../invite/actions.native';
12
 
13
 
125
  */
126
  */
126
 function _mapStateToProps(state): $Shape<Props> {
127
 function _mapStateToProps(state): $Shape<Props> {
127
     const { disableInviteFunctions } = state['features/base/config'];
128
     const { disableInviteFunctions } = state['features/base/config'];
129
+    const flag = getFeatureFlag(state, INVITE_ENABLED, true);
128
 
130
 
129
     return {
131
     return {
130
-        _isInviteFunctionsDiabled: disableInviteFunctions,
132
+        _isInviteFunctionsDiabled: !flag || disableInviteFunctions,
131
         _isLonelyMeeting: getParticipantCount(state) === 1,
133
         _isLonelyMeeting: getParticipantCount(state) === 1,
132
         _styles: ColorSchemeRegistry.get(state, 'Conference')
134
         _styles: ColorSchemeRegistry.get(state, 'Conference')
133
     };
135
     };

+ 16
- 9
react/features/conference/components/native/NavigationBar.js View File

5
 import LinearGradient from 'react-native-linear-gradient';
5
 import LinearGradient from 'react-native-linear-gradient';
6
 
6
 
7
 import { getConferenceName } from '../../../base/conference';
7
 import { getConferenceName } from '../../../base/conference';
8
+import { getFeatureFlag, MEETING_NAME_ENABLED } from '../../../base/flags';
8
 import { connect } from '../../../base/redux';
9
 import { connect } from '../../../base/redux';
9
 import { PictureInPictureButton } from '../../../mobile/picture-in-picture';
10
 import { PictureInPictureButton } from '../../../mobile/picture-in-picture';
10
 import { isToolboxVisible } from '../../../toolbox';
11
 import { isToolboxVisible } from '../../../toolbox';
19
      */
20
      */
20
     _meetingName: string,
21
     _meetingName: string,
21
 
22
 
23
+    /**
24
+     * Whether displaying the current meeting name is enabled or not.
25
+     */
26
+    _meetingNameEnabled: boolean,
27
+
22
     /**
28
     /**
23
      * True if the navigation bar should be visible.
29
      * True if the navigation bar should be visible.
24
      */
30
      */
59
                 <View
65
                 <View
60
                     pointerEvents = 'box-none'
66
                     pointerEvents = 'box-none'
61
                     style = { styles.roomNameWrapper }>
67
                     style = { styles.roomNameWrapper }>
62
-                    <Text
63
-                        numberOfLines = { 1 }
64
-                        style = { styles.roomName }>
65
-                        { this.props._meetingName }
66
-                    </Text>
68
+                    {
69
+                        this.props._meetingNameEnabled
70
+                        && <Text
71
+                            numberOfLines = { 1 }
72
+                            style = { styles.roomName }>
73
+                            { this.props._meetingName }
74
+                        </Text>
75
+                    }
67
                     <ConferenceTimer />
76
                     <ConferenceTimer />
68
                 </View>
77
                 </View>
69
             </View>
78
             </View>
76
  * Maps part of the Redux store to the props of this component.
85
  * Maps part of the Redux store to the props of this component.
77
  *
86
  *
78
  * @param {Object} state - The Redux state.
87
  * @param {Object} state - The Redux state.
79
- * @returns {{
80
- *     _meetingName: string,
81
- *     _visible: boolean
82
- * }}
88
+ * @returns {Props}
83
  */
89
  */
84
 function _mapStateToProps(state) {
90
 function _mapStateToProps(state) {
85
     return {
91
     return {
86
         _meetingName: getConferenceName(state),
92
         _meetingName: getConferenceName(state),
93
+        _meetingNameEnabled: getFeatureFlag(state, MEETING_NAME_ENABLED, true),
87
         _visible: isToolboxVisible(state)
94
         _visible: isToolboxVisible(state)
88
     };
95
     };
89
 }
96
 }

+ 2
- 2
react/features/invite/actions.native.js View File

2
 
2
 
3
 import type { Dispatch } from 'redux';
3
 import type { Dispatch } from 'redux';
4
 
4
 
5
-import { getFeatureFlag, INVITE_ENABLED } from '../base/flags';
5
+import { getFeatureFlag, ADD_PEOPLE_ENABLED } from '../base/flags';
6
 import { setActiveModalId } from '../base/modal';
6
 import { setActiveModalId } from '../base/modal';
7
 import { beginShareRoom } from '../share-room';
7
 import { beginShareRoom } from '../share-room';
8
 
8
 
20
 export function doInvitePeople() {
20
 export function doInvitePeople() {
21
     return (dispatch: Dispatch<any>, getState: Function) => {
21
     return (dispatch: Dispatch<any>, getState: Function) => {
22
         const state = getState();
22
         const state = getState();
23
-        const addPeopleEnabled = getFeatureFlag(state, INVITE_ENABLED, true)
23
+        const addPeopleEnabled = getFeatureFlag(state, ADD_PEOPLE_ENABLED, true)
24
             && (isAddPeopleEnabled(state) || isDialOutEnabled(state));
24
             && (isAddPeopleEnabled(state) || isDialOutEnabled(state));
25
 
25
 
26
         if (addPeopleEnabled) {
26
         if (addPeopleEnabled) {

+ 3
- 1
react/features/invite/components/add-people-dialog/native/InviteButton.js View File

2
 
2
 
3
 import type { Dispatch } from 'redux';
3
 import type { Dispatch } from 'redux';
4
 
4
 
5
+import { getFeatureFlag, INVITE_ENABLED } from '../../../../base/flags';
5
 import { translate } from '../../../../base/i18n';
6
 import { translate } from '../../../../base/i18n';
6
 import { IconAddPeople } from '../../../../base/icons';
7
 import { IconAddPeople } from '../../../../base/icons';
7
 import { connect } from '../../../../base/redux';
8
 import { connect } from '../../../../base/redux';
47
  */
48
  */
48
 function _mapStateToProps(state, ownProps: Props) {
49
 function _mapStateToProps(state, ownProps: Props) {
49
     const { disableInviteFunctions } = state['features/base/config'];
50
     const { disableInviteFunctions } = state['features/base/config'];
51
+    const flag = getFeatureFlag(state, INVITE_ENABLED, true);
50
 
52
 
51
     return {
53
     return {
52
-        visible: !disableInviteFunctions && ownProps.visible
54
+        visible: flag && !disableInviteFunctions && ownProps.visible
53
     };
55
     };
54
 }
56
 }
55
 
57
 

+ 22
- 2
react/features/recording/components/LiveStream/native/LiveStreamButton.js View File

2
 
2
 
3
 import { translate } from '../../../../base/i18n';
3
 import { translate } from '../../../../base/i18n';
4
 import { IconLiveStreaming } from '../../../../base/icons';
4
 import { IconLiveStreaming } from '../../../../base/icons';
5
+import { LIVE_STREAMING_ENABLED, getFeatureFlag } from '../../../../base/flags';
5
 import { connect } from '../../../../base/redux';
6
 import { connect } from '../../../../base/redux';
6
 
7
 
7
 import AbstractLiveStreamButton, {
8
 import AbstractLiveStreamButton, {
8
-    _mapStateToProps,
9
+    _mapStateToProps as _abstractMapStateToProps,
9
     type Props
10
     type Props
10
 } from '../AbstractLiveStreamButton';
11
 } from '../AbstractLiveStreamButton';
11
 
12
 
16
     icon = IconLiveStreaming;
17
     icon = IconLiveStreaming;
17
 }
18
 }
18
 
19
 
19
-export default translate(connect(_mapStateToProps)(LiveStreamButton));
20
+/**
21
+ * Maps (parts of) the redux state to the associated props for this component.
22
+ *
23
+ * @param {Object} state - The redux state.
24
+ * @param {Object} ownProps - The properties explicitly passed to the component
25
+ * instance.
26
+ * @private
27
+ * @returns {Props}
28
+ */
29
+export function mapStateToProps(state: Object, ownProps: Object) {
30
+    const enabled = getFeatureFlag(state, LIVE_STREAMING_ENABLED, true);
31
+    const abstractProps = _abstractMapStateToProps(state, ownProps);
32
+
33
+    return {
34
+        ...abstractProps,
35
+        visible: enabled && abstractProps.visible
36
+    };
37
+}
38
+
39
+export default translate(connect(mapStateToProps)(LiveStreamButton));

+ 25
- 2
react/features/recording/components/Recording/native/RecordButton.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
+import { Platform } from 'react-native';
4
+
5
+import { IOS_RECORDING_ENABLED, RECORDING_ENABLED, getFeatureFlag } from '../../../../base/flags';
3
 import { translate } from '../../../../base/i18n';
6
 import { translate } from '../../../../base/i18n';
4
 import { IconToggleRecording } from '../../../../base/icons';
7
 import { IconToggleRecording } from '../../../../base/icons';
5
 import { connect } from '../../../../base/redux';
8
 import { connect } from '../../../../base/redux';
6
 
9
 
7
 import AbstractRecordButton, {
10
 import AbstractRecordButton, {
8
-    _mapStateToProps,
11
+    _mapStateToProps as _abstractMapStateToProps,
9
     type Props
12
     type Props
10
 } from '../AbstractRecordButton';
13
 } from '../AbstractRecordButton';
11
 
14
 
16
     icon = IconToggleRecording;
19
     icon = IconToggleRecording;
17
 }
20
 }
18
 
21
 
19
-export default translate(connect(_mapStateToProps)(RecordButton));
22
+/**
23
+ * Maps (parts of) the redux state to the associated props for this component.
24
+ *
25
+ * @param {Object} state - The redux state.
26
+ * @param {Object} ownProps - The properties explicitly passed to the component
27
+ * instance.
28
+ * @private
29
+ * @returns {Props}
30
+ */
31
+export function mapStateToProps(state: Object, ownProps: Object) {
32
+    const enabled = getFeatureFlag(state, RECORDING_ENABLED, true);
33
+    const iosEnabled = Platform.OS !== 'ios' || getFeatureFlag(state, IOS_RECORDING_ENABLED, false);
34
+    const abstractProps = _abstractMapStateToProps(state, ownProps);
35
+
36
+    return {
37
+        ...abstractProps,
38
+        visible: enabled && iosEnabled && abstractProps.visible
39
+    };
40
+}
41
+
42
+export default translate(connect(mapStateToProps)(RecordButton));

+ 9
- 8
react/features/room-lock/components/RoomLockButton.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
+import { MEETING_PASSWORD_ENABLED, getFeatureFlag } from '../../base/flags';
3
 import { translate } from '../../base/i18n';
4
 import { translate } from '../../base/i18n';
4
 import { IconRoomLock, IconRoomUnlock } from '../../base/icons';
5
 import { IconRoomLock, IconRoomUnlock } from '../../base/icons';
5
 import { isLocalParticipantModerator } from '../../base/participants';
6
 import { isLocalParticipantModerator } from '../../base/participants';
83
  * {@code RoomLockButton} component.
84
  * {@code RoomLockButton} component.
84
  *
85
  *
85
  * @param {Object} state - The Redux state.
86
  * @param {Object} state - The Redux state.
87
+ * @param {Object} ownProps - The properties explicitly passed to the component instance.
86
  * @private
88
  * @private
87
- * @returns {{
88
- *     _localParticipantModerator: boolean,
89
- *     _locked: boolean
90
- * }}
89
+ * @returns {Props}
91
  */
90
  */
92
-function _mapStateToProps(state): Object {
91
+function _mapStateToProps(state, ownProps): Object {
93
     const { conference, locked } = state['features/base/conference'];
92
     const { conference, locked } = state['features/base/conference'];
93
+    const enabled = getFeatureFlag(state, MEETING_PASSWORD_ENABLED, true);
94
+    const { visible = enabled } = ownProps;
94
 
95
 
95
     return {
96
     return {
96
-        _localParticipantModerator:
97
-            Boolean(conference && isLocalParticipantModerator(state)),
98
-        _locked: Boolean(conference && locked)
97
+        _localParticipantModerator: Boolean(conference && isLocalParticipantModerator(state)),
98
+        _locked: Boolean(conference && locked),
99
+        visible
99
     };
100
     };
100
 }
101
 }
101
 
102
 

+ 3
- 8
react/features/toolbox/components/native/OverflowMenu.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
 import React, { PureComponent } from 'react';
3
 import React, { PureComponent } from 'react';
4
-import { Platform, TouchableOpacity, View } from 'react-native';
4
+import { TouchableOpacity, View } from 'react-native';
5
 import Collapsible from 'react-native-collapsible';
5
 import Collapsible from 'react-native-collapsible';
6
 
6
 
7
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
7
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
8
 import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
8
 import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
9
-import { IOS_RECORDING_ENABLED, getFeatureFlag } from '../../../base/flags';
10
 import { IconDragHandle } from '../../../base/icons';
9
 import { IconDragHandle } from '../../../base/icons';
11
 import { connect } from '../../../base/redux';
10
 import { connect } from '../../../base/redux';
12
 import { StyleType } from '../../../base/styles';
11
 import { StyleType } from '../../../base/styles';
134
                 <Collapsible collapsed = { !showMore }>
133
                 <Collapsible collapsed = { !showMore }>
135
                     <ToggleCameraButton { ...buttonProps } />
134
                     <ToggleCameraButton { ...buttonProps } />
136
                     <TileViewButton { ...buttonProps } />
135
                     <TileViewButton { ...buttonProps } />
137
-                    {
138
-                        this.props._recordingEnabled
139
-                            && <RecordButton { ...buttonProps } />
140
-                    }
136
+                    <RecordButton { ...buttonProps } />
141
                     <LiveStreamButton { ...buttonProps } />
137
                     <LiveStreamButton { ...buttonProps } />
142
                     <RoomLockButton { ...buttonProps } />
138
                     <RoomLockButton { ...buttonProps } />
143
                     <ClosedCaptionButton { ...buttonProps } />
139
                     <ClosedCaptionButton { ...buttonProps } />
240
 function _mapStateToProps(state) {
236
 function _mapStateToProps(state) {
241
     return {
237
     return {
242
         _bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
238
         _bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
243
-        _isOpen: isDialogOpen(state, OverflowMenu_),
244
-        _recordingEnabled: Platform.OS !== 'ios' || getFeatureFlag(state, IOS_RECORDING_ENABLED)
239
+        _isOpen: isDialogOpen(state, OverflowMenu_)
245
     };
240
     };
246
 }
241
 }
247
 
242
 

+ 5
- 28
react/features/toolbox/components/native/Toolbox.js View File

4
 import { View } from 'react-native';
4
 import { View } from 'react-native';
5
 
5
 
6
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
6
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
7
-import { CHAT_ENABLED, getFeatureFlag } from '../../../base/flags';
8
 import { Container } from '../../../base/react';
7
 import { Container } from '../../../base/react';
9
 import { connect } from '../../../base/redux';
8
 import { connect } from '../../../base/redux';
10
 import { StyleType } from '../../../base/styles';
9
 import { StyleType } from '../../../base/styles';
11
 import { ChatButton } from '../../../chat';
10
 import { ChatButton } from '../../../chat';
12
-import { InviteButton } from '../../../invite';
13
 
11
 
14
 import { isToolboxVisible } from '../../functions';
12
 import { isToolboxVisible } from '../../functions';
15
 
13
 
25
  */
23
  */
26
 type Props = {
24
 type Props = {
27
 
25
 
28
-    /**
29
-     * Whether the chat feature has been enabled. The meeting info button will be displayed in its place when disabled.
30
-     */
31
-    _chatEnabled: boolean,
32
-
33
     /**
26
     /**
34
      * The color-schemed stylesheet of the feature.
27
      * The color-schemed stylesheet of the feature.
35
      */
28
      */
105
      * @returns {React$Node}
98
      * @returns {React$Node}
106
      */
99
      */
107
     _renderToolbar() {
100
     _renderToolbar() {
108
-        const { _chatEnabled, _styles } = this.props;
101
+        const { _styles } = this.props;
109
         const { buttonStyles, buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
102
         const { buttonStyles, buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
110
 
103
 
111
         return (
104
         return (
113
                 accessibilityRole = 'toolbar'
106
                 accessibilityRole = 'toolbar'
114
                 pointerEvents = 'box-none'
107
                 pointerEvents = 'box-none'
115
                 style = { styles.toolbar }>
108
                 style = { styles.toolbar }>
116
-                {
117
-                    _chatEnabled
118
-                        && <ChatButton
119
-                            styles = { buttonStylesBorderless }
120
-                            toggledStyles = {
121
-                                this._getChatButtonToggledStyle(toggledButtonStyles)
122
-                            } />
123
-                }
124
-                {
125
-                    !_chatEnabled
126
-                        && <InviteButton
127
-                            styles = { buttonStyles }
128
-                            toggledStyles = { toggledButtonStyles } />
129
-                }
109
+                <ChatButton
110
+                    styles = { buttonStylesBorderless }
111
+                    toggledStyles = { this._getChatButtonToggledStyle(toggledButtonStyles) } />
130
                 <AudioMuteButton
112
                 <AudioMuteButton
131
                     styles = { buttonStyles }
113
                     styles = { buttonStyles }
132
                     toggledStyles = { toggledButtonStyles } />
114
                     toggledStyles = { toggledButtonStyles } />
150
  * @param {Object} state - The redux state of which parts are to be mapped to
132
  * @param {Object} state - The redux state of which parts are to be mapped to
151
  * {@code Toolbox} props.
133
  * {@code Toolbox} props.
152
  * @private
134
  * @private
153
- * @returns {{
154
- *     _chatEnabled: boolean,
155
- *     _styles: StyleType,
156
- *     _visible: boolean
157
- * }}
135
+ * @returns {Props}
158
  */
136
  */
159
 function _mapStateToProps(state: Object): Object {
137
 function _mapStateToProps(state: Object): Object {
160
     return {
138
     return {
161
-        _chatEnabled: getFeatureFlag(state, CHAT_ENABLED, true),
162
         _styles: ColorSchemeRegistry.get(state, 'Toolbox'),
139
         _styles: ColorSchemeRegistry.get(state, 'Toolbox'),
163
         _visible: isToolboxVisible(state)
140
         _visible: isToolboxVisible(state)
164
     };
141
     };

Loading…
Cancel
Save