changeset 423:4387175f594b

Basic action tray for feature analysis. WIP, bit buggy wrt scrolling and not dismissed automatically when extractor selected.
author Lucas Thompson <dev@lucas.im>
date Tue, 06 Jun 2017 18:11:30 +0100
parents 1811801a9830
children bb2bc6af642b
files src/app/actions/action-tray.component.ts src/app/app.component.html src/app/app.module.ts src/app/feature-extraction-menu/feature-extraction-menu.component.html src/app/feature-extraction-menu/feature-extraction-menu.component.ts
diffstat 5 files changed, 106 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/app/actions/action-tray.component.ts	Tue Jun 06 18:11:30 2017 +0100
@@ -0,0 +1,57 @@
+/**
+ * Created by lucast on 06/06/2017.
+ */
+import {Component, Input} from '@angular/core';
+import {
+  animate, keyframes, state, style, transition,
+  trigger
+} from '@angular/animations';
+
+@Component({
+  selector: 'ugly-action-tray',
+  template: `<div
+    class="tray"
+    [@visibility]="visibility"
+  ><ng-content></ng-content></div>`,
+  styles: [
+    `.tray {
+      background: white;
+      height: 100%;
+      width: 100%;
+      position: absolute;
+      z-index: 100;
+      overflow-y: hidden;
+    }`
+  ],
+  animations: [
+    trigger('visibility', [
+      state('show', style({
+        height: '100%',
+        'overflow-y': 'scroll'
+      })),
+      state('hide', style({
+        height: 0,
+        'overflow-y': 'hidden',
+      })),
+      transition('hide => show', [
+        animate(300, keyframes([
+          style({height: 0, offset: 0}),
+          style({height: '100%',  offset: 1.0}),
+        ]))
+      ]),
+      transition('show => hide', [
+        animate(300, keyframes([
+          style({height: '100%', offset: 0.0}),
+          style({height: 0, offset: 1.0}),
+        ]))
+      ]),
+    ])
+  ]
+})
+export class ActionTrayComponent {
+  @Input() visibility: 'show' | 'hide' = 'hide';
+
+  toggle() {
+    this.visibility = this.visibility === 'show' ? 'hide' : 'show';
+  }
+}
--- a/src/app/app.component.html	Tue Jun 06 16:10:00 2017 +0100
+++ b/src/app/app.component.html	Tue Jun 06 18:11:30 2017 +0100
@@ -18,13 +18,19 @@
         (fileOpened)="onFileOpened($event)"
       ></ugly-audio-file-open>
       <!-- menu opens when trigger button is clicked -->
-      <button md-icon-button>
+      <button md-icon-button (click)="tray.toggle()">
         <md-icon>extension</md-icon>
       </button>
     </md-toolbar>
   </div>
 
   <div class="ugly-content">
+    <ugly-action-tray #tray>
+      <ugly-feature-extraction-menu
+        (requestOutput)="extractFeatures($event)"
+        [disabled]="!canExtract">
+      </ugly-feature-extraction-menu>
+    </ugly-action-tray>
     <ugly-notebook-feed
       [analyses]="analyses.toIterable()"
       [rootAudioUri]="rootAudioItem.uri"
--- a/src/app/app.module.ts	Tue Jun 06 16:10:00 2017 +0100
+++ b/src/app/app.module.ts	Tue Jun 06 18:11:30 2017 +0100
@@ -40,6 +40,9 @@
 import {CrossHairInspectorComponent} from './visualisations/cross-hair-inspector.component';
 import {RenderLoopService} from './services/render-loop/render-loop.service';
 import {WavesPlayHeadComponent} from './playhead/waves-ui-play-head.component';
+import {
+  ActionTrayComponent
+} from './actions/action-tray.component';
 
 export function createAudioContext(): AudioContext {
   return new (
@@ -135,7 +138,8 @@
     GridComponent,
     VerticalScaleComponent,
     CrossHairInspectorComponent,
-    WavesPlayHeadComponent
+    WavesPlayHeadComponent,
+    ActionTrayComponent
   ],
   imports: [
     BrowserModule,
--- a/src/app/feature-extraction-menu/feature-extraction-menu.component.html	Tue Jun 06 16:10:00 2017 +0100
+++ b/src/app/feature-extraction-menu/feature-extraction-menu.component.html	Tue Jun 06 18:11:30 2017 +0100
@@ -1,21 +1,18 @@
 <div class="container">
-  <md-select #extractorSelect
-    placeholder="Extractors">
-    <md-option
+  <md-list dense>
+    <ng-container
       *ngFor="let extractor of extractors"
-      [value]="extractor.combinedKey"
     >
-      {{extractor.name}}
-    </md-option>
-  </md-select>
-  <p>
-    <button md-raised-button
-            color="primary"
-            (click)="extract(getFirstSelectedItemOrEmpty(extractorSelect))"
-            [disabled]="disabled">Extract</button>
-  </p>
-  <p>
-    <button md-raised-button
-            (click)="load()">Load Remote Plugins</button>
-  </p>
+      <h3 md-subheader>{{extractor.name}}</h3>
+      <md-list-item *ngFor="let output of extractor.outputs">
+        <md-icon md-list-icon>extension</md-icon>
+        <h4 md-line>{{output.name}}</h4>
+        <p md-line>{{output.combinedKey}}</p>
+        <button md-icon-button (click)="extract(output)" [disabled]="disabled">
+          <md-icon>add</md-icon>
+        </button>
+      </md-list-item>
+      <md-divider></md-divider>
+    </ng-container>
+  </md-list>
 </div>
--- a/src/app/feature-extraction-menu/feature-extraction-menu.component.ts	Tue Jun 06 16:10:00 2017 +0100
+++ b/src/app/feature-extraction-menu/feature-extraction-menu.component.ts	Tue Jun 06 18:11:30 2017 +0100
@@ -20,6 +20,11 @@
   name: string;
 }
 
+interface ExtractorInfo {
+  name: string;
+  outputs: ExtractorOutputInfo[];
+}
+
 @Component({
   selector: 'ugly-feature-extraction-menu',
   templateUrl: './feature-extraction-menu.component.html',
@@ -39,35 +44,30 @@
   @Output() requestOutput: EventEmitter<ExtractorOutputInfo>;
 
   private isDisabled: boolean;
-  private extractorsMap: Map<string, ExtractorOutputInfo>;
   private populateExtractors: (available: ListResponse) => void;
-  extractors: Iterable<ExtractorOutputInfo>;
+  extractors: Iterable<ExtractorInfo>;
   private librariesUpdatedSubscription: Subscription;
 
   constructor(private piperService: FeatureExtractionService) {
-    this.extractorsMap = new Map();
     this.extractors = [];
     this.requestOutput = new EventEmitter<ExtractorOutputInfo>();
     this.isDisabled = true;
     this.populateExtractors = available => {
-      const maxCharacterLimit = 50;
-      available.available.forEach(staticData => {
-        const isSingleOutputExtractor = staticData.basicOutputInfo.length === 1;
-        staticData.basicOutputInfo.forEach(output => {
-          const combinedKey = `${staticData.key}:${output.identifier}`;
-          this.extractorsMap.set(combinedKey, {
-            extractorKey: staticData.key,
-            combinedKey: combinedKey,
-            name: (
-              isSingleOutputExtractor
-                ? staticData.basic.name
-                : `${staticData.basic.name}: ${output.name}`
-            ).substr(0, maxCharacterLimit) + '...',
-            outputId: output.identifier
+      this.extractors = available.available.reduce((acc, staticData) => {
+        const name = staticData.basic.name;
+        const outputs: ExtractorOutputInfo[] =
+          staticData.basicOutputInfo.map(output => {
+            const combinedKey = `${staticData.key}:${output.identifier}`;
+            return {
+              extractorKey: staticData.key,
+              combinedKey: combinedKey,
+              name: output.name,
+              outputId: output.identifier
+            };
           });
-        });
-      });
-      this.extractors = [...this.extractorsMap.values()];
+        acc.push({name, outputs});
+        return acc;
+      }, [] as ExtractorInfo[]);
     };
   }
 
@@ -85,10 +85,10 @@
     this.piperService.list().then(this.populateExtractors);
   }
 
-  extract(combinedKey: string): void {
-    const info: ExtractorOutputInfo =
-      this.extractorsMap.get(combinedKey);
+  extract(info: ExtractorOutputInfo): void {
+    console.warn('extract?', info);
     if (info) {
+      console.warn('emit');
       this.requestOutput.emit(info);
     }
   }