import React from 'react'; import cx from 'classnames'; import Button from '/imports/ui/components/button/component'; import Toggle from '/imports/ui/components/switch/component'; import LocalesDropdown from '/imports/ui/components/locales-dropdown/component'; import { defineMessages, injectIntl } from 'react-intl'; import BaseMenu from '../base/component'; import { styles } from '../styles'; import VideoService from '/imports/ui/components/video-provider/service'; import { ACTIONS } from '/imports/ui/components/layout/enums'; const MIN_FONTSIZE = 0; const SHOW_AUDIO_FILTERS = (Meteor.settings.public.app .showAudioFilters === undefined) ? true : Meteor.settings.public.app.showAudioFilters; const intlMessages = defineMessages({ applicationSectionTitle: { id: 'app.submenu.application.applicationSectionTitle', description: 'Application section title', }, animationsLabel: { id: 'app.submenu.application.animationsLabel', description: 'animations label', }, audioFilterLabel: { id: 'app.submenu.application.audioFilterLabel', description: 'audio filters label', }, fontSizeControlLabel: { id: 'app.submenu.application.fontSizeControlLabel', description: 'label for font size ontrol', }, increaseFontBtnLabel: { id: 'app.submenu.application.increaseFontBtnLabel', description: 'label for button to increase font size', }, increaseFontBtnDesc: { id: 'app.submenu.application.increaseFontBtnDesc', description: 'adds descriptive context to increase font size button', }, decreaseFontBtnLabel: { id: 'app.submenu.application.decreaseFontBtnLabel', description: 'label for button to reduce font size', }, decreaseFontBtnDesc: { id: 'app.submenu.application.decreaseFontBtnDesc', description: 'adds descriptive context to decrease font size button', }, languageLabel: { id: 'app.submenu.application.languageLabel', description: 'displayed label for changing application locale', }, currentValue: { id: 'app.submenu.application.currentSize', description: 'current value label', }, languageOptionLabel: { id: 'app.submenu.application.languageOptionLabel', description: 'default change language option when locales are available', }, noLocaleOptionLabel: { id: 'app.submenu.application.noLocaleOptionLabel', description: 'default change language option when no locales available', }, paginationEnabledLabel: { id: 'app.submenu.application.paginationEnabledLabel', description: 'enable/disable video pagination', }, }); class ApplicationMenu extends BaseMenu { static setHtmlFontSize(size) { document.getElementsByTagName('html')[0].style.fontSize = size; } constructor(props) { super(props); this.state = { settingsName: 'application', settings: props.settings, isLargestFontSize: false, isSmallestFontSize: false, showSelect: false, fontSizes: [ '12px', '14px', '16px', '18px', '20px', ], audioFilterEnabled: ApplicationMenu.isAudioFilterEnabled(props .settings.microphoneConstraints), }; } componentDidMount() { this.setInitialFontSize(); } componentWillUnmount() { // fix Warning: Can't perform a React state update on an unmounted component this.setState = (state, callback) => { }; } setInitialFontSize() { const { fontSizes } = this.state; const clientFont = document.getElementsByTagName('html')[0].style.fontSize; const hasFont = fontSizes.includes(clientFont); if (!hasFont) { fontSizes.push(clientFont); fontSizes.sort(); } const fontIndex = fontSizes.indexOf(clientFont); this.changeFontSize(clientFont); this.setState({ isSmallestFontSize: fontIndex <= MIN_FONTSIZE, isLargestFontSize: fontIndex >= (fontSizes.length - 1), fontSizes, }); } static isAudioFilterEnabled(_constraints) { if (typeof _constraints === 'undefined') return true; const _isConstraintEnabled = (constraintValue) => { switch (typeof constraintValue) { case 'boolean': return constraintValue; case 'string': return constraintValue === 'true'; case 'object': return !!(constraintValue.exact || constraintValue.ideal); default: return false; } }; let isAnyFilterEnabled = true; const constraints = _constraints && (typeof _constraints.advanced === 'object') ? _constraints.advanced : _constraints || {}; isAnyFilterEnabled = Object.values(constraints).find( constraintValue => _isConstraintEnabled(constraintValue), ); return isAnyFilterEnabled; } handleAudioFilterChange() { const _audioFilterEnabled = !ApplicationMenu.isAudioFilterEnabled(this .state.settings.microphoneConstraints); const _newConstraints = { autoGainControl: _audioFilterEnabled, echoCancellation: _audioFilterEnabled, noiseSuppression: _audioFilterEnabled, }; const obj = this.state; obj.settings.microphoneConstraints = _newConstraints; this.handleUpdateSettings(this.state.settings, obj.settings); } handleUpdateFontSize(size) { const obj = this.state; obj.settings.fontSize = size; this.handleUpdateSettings(this.state.settingsName, obj.settings); } changeFontSize(size) { const { newLayoutContextDispatch } = this.props; const obj = this.state; obj.settings.fontSize = size; this.setState(obj, () => { ApplicationMenu.setHtmlFontSize(this.state.settings.fontSize); this.handleUpdateFontSize(this.state.settings.fontSize); }); newLayoutContextDispatch({ type: ACTIONS.SET_FONT_SIZE, value: parseInt(size.slice(0, -2)), }); } handleIncreaseFontSize() { const currentFontSize = this.state.settings.fontSize; const availableFontSizes = this.state.fontSizes; const maxFontSize = availableFontSizes.length - 1; const canIncreaseFontSize = availableFontSizes.indexOf(currentFontSize) < maxFontSize; const fs = canIncreaseFontSize ? availableFontSizes.indexOf(currentFontSize) + 1 : maxFontSize; this.changeFontSize(availableFontSizes[fs]); if (fs === maxFontSize) this.setState({ isLargestFontSize: true }); this.setState({ isSmallestFontSize: false }); } handleDecreaseFontSize() { const currentFontSize = this.state.settings.fontSize; const availableFontSizes = this.state.fontSizes; const canDecreaseFontSize = availableFontSizes.indexOf(currentFontSize) > MIN_FONTSIZE; const fs = canDecreaseFontSize ? availableFontSizes.indexOf(currentFontSize) - 1 : MIN_FONTSIZE; this.changeFontSize(availableFontSizes[fs]); if (fs === MIN_FONTSIZE) this.setState({ isSmallestFontSize: true }); this.setState({ isLargestFontSize: false }); } handleSelectChange(fieldname, options, e) { const obj = this.state; obj.settings[fieldname] = e.target.value; this.handleUpdateSettings('application', obj.settings); } renderAudioFilters() { let audioFilterOption = null; if (SHOW_AUDIO_FILTERS) { const { intl, showToggleLabel, displaySettingsStatus } = this.props; const { settings } = this.state; const audioFilterStatus = ApplicationMenu .isAudioFilterEnabled(settings.microphoneConstraints); audioFilterOption = (
{displaySettingsStatus(audioFilterStatus)} this.handleAudioFilterChange()} ariaLabel={intl.formatMessage(intlMessages.audioFilterLabel)} showToggleLabel={showToggleLabel} />
); } return audioFilterOption; } renderPaginationToggle() { // See VideoService's method for an explanation if (!VideoService.shouldRenderPaginationToggle()) return; const { intl, showToggleLabel, displaySettingsStatus } = this.props; const { settings } = this.state; return (
{displaySettingsStatus(settings.paginationEnabled)} this.handleToggle('paginationEnabled')} ariaLabel={intl.formatMessage(intlMessages.paginationEnabledLabel)} showToggleLabel={showToggleLabel} />
); } render() { const { allLocales, intl, showToggleLabel, displaySettingsStatus, } = this.props; const { isLargestFontSize, isSmallestFontSize, settings, } = this.state; // conversions can be found at http://pxtoem.com const pixelPercentage = { '12px': '75%', // 14px is actually 87.5%, rounding up to show more friendly value '14px': '90%', '16px': '100%', // 18px is actually 112.5%, rounding down to show more friendly value '18px': '110%', '20px': '125%', }; const ariaValueLabel = intl.formatMessage(intlMessages.currentValue, { 0: `${pixelPercentage[settings.fontSize]}` }); const showSelect = allLocales && allLocales.length > 0; return (

{intl.formatMessage(intlMessages.applicationSectionTitle)}

{displaySettingsStatus(settings.animations)} this.handleToggle('animations')} ariaLabel={intl.formatMessage(intlMessages.animationsLabel)} showToggleLabel={showToggleLabel} />
{this.renderAudioFilters()} {this.renderPaginationToggle()}
{showSelect ? ( this.handleSelectChange('locale', allLocales, e)} value={settings.locale} elementId="langSelector" elementClass={styles.select} selectMessage={intl.formatMessage(intlMessages.languageOptionLabel)} /> ) : (
) }

); } } export default injectIntl(ApplicationMenu);