import { OnInit, AfterContentInit, OnDestroy, Component, EventEmitter, Input, Output } from '@angular/core'; import { MatSliderChange } from '@angular/material/slider'; import { AudioElement } from '../../models/audio-element'; import { VideoElement } from '../../models/video-element'; import { ValueChangeElement } from '../../models/uI-element'; @Component({ selector: 'app-control-bar', templateUrl: './control-bar.component.html', styleUrls: ['./control-bar.component.css'] }) export class ControlBarComponent implements OnInit, AfterContentInit, OnDestroy { @Input() player!: HTMLVideoElement | HTMLAudioElement; @Input() elementModel!: AudioElement | VideoElement; @Input() active!: boolean; @Output() playbackTimeChanged = new EventEmitter<ValueChangeElement>(); duration!: number; currentTime!: number; currentRestTime!: number; started!: boolean; playing!: boolean; pausing!: boolean; runCounter!: number; lastVolume!: number; restTimeMode: boolean = true; showHint!: boolean; disabled!: boolean; isAspectPlayer!: boolean; playbackTime!: number; // TODO: // uninterruptible: boolean; // false kein Blättern; starten eines anderen Videos; .... // hideOtherPages: boolean; // false (Solange nicht vollständig gespielt, sind alle anderen Seiten verborgen) // activeAfterID: string; // '' (andere Audio-id; Audio ist deaktiviert, solange anderes nicht vollständig abgespielt) // minRuns: number; // 1 ngOnInit(): void { // Firefox has problems to get the duration this.player.ondurationchange = () => this.initTimeValues(); this.player.ontimeupdate = () => { this.currentTime = this.player.currentTime / 60; this.currentRestTime = this.player.duration ? (this.player.duration - this.player.currentTime) / 60 : 0; this.sendPlaybackTimeChanged(); }; this.player.onpause = () => { this.playing = false; this.pausing = true; }; this.player.onplaying = () => { this.playing = true; this.pausing = false; this.started = true; this.showHint = false; }; this.player.onended = () => { if (!this.checkStatus(this.runCounter + 1)) { this.runCounter += 1; if (this.elementModel.loop) { this._play(); } } }; this.player.onvolumechange = () => { this.player.muted = !this.player.volume; }; this.lastVolume = this.player.volume; } ngAfterContentInit(): void { // player-aspect should work, but doesn't in production this.isAspectPlayer = !!this.player.closest('app-element-container'); if (this.isAspectPlayer) { this.initAutostart(); this.initHint(); } } play(event: MouseEvent): void { this._play(); event.stopPropagation(); event.preventDefault(); } pause(event: MouseEvent): void { this.player.pause(); event.stopPropagation(); event.preventDefault(); } onTimeChange(event: MatSliderChange): void { this.player.currentTime = event.value ? event.value : 0; } onVolumeChange(event: MatSliderChange): void { this.player.volume = event.value ? event.value : 0; } toggleTime(event: MouseEvent): void { this.restTimeMode = !this.restTimeMode; event.stopPropagation(); event.preventDefault(); } toggleVolume(event: MouseEvent): void { if (this.player.volume) { this.lastVolume = this.player.volume; this.player.volume = 0; } else { this.player.volume = this.lastVolume; } event.stopPropagation(); event.preventDefault(); } private checkStatus(runCounter: number): boolean { this.disabled = !this.elementModel.maxRuns ? false : this.elementModel.maxRuns <= runCounter; return this.disabled; } private initAutostart(): void { if (this.elementModel.autostart && !this.started) { setTimeout(() => { if (!this.started) { this._play(); } }, this.elementModel.autostartDelay); } } private initHint(): void { if (this.elementModel.hintLabel && !this.started) { setTimeout(() => { if (!this.started) { this.showHint = true; } }, this.elementModel.hintLabelDelay); } } private _play(): void { this.player.play().then(() => {}, // eslint-disable-next-line no-console () => console.error('player: cannot play this media file')); } private sendPlaybackTimeChanged() { this.playbackTimeChanged.emit({ id: this.elementModel.id, values: [this.playbackTime, this.toPlaybackTime()] }); } private toPlaybackTime(): number { let newPlayBackTime: number = 0; if (this.player.duration && this.player.currentTime) { newPlayBackTime = this.runCounter + this.player.currentTime / this.player.duration; } this.playbackTime = newPlayBackTime; return newPlayBackTime; } private initTimeValues(): void { if (!this.duration) { if ((this.player.duration !== Infinity) && this.player.duration) { this.duration = this.player.duration / 60; this.currentRestTime = (this.player.duration - this.player.currentTime) / 60; this.runCounter = Math.floor(this.elementModel.playbackTime); this.player.currentTime = (this.elementModel.playbackTime - this.runCounter) * this.player.duration; } else { this.duration = 0; this.runCounter = 0; } } } ngOnDestroy(): void { this.player.pause(); } }