playable
Version:
Video player based on HTML5Video
236 lines (195 loc) • 6.5 kB
text/typescript
import View from './volume.view';
import KeyboardInterceptor, {
KEYCODES,
} from '../../../../utils/keyboard-interceptor';
import { AMOUNT_TO_CHANGE_VOLUME } from '../../../keyboard-control/keyboard-control';
import { VideoEvent, UIEvent } from '../../../../constants';
import { IEventEmitter } from '../../../event-emitter/types';
import { ITooltipService } from '../../core/tooltip/types';
import { IVolumeControl, IVolumeViewConfig } from './types';
import { ITextMap } from '../../../text-map/types';
import { IPlaybackEngine } from '../../../playback-engine/types';
import { IThemeService } from '../../core/theme';
export default class VolumeControl implements IVolumeControl {
static moduleName = 'volumeControl';
static View = View;
static dependencies = [
'engine',
'eventEmitter',
'textMap',
'tooltipService',
'theme',
];
private _engine: IPlaybackEngine;
private _eventEmitter: IEventEmitter;
private _textMap: ITextMap;
private _tooltipService: ITooltipService;
private _theme: IThemeService;
private _buttonInterceptor: KeyboardInterceptor;
private _inputInterceptor: KeyboardInterceptor;
private _unbindEvents: () => void;
view: View;
isHidden: boolean;
constructor({
engine,
eventEmitter,
textMap,
tooltipService,
theme,
}: {
eventEmitter: IEventEmitter;
engine: IPlaybackEngine;
textMap: ITextMap;
tooltipService: ITooltipService;
theme: IThemeService;
}) {
this._engine = engine;
this._eventEmitter = eventEmitter;
this._textMap = textMap;
this._tooltipService = tooltipService;
this._theme = theme;
this._bindCallbacks();
this._initUI();
this._bindEvents();
this.view.setVolume(this._engine.getVolume());
this.view.setMute(this._engine.isMuted);
this._initInterceptor();
}
getElement() {
return this.view.getElement();
}
private _initUI() {
const config: IVolumeViewConfig = {
callbacks: {
onDragStart: this._broadcastDragStart,
onDragEnd: this._broadcastDragEnd,
onVolumeLevelChangeFromInput: this._getVolumeLevelFromInput,
onVolumeLevelChangeFromWheel: this._getVolumeLevelFromWheel,
onToggleMuteClick: this._toggleMuteState,
},
theme: this._theme,
textMap: this._textMap,
tooltipService: this._tooltipService,
};
this.view = new VolumeControl.View(config);
}
private _initInterceptor() {
this._buttonInterceptor = new KeyboardInterceptor(
this.view.getButtonElement(),
{
[KEYCODES.SPACE_BAR]: e => {
e.stopPropagation();
this._eventEmitter.emitAsync(UIEvent.KEYBOARD_KEYDOWN_INTERCEPTED);
this._eventEmitter.emitAsync(
this._engine.isMuted
? UIEvent.UNMUTE_WITH_KEYBOARD
: UIEvent.MUTE_WITH_KEYBOARD,
);
},
[KEYCODES.ENTER]: e => {
e.stopPropagation();
this._eventEmitter.emitAsync(UIEvent.KEYBOARD_KEYDOWN_INTERCEPTED);
this._eventEmitter.emitAsync(
this._engine.isMuted
? UIEvent.UNMUTE_WITH_KEYBOARD
: UIEvent.MUTE_WITH_KEYBOARD,
);
},
},
);
this._inputInterceptor = new KeyboardInterceptor(
this.view.getInputElement(),
{
[KEYCODES.RIGHT_ARROW]: e => {
e.stopPropagation();
e.preventDefault();
this._eventEmitter.emitAsync(UIEvent.KEYBOARD_KEYDOWN_INTERCEPTED);
this._eventEmitter.emitAsync(UIEvent.INCREASE_VOLUME_WITH_KEYBOARD);
this._engine.setMute(false);
this._engine.increaseVolume(AMOUNT_TO_CHANGE_VOLUME);
},
[KEYCODES.LEFT_ARROW]: e => {
e.stopPropagation();
e.preventDefault();
this._eventEmitter.emitAsync(UIEvent.KEYBOARD_KEYDOWN_INTERCEPTED);
this._eventEmitter.emitAsync(UIEvent.DECREASE_VOLUME_WITH_KEYBOARD);
this._engine.setMute(false);
this._engine.decreaseVolume(AMOUNT_TO_CHANGE_VOLUME);
},
},
);
}
private _destroyInterceptor() {
this._buttonInterceptor.destroy();
this._inputInterceptor.destroy();
}
private _bindEvents() {
this._unbindEvents = this._eventEmitter.bindEvents(
[[VideoEvent.SOUND_STATE_CHANGED, this._updateSoundState]],
this,
);
}
private _bindCallbacks() {
this._getVolumeLevelFromInput = this._getVolumeLevelFromInput.bind(this);
this._toggleMuteState = this._toggleMuteState.bind(this);
this._getVolumeLevelFromWheel = this._getVolumeLevelFromWheel.bind(this);
this._broadcastDragStart = this._broadcastDragStart.bind(this);
this._broadcastDragEnd = this._broadcastDragEnd.bind(this);
}
private _broadcastDragStart() {
this._eventEmitter.emitAsync(UIEvent.CONTROL_DRAG_START);
}
private _broadcastDragEnd() {
this._eventEmitter.emitAsync(UIEvent.CONTROL_DRAG_END);
}
private _changeVolumeLevel(level: number) {
this._engine.setVolume(level);
this._eventEmitter.emitAsync(UIEvent.VOLUME_CHANGE, level);
if (this._engine.isMuted) {
this._toggleMuteState();
}
}
private _toggleMuteState() {
const desiredMuteState = !this._engine.isMuted;
this._engine.setMute(desiredMuteState);
this._eventEmitter.emitAsync(
desiredMuteState ? UIEvent.MUTE_CLICK : UIEvent.UNMUTE_CLICK,
);
}
private _getVolumeLevelFromWheel(delta: number) {
if (!this._engine.isMuted) {
const adjustedVolume = this._engine.getVolume() + delta / 10;
const validatedVolume = Math.min(100, Math.max(0, adjustedVolume));
this._changeVolumeLevel(validatedVolume);
}
}
private _getVolumeLevelFromInput(level: number) {
this._changeVolumeLevel(level);
}
private _updateSoundState() {
this._setVolumeLevel(this._engine.getVolume());
this._setMuteState(this._engine.isMuted);
}
private _setVolumeLevel(level: number) {
this.view.setVolume(level);
this.view.setMute(Boolean(!level));
}
private _setMuteState(isMuted: boolean) {
const volume = this._engine.getVolume();
this.view.setVolume(isMuted ? 0 : volume);
this.view.setMute(isMuted || Boolean(!volume));
}
hide() {
this.isHidden = true;
this.view.hide();
}
show() {
this.isHidden = false;
this.view.show();
}
destroy() {
this._destroyInterceptor();
this._unbindEvents();
this.view.destroy();
}
}