From 8ef48a8a1d35d35ae7adadc8e7691b990b1f5f72 Mon Sep 17 00:00:00 2001 From: Andrei Oltean Date: Mon, 29 Nov 2021 11:33:38 +0200 Subject: [PATCH] feat: (speaker-stats) fix refresh and minor refactoring --- react/features/base/flags/constants.js | 4 +-- .../components/AbstractSpeakerStatsList.js | 30 ++++++++++--------- .../components/native/SpeakerStatsButton.js | 22 +++++++++++++- .../components/native/SpeakerStatsItem.js | 7 ++++- .../components/native/SpeakerStatsList.js | 2 +- .../components/web/SpeakerStatsItem.js | 7 ++++- react/features/speaker-stats/constants.js | 2 -- .../toolbox/components/web/Toolbox.js | 3 +- 8 files changed, 54 insertions(+), 23 deletions(-) diff --git a/react/features/base/flags/constants.js b/react/features/base/flags/constants.js index 72d16c145..2e17c8458 100644 --- a/react/features/base/flags/constants.js +++ b/react/features/base/flags/constants.js @@ -99,10 +99,10 @@ export const IOS_SCREENSHARING_ENABLED = 'ios.screensharing.enabled'; export const ANDROID_SCREENSHARING_ENABLED = 'android.screensharing.enabled'; /** - * Flag indicating if speaker statistics should be enabled in android. + * Flag indicating if speaker statistics should be enabled. * Default: enabled (true). */ -export const ANDROID_SPEAKERSTATS_ENABLED = 'android.speakerstats.enabled'; +export const SPEAKERSTATS_ENABLED = 'speakerstats.enabled'; /** * Flag indicating if kickout is enabled. diff --git a/react/features/speaker-stats/components/AbstractSpeakerStatsList.js b/react/features/speaker-stats/components/AbstractSpeakerStatsList.js index 3092c8f24..d3fbdda62 100644 --- a/react/features/speaker-stats/components/AbstractSpeakerStatsList.js +++ b/react/features/speaker-stats/components/AbstractSpeakerStatsList.js @@ -14,17 +14,17 @@ import { * Component that renders the list of speaker stats. * * @param {Function} speakerStatsItem - React element tu use when rendering. - * @param {boolean} [isWeb=false] - Is for web in browser. * @returns {Function} */ -const abstractSpeakerStatsList = (speakerStatsItem: Function, isWeb: boolean = true): Function[] => { +const abstractSpeakerStatsList = (speakerStatsItem: Function): Function[] => { const dispatch = useDispatch(); const { t } = useTranslation(); const conference = useSelector(state => state['features/base/conference'].conference); + const speakerStats = useSelector(state => state['features/speaker-stats'].stats); const localParticipant = useSelector(getLocalParticipant); - const { enableFacialRecognition } = isWeb ? useSelector(state => state['features/base/config']) : {}; - const { facialExpressions: localFacialExpressions } = isWeb - ? useSelector(state => state['features/facial-recognition']) : {}; + const { enableFacialRecognition } = useSelector(state => state['features/base/config']) || {}; + const { facialExpressions: localFacialExpressions } = useSelector( + state => state['features/facial-recognition']) || {}; /** * Update the internal state with the latest speaker stats. @@ -62,21 +62,22 @@ const abstractSpeakerStatsList = (speakerStatsItem: Function, isWeb: boolean = t }); const updateStats = useCallback( - () => dispatch(initUpdateStats( - () => getLocalSpeakerStats())), [ dispatch, initUpdateStats() ]); + () => dispatch(initUpdateStats(getLocalSpeakerStats)), + [ dispatch, initUpdateStats ]); useEffect(() => { - const updateInterval = setInterval(() => updateStats(), SPEAKER_STATS_RELOAD_INTERVAL); + const intervalId = setInterval(() => { + updateStats(); + }, SPEAKER_STATS_RELOAD_INTERVAL); - return () => { - clearInterval(updateInterval); - }; - }, [ dispatch, conference ]); + return () => clearInterval(intervalId); + }, []); - const userIds = Object.keys(getLocalSpeakerStats()); + const localSpeakerStats = Object.keys(speakerStats).length === 0 ? getLocalSpeakerStats() : speakerStats; + const userIds = Object.keys(localSpeakerStats); return userIds.map(userId => { - const statsModel = getLocalSpeakerStats()[userId]; + const statsModel = localSpeakerStats[userId]; if (!statsModel || statsModel.hidden) { return null; @@ -85,6 +86,7 @@ const abstractSpeakerStatsList = (speakerStatsItem: Function, isWeb: boolean = t props.isDominantSpeaker = statsModel.isDominantSpeaker(); props.dominantSpeakerTime = statsModel.getTotalDominantSpeakerTime(); + props.participantId = userId; props.hasLeft = statsModel.hasLeft(); if (enableFacialRecognition) { props.facialExpressions = statsModel.getFacialExpressions(); diff --git a/react/features/speaker-stats/components/native/SpeakerStatsButton.js b/react/features/speaker-stats/components/native/SpeakerStatsButton.js index e9d557330..8ade77154 100644 --- a/react/features/speaker-stats/components/native/SpeakerStatsButton.js +++ b/react/features/speaker-stats/components/native/SpeakerStatsButton.js @@ -1,6 +1,7 @@ // @flow import { createToolbarEvent, sendAnalytics } from '../../../analytics'; +import { getFeatureFlag, SPEAKERSTATS_ENABLED } from '../../../base/flags'; import { translate } from '../../../base/i18n'; import { connect } from '../../../base/redux'; import { navigate } from '../../../conference/components/native/ConferenceNavigationContainerRef'; @@ -25,4 +26,23 @@ class SpeakerStatsButton extends AbstractSpeakerStatsButton { } } -export default translate(connect()(SpeakerStatsButton)); +/** + * Maps (parts of) the redux state to the associated props for the + * {@code SpeakerStatsButton} component. + * + * @param {Object} state - The Redux state. + * @private + * @returns {{ + * visible: boolean + * }} + */ +function _mapStateToProps(state): Object { + const enabled = getFeatureFlag(state, SPEAKERSTATS_ENABLED, true); + + return { + visible: enabled + }; +} + + +export default translate(connect(_mapStateToProps)(SpeakerStatsButton)); diff --git a/react/features/speaker-stats/components/native/SpeakerStatsItem.js b/react/features/speaker-stats/components/native/SpeakerStatsItem.js index 50eb3f873..8aa7b10cd 100644 --- a/react/features/speaker-stats/components/native/SpeakerStatsItem.js +++ b/react/features/speaker-stats/components/native/SpeakerStatsItem.js @@ -20,6 +20,11 @@ type Props = { */ dominantSpeakerTime: number, + /** + * The id of the user. + */ + participantId: string, + /** * True if the participant is no longer in the meeting. */ @@ -41,7 +46,7 @@ const SpeakerStatsItem = (props: Props) => { return ( diff --git a/react/features/speaker-stats/components/native/SpeakerStatsList.js b/react/features/speaker-stats/components/native/SpeakerStatsList.js index 3fc6071c0..949122a66 100644 --- a/react/features/speaker-stats/components/native/SpeakerStatsList.js +++ b/react/features/speaker-stats/components/native/SpeakerStatsList.js @@ -13,7 +13,7 @@ import SpeakerStatsItem from './SpeakerStatsItem'; * @returns {React$Element} */ const SpeakerStatsList = () => { - const items = abstractSpeakerStatsList(SpeakerStatsItem, false); + const items = abstractSpeakerStatsList(SpeakerStatsItem); return ( diff --git a/react/features/speaker-stats/components/web/SpeakerStatsItem.js b/react/features/speaker-stats/components/web/SpeakerStatsItem.js index fd7d19bb1..94a7a91ff 100644 --- a/react/features/speaker-stats/components/web/SpeakerStatsItem.js +++ b/react/features/speaker-stats/components/web/SpeakerStatsItem.js @@ -35,6 +35,11 @@ type Props = { */ dominantSpeakerTime: number, + /** + * The id of the user. + */ + participantId: string, + /** * True if the participant is no longer in the meeting. */ @@ -68,7 +73,7 @@ const SpeakerStatsItem = (props: Props) => { return (
+ key = { props.participantId } >
diff --git a/react/features/speaker-stats/constants.js b/react/features/speaker-stats/constants.js index 072538631..94a9143cb 100644 --- a/react/features/speaker-stats/constants.js +++ b/react/features/speaker-stats/constants.js @@ -1,3 +1 @@ export const SPEAKER_STATS_RELOAD_INTERVAL = 1000; - -export const SPEAKER_STATS_VIEW_MODEL_ID = 'speakerStats'; diff --git a/react/features/toolbox/components/web/Toolbox.js b/react/features/toolbox/components/web/Toolbox.js index 9a2e7c157..96925a9db 100644 --- a/react/features/toolbox/components/web/Toolbox.js +++ b/react/features/toolbox/components/web/Toolbox.js @@ -10,7 +10,8 @@ import { createToolbarEvent, sendAnalytics } from '../../../analytics'; -import { getToolbarButtons, isToolbarButtonEnabled } from '../../../base/config'; +import { getToolbarButtons } from '../../../base/config'; +import { isToolbarButtonEnabled } from '../../../base/config/functions.web'; import { openDialog, toggleDialog } from '../../../base/dialog'; import { isIosMobileBrowser, isMobileBrowser } from '../../../base/environment/utils'; import { translate } from '../../../base/i18n';