浏览代码

[WEB] Move RecordButton to the new ToolBox abstraction layer

j8
Bettenbuk Zoltan 7 年前
父节点
当前提交
b48c897d9b

+ 1
- 3
react/features/base/toolbox/components/ToolboxItem.web.js 查看文件

@@ -70,9 +70,7 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
70 70
         const elementType = showLabel ? 'span' : 'div';
71 71
         const className
72 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 查看文件

@@ -0,0 +1,138 @@
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 查看文件

@@ -2,107 +2,19 @@
2 2
 
3 3
 import { connect } from 'react-redux';
4 4
 
5
-import { openDialog } from '../../../base/dialog';
6 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 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 20
 export default translate(connect(_mapStateToProps)(RecordButton));

+ 124
- 0
react/features/recording/components/Recording/RecordButton.web.js 查看文件

@@ -0,0 +1,124 @@
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 查看文件

@@ -30,10 +30,9 @@ import {
30 30
 } from '../../../invite';
31 31
 import { openKeyboardShortcutsDialog } from '../../../keyboard-shortcuts';
32 32
 import {
33
+    RecordButton,
33 34
     StartLiveStreamDialog,
34
-    StartRecordingDialog,
35 35
     StopLiveStreamDialog,
36
-    StopRecordingDialog,
37 36
     getActiveSession
38 37
 } from '../../../recording';
39 38
 import {
@@ -108,22 +107,6 @@ type Props = {
108 107
      */
109 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 111
      * Whether or not the app is currently in full screen.
129 112
      */
@@ -253,8 +236,6 @@ class Toolbox extends Component<Props> {
253 236
             = this._onToolbarToggleProfile.bind(this);
254 237
         this._onToolbarToggleRaiseHand
255 238
             = this._onToolbarToggleRaiseHand.bind(this);
256
-        this._onToolbarToggleRecording
257
-            = this._onToolbarToggleRecording.bind(this);
258 239
         this._onToolbarToggleScreenshare
259 240
             = this._onToolbarToggleScreenshare.bind(this);
260 241
         this._onToolbarToggleSharedVideo
@@ -543,21 +524,6 @@ class Toolbox extends Component<Props> {
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 528
      * Dispatches an action to toggle screensharing.
563 529
      *
@@ -875,25 +841,6 @@ class Toolbox extends Component<Props> {
875 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 844
     _onToolbarToggleScreenshare: () => void;
898 845
 
899 846
     /**
@@ -1020,8 +967,6 @@ class Toolbox extends Component<Props> {
1020 967
             _editingDocument,
1021 968
             _etherpadInitialized,
1022 969
             _feedbackConfigured,
1023
-            _fileRecordingsDisabledTooltipKey,
1024
-            _fileRecordingsEnabled,
1025 970
             _fullScreen,
1026 971
             _isGuest,
1027 972
             _liveStreamingDisabledTooltipKey,
@@ -1055,9 +1000,9 @@ class Toolbox extends Component<Props> {
1055 1000
             (_liveStreamingEnabled || _liveStreamingDisabledTooltipKey)
1056 1001
                 && this._shouldShowButton('livestreaming')
1057 1002
                 && this._renderLiveStreamingButton(),
1058
-            (_fileRecordingsEnabled || _fileRecordingsDisabledTooltipKey)
1059
-                && this._shouldShowButton('recording')
1060
-                && this._renderRecordingButton(),
1003
+            <RecordButton
1004
+                key = 'record'
1005
+                showLabel = { true } />,
1061 1006
             this._shouldShowButton('sharedvideo')
1062 1007
                 && <OverflowMenuItem
1063 1008
                     accessibilityLabel =
@@ -1111,37 +1056,6 @@ class Toolbox extends Component<Props> {
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 1059
     _shouldShowButton: (string) => boolean;
1146 1060
 
1147 1061
     /**
@@ -1172,10 +1086,7 @@ function _mapStateToProps(state) {
1172 1086
         callStatsID,
1173 1087
         iAmRecorder
1174 1088
     } = state['features/base/config'];
1175
-    let {
1176
-        fileRecordingsEnabled,
1177
-        liveStreamingEnabled
1178
-    } = state['features/base/config'];
1089
+    let { liveStreamingEnabled } = state['features/base/config'];
1179 1090
     const sharedVideoStatus = state['features/shared-video'].status;
1180 1091
     const { current } = state['features/side-panel'];
1181 1092
     const {
@@ -1191,11 +1102,8 @@ function _mapStateToProps(state) {
1191 1102
     const dialOutEnabled = isDialOutEnabled(state);
1192 1103
 
1193 1104
     let desktopSharingDisabledTooltipKey;
1194
-    let fileRecordingsDisabledTooltipKey;
1195 1105
     let liveStreamingDisabledTooltipKey;
1196 1106
 
1197
-    fileRecordingsEnabled
1198
-        = isLocalParticipantModerator(state) && fileRecordingsEnabled;
1199 1107
     liveStreamingEnabled
1200 1108
         = isLocalParticipantModerator(state) && liveStreamingEnabled;
1201 1109
 
@@ -1220,22 +1128,6 @@ function _mapStateToProps(state) {
1220 1128
         const { features = {} } = localParticipant;
1221 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 1131
         liveStreamingEnabled
1240 1132
             = liveStreamingEnabled && String(features.livestreaming) === 'true';
1241 1133
 
@@ -1265,10 +1157,6 @@ function _mapStateToProps(state) {
1265 1157
         _hideInviteButton:
1266 1158
             iAmRecorder || (!addPeopleEnabled && !dialOutEnabled),
1267 1159
         _isGuest: state['features/base/jwt'].isGuest,
1268
-        _fileRecordingsDisabledTooltipKey: fileRecordingsDisabledTooltipKey,
1269
-        _fileRecordingsEnabled: fileRecordingsEnabled,
1270
-        _fileRecordingSession:
1271
-            getActiveSession(state, JitsiRecordingConstants.mode.FILE),
1272 1160
         _fullScreen: fullScreen,
1273 1161
         _liveStreamingDisabledTooltipKey: liveStreamingDisabledTooltipKey,
1274 1162
         _liveStreamingEnabled: liveStreamingEnabled,

正在加载...
取消
保存