Browse Source

[WEB] Move RecordButton to the new ToolBox abstraction layer

j8
Bettenbuk Zoltan 7 years ago
parent
commit
b48c897d9b

+ 1
- 3
react/features/base/toolbox/components/ToolboxItem.web.js View File

70
         const elementType = showLabel ? 'span' : 'div';
70
         const elementType = showLabel ? 'span' : 'div';
71
         const className
71
         const className
72
             = showLabel ? 'overflow-menu-item-icon' : 'toolbox-icon';
72
             = showLabel ? 'overflow-menu-item-icon' : 'toolbox-icon';
73
-        const iconWrapper
74
-            = React.createElement(elementType, { className }, icon);
75
 
73
 
76
-        return iconWrapper;
74
+        return React.createElement(elementType, { className }, icon);
77
     }
75
     }
78
 }
76
 }

+ 138
- 0
react/features/recording/components/Recording/AbstractRecordButton.js View File

1
+// @flow
2
+
3
+import {
4
+    createToolbarEvent,
5
+    sendAnalytics
6
+} from '../../../analytics';
7
+
8
+import { openDialog } from '../../../base/dialog';
9
+import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
10
+import {
11
+    getLocalParticipant,
12
+    isLocalParticipantModerator
13
+} from '../../../base/participants';
14
+import {
15
+    AbstractButton,
16
+    type AbstractButtonProps
17
+} from '../../../base/toolbox';
18
+
19
+import { getActiveSession } from '../../functions';
20
+
21
+import StartRecordingDialog from './StartRecordingDialog';
22
+import StopRecordingDialog from './StopRecordingDialog';
23
+
24
+/**
25
+ * The type of the React {@code Component} props of
26
+ * {@link AbstractRecordButton}.
27
+ */
28
+export type Props = AbstractButtonProps & {
29
+
30
+    /**
31
+     * True if there is a running active recording, false otherwise.
32
+     */
33
+    _isRecordingRunning: boolean,
34
+
35
+    /**
36
+     * The redux {@code dispatch} function.
37
+     */
38
+    dispatch: Function,
39
+
40
+    /**
41
+     * The i18n translate function.
42
+     */
43
+    t: Function
44
+};
45
+
46
+/**
47
+ * An abstract implementation of a button for starting and stopping recording.
48
+ */
49
+export default class AbstractRecordButton<P: Props>
50
+    extends AbstractButton<P, *> {
51
+    accessibilityLabel = 'toolbar.accessibilityLabel.recording';
52
+    label = 'dialog.startRecording';
53
+    toggledLabel = 'dialog.stopRecording';
54
+
55
+    /**
56
+     * Handles clicking / pressing the button.
57
+     *
58
+     * @override
59
+     * @protected
60
+     * @returns {void}
61
+     */
62
+    _handleClick() {
63
+        const { _isRecordingRunning, dispatch } = this.props;
64
+
65
+        sendAnalytics(createToolbarEvent(
66
+            'recording.button',
67
+            {
68
+                'is_recording': _isRecordingRunning,
69
+                type: JitsiRecordingConstants.mode.FILE
70
+            }));
71
+
72
+        dispatch(openDialog(
73
+            _isRecordingRunning ? StopRecordingDialog : StartRecordingDialog
74
+        ));
75
+    }
76
+
77
+    /**
78
+     * Helper function to be implemented by subclasses, which must return a
79
+     * boolean value indicating if this button is disabled or not.
80
+     *
81
+     * @override
82
+     * @protected
83
+     * @returns {boolean}
84
+     */
85
+    _isDisabled() {
86
+        return false;
87
+    }
88
+
89
+    /**
90
+     * Indicates whether this button is in toggled state or not.
91
+     *
92
+     * @override
93
+     * @protected
94
+     * @returns {boolean}
95
+     */
96
+    _isToggled() {
97
+        return this.props._isRecordingRunning;
98
+    }
99
+}
100
+
101
+/**
102
+ * Maps (parts of) the redux state to the associated props for the
103
+ * {@code RecordButton} component.
104
+ *
105
+ * @param {Object} state - The Redux state.
106
+ * @param {Props} ownProps - The own props of the Component.
107
+ * @private
108
+ * @returns {{
109
+ *     _isRecordingRunning: boolean,
110
+ *     visible: boolean
111
+ * }}
112
+ */
113
+export function _mapStateToProps(state: Object, ownProps: Props): Object {
114
+    let { visible } = ownProps;
115
+
116
+    if (typeof visible === 'undefined') {
117
+        // If the containing component provides the visible prop, that is one
118
+        // above all, but if not, the button should be autonomus and decide on
119
+        // its own to be visible or not.
120
+        const isModerator = isLocalParticipantModerator(state);
121
+        const {
122
+            enableFeaturesBasedOnToken,
123
+            fileRecordingsEnabled
124
+        } = state['features/base/config'];
125
+        const { features = {} } = getLocalParticipant(state);
126
+
127
+        visible = isModerator
128
+            && fileRecordingsEnabled
129
+            && (!enableFeaturesBasedOnToken
130
+                || String(features.recording) === 'true');
131
+    }
132
+
133
+    return {
134
+        _isRecordingRunning:
135
+            Boolean(getActiveSession(state, JitsiRecordingConstants.mode.FILE)),
136
+        visible
137
+    };
138
+}

+ 7
- 95
react/features/recording/components/Recording/RecordButton.native.js View File

2
 
2
 
3
 import { connect } from 'react-redux';
3
 import { connect } from 'react-redux';
4
 
4
 
5
-import { openDialog } from '../../../base/dialog';
6
 import { translate } from '../../../base/i18n';
5
 import { translate } from '../../../base/i18n';
7
-import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
8
-import {
9
-    isLocalParticipantModerator
10
-} from '../../../base/participants';
11
-import {
12
-    AbstractButton,
13
-    type AbstractButtonProps
14
-} from '../../../base/toolbox';
15
 
6
 
16
-import { getActiveSession } from '../../functions';
17
-
18
-import StartRecordingDialog from './StartRecordingDialog';
19
-import StopRecordingDialog from './StopRecordingDialog';
20
-
21
-/**
22
- * The type of the React {@code Component} props of {@link RecordButton}.
23
- */
24
-type Props = AbstractButtonProps & {
25
-
26
-    /**
27
-     * The current conference object.
28
-     */
29
-    _conference: Object,
30
-
31
-    /**
32
-     * True if there is a running active recording, false otherwise.
33
-     */
34
-    _isRecordingRunning: boolean,
35
-
36
-    /**
37
-     * The redux {@code dispatch} function.
38
-     */
39
-    dispatch: Function,
40
-
41
-    /**
42
-     * The i18n translate function.
43
-     */
44
-    t: Function
45
-};
7
+import AbstractRecordButton, {
8
+    _mapStateToProps,
9
+    type Props
10
+} from './AbstractRecordButton';
46
 
11
 
47
 /**
12
 /**
48
  * An implementation of a button for starting and stopping recording.
13
  * An implementation of a button for starting and stopping recording.
49
  */
14
  */
50
-class RecordButton extends AbstractButton<Props, *> {
51
-    accessibilityLabel = 'Recording';
52
-    iconName = 'recEnable';
53
-    label = 'dialog.startRecording';
54
-    toggledIconName = 'recDisable';
55
-    toggledLabel = 'dialog.stopRecording';
56
-
57
-    /**
58
-     * Handles clicking / pressing the button.
59
-     *
60
-     * @override
61
-     * @protected
62
-     * @returns {void}
63
-     */
64
-    _handleClick() {
65
-        const { _isRecordingRunning, dispatch } = this.props;
66
-
67
-        dispatch(openDialog(
68
-            _isRecordingRunning ? StopRecordingDialog : StartRecordingDialog
69
-        ));
70
-    }
71
-
72
-    /**
73
-     * Indicates whether this button is in toggled state or not.
74
-     *
75
-     * @override
76
-     * @protected
77
-     * @returns {boolean}
78
-     */
79
-    _isToggled() {
80
-        return this.props._isRecordingRunning;
81
-    }
82
-}
83
-
84
-/**
85
- * Maps (parts of) the redux state to the associated props for the
86
- * {@code RecordButton} component.
87
- *
88
- * @param {Object} state - The Redux state.
89
- * @private
90
- * @returns {{
91
- *     _conference: Object,
92
- *     _isRecordingRunning: boolean,
93
- *     visible: boolean
94
- * }}
95
- */
96
-function _mapStateToProps(state): Object {
97
-    const isModerator = isLocalParticipantModerator(state);
98
-    const { fileRecordingsEnabled } = state['features/base/config'];
99
-
100
-    return {
101
-        _conference: state['features/base/conference'].conference,
102
-        _isRecordingRunning:
103
-            Boolean(getActiveSession(state, JitsiRecordingConstants.mode.FILE)),
104
-        visible: isModerator && fileRecordingsEnabled
105
-    };
15
+class RecordButton extends AbstractRecordButton<Props> {
16
+    iconName = 'camera-take-picture';
17
+    toggledIconName = 'camera-take-picture';
106
 }
18
 }
107
 
19
 
108
 export default translate(connect(_mapStateToProps)(RecordButton));
20
 export default translate(connect(_mapStateToProps)(RecordButton));

+ 124
- 0
react/features/recording/components/Recording/RecordButton.web.js View File

1
+// @flow
2
+
3
+import { connect } from 'react-redux';
4
+
5
+import { translate } from '../../../base/i18n';
6
+import { getLocalParticipant } from '../../../base/participants';
7
+
8
+import AbstractRecordButton, {
9
+    _mapStateToProps as _abstractMapStateToProps,
10
+    type Props as AbstractProps
11
+} from './AbstractRecordButton';
12
+
13
+declare var interfaceConfig: Object;
14
+
15
+type Props = AbstractProps & {
16
+
17
+    /**
18
+     * True if the button should be disabled, false otherwise.
19
+     *
20
+     * NOTE: On web, if the feature is not disabled on purpose, then we still
21
+     * show the button but disabled and with a tooltip rendered on it,
22
+     * explaining why it's not available.
23
+     */
24
+    _disabled: boolean,
25
+
26
+    /**
27
+     * Tooltip for the button when it's disabled in a certain way.
28
+     */
29
+    _fileRecordingsDisabledTooltipKey: ?string
30
+}
31
+
32
+/**
33
+ * An implementation of a button for starting and stopping recording.
34
+ */
35
+class RecordButton extends AbstractRecordButton<Props> {
36
+    iconName = 'icon-camera-take-picture';
37
+    toggledIconName = 'icon-camera-take-picture';
38
+
39
+    /**
40
+     * Constructor of the component.
41
+     *
42
+     * @inheritdoc
43
+     */
44
+    constructor(props: Props) {
45
+        super(props);
46
+
47
+        this.tooltip = props._fileRecordingsDisabledTooltipKey;
48
+    }
49
+
50
+    /**
51
+     * Implements {@code Component}'s componentWillReceiveProps.
52
+     *
53
+     * @inheritdoc
54
+     */
55
+    componentWillReceiveProps(newProps: Props) {
56
+        this.tooltip = newProps._fileRecordingsDisabledTooltipKey;
57
+    }
58
+
59
+    /**
60
+     * Helper function to be implemented by subclasses, which must return a
61
+     * boolean value indicating if this button is disabled or not.
62
+     *
63
+     * @override
64
+     * @protected
65
+     * @returns {boolean}
66
+     */
67
+    _isDisabled() {
68
+        return this.props._disabled;
69
+    }
70
+}
71
+
72
+/**
73
+ * Maps (parts of) the redux state to the associated props for the
74
+ * {@code RecordButton} component.
75
+ *
76
+ * @param {Object} state - The Redux state.
77
+ * @param {Props} ownProps - The own props of the Component.
78
+ * @private
79
+ * @returns {{
80
+ *     _fileRecordingsDisabledTooltipKey: ?string,
81
+ *     _isRecordingRunning: boolean,
82
+ *     _disabled: boolean,
83
+ *     visible: boolean
84
+ * }}
85
+ */
86
+export function _mapStateToProps(state: Object, ownProps: Props): Object {
87
+    const abstractProps = _abstractMapStateToProps(state, ownProps);
88
+    const localParticipant = getLocalParticipant(state);
89
+    const { features = {} } = localParticipant;
90
+    let { visible } = ownProps;
91
+
92
+    let _disabled = false;
93
+    let _fileRecordingsDisabledTooltipKey;
94
+
95
+    if (!abstractProps.visible
96
+            && String(features.recording) !== 'disabled') {
97
+        _disabled = true;
98
+
99
+        // button and tooltip
100
+        if (state['features/base/jwt'].isGuest) {
101
+            _fileRecordingsDisabledTooltipKey
102
+                = 'dialog.recordingDisabledForGuestTooltip';
103
+        } else {
104
+            _fileRecordingsDisabledTooltipKey
105
+                = 'dialog.recordingDisabledTooltip';
106
+        }
107
+    }
108
+
109
+    if (typeof visible === 'undefined') {
110
+        const visibleButtons = new Set(interfaceConfig.TOOLBAR_BUTTONS);
111
+
112
+        visible = visibleButtons.has('recording')
113
+            && (abstractProps.visible || _fileRecordingsDisabledTooltipKey);
114
+    }
115
+
116
+    return {
117
+        ...abstractProps,
118
+        visible,
119
+        _disabled,
120
+        _fileRecordingsDisabledTooltipKey
121
+    };
122
+}
123
+
124
+export default translate(connect(_mapStateToProps)(RecordButton));

+ 5
- 117
react/features/toolbox/components/web/Toolbox.js View File

30
 } from '../../../invite';
30
 } from '../../../invite';
31
 import { openKeyboardShortcutsDialog } from '../../../keyboard-shortcuts';
31
 import { openKeyboardShortcutsDialog } from '../../../keyboard-shortcuts';
32
 import {
32
 import {
33
+    RecordButton,
33
     StartLiveStreamDialog,
34
     StartLiveStreamDialog,
34
-    StartRecordingDialog,
35
     StopLiveStreamDialog,
35
     StopLiveStreamDialog,
36
-    StopRecordingDialog,
37
     getActiveSession
36
     getActiveSession
38
 } from '../../../recording';
37
 } from '../../../recording';
39
 import {
38
 import {
108
      */
107
      */
109
     _feedbackConfigured: boolean,
108
     _feedbackConfigured: boolean,
110
 
109
 
111
-    /**
112
-     * The tooltip key to use when file recording is disabled. Or undefined
113
-     * if non to be shown and the button to be hidden.
114
-     */
115
-    _fileRecordingsDisabledTooltipKey: boolean,
116
-
117
-    /**
118
-     * Whether or not the file recording feature is enabled for use.
119
-     */
120
-    _fileRecordingsEnabled: boolean,
121
-
122
-    /**
123
-     * The current file recording session, if any.
124
-     */
125
-    _fileRecordingSession: Object,
126
-
127
     /**
110
     /**
128
      * Whether or not the app is currently in full screen.
111
      * Whether or not the app is currently in full screen.
129
      */
112
      */
253
             = this._onToolbarToggleProfile.bind(this);
236
             = this._onToolbarToggleProfile.bind(this);
254
         this._onToolbarToggleRaiseHand
237
         this._onToolbarToggleRaiseHand
255
             = this._onToolbarToggleRaiseHand.bind(this);
238
             = this._onToolbarToggleRaiseHand.bind(this);
256
-        this._onToolbarToggleRecording
257
-            = this._onToolbarToggleRecording.bind(this);
258
         this._onToolbarToggleScreenshare
239
         this._onToolbarToggleScreenshare
259
             = this._onToolbarToggleScreenshare.bind(this);
240
             = this._onToolbarToggleScreenshare.bind(this);
260
         this._onToolbarToggleSharedVideo
241
         this._onToolbarToggleSharedVideo
543
         }));
524
         }));
544
     }
525
     }
545
 
526
 
546
-    /**
547
-     * Dispatches an action to toggle recording.
548
-     *
549
-     * @private
550
-     * @returns {void}
551
-     */
552
-    _doToggleRecording() {
553
-        const { _fileRecordingSession } = this.props;
554
-        const dialog = _fileRecordingSession
555
-            ? StopRecordingDialog : StartRecordingDialog;
556
-
557
-        this.props.dispatch(
558
-            openDialog(dialog, { session: _fileRecordingSession }));
559
-    }
560
-
561
     /**
527
     /**
562
      * Dispatches an action to toggle screensharing.
528
      * Dispatches an action to toggle screensharing.
563
      *
529
      *
875
         this._doToggleRaiseHand();
841
         this._doToggleRaiseHand();
876
     }
842
     }
877
 
843
 
878
-    _onToolbarToggleRecording: () => void;
879
-
880
-    /**
881
-     * Dispatches an action to toggle recording.
882
-     *
883
-     * @private
884
-     * @returns {void}
885
-     */
886
-    _onToolbarToggleRecording() {
887
-        sendAnalytics(createToolbarEvent(
888
-            'recording.button',
889
-            {
890
-                'is_recording': Boolean(this.props._fileRecordingSession),
891
-                type: JitsiRecordingConstants.mode.FILE
892
-            }));
893
-
894
-        this._doToggleRecording();
895
-    }
896
-
897
     _onToolbarToggleScreenshare: () => void;
844
     _onToolbarToggleScreenshare: () => void;
898
 
845
 
899
     /**
846
     /**
1020
             _editingDocument,
967
             _editingDocument,
1021
             _etherpadInitialized,
968
             _etherpadInitialized,
1022
             _feedbackConfigured,
969
             _feedbackConfigured,
1023
-            _fileRecordingsDisabledTooltipKey,
1024
-            _fileRecordingsEnabled,
1025
             _fullScreen,
970
             _fullScreen,
1026
             _isGuest,
971
             _isGuest,
1027
             _liveStreamingDisabledTooltipKey,
972
             _liveStreamingDisabledTooltipKey,
1055
             (_liveStreamingEnabled || _liveStreamingDisabledTooltipKey)
1000
             (_liveStreamingEnabled || _liveStreamingDisabledTooltipKey)
1056
                 && this._shouldShowButton('livestreaming')
1001
                 && this._shouldShowButton('livestreaming')
1057
                 && this._renderLiveStreamingButton(),
1002
                 && this._renderLiveStreamingButton(),
1058
-            (_fileRecordingsEnabled || _fileRecordingsDisabledTooltipKey)
1059
-                && this._shouldShowButton('recording')
1060
-                && this._renderRecordingButton(),
1003
+            <RecordButton
1004
+                key = 'record'
1005
+                showLabel = { true } />,
1061
             this._shouldShowButton('sharedvideo')
1006
             this._shouldShowButton('sharedvideo')
1062
                 && <OverflowMenuItem
1007
                 && <OverflowMenuItem
1063
                     accessibilityLabel =
1008
                     accessibilityLabel =
1111
         ];
1056
         ];
1112
     }
1057
     }
1113
 
1058
 
1114
-    /**
1115
-     * Renders an {@code OverflowMenuItem} to start or stop recording of the
1116
-     * current conference.
1117
-     *
1118
-     * @private
1119
-     * @returns {ReactElement}
1120
-     */
1121
-    _renderRecordingButton() {
1122
-        const {
1123
-            _fileRecordingSession,
1124
-            _fileRecordingsDisabledTooltipKey,
1125
-            _fileRecordingsEnabled,
1126
-            t } = this.props;
1127
-
1128
-        const translationKey = _fileRecordingSession
1129
-            ? 'dialog.stopRecording'
1130
-            : 'dialog.startRecording';
1131
-
1132
-        return (
1133
-            <OverflowMenuItem
1134
-                accessibilityLabel =
1135
-                    { t('toolbar.accessibilityLabel.recording') }
1136
-                disabled = { !_fileRecordingsEnabled }
1137
-                icon = 'icon-camera-take-picture'
1138
-                key = 'recording'
1139
-                onClick = { this._onToolbarToggleRecording }
1140
-                text = { t(translationKey) }
1141
-                tooltip = { t(_fileRecordingsDisabledTooltipKey) } />
1142
-        );
1143
-    }
1144
-
1145
     _shouldShowButton: (string) => boolean;
1059
     _shouldShowButton: (string) => boolean;
1146
 
1060
 
1147
     /**
1061
     /**
1172
         callStatsID,
1086
         callStatsID,
1173
         iAmRecorder
1087
         iAmRecorder
1174
     } = state['features/base/config'];
1088
     } = state['features/base/config'];
1175
-    let {
1176
-        fileRecordingsEnabled,
1177
-        liveStreamingEnabled
1178
-    } = state['features/base/config'];
1089
+    let { liveStreamingEnabled } = state['features/base/config'];
1179
     const sharedVideoStatus = state['features/shared-video'].status;
1090
     const sharedVideoStatus = state['features/shared-video'].status;
1180
     const { current } = state['features/side-panel'];
1091
     const { current } = state['features/side-panel'];
1181
     const {
1092
     const {
1191
     const dialOutEnabled = isDialOutEnabled(state);
1102
     const dialOutEnabled = isDialOutEnabled(state);
1192
 
1103
 
1193
     let desktopSharingDisabledTooltipKey;
1104
     let desktopSharingDisabledTooltipKey;
1194
-    let fileRecordingsDisabledTooltipKey;
1195
     let liveStreamingDisabledTooltipKey;
1105
     let liveStreamingDisabledTooltipKey;
1196
 
1106
 
1197
-    fileRecordingsEnabled
1198
-        = isLocalParticipantModerator(state) && fileRecordingsEnabled;
1199
     liveStreamingEnabled
1107
     liveStreamingEnabled
1200
         = isLocalParticipantModerator(state) && liveStreamingEnabled;
1108
         = isLocalParticipantModerator(state) && liveStreamingEnabled;
1201
 
1109
 
1220
         const { features = {} } = localParticipant;
1128
         const { features = {} } = localParticipant;
1221
         const { isGuest } = state['features/base/jwt'];
1129
         const { isGuest } = state['features/base/jwt'];
1222
 
1130
 
1223
-        fileRecordingsEnabled
1224
-            = fileRecordingsEnabled && String(features.recording) === 'true';
1225
-
1226
-        // if the feature is disabled on purpose, do no show it, no tooltip
1227
-        if (!fileRecordingsEnabled
1228
-            && String(features.recording) !== 'disabled') {
1229
-            // button and tooltip
1230
-            if (isGuest) {
1231
-                fileRecordingsDisabledTooltipKey
1232
-                    = 'dialog.recordingDisabledForGuestTooltip';
1233
-            } else {
1234
-                fileRecordingsDisabledTooltipKey
1235
-                    = 'dialog.recordingDisabledTooltip';
1236
-            }
1237
-        }
1238
-
1239
         liveStreamingEnabled
1131
         liveStreamingEnabled
1240
             = liveStreamingEnabled && String(features.livestreaming) === 'true';
1132
             = liveStreamingEnabled && String(features.livestreaming) === 'true';
1241
 
1133
 
1265
         _hideInviteButton:
1157
         _hideInviteButton:
1266
             iAmRecorder || (!addPeopleEnabled && !dialOutEnabled),
1158
             iAmRecorder || (!addPeopleEnabled && !dialOutEnabled),
1267
         _isGuest: state['features/base/jwt'].isGuest,
1159
         _isGuest: state['features/base/jwt'].isGuest,
1268
-        _fileRecordingsDisabledTooltipKey: fileRecordingsDisabledTooltipKey,
1269
-        _fileRecordingsEnabled: fileRecordingsEnabled,
1270
-        _fileRecordingSession:
1271
-            getActiveSession(state, JitsiRecordingConstants.mode.FILE),
1272
         _fullScreen: fullScreen,
1160
         _fullScreen: fullScreen,
1273
         _liveStreamingDisabledTooltipKey: liveStreamingDisabledTooltipKey,
1161
         _liveStreamingDisabledTooltipKey: liveStreamingDisabledTooltipKey,
1274
         _liveStreamingEnabled: liveStreamingEnabled,
1162
         _liveStreamingEnabled: liveStreamingEnabled,

Loading…
Cancel
Save