view src/app/notebook-feed/notebook-feed.component.ts @ 456:7bb0bac6f8dc

Add export button for recordings and option to remove audio item (also removes all related analyses atm). Revokes associated object url for audio on removal. Will be problematic if the history is used for undo / redo.
author Lucas Thompson <dev@lucas.im>
date Thu, 29 Jun 2017 20:11:14 +0100
parents 524f5cd75737
children ccce2c09502e
line wrap: on
line source
/**
 * Created by lucast on 21/03/2017.
 */
import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component, EventEmitter,
  Inject,
  Input,
  OnDestroy, Output
} from '@angular/core';
import Waves from 'waves-ui-piper';
import {
  getRootUri,
  isRootAudioItem,
  Item
} from '../analysis-item/analysis-item.component';
import {Observable} from 'rxjs/Observable';
import {Dimension} from '../app.module';
import {Subscription} from 'rxjs/Subscription';
import {OnSeekHandler} from '../playhead/PlayHeadHelpers';

@Component({
  selector: 'ugly-notebook-feed',
  templateUrl: './notebook-feed.component.html',
  styleUrls: ['./notebook-feed.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotebookFeedComponent implements OnDestroy {
  @Input() analyses: Item[];
  @Input() set rootAudioUri(uri: string) {
    this._rootAudioUri = uri;
  }
  @Input() onSeek: OnSeekHandler;
  @Output() removeItem: EventEmitter<Item>;

  get rootAudioUri(): string {
    return this._rootAudioUri;
  }
  private _rootAudioUri: string;
  private resizeSubscription: Subscription;
  private width: number;
  private lastWidth: number;
  private timelines: Map<string, Timeline>;

  constructor(
    private ref: ChangeDetectorRef,
    @Inject('DimensionObservable') private onResize: Observable<Dimension>
  ) {
    this.removeItem = new EventEmitter<Item>();
    this.timelines = new Map();
    this.onResize.subscribe(dim => {
      this.lastWidth = this.width;
      this.width = dim.width;
    });

    // the use of requestAnimationFrame here is to leave the dom updates
    // to a time convenient for the browser, and avoid a cascade / waterfall
    // of DOM changes for rapid resize events in the event handler above.
    // ..I'm not convinced this is particularly beneficial here // TODO
    const triggerChangeDetectionOnResize = () => {
      requestAnimationFrame(triggerChangeDetectionOnResize);
      if (this.width !== this.lastWidth) {
        ref.markForCheck(); // only trigger change detection if width changed
      }
    };
    requestAnimationFrame(triggerChangeDetectionOnResize);
  }

  getOrCreateTimeline(item: Item): Timeline | void {
    if (!item.hasSharedTimeline) {
      return;
    }
    const uri = getRootUri(item);
    if (this.timelines.has(uri)) {
      return this.timelines.get(uri);
    } else {
      const timeline = new Waves.core.Timeline();
      this.timelines.set(uri, timeline);
      return timeline;
    }
  }

  isAudioItem(item: Item): boolean {
    return isRootAudioItem(item);
  }

  isActiveItem(item: Item): boolean {
    return this.rootAudioUri === getRootUri(item);
  }

  getOnSeekForItem(item: Item): (timeSeconds: number) => any {
    return this.isActiveItem(item) ? this.onSeek : () => {};
  }

  ngOnDestroy(): void {
    if (this.resizeSubscription) {
      this.resizeSubscription.unsubscribe();
    }
  }
}