dev@171: /** dev@171: * Created by lucast on 21/03/2017. dev@171: */ dev@232: import { dev@232: ChangeDetectionStrategy, dev@285: ChangeDetectorRef, dev@456: Component, EventEmitter, dev@285: Inject, dev@285: Input, dev@456: OnDestroy, Output dev@236: } from '@angular/core'; dev@289: import Waves from 'waves-ui-piper'; dev@350: import { dev@350: getRootUri, dev@460: isLoadedRootAudioItem, dev@350: Item dev@460: } from '../analysis-item/AnalysisItem'; dev@285: import {Observable} from 'rxjs/Observable'; dev@285: import {Dimension} from '../app.module'; dev@285: import {Subscription} from 'rxjs/Subscription'; dev@348: import {OnSeekHandler} from '../playhead/PlayHeadHelpers'; dev@464: import {AudioPlayerService} from '../services/audio-player/audio-player.service'; dev@171: dev@171: @Component({ dev@171: selector: 'ugly-notebook-feed', dev@171: templateUrl: './notebook-feed.component.html', dev@232: styleUrls: ['./notebook-feed.component.css'], dev@232: changeDetection: ChangeDetectionStrategy.OnPush dev@171: }) dev@285: export class NotebookFeedComponent implements OnDestroy { dev@464: @Input() set analyses(analyses: Item[]) { dev@464: const front = analyses[0]; dev@464: if (analyses !== this.mAnalyses) { dev@464: if (front && getRootUri(front) !== this.currentAudioUri) { dev@464: this.audioService.unload(); dev@464: this.audioService.loadAudioFromUri(getRootUri(front)); dev@469: } else if (!front) { dev@469: this.audioService.unload(); dev@464: } dev@464: } dev@464: this.mAnalyses = analyses; dev@464: if (front) { dev@464: this.currentAudioUri = this.getCurrentAudioUri(); dev@470: } else { dev@470: this.currentAudioUri = ''; dev@464: } dev@171: } dev@464: dev@464: get analyses(): Item[] { dev@464: return this.mAnalyses; dev@464: } dev@464: dev@348: @Input() onSeek: OnSeekHandler; dev@456: @Output() removeItem: EventEmitter; dev@171: dev@285: private resizeSubscription: Subscription; dev@285: private width: number; dev@285: private lastWidth: number; dev@282: private timelines: Map; dev@464: private mAnalyses: Item[]; dev@464: private currentAudioUri: string; dev@181: dev@285: constructor( dev@285: private ref: ChangeDetectorRef, dev@464: @Inject('DimensionObservable') private onResize: Observable, dev@464: private audioService: AudioPlayerService dev@285: ) { dev@456: this.removeItem = new EventEmitter(); dev@282: this.timelines = new Map(); dev@285: this.onResize.subscribe(dim => { dev@285: this.lastWidth = this.width; dev@285: this.width = dim.width; dev@285: }); dev@285: dev@285: // the use of requestAnimationFrame here is to leave the dom updates dev@285: // to a time convenient for the browser, and avoid a cascade / waterfall dev@285: // of DOM changes for rapid resize events in the event handler above. dev@285: // ..I'm not convinced this is particularly beneficial here // TODO dev@285: const triggerChangeDetectionOnResize = () => { dev@285: requestAnimationFrame(triggerChangeDetectionOnResize); dev@285: if (this.width !== this.lastWidth) { dev@285: ref.markForCheck(); // only trigger change detection if width changed dev@285: } dev@285: }; dev@285: requestAnimationFrame(triggerChangeDetectionOnResize); dev@282: } dev@282: dev@350: getOrCreateTimeline(item: Item): Timeline | void { dev@282: if (!item.hasSharedTimeline) { dev@282: return; dev@282: } dev@350: const uri = getRootUri(item); dev@350: if (this.timelines.has(uri)) { dev@350: return this.timelines.get(uri); dev@282: } else { dev@282: const timeline = new Waves.core.Timeline(); dev@350: this.timelines.set(uri, timeline); dev@282: return timeline; dev@282: } dev@181: } dev@285: dev@350: isAudioItem(item: Item): boolean { dev@460: return isLoadedRootAudioItem(item); dev@348: } dev@348: dev@350: isActiveItem(item: Item): boolean { dev@464: return this.getCurrentAudioUri() === getRootUri(item); dev@350: } dev@350: dev@350: getOnSeekForItem(item: Item): (timeSeconds: number) => any { dev@348: return this.isActiveItem(item) ? this.onSeek : () => {}; dev@348: } dev@348: dev@285: ngOnDestroy(): void { dev@285: if (this.resizeSubscription) { dev@285: this.resizeSubscription.unsubscribe(); dev@285: } dev@285: } dev@464: dev@464: private getCurrentAudioUri(): string { dev@464: if (this.analyses.length === 0) { dev@464: return ''; dev@464: } dev@464: try { dev@464: return getRootUri(this.analyses[0]); dev@464: } catch (e) { dev@464: return ''; dev@464: } dev@464: } dev@171: }