import React, { Component } from 'react'; import JitsiPopover from '../../../../modules/UI/util/JitsiPopover'; import { JitsiParticipantConnectionStatus } from '../../base/lib-jitsi-meet'; import { ConnectionStatsTable } from '../../connection-stats'; declare var $: Object; declare var interfaceConfig: Object; // Converts the percent for connection quality into a string recognized for CSS. const QUALITY_TO_WIDTH = [ // Full (5 bars) { percent: 80, width: '100%' }, // 4 bars { percent: 60, width: '80%' }, // 3 bars { percent: 40, width: '55%' }, // 2 bars { percent: 20, width: '40%' }, // 1 bar { percent: 0, width: '20%' } // Note: we never show 0 bars. ]; /** * Implements a React {@link Component} which displays the current connection * quality percentage and has a popover to show more detailed connection stats. * * @extends {Component} */ class ConnectionIndicator extends Component { /** * {@code ConnectionIndicator} component's property types. * * @static */ static propTypes = { /** * Whether or not the displays stats are for local video. */ isLocalVideo: React.PropTypes.bool, /** * The callback to invoke when the hover state over the popover changes. */ onHover: React.PropTypes.func, /** * Whether or not the popover should display a link that can toggle * a more detailed view of the stats. */ showMoreLink: React.PropTypes.bool, /** * An object that contains statistics related to connection quality. * * { * bandwidth: Object, * bitrate: Object, * connectionStatus: String, * framerate: Object, * packetLoss: Object, * percent: Number, * resolution: Object, * transport: Array * } */ stats: React.PropTypes.object, /** * Invoked to obtain translated strings. */ t: React.PropTypes.func }; /** * Initializes a new {@code ConnectionIndicator} instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. */ constructor(props) { super(props); /** * The internal reference to topmost DOM/HTML element backing the React * {@code Component}. Accessed directly for associating an element as * the trigger for a popover. * * @private * @type {HTMLDivElement} */ this._rootElement = null; this.state = { /** * Whether or not the popover content should display additional * statistics. * * @type {boolean} */ showMoreStats: false }; // Bind event handlers so they are only bound once for every instance. this._onToggleShowMore = this._onToggleShowMore.bind(this); this._setRootElement = this._setRootElement.bind(this); } /** * Creates a popover instance to display when the component is hovered. * * @inheritdoc * returns {void} */ componentDidMount() { this.popover = new JitsiPopover($(this._rootElement), { content: this._renderStatisticsTable(), skin: 'black', position: interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top' }); this.popover.addOnHoverPopover(this.props.onHover); } /** * Updates the contents of the popover. This is done manually because the * popover is not a React Component yet and so is not automatiucally aware * of changed data. * * @inheritdoc * returns {void} */ componentDidUpdate() { this.popover.updateContent(this._renderStatisticsTable()); } /** * Cleans up any popover instance that is linked to the component. * * @inheritdoc * returns {void} */ componentWillUnmount() { this.popover.forceHide(); this.popover.remove(); } /** * Implements React's {@link Component#render()}. * * @inheritdoc * @returns {ReactElement} */ render() { return (