feat: (speaker-stats) fix refresh and minor refactoring

This commit is contained in:
Andrei Oltean 2021-11-29 11:33:38 +02:00 committed by Calinteodor
parent 827e8201d4
commit 8ef48a8a1d
8 changed files with 54 additions and 23 deletions

View File

@ -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.

View File

@ -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();

View File

@ -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));

View File

@ -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 (
<View
key = { props.displayName + props.dominantSpeakerTime }
key = { props.participantId }
style = { style.speakerStatsItemContainer }>
<View style = { style.speakerStatsItemStatus }>
<View style = { [ style.speakerStatsItemStatusDot, { backgroundColor: dotColor } ] } />

View File

@ -13,7 +13,7 @@ import SpeakerStatsItem from './SpeakerStatsItem';
* @returns {React$Element<any>}
*/
const SpeakerStatsList = () => {
const items = abstractSpeakerStatsList(SpeakerStatsItem, false);
const items = abstractSpeakerStatsList(SpeakerStatsItem);
return (
<View>

View File

@ -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 (
<div
className = { rowDisplayClass }
key = { props.displayName } >
key = { props.participantId } >
<div className = 'speaker-stats-item__status'>
<span className = { speakerStatusClass } />
</div>

View File

@ -1,3 +1 @@
export const SPEAKER_STATS_RELOAD_INTERVAL = 1000;
export const SPEAKER_STATS_VIEW_MODEL_ID = 'speakerStats';

View File

@ -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';