Sfoglia il codice sorgente

fix(reactions) Reactions improvements (#9964)

* Register shortcuts on mount

* Changed icon for reactions menu

* Enable reactions by default

* Fix unreadCount bug

When having unread messages and sending a reaction the unread count now shows the correct count

* Fix overflow menu bottom color when reactions are enabled

* Revert raise hand icon

* Update raise hand functionality

On desktop show raise button with arrow for reactions. Only show raise hand in the reactions menu on mobile

* Fix lint error

Add required prop to ToolboxButtonWithIcon

* Legacy support for enable reactions

If disableReactions is undefined treat it as true

* Remove unnecessary code

* Fix unread counter showing negative count

* Fix unreadCount with reactions

UnreadCount ignores all reactions messages

* Fixed typo

* Fix background color
master
robertpin 4 anni fa
parent
commit
584ec7c82e
Nessun account collegato all'indirizzo email del committer

+ 2
- 2
config.js Vedi File

77
     // Disables moderator indicators.
77
     // Disables moderator indicators.
78
     // disableModeratorIndicator: false,
78
     // disableModeratorIndicator: false,
79
 
79
 
80
-    // Enables reactions feature.
81
-    // enableReactions: false,
80
+    // Disables the reactions feature.
81
+    // disableReactions: true,
82
 
82
 
83
     // Disables polls feature.
83
     // Disables polls feature.
84
     // disablePolls: false,
84
     // disablePolls: false,

+ 1
- 1
css/_reactions-menu.scss Vedi File

2
 
2
 
3
 .reactions-menu {
3
 .reactions-menu {
4
 	width: 280px;
4
 	width: 280px;
5
-	background: #292929;
5
+	background: $menuBG;
6
 	box-shadow: 0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
6
 	box-shadow: 0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
7
 	border-radius: 3px;
7
 	border-radius: 3px;
8
 	padding: 16px;
8
 	padding: 16px;

+ 1
- 1
react/features/base/config/configWhitelist.js Vedi File

100
     'disableNS',
100
     'disableNS',
101
     'disablePolls',
101
     'disablePolls',
102
     'disableProfile',
102
     'disableProfile',
103
+    'disableReactions',
103
     'disableRecordAudioNotification',
104
     'disableRecordAudioNotification',
104
     'disableRemoteControl',
105
     'disableRemoteControl',
105
     'disableRemoteMute',
106
     'disableRemoteMute',
127
     'enableLayerSuspension',
128
     'enableLayerSuspension',
128
     'enableLipSync',
129
     'enableLipSync',
129
     'enableOpusRed',
130
     'enableOpusRed',
130
-    'enableReactions',
131
     'enableRemb',
131
     'enableRemb',
132
     'enableSaveLogs',
132
     'enableSaveLogs',
133
     'enableScreenshotCapture',
133
     'enableScreenshotCapture',

+ 5
- 1
react/features/base/dialog/components/native/BottomSheet.js Vedi File

145
                             renderHeader
145
                             renderHeader
146
                                 ? _styles.sheetHeader
146
                                 ? _styles.sheetHeader
147
                                 : _styles.sheet,
147
                                 : _styles.sheet,
148
+                            renderFooter && _styles.sheetFooter,
148
                             style,
149
                             style,
149
                             {
150
                             {
150
                                 maxHeight: _height - 100
151
                                 maxHeight: _height - 100
154
                         <ScrollView
155
                         <ScrollView
155
                             bounces = { false }
156
                             bounces = { false }
156
                             showsVerticalScrollIndicator = { false }
157
                             showsVerticalScrollIndicator = { false }
157
-                            style = { addScrollViewPadding && styles.scrollView } >
158
+                            style = { [
159
+                                renderFooter && _styles.sheet,
160
+                                addScrollViewPadding && styles.scrollView
161
+                            ] } >
158
                             { this.props.children }
162
                             { this.props.children }
159
                         </ScrollView>
163
                         </ScrollView>
160
                         { renderFooter && renderFooter() }
164
                         { renderFooter && renderFooter() }

+ 7
- 0
react/features/base/dialog/components/native/styles.js Vedi File

213
      */
213
      */
214
     sheetHeader: {
214
     sheetHeader: {
215
         backgroundColor: BaseTheme.palette.ui02
215
         backgroundColor: BaseTheme.palette.ui02
216
+    },
217
+
218
+    /**
219
+     * Bottom sheet's background color with footer.
220
+     */
221
+    sheetFooter: {
222
+        backgroundColor: BaseTheme.palette.bottomSheet
216
     }
223
     }
217
 });
224
 });
218
 
225
 

+ 3
- 0
react/features/chat/actions.any.js Vedi File

22
  * "error" or "local" or "remote".
22
  * "error" or "local" or "remote".
23
  * @param {string} messageDetails.timestamp - A timestamp to display for when
23
  * @param {string} messageDetails.timestamp - A timestamp to display for when
24
  * the message was received.
24
  * the message was received.
25
+ * @param {string} messageDetails.isReaction - Whether or not the
26
+ * message is a reaction message.
25
  * @returns {{
27
  * @returns {{
26
  *     type: ADD_MESSAGE,
28
  *     type: ADD_MESSAGE,
27
  *     displayName: string,
29
  *     displayName: string,
29
  *     message: string,
31
  *     message: string,
30
  *     messageType: string,
32
  *     messageType: string,
31
  *     timestamp: string,
33
  *     timestamp: string,
34
+ *     isReaction: boolean
32
  * }}
35
  * }}
33
  */
36
  */
34
 export function addMessage(messageDetails: Object) {
37
 export function addMessage(messageDetails: Object) {

+ 18
- 2
react/features/chat/functions.js Vedi File

69
         return 0;
69
         return 0;
70
     }
70
     }
71
 
71
 
72
+    let reactionMessages = 0;
73
+
72
     if (navigator.product === 'ReactNative') {
74
     if (navigator.product === 'ReactNative') {
73
         // React native stores the messages in a reversed order.
75
         // React native stores the messages in a reversed order.
74
-        return messages.indexOf(lastReadMessage);
76
+        const lastReadIndex = messages.indexOf(lastReadMessage);
77
+
78
+        for (let i = 0; i < lastReadIndex; i++) {
79
+            if (messages[i].isReaction) {
80
+                reactionMessages++;
81
+            }
82
+        }
83
+
84
+        return lastReadIndex - reactionMessages;
75
     }
85
     }
76
 
86
 
77
     const lastReadIndex = messages.lastIndexOf(lastReadMessage);
87
     const lastReadIndex = messages.lastIndexOf(lastReadMessage);
78
 
88
 
79
-    return messagesCount - (lastReadIndex + 1);
89
+    for (let i = lastReadIndex + 1; i < messagesCount; i++) {
90
+        if (messages[i].isReaction) {
91
+            reactionMessages++;
92
+        }
93
+    }
94
+
95
+    return messagesCount - (lastReadIndex + 1) - reactionMessages;
80
 }
96
 }
81
 
97
 
82
 /**
98
 /**

+ 13
- 5
react/features/chat/middleware.js Vedi File

68
 
68
 
69
     switch (action.type) {
69
     switch (action.type) {
70
     case ADD_MESSAGE:
70
     case ADD_MESSAGE:
71
-        unreadCount = action.hasRead ? 0 : getUnreadCount(getState()) + 1;
71
+        unreadCount = getUnreadCount(getState());
72
+        if (action.isReaction) {
73
+            action.hasRead = false;
74
+        } else {
75
+            unreadCount = action.hasRead ? 0 : unreadCount + 1;
76
+        }
72
         isOpen = getState()['features/chat'].isOpen;
77
         isOpen = getState()['features/chat'].isOpen;
73
 
78
 
74
         if (typeof APP !== 'undefined') {
79
         if (typeof APP !== 'undefined') {
171
             message: action.message,
176
             message: action.message,
172
             privateMessage: false,
177
             privateMessage: false,
173
             timestamp: Date.now()
178
             timestamp: Date.now()
174
-        }, false);
179
+        }, false, true);
175
     }
180
     }
176
     }
181
     }
177
 
182
 
270
                         message: getReactionMessageFromBuffer(eventData.reactions),
275
                         message: getReactionMessageFromBuffer(eventData.reactions),
271
                         privateMessage: false,
276
                         privateMessage: false,
272
                         timestamp: eventData.timestamp
277
                         timestamp: eventData.timestamp
273
-                    }, false);
278
+                    }, false, true);
274
                 }
279
                 }
275
             }
280
             }
276
         });
281
         });
304
  * @param {Store} store - The Redux store.
309
  * @param {Store} store - The Redux store.
305
  * @param {Object} message - The message object.
310
  * @param {Object} message - The message object.
306
  * @param {boolean} shouldPlaySound - Whether or not to play the incoming message sound.
311
  * @param {boolean} shouldPlaySound - Whether or not to play the incoming message sound.
312
+ * @param {boolean} isReaction - Whether or not the message is a reaction message.
307
  * @returns {void}
313
  * @returns {void}
308
  */
314
  */
309
 function _handleReceivedMessage({ dispatch, getState },
315
 function _handleReceivedMessage({ dispatch, getState },
310
         { id, message, privateMessage, timestamp },
316
         { id, message, privateMessage, timestamp },
311
-        shouldPlaySound = true
317
+        shouldPlaySound = true,
318
+        isReaction = false
312
 ) {
319
 ) {
313
     // Logic for all platforms:
320
     // Logic for all platforms:
314
     const state = getState();
321
     const state = getState();
337
         message,
344
         message,
338
         privateMessage,
345
         privateMessage,
339
         recipient: getParticipantDisplayName(state, localParticipant.id),
346
         recipient: getParticipantDisplayName(state, localParticipant.id),
340
-        timestamp: millisecondsTimestamp
347
+        timestamp: millisecondsTimestamp,
348
+        isReaction
341
     }));
349
     }));
342
 
350
 
343
     if (typeof APP !== 'undefined') {
351
     if (typeof APP !== 'undefined') {

+ 1
- 0
react/features/chat/reducer.js Vedi File

28
             displayName: action.displayName,
28
             displayName: action.displayName,
29
             error: action.error,
29
             error: action.error,
30
             id: action.id,
30
             id: action.id,
31
+            isReaction: action.isReaction,
31
             messageType: action.messageType,
32
             messageType: action.messageType,
32
             message: action.message,
33
             message: action.message,
33
             privateMessage: action.privateMessage,
34
             privateMessage: action.privateMessage,

+ 30
- 21
react/features/reactions/components/web/ReactionsMenu.js Vedi File

8
     createToolbarEvent,
8
     createToolbarEvent,
9
     sendAnalytics
9
     sendAnalytics
10
 } from '../../../analytics';
10
 } from '../../../analytics';
11
+import { isMobileBrowser } from '../../../base/environment/utils';
11
 import { translate } from '../../../base/i18n';
12
 import { translate } from '../../../base/i18n';
12
 import { getLocalParticipant, participantUpdated } from '../../../base/participants';
13
 import { getLocalParticipant, participantUpdated } from '../../../base/participants';
13
 import { connect } from '../../../base/redux';
14
 import { connect } from '../../../base/redux';
21
 type Props = {
22
 type Props = {
22
 
23
 
23
     /**
24
     /**
24
-     * Used for translation.
25
+     * Docks the toolbox
25
      */
26
      */
26
-    t: Function,
27
+    _dockToolbox: Function,
27
 
28
 
28
     /**
29
     /**
29
-     * Whether or not the local participant's hand is raised.
30
+     * Whether or not it's a mobile browser.
30
      */
31
      */
31
-    _raisedHand: boolean,
32
+    _isMobile: boolean,
32
 
33
 
33
     /**
34
     /**
34
      * The ID of the local participant.
35
      * The ID of the local participant.
35
      */
36
      */
36
     _localParticipantID: String,
37
     _localParticipantID: String,
37
 
38
 
39
+    /**
40
+     * Whether or not the local participant's hand is raised.
41
+     */
42
+    _raisedHand: boolean,
43
+
38
     /**
44
     /**
39
      * The Redux Dispatch function.
45
      * The Redux Dispatch function.
40
      */
46
      */
41
     dispatch: Function,
47
     dispatch: Function,
42
 
48
 
43
     /**
49
     /**
44
-     * Docks the toolbox
50
+     * Whether or not it's displayed in the overflow menu.
45
      */
51
      */
46
-    _dockToolbox: Function,
52
+    overflowMenu: boolean,
47
 
53
 
48
     /**
54
     /**
49
-     * Whether or not it's displayed in the overflow menu.
55
+     * Used for translation.
50
      */
56
      */
51
-    overflowMenu: boolean
57
+    t: Function
52
 };
58
 };
53
 
59
 
54
 declare var APP: Object;
60
 declare var APP: Object;
177
      * @inheritdoc
183
      * @inheritdoc
178
      */
184
      */
179
     render() {
185
     render() {
180
-        const { _raisedHand, t, overflowMenu } = this.props;
186
+        const { _raisedHand, t, overflowMenu, _isMobile } = this.props;
181
 
187
 
182
         return (
188
         return (
183
             <div className = { `reactions-menu ${overflowMenu ? 'overflow' : ''}` }>
189
             <div className = { `reactions-menu ${overflowMenu ? 'overflow' : ''}` }>
184
                 <div className = 'reactions-row'>
190
                 <div className = 'reactions-row'>
185
                     { this._getReactionButtons() }
191
                     { this._getReactionButtons() }
186
                 </div>
192
                 </div>
187
-                <div className = 'raise-hand-row'>
188
-                    <ReactionButton
189
-                        accessibilityLabel = { t('toolbar.accessibilityLabel.raiseHand') }
190
-                        icon = '✋'
191
-                        key = 'raisehand'
192
-                        label = {
193
-                            `${t(`toolbar.${_raisedHand ? 'lowerYourHand' : 'raiseYourHand'}`)}
194
-                            ${overflowMenu ? '' : ' (R)'}`
195
-                        }
196
-                        onClick = { this._onToolbarToggleRaiseHand }
197
-                        toggled = { true } />
198
-                </div>
193
+                {_isMobile && (
194
+                    <div className = 'raise-hand-row'>
195
+                        <ReactionButton
196
+                            accessibilityLabel = { t('toolbar.accessibilityLabel.raiseHand') }
197
+                            icon = '✋'
198
+                            key = 'raisehand'
199
+                            label = {
200
+                                `${t(`toolbar.${_raisedHand ? 'lowerYourHand' : 'raiseYourHand'}`)}
201
+                                ${overflowMenu ? '' : ' (R)'}`
202
+                            }
203
+                            onClick = { this._onToolbarToggleRaiseHand }
204
+                            toggled = { true } />
205
+                    </div>
206
+                )}
199
             </div>
207
             </div>
200
         );
208
         );
201
     }
209
     }
212
 
220
 
213
     return {
221
     return {
214
         _localParticipantID: localParticipant.id,
222
         _localParticipantID: localParticipant.id,
223
+        _isMobile: isMobileBrowser(),
215
         _raisedHand: localParticipant.raisedHand
224
         _raisedHand: localParticipant.raisedHand
216
     };
225
     };
217
 }
226
 }

+ 53
- 20
react/features/reactions/components/web/ReactionsMenuButton.js Vedi File

2
 
2
 
3
 import React from 'react';
3
 import React from 'react';
4
 
4
 
5
+import { isMobileBrowser } from '../../../base/environment/utils';
5
 import { translate } from '../../../base/i18n';
6
 import { translate } from '../../../base/i18n';
6
-import { IconRaisedHand } from '../../../base/icons';
7
+import { IconArrowUp, IconRaisedHand } from '../../../base/icons';
7
 import { getLocalParticipant } from '../../../base/participants';
8
 import { getLocalParticipant } from '../../../base/participants';
8
 import { connect } from '../../../base/redux';
9
 import { connect } from '../../../base/redux';
10
+import { ToolboxButtonWithIcon } from '../../../base/toolbox/components';
9
 import ToolbarButton from '../../../toolbox/components/web/ToolbarButton';
11
 import ToolbarButton from '../../../toolbox/components/web/ToolbarButton';
10
 import { toggleReactionsMenuVisibility } from '../../actions.web';
12
 import { toggleReactionsMenuVisibility } from '../../actions.web';
11
 import { type ReactionEmojiProps } from '../../constants';
13
 import { type ReactionEmojiProps } from '../../constants';
12
-import { getReactionsQueue } from '../../functions.any';
14
+import { getReactionsQueue, isReactionsEnabled } from '../../functions.any';
13
 import { getReactionsMenuVisibility } from '../../functions.web';
15
 import { getReactionsMenuVisibility } from '../../functions.web';
14
 
16
 
15
 import ReactionEmoji from './ReactionEmoji';
17
 import ReactionEmoji from './ReactionEmoji';
18
 type Props = {
20
 type Props = {
19
 
21
 
20
     /**
22
     /**
21
-     * Used for translation.
23
+     * Whether or not reactions are enabled.
22
      */
24
      */
23
-    t: Function,
25
+    _reactionsEnabled: Boolean,
24
 
26
 
25
     /**
27
     /**
26
-     * Whether or not the local participant's hand is raised.
28
+     * Redux dispatch function.
27
      */
29
      */
28
-    raisedHand: boolean,
30
+    dispatch: Function,
29
 
31
 
30
     /**
32
     /**
31
-     * Click handler for the reaction button. Toggles the reactions menu.
33
+     * Click handler for raise hand functionality.
32
      */
34
      */
33
-    onReactionsClick: Function,
35
+    handleClick: Function,
34
 
36
 
35
     /**
37
     /**
36
      * Whether or not the reactions menu is open.
38
      * Whether or not the reactions menu is open.
37
      */
39
      */
38
     isOpen: boolean,
40
     isOpen: boolean,
39
 
41
 
42
+    /**
43
+     * Whether or not it's a mobile browser.
44
+     */
45
+    isMobile: boolean,
46
+
47
+    /**
48
+     * Whether or not the local participant's hand is raised.
49
+     */
50
+    raisedHand: boolean,
51
+
40
     /**
52
     /**
41
      * The array of reactions to be displayed.
53
      * The array of reactions to be displayed.
42
      */
54
      */
43
     reactionsQueue: Array<ReactionEmojiProps>,
55
     reactionsQueue: Array<ReactionEmojiProps>,
44
 
56
 
45
     /**
57
     /**
46
-     * Redux dispatch function.
58
+     * Used for translation.
47
      */
59
      */
48
-    dispatch: Function
60
+    t: Function
49
 };
61
 };
50
 
62
 
51
 
63
 
57
  * @returns {ReactElement}
69
  * @returns {ReactElement}
58
  */
70
  */
59
 function ReactionsMenuButton({
71
 function ReactionsMenuButton({
60
-    t,
61
-    raisedHand,
72
+    _reactionsEnabled,
73
+    dispatch,
74
+    handleClick,
62
     isOpen,
75
     isOpen,
76
+    isMobile,
77
+    raisedHand,
63
     reactionsQueue,
78
     reactionsQueue,
64
-    dispatch
79
+    t
65
 }: Props) {
80
 }: Props) {
66
 
81
 
67
     /**
82
     /**
73
         dispatch(toggleReactionsMenuVisibility());
88
         dispatch(toggleReactionsMenuVisibility());
74
     }
89
     }
75
 
90
 
91
+    const raiseHandButton = (<ToolbarButton
92
+        accessibilityLabel = { t('toolbar.accessibilityLabel.raiseHand') }
93
+        icon = { IconRaisedHand }
94
+        key = 'raise-hand'
95
+        onClick = { handleClick }
96
+        toggled = { raisedHand }
97
+        tooltip = { t('toolbar.raiseHand') } />);
98
+
76
     return (
99
     return (
77
         <div className = 'reactions-menu-popup-container'>
100
         <div className = 'reactions-menu-popup-container'>
78
             <ReactionsMenuPopup>
101
             <ReactionsMenuPopup>
79
-                <ToolbarButton
80
-                    accessibilityLabel = { t('toolbar.accessibilityLabel.reactionsMenu') }
81
-                    icon = { IconRaisedHand }
82
-                    key = 'reactions'
83
-                    onClick = { toggleReactionsMenu }
84
-                    toggled = { raisedHand }
85
-                    tooltip = { t(`toolbar.${isOpen ? 'closeReactionsMenu' : 'openReactionsMenu'}`) } />
102
+                {!_reactionsEnabled || isMobile ? raiseHandButton
103
+                    : (
104
+                        <ToolboxButtonWithIcon
105
+                            ariaControls = 'reactions-menu-dialog'
106
+                            ariaExpanded = { isOpen }
107
+                            ariaHasPopup = { true }
108
+                            ariaLabel = { t('toolbar.accessibilityLabel.reactionsMenu') }
109
+                            icon = { IconArrowUp }
110
+                            iconDisabled = { false }
111
+                            iconId = 'reactions-menu-button'
112
+                            iconTooltip = { t(`toolbar.${isOpen ? 'closeReactionsMenu' : 'openReactionsMenu'}`) }
113
+                            onIconClick = { toggleReactionsMenu }>
114
+                            {raiseHandButton}
115
+                        </ToolboxButtonWithIcon>
116
+                    )}
86
             </ReactionsMenuPopup>
117
             </ReactionsMenuPopup>
87
             {reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji
118
             {reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji
88
                 index = { index }
119
                 index = { index }
103
     const localParticipant = getLocalParticipant(state);
134
     const localParticipant = getLocalParticipant(state);
104
 
135
 
105
     return {
136
     return {
137
+        _reactionsEnabled: isReactionsEnabled(state),
106
         isOpen: getReactionsMenuVisibility(state),
138
         isOpen: getReactionsMenuVisibility(state),
139
+        isMobile: isMobileBrowser(),
107
         reactionsQueue: getReactionsQueue(state),
140
         reactionsQueue: getReactionsQueue(state),
108
         raisedHand: localParticipant?.raisedHand
141
         raisedHand: localParticipant?.raisedHand
109
     };
142
     };

+ 3
- 3
react/features/reactions/functions.any.js Vedi File

151
  * @returns {boolean}
151
  * @returns {boolean}
152
  */
152
  */
153
 export function isReactionsEnabled(state: Object) {
153
 export function isReactionsEnabled(state: Object) {
154
-    const { enableReactions } = state['features/base/config'];
154
+    const { disableReactions } = state['features/base/config'];
155
 
155
 
156
     if (navigator.product === 'ReactNative') {
156
     if (navigator.product === 'ReactNative') {
157
-        return enableReactions && getFeatureFlag(state, REACTIONS_ENABLED, true);
157
+        return !disableReactions && getFeatureFlag(state, REACTIONS_ENABLED, true);
158
     }
158
     }
159
 
159
 
160
-    return enableReactions;
160
+    return !disableReactions;
161
 }
161
 }

+ 5
- 5
react/features/settings/components/web/SoundsTab.js Vedi File

15
 export type Props = {
15
 export type Props = {
16
     ...$Exact<AbstractDialogTabProps>,
16
     ...$Exact<AbstractDialogTabProps>,
17
 
17
 
18
+    /**
19
+     * Whether or not the reactions feature is enabled.
20
+     */
21
+    enableReactions: Boolean,
22
+
18
     /**
23
     /**
19
      * Whether or not the sound for the incoming message should play.
24
      * Whether or not the sound for the incoming message should play.
20
      */
25
      */
40
     */
45
     */
41
     soundsReactions: Boolean,
46
     soundsReactions: Boolean,
42
 
47
 
43
-    /**
44
-     * Whether or not the reactions feature is enabled.
45
-     */
46
-    enableReactions: Boolean,
47
-
48
     /**
48
     /**
49
      * Invoked to obtain translated strings.
49
      * Invoked to obtain translated strings.
50
      */
50
      */

+ 2
- 1
react/features/settings/functions.js Vedi File

10
 import { toState } from '../base/redux';
10
 import { toState } from '../base/redux';
11
 import { parseStandardURIString } from '../base/util';
11
 import { parseStandardURIString } from '../base/util';
12
 import { isFollowMeActive } from '../follow-me';
12
 import { isFollowMeActive } from '../follow-me';
13
+import { isReactionsEnabled } from '../reactions/functions.any';
13
 
14
 
14
 import { SS_DEFAULT_FRAME_RATE, SS_SUPPORTED_FRAMERATES } from './constants';
15
 import { SS_DEFAULT_FRAME_RATE, SS_SUPPORTED_FRAMERATES } from './constants';
15
 
16
 
174
         soundsTalkWhileMuted,
175
         soundsTalkWhileMuted,
175
         soundsReactions
176
         soundsReactions
176
     } = state['features/base/settings'];
177
     } = state['features/base/settings'];
177
-    const { enableReactions } = state['features/base/config'];
178
+    const enableReactions = isReactionsEnabled(state);
178
 
179
 
179
     return {
180
     return {
180
         soundsIncomingMessage,
181
         soundsIncomingMessage,

+ 0
- 84
react/features/toolbox/components/web/RaiseHandButton.js Vedi File

1
-// @flow
2
-
3
-import { translate } from '../../../base/i18n';
4
-import { IconRaisedHand } from '../../../base/icons';
5
-import { getLocalParticipant } from '../../../base/participants';
6
-import { connect } from '../../../base/redux';
7
-import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
8
-
9
-type Props = AbstractButtonProps & {
10
-
11
-    /**
12
-     * Whether or not the local participant's hand is raised.
13
-     */
14
-    _raisedHand: boolean,
15
-};
16
-
17
-/**
18
- * Implementation of a button for toggling raise hand functionality.
19
- */
20
-class RaiseHandButton extends AbstractButton<Props, *> {
21
-    accessibilityLabel = 'toolbar.accessibilityLabel.raiseHand';
22
-    icon = IconRaisedHand
23
-    label = 'toolbar.raiseYourHand';
24
-    toggledLabel = 'toolbar.lowerYourHand'
25
-
26
-    /**
27
-     * Retrieves tooltip dynamically.
28
-     */
29
-    get tooltip() {
30
-        return this.props._raisedHand ? 'toolbar.lowerYourHand' : 'toolbar.raiseYourHand';
31
-    }
32
-
33
-    /**
34
-     * Required by linter due to AbstractButton overwritten prop being writable.
35
-     *
36
-     * @param {string} value - The value.
37
-     */
38
-    set tooltip(value) {
39
-        return value;
40
-    }
41
-
42
-    /**
43
-     * Handles clicking / pressing the button, and opens the appropriate dialog.
44
-     *
45
-     * @protected
46
-     * @returns {void}
47
-     */
48
-    _handleClick() {
49
-        const { handleClick } = this.props;
50
-
51
-        if (handleClick) {
52
-            handleClick();
53
-
54
-            return;
55
-        }
56
-    }
57
-
58
-    /**
59
-     * Indicates whether this button is in toggled state or not.
60
-     *
61
-     * @override
62
-     * @protected
63
-     * @returns {boolean}
64
-     */
65
-    _isToggled() {
66
-        return this.props._raisedHand;
67
-    }
68
-}
69
-
70
-/**
71
- * Function that maps parts of Redux state tree into component props.
72
- *
73
- * @param {Object} state - Redux state.
74
- * @returns {Object}
75
- */
76
-const mapStateToProps = state => {
77
-    const localParticipant = getLocalParticipant(state);
78
-
79
-    return {
80
-        _raisedHand: localParticipant.raisedHand
81
-    };
82
-};
83
-
84
-export default translate(connect(mapStateToProps)(RaiseHandButton));

+ 8
- 60
react/features/toolbox/components/web/Toolbox.js Vedi File

17
 import JitsiMeetJS from '../../../base/lib-jitsi-meet';
17
 import JitsiMeetJS from '../../../base/lib-jitsi-meet';
18
 import {
18
 import {
19
     getLocalParticipant,
19
     getLocalParticipant,
20
-    getParticipantCount,
21
     haveParticipantWithScreenSharingFeature,
20
     haveParticipantWithScreenSharingFeature,
22
     raiseHand
21
     raiseHand
23
 } from '../../../base/participants';
22
 } from '../../../base/participants';
87
 import FullscreenButton from './FullscreenButton';
86
 import FullscreenButton from './FullscreenButton';
88
 import OverflowMenuButton from './OverflowMenuButton';
87
 import OverflowMenuButton from './OverflowMenuButton';
89
 import ProfileButton from './ProfileButton';
88
 import ProfileButton from './ProfileButton';
90
-import RaiseHandButton from './RaiseHandButton';
91
 import Separator from './Separator';
89
 import Separator from './Separator';
92
 import ShareDesktopButton from './ShareDesktopButton';
90
 import ShareDesktopButton from './ShareDesktopButton';
93
 import ToggleCameraButton from './ToggleCameraButton';
91
 import ToggleCameraButton from './ToggleCameraButton';
180
      */
178
      */
181
     _overflowMenuVisible: boolean,
179
     _overflowMenuVisible: boolean,
182
 
180
 
183
-    /**
184
-     * Number of participants in the conference.
185
-     */
186
-    _participantCount: number,
187
-
188
     /**
181
     /**
189
      * Whether or not the participants pane is open.
182
      * Whether or not the participants pane is open.
190
      */
183
      */
254
 
247
 
255
 declare var APP: Object;
248
 declare var APP: Object;
256
 
249
 
257
-type State = {
258
-    reactionsShortcutsRegistered: boolean
259
-};
260
-
261
 /**
250
 /**
262
  * Implements the conference toolbox on React/Web.
251
  * Implements the conference toolbox on React/Web.
263
  *
252
  *
264
  * @extends Component
253
  * @extends Component
265
  */
254
  */
266
-class Toolbox extends Component<Props, State> {
255
+class Toolbox extends Component<Props> {
267
     /**
256
     /**
268
      * Initializes a new {@code Toolbox} instance.
257
      * Initializes a new {@code Toolbox} instance.
269
      *
258
      *
273
     constructor(props: Props) {
262
     constructor(props: Props) {
274
         super(props);
263
         super(props);
275
 
264
 
276
-        this.state = {
277
-            reactionsShortcutsRegistered: false
278
-        };
279
-
280
         // Bind event handlers so they are only bound once per instance.
265
         // Bind event handlers so they are only bound once per instance.
281
         this._onMouseOut = this._onMouseOut.bind(this);
266
         this._onMouseOut = this._onMouseOut.bind(this);
282
         this._onMouseOver = this._onMouseOver.bind(this);
267
         this._onMouseOver = this._onMouseOver.bind(this);
306
      * @returns {void}
291
      * @returns {void}
307
      */
292
      */
308
     componentDidMount() {
293
     componentDidMount() {
309
-        const { _toolbarButtons, t, dispatch, _reactionsEnabled, _participantCount } = this.props;
294
+        const { _toolbarButtons, t, dispatch, _reactionsEnabled } = this.props;
310
         const KEYBOARD_SHORTCUTS = [
295
         const KEYBOARD_SHORTCUTS = [
311
             isToolbarButtonEnabled('videoquality', _toolbarButtons) && {
296
             isToolbarButtonEnabled('videoquality', _toolbarButtons) && {
312
                 character: 'A',
297
                 character: 'A',
355
             }
340
             }
356
         });
341
         });
357
 
342
 
358
-        if (_reactionsEnabled && _participantCount > 1) {
343
+        if (_reactionsEnabled) {
359
             const REACTION_SHORTCUTS = Object.keys(REACTIONS).map(key => {
344
             const REACTION_SHORTCUTS = Object.keys(REACTIONS).map(key => {
360
                 const onShortcutSendReaction = () => {
345
                 const onShortcutSendReaction = () => {
361
                     dispatch(addReactionToBuffer(key));
346
                     dispatch(addReactionToBuffer(key));
389
      * @inheritdoc
374
      * @inheritdoc
390
      */
375
      */
391
     componentDidUpdate(prevProps) {
376
     componentDidUpdate(prevProps) {
392
-        const { _dialog, _reactionsEnabled, _participantCount, dispatch, t } = this.props;
377
+        const { _dialog, dispatch } = this.props;
393
 
378
 
394
 
379
 
395
         if (prevProps._overflowMenuVisible
380
         if (prevProps._overflowMenuVisible
398
             this._onSetOverflowVisible(false);
383
             this._onSetOverflowVisible(false);
399
             dispatch(setToolbarHovered(false));
384
             dispatch(setToolbarHovered(false));
400
         }
385
         }
401
-
402
-        if (!this.state.reactionsShortcutsRegistered
403
-            && (prevProps._reactionsEnabled !== _reactionsEnabled
404
-            || prevProps._participantCount !== _participantCount)) {
405
-            if (_reactionsEnabled && _participantCount > 1) {
406
-                // eslint-disable-next-line react/no-did-update-set-state
407
-                this.setState({
408
-                    reactionsShortcutsRegistered: true
409
-                });
410
-                const REACTION_SHORTCUTS = Object.keys(REACTIONS).map(key => {
411
-                    const onShortcutSendReaction = () => {
412
-                        dispatch(addReactionToBuffer(key));
413
-                        sendAnalytics(createShortcutEvent(
414
-                            `reaction.${key}`
415
-                        ));
416
-                    };
417
-
418
-                    return {
419
-                        character: REACTIONS[key].shortcutChar,
420
-                        exec: onShortcutSendReaction,
421
-                        helpDescription: t(`toolbar.reaction${key.charAt(0).toUpperCase()}${key.slice(1)}`),
422
-                        altKey: true
423
-                    };
424
-                });
425
-
426
-                REACTION_SHORTCUTS.forEach(shortcut => {
427
-                    APP.keyboardshortcut.registerShortcut(
428
-                        shortcut.character,
429
-                        null,
430
-                        shortcut.exec,
431
-                        shortcut.helpDescription,
432
-                        shortcut.altKey);
433
-                });
434
-            }
435
-        }
436
     }
386
     }
437
 
387
 
438
     /**
388
     /**
445
         [ 'A', 'C', 'D', 'R', 'S' ].forEach(letter =>
395
         [ 'A', 'C', 'D', 'R', 'S' ].forEach(letter =>
446
             APP.keyboardshortcut.unregisterShortcut(letter));
396
             APP.keyboardshortcut.unregisterShortcut(letter));
447
 
397
 
448
-        if (this.props._reactionsEnabled && this.state.reactionsShortcutsRegistered) {
398
+        if (this.props._reactionsEnabled) {
449
             Object.keys(REACTIONS).map(key => REACTIONS[key].shortcutChar)
399
             Object.keys(REACTIONS).map(key => REACTIONS[key].shortcutChar)
450
                 .forEach(letter =>
400
                 .forEach(letter =>
451
                     APP.keyboardshortcut.unregisterShortcut(letter, true));
401
                     APP.keyboardshortcut.unregisterShortcut(letter, true));
613
         const {
563
         const {
614
             _feedbackConfigured,
564
             _feedbackConfigured,
615
             _isMobile,
565
             _isMobile,
616
-            _screenSharing,
617
-            _reactionsEnabled
566
+            _screenSharing
618
         } = this.props;
567
         } = this.props;
619
 
568
 
620
         const microphone = {
569
         const microphone = {
651
 
600
 
652
         const raisehand = {
601
         const raisehand = {
653
             key: 'raisehand',
602
             key: 'raisehand',
654
-            Content: _reactionsEnabled ? ReactionsMenuButton : RaiseHandButton,
655
-            handleClick: _reactionsEnabled ? null : this._onToolbarToggleRaiseHand,
603
+            Content: ReactionsMenuButton,
604
+            handleClick: this._onToolbarToggleRaiseHand,
656
             group: 2
605
             group: 2
657
         };
606
         };
658
 
607
 
1388
         _localParticipantID: localParticipant?.id,
1337
         _localParticipantID: localParticipant?.id,
1389
         _localVideo: localVideo,
1338
         _localVideo: localVideo,
1390
         _overflowMenuVisible: overflowMenuVisible,
1339
         _overflowMenuVisible: overflowMenuVisible,
1391
-        _participantCount: getParticipantCount(state),
1392
         _participantsPaneOpen: getParticipantsPaneOpen(state),
1340
         _participantsPaneOpen: getParticipantsPaneOpen(state),
1393
         _raisedHand: localParticipant?.raisedHand,
1341
         _raisedHand: localParticipant?.raisedHand,
1394
         _reactionsEnabled: isReactionsEnabled(state),
1342
         _reactionsEnabled: isReactionsEnabled(state),

Loading…
Annulla
Salva