annotate src/app/analysis-item/analysis-item.component.ts @ 509:041468f553e1 tip master

Merge pull request #57 from LucasThompson/fix/session-stack-max-call-stack Fix accidental recursion in PersistentStack
author Lucas Thompson <LucasThompson@users.noreply.github.com>
date Mon, 27 Nov 2017 11:04:30 +0000
parents ccce2c09502e
children
rev   line source
dev@170 1 /**
dev@170 2 * Created by lucast on 21/03/2017.
dev@170 3 */
dev@231 4 import {
dev@231 5 ChangeDetectionStrategy,
dev@231 6 Component,
dev@231 7 Input,
dev@408 8 OnDestroy,
dev@456 9 OnInit,
dev@456 10 Output,
dev@456 11 EventEmitter
dev@236 12 } from '@angular/core';
dev@348 13 import {naivePagingMapper} from '../visualisations/WavesJunk';
dev@408 14 import {OnSeekHandler} from '../playhead/PlayHeadHelpers';
dev@361 15 import {
dev@381 16 defaultColourGenerator,
dev@460 17 HigherLevelFeatureShape
dev@361 18 } from '../visualisations/FeatureUtilities';
dev@408 19 import {
dev@408 20 RenderLoopService,
dev@408 21 TaskRemover
dev@408 22 } from '../services/render-loop/render-loop.service';
dev@456 23 import {DomSanitizer} from '@angular/platform-browser';
dev@460 24 import {
dev@460 25 isExtractedAnalysisItem,
dev@460 26 isLoadedRootAudioItem,
dev@460 27 isPendingAnalysisItem,
dev@460 28 isPendingRootAudioItem,
dev@460 29 Item,
dev@460 30 RootAudioItem
dev@460 31 } from './AnalysisItem';
dev@170 32
dev@170 33 @Component({
dev@170 34 selector: 'ugly-analysis-item',
dev@170 35 templateUrl: './analysis-item.component.html',
dev@231 36 styleUrls: ['./analysis-item.component.css'],
dev@231 37 changeDetection: ChangeDetectionStrategy.OnPush
dev@170 38 })
dev@408 39 export class AnalysisItemComponent implements OnInit, OnDestroy {
dev@224 40
dev@408 41 // TODO should be TimelineTimeContext?
dev@408 42 @Input() set timeline(timeline: Timeline) {
dev@408 43 this.mTimeline = timeline;
dev@408 44 this.resetRemoveAnimation();
dev@408 45 }
dev@408 46
dev@408 47 get timeline(): Timeline {
dev@408 48 return this.mTimeline;
dev@408 49 }
dev@408 50
dev@408 51 @Input() set isActive(isActive: boolean) {
dev@408 52 this.removeAnimation();
dev@408 53 this.mIsActive = isActive;
dev@408 54 if (isActive) {
dev@408 55 this.resetRemoveAnimation();
dev@408 56 }
dev@408 57 }
dev@408 58
dev@408 59 get isActive() {
dev@408 60 return this.mIsActive;
dev@408 61 }
dev@408 62
dev@350 63 @Input() item: Item;
dev@285 64 @Input() contentWidth: number;
dev@348 65 @Input() onSeek: OnSeekHandler;
dev@456 66 @Output() remove: EventEmitter<Item>;
dev@408 67 // TODO move / re-think - naivePagingMapper feels like a big ol' bodge
dev@408 68 private removeAnimation: TaskRemover;
dev@224 69 private hasProgressOnInit = false;
dev@408 70 private mIsActive: boolean;
dev@408 71 private mTimeline: Timeline;
dev@224 72
dev@456 73 constructor(private renderLoop: RenderLoopService,
dev@456 74 private sanitizer: DomSanitizer) {
dev@456 75 this.remove = new EventEmitter<Item>();
dev@456 76 }
dev@348 77
dev@224 78 ngOnInit(): void {
dev@408 79 this.resetRemoveAnimation();
dev@231 80 this.hasProgressOnInit = this.item.progress != null;
dev@224 81 }
dev@224 82
dev@224 83 isLoading(): boolean {
dev@231 84 return this.hasProgressOnInit && this.item.progress < 100;
dev@224 85 }
dev@348 86
dev@348 87 isAudioItem(): boolean {
dev@460 88 return this.item && isLoadedRootAudioItem(this.item);
dev@348 89 }
dev@361 90
dev@410 91 isPending(): boolean {
dev@410 92 return this.item &&
dev@460 93 !isLoadedRootAudioItem(this.item) && !isExtractedAnalysisItem(this.item) &&
dev@410 94 (isPendingAnalysisItem(this.item) || isPendingRootAudioItem(this.item));
dev@410 95 }
dev@410 96
dev@361 97 getFeatureShape(): HigherLevelFeatureShape | null {
dev@361 98 return !isPendingRootAudioItem(this.item) &&
dev@460 99 isExtractedAnalysisItem(this.item) ? this.item.shape : null;
dev@361 100 }
dev@381 101
dev@412 102 getDuration(): number | null {
dev@460 103 if (isLoadedRootAudioItem(this.item)) {
dev@412 104 return this.item.audioData.duration;
dev@412 105 }
dev@460 106 if (isExtractedAnalysisItem(this.item)) {
dev@412 107 return this.item.parent.audioData.duration;
dev@412 108 }
dev@412 109 }
dev@412 110
dev@381 111 getNextColour(): string {
dev@381 112 return defaultColourGenerator.next().value;
dev@381 113 }
dev@408 114
dev@408 115 ngOnDestroy(): void {
dev@408 116 this.removeAnimation();
dev@408 117 }
dev@408 118
dev@456 119 private sanitize(url: string) {
dev@456 120 return this.sanitizer.bypassSecurityTrustUrl(url);
dev@456 121 }
dev@456 122
dev@460 123 private generateFilename(item: RootAudioItem): string {
dev@456 124 // TODO this is too brittle, and will often produce the wrong result
dev@456 125 // i.e. audio/mpeg results in .mpeg, when .mp3 is likely desired
dev@456 126 const mimeParts = item.mimeType ? item.mimeType.split('/') : [];
dev@456 127 const extension = mimeParts.length === 2 ? mimeParts[1] : '';
dev@456 128 return `${item.title}.${extension}`;
dev@456 129 }
dev@456 130
dev@408 131 private resetRemoveAnimation(): void {
dev@408 132 if (this.removeAnimation) {
dev@408 133 this.removeAnimation();
dev@408 134 }
dev@408 135 const createPagingTask = () => {
dev@408 136 const pagingMapper = naivePagingMapper(this.timeline);
dev@408 137 return this.renderLoop.addPlayingTask(currentTime => {
dev@408 138 pagingMapper(currentTime);
dev@408 139 });
dev@408 140 };
dev@408 141 // only add a pager to audio items, it can drive the feature items
dev@408 142 const remover = this.timeline && this.isAudioItem() ?
dev@408 143 createPagingTask() : () => {};
dev@408 144 this.removeAnimation = () => {
dev@408 145 remover();
dev@408 146 this.removeAnimation = () => {};
dev@408 147 };
dev@408 148 }
dev@170 149 }