mirror of
https://github.com/bitgapp/eqMac.git
synced 2024-11-22 22:32:17 +03:00
added event destroyers to all components with event listening
This commit is contained in:
parent
40416ee97c
commit
f50c29e0a6
@ -38,9 +38,6 @@ import {
|
||||
import {
|
||||
EqualizersComponent
|
||||
} from './sections/effects/equalizers/equalizers.component'
|
||||
import {
|
||||
ReverbComponent
|
||||
} from './sections/effects/reverb/reverb.component'
|
||||
import {
|
||||
RecorderComponent
|
||||
} from './sections/recorder/recorder.component'
|
||||
@ -101,7 +98,6 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'
|
||||
BoosterComponent,
|
||||
BalanceComponent,
|
||||
EqualizersComponent,
|
||||
ReverbComponent,
|
||||
RecorderComponent,
|
||||
OutputsComponent,
|
||||
InputComponent,
|
||||
|
@ -10,4 +10,4 @@
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<eqm-label>Loading</eqm-label>
|
||||
<eqm-label *ngIf="showText">{{text || 'Loading'}}</eqm-label>
|
@ -1,4 +1,4 @@
|
||||
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core'
|
||||
import { Component, ViewChild, ElementRef, AfterViewInit, Input } from '@angular/core'
|
||||
|
||||
@Component({
|
||||
selector: 'eqm-loading',
|
||||
@ -7,6 +7,8 @@ import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core'
|
||||
})
|
||||
export class LoadingComponent implements AfterViewInit {
|
||||
@ViewChild('wave', { static: true }) wave: ElementRef
|
||||
@Input() text?: string
|
||||
@Input() showText = true
|
||||
|
||||
ngAfterViewInit () {
|
||||
const path = this.wave.nativeElement
|
||||
|
@ -2,9 +2,9 @@
|
||||
<div #arrow
|
||||
[hidden]="!showArrow"
|
||||
class="arrow-container"
|
||||
[ngStyle]="arrowStyle">
|
||||
<div
|
||||
class="arrow"></div>
|
||||
[ngStyle]="arrowStyle"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
</div>
|
||||
<eqm-container class="tooltip" #tooltip>
|
||||
<ng-content></ng-content>
|
||||
|
@ -42,6 +42,11 @@ export class TooltipComponent implements OnInit {
|
||||
}
|
||||
|
||||
get style () {
|
||||
if (!this.text?.length) {
|
||||
return {
|
||||
display: 'none'
|
||||
}
|
||||
}
|
||||
let x = -999
|
||||
let y = -999
|
||||
const body = document.body
|
||||
|
@ -16,7 +16,13 @@ export class EffectService extends DataService {
|
||||
return this.request({ method: 'POST', endpoint: '/enabled', data: { enabled } })
|
||||
}
|
||||
|
||||
onEnabledChanged (callback: (enabled: boolean) => void) {
|
||||
this.on('/enabled', ({ enabled }) => callback(enabled))
|
||||
onEnabledChanged (callback: EffectEnabledChangedEventCallback) {
|
||||
this.on('/enabled', callback)
|
||||
}
|
||||
|
||||
offEnabledChanged (callback: EffectEnabledChangedEventCallback) {
|
||||
this.off('/enabled', callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type EffectEnabledChangedEventCallback = (data: { enabled: boolean }) => void
|
||||
|
@ -4,9 +4,10 @@ import {
|
||||
Input,
|
||||
EventEmitter,
|
||||
Output,
|
||||
ChangeDetectorRef
|
||||
ChangeDetectorRef,
|
||||
OnDestroy
|
||||
} from '@angular/core'
|
||||
import { AdvancedEqualizerService, AdvancedEqualizerPreset } from 'src/app/sections/effects/equalizers/advanced-equalizer/advanced-equalizer.service'
|
||||
import { AdvancedEqualizerService, AdvancedEqualizerPreset, AdvancedEqualizerPresetsChangedEventCallback, AdvancedEqualizerSelectedPresetChangedEventCallback } from 'src/app/sections/effects/equalizers/advanced-equalizer/advanced-equalizer.service'
|
||||
import { EqualizerComponent } from '../equalizer.component'
|
||||
import { Options, CheckboxOption } from 'src/app/components/options/options.component'
|
||||
import { TransitionService } from '../../../../services/transitions.service'
|
||||
@ -17,7 +18,7 @@ import { ApplicationService } from '../../../../services/app.service'
|
||||
templateUrl: './advanced-equalizer.component.html',
|
||||
styleUrls: [ './advanced-equalizer.component.scss' ]
|
||||
})
|
||||
export class AdvancedEqualizerComponent extends EqualizerComponent implements OnInit {
|
||||
export class AdvancedEqualizerComponent extends EqualizerComponent implements OnInit, OnDestroy {
|
||||
@Input() enabled = true
|
||||
|
||||
public ShowDefaultPresetsCheckbox: CheckboxOption = {
|
||||
@ -159,15 +160,25 @@ export class AdvancedEqualizerComponent extends EqualizerComponent implements On
|
||||
this.ShowDefaultPresetsCheckbox.value = await this.service.getShowDefaultPresets()
|
||||
}
|
||||
|
||||
private onPresetsChangedEventCallback: AdvancedEqualizerPresetsChangedEventCallback
|
||||
private onSelectedPresetChangedEventCallback: AdvancedEqualizerSelectedPresetChangedEventCallback
|
||||
protected setupEvents () {
|
||||
this.service.onPresetsChanged(presets => {
|
||||
this.onPresetsChangedEventCallback = presets => {
|
||||
if (!presets) return
|
||||
this.presets = presets
|
||||
})
|
||||
this.service.onSelectedPresetChanged(preset => {
|
||||
}
|
||||
this.service.onPresetsChanged(this.onPresetsChangedEventCallback)
|
||||
|
||||
this.onSelectedPresetChangedEventCallback = preset => {
|
||||
this.selectedPreset = preset
|
||||
this.setSelectedPresetsGains()
|
||||
})
|
||||
}
|
||||
this.service.onSelectedPresetChanged(this.onSelectedPresetChangedEventCallback)
|
||||
}
|
||||
|
||||
private destroyEvents () {
|
||||
this.service.offPresetsChanged(this.onPresetsChangedEventCallback)
|
||||
this.service.offSelectedPresetChanged(this.onSelectedPresetChangedEventCallback)
|
||||
}
|
||||
|
||||
async selectPreset (preset: AdvancedEqualizerPreset) {
|
||||
@ -248,4 +259,8 @@ export class AdvancedEqualizerComponent extends EqualizerComponent implements On
|
||||
get globalGainScreenValue () {
|
||||
return `${this.selectedPreset.gains.global > 0 ? '+' : ''}${(this.selectedPreset.gains.global.toFixed(1))}dB`
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.destroyEvents()
|
||||
}
|
||||
}
|
||||
|
@ -80,11 +80,22 @@ export class AdvancedEqualizerService extends EqualizersService {
|
||||
return this.request({ method: 'POST', endpoint: '/settings/show-default-presets', data: { show } })
|
||||
}
|
||||
|
||||
onPresetsChanged (callback: (presets: AdvancedEqualizerPreset[]) => void) {
|
||||
this.on('/presets', (presets) => callback(presets))
|
||||
onPresetsChanged (callback: AdvancedEqualizerPresetsChangedEventCallback) {
|
||||
this.on('/presets', callback)
|
||||
}
|
||||
|
||||
onSelectedPresetChanged (callback: (preset: AdvancedEqualizerPreset) => void) {
|
||||
this.on('/presets/selected', (preset) => callback(preset))
|
||||
offPresetsChanged (callback: AdvancedEqualizerPresetsChangedEventCallback) {
|
||||
this.off('/presets', callback)
|
||||
}
|
||||
|
||||
onSelectedPresetChanged (callback: AdvancedEqualizerSelectedPresetChangedEventCallback) {
|
||||
this.on('/presets/selected', callback)
|
||||
}
|
||||
|
||||
offSelectedPresetChanged (callback: AdvancedEqualizerSelectedPresetChangedEventCallback) {
|
||||
this.off('/presets/selected', callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type AdvancedEqualizerPresetsChangedEventCallback = (presets: AdvancedEqualizerPreset[]) => void
|
||||
export type AdvancedEqualizerSelectedPresetChangedEventCallback = (preset: AdvancedEqualizerPreset) => void
|
||||
|
@ -53,11 +53,22 @@ export class BasicEqualizerService extends EqualizersService {
|
||||
return this.request({ method: 'DELETE', endpoint: '/presets', data: { ...preset } as any })
|
||||
}
|
||||
|
||||
onPresetsChanged (callback: (presets: BasicEqualizerPreset[]) => void) {
|
||||
this.on('/presets', (presets) => callback(presets))
|
||||
onPresetsChanged (callback: BasicEqualizerPresetsChangedEventCallback) {
|
||||
this.on('/presets', callback)
|
||||
}
|
||||
|
||||
onSelectedPresetChanged (callback: (preset: BasicEqualizerPreset) => void) {
|
||||
this.on('/presets/selected', (preset) => callback(preset))
|
||||
offPresetsChanged (callback: BasicEqualizerPresetsChangedEventCallback) {
|
||||
this.off('/presets', callback)
|
||||
}
|
||||
|
||||
onSelectedPresetChanged (callback: BasicEqualizerSelectedPresetChangedEventCallback) {
|
||||
this.on('/presets/selected', callback)
|
||||
}
|
||||
|
||||
offSelectedPresetChanged (callback: BasicEqualizerSelectedPresetChangedEventCallback) {
|
||||
this.off('/presets/selected', callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type BasicEqualizerPresetsChangedEventCallback = (presets: BasicEqualizerPreset[]) => void
|
||||
export type BasicEqualizerSelectedPresetChangedEventCallback = (preset: BasicEqualizerPreset) => void
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, OnInit, EventEmitter, Output, ViewChild, Input, ChangeDetectorRef } from '@angular/core'
|
||||
import { EqualizersService, EqualizerType } from './equalizers.service'
|
||||
import { Component, OnInit, EventEmitter, Output, ViewChild, Input, ChangeDetectorRef, OnDestroy } from '@angular/core'
|
||||
import { EqualizersService, EqualizersTypeChangedEventCallback, EqualizerType } from './equalizers.service'
|
||||
import { BasicEqualizerComponent } from './basic-equalizer/basic-equalizer.component'
|
||||
import { AdvancedEqualizerComponent } from './advanced-equalizer/advanced-equalizer.component'
|
||||
import { EqualizerComponent } from './equalizer.component'
|
||||
@ -8,6 +8,7 @@ import { MatDialog, MatDialogRef } from '@angular/material/dialog'
|
||||
import { OptionsDialogComponent } from '../../../components/options-dialog/options-dialog.component'
|
||||
import { EqualizerPreset } from './presets/equalizer-presets.component'
|
||||
import { UIService } from '../../../services/ui.service'
|
||||
import { EffectEnabledChangedEventCallback } from '../effect.service'
|
||||
|
||||
@Component({
|
||||
selector: 'eqm-equalizers',
|
||||
@ -15,7 +16,7 @@ import { UIService } from '../../../services/ui.service'
|
||||
styleUrls: [ './equalizers.component.scss' ],
|
||||
animations: [ FadeInOutAnimation ]
|
||||
})
|
||||
export class EqualizersComponent implements OnInit {
|
||||
export class EqualizersComponent implements OnInit, OnDestroy {
|
||||
@Input() animationDuration = 500
|
||||
@Input() animationFps = 30
|
||||
|
||||
@ -75,14 +76,23 @@ export class EqualizersComponent implements OnInit {
|
||||
this.enabled = await this.equalizersService.getEnabled()
|
||||
}
|
||||
|
||||
private onEnabledChangedEventCallback: EffectEnabledChangedEventCallback
|
||||
private onTypeChangedEventCallback: EqualizersTypeChangedEventCallback
|
||||
protected setupEvents () {
|
||||
this.equalizersService.onEnabledChanged(enabled => {
|
||||
this.onEnabledChangedEventCallback = ({ enabled }) => {
|
||||
this.enabled = enabled
|
||||
})
|
||||
}
|
||||
this.equalizersService.onEnabledChanged(this.onEnabledChangedEventCallback)
|
||||
|
||||
this.equalizersService.onTypeChanged(type => {
|
||||
this.onTypeChangedEventCallback = ({ type }) => {
|
||||
this.type = type
|
||||
})
|
||||
}
|
||||
this.equalizersService.onTypeChanged(this.onTypeChangedEventCallback)
|
||||
}
|
||||
|
||||
private destroyEvents () {
|
||||
this.equalizersService.offEnabledChanged(this.onEnabledChangedEventCallback)
|
||||
this.equalizersService.offTypeChanged(this.onTypeChangedEventCallback)
|
||||
}
|
||||
|
||||
setEnabled () {
|
||||
@ -133,4 +143,8 @@ export class EqualizersComponent implements OnInit {
|
||||
selectPreset (preset: EqualizerPreset) {
|
||||
return this.activeEqualizer.selectPreset(preset)
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.destroyEvents()
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,13 @@ export class EqualizersService extends EffectService {
|
||||
return this.request({ method: 'POST', endpoint: '/type', data: { type } })
|
||||
}
|
||||
|
||||
onTypeChanged (callback: (type: EqualizerType) => void) {
|
||||
this.on('/type', ({ type }) => callback(type))
|
||||
onTypeChanged (callback: EqualizersTypeChangedEventCallback) {
|
||||
this.on('/type', callback)
|
||||
}
|
||||
|
||||
offTypeChanged (callback: EqualizersTypeChangedEventCallback) {
|
||||
this.off('/type', callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type EqualizersTypeChangedEventCallback = (data: { type: EqualizerType }) => void
|
||||
|
@ -1,22 +0,0 @@
|
||||
<div class="reverb" fxLayout="column" fxFill fxLayoutAlign="center center">
|
||||
<div fxLayout="row" [style.padding]="'0 5px'" fxLayoutAlign="space-between center" fxFill>
|
||||
<eqm-toggle class="on-off" [(state)]="enabled" (stateChange)="setEnabled()"></eqm-toggle>
|
||||
<eqm-label>Reverb</eqm-label>
|
||||
<eqm-icon (click)="toggleVisibility()" [name]="hide ? 'show' : 'hide'"></eqm-icon>
|
||||
</div>
|
||||
<div fxFill class="reverb-controls" [fxHide]="hide">
|
||||
<div fxLayout="row" fxFill fxLayoutAlign="space-around center">
|
||||
<eqm-knob [min]="0" [max]="1" [(value)]="dryWetMix" (valueChange)="setMix()" [disabled]="enabled"></eqm-knob>
|
||||
<div fxLayout="column" fxFlex="70" fxLayoutAlign="space-between start" fxLayoutGap="10px">
|
||||
<div fxLayout="row" fxFill fxLayoutAlign="space-around start" fxLayoutGap="20px">
|
||||
<eqm-label>Preset</eqm-label>
|
||||
<eqm-dropdown [items]="presets" [labelParam]="'name'" [(selectedItem)]="selectedPreset"></eqm-dropdown>
|
||||
</div>
|
||||
<div fxLayout="row" fxFill fxLayoutGap="20px">
|
||||
<eqm-label>Dry/Wet Mix</eqm-label>
|
||||
<eqm-value-screen>{{formatDryWetMixValue()}}%</eqm-value-screen>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,7 +0,0 @@
|
||||
.reverb {
|
||||
position: relative;
|
||||
|
||||
.reverb-controls{
|
||||
// filter: grayscale(100%);
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
EventEmitter,
|
||||
Output
|
||||
} from '@angular/core'
|
||||
import {
|
||||
ReverbService
|
||||
} from './reverb.service'
|
||||
|
||||
@Component({
|
||||
selector: 'eqm-reverb',
|
||||
templateUrl: './reverb.component.html',
|
||||
styleUrls: [ './reverb.component.scss' ]
|
||||
})
|
||||
export class ReverbComponent implements OnInit {
|
||||
presets = []
|
||||
dryWetMix = 0.5
|
||||
enabled = true
|
||||
selectedPreset = null
|
||||
hide = false
|
||||
|
||||
@Output() visibilityToggled = new EventEmitter()
|
||||
|
||||
constructor (public reverbService: ReverbService) {}
|
||||
|
||||
ngOnInit () {
|
||||
this.getPresets()
|
||||
this.sync()
|
||||
this.setupEvents()
|
||||
}
|
||||
|
||||
protected setupEvents () {
|
||||
this.reverbService.onEnabledChanged(enabled => {
|
||||
this.enabled = enabled
|
||||
})
|
||||
|
||||
this.reverbService.onMixChanged(mix => {
|
||||
this.dryWetMix = mix
|
||||
})
|
||||
|
||||
this.reverbService.onPresetChanged(preset => {
|
||||
this.selectedPreset = preset
|
||||
})
|
||||
}
|
||||
|
||||
async sync () {
|
||||
if (this.presets.length === 0) {
|
||||
this.getPresets()
|
||||
}
|
||||
this.getSelectedPreset()
|
||||
this.getMix()
|
||||
this.getEnabled()
|
||||
}
|
||||
|
||||
async getPresets () {
|
||||
this.presets = await this.reverbService.getPresets()
|
||||
}
|
||||
|
||||
async getSelectedPreset () {
|
||||
const selectedPresetId = await this.reverbService.getSelectedPresetId()
|
||||
this.selectedPreset = this.presets.find(preset => preset.id === selectedPresetId)
|
||||
}
|
||||
|
||||
async getMix () {
|
||||
this.dryWetMix = await this.reverbService.getMix()
|
||||
}
|
||||
|
||||
setMix () {
|
||||
this.reverbService.setMix(this.dryWetMix)
|
||||
}
|
||||
|
||||
async getEnabled () {
|
||||
this.enabled = await this.reverbService.getEnabled()
|
||||
}
|
||||
|
||||
setEnabled () {
|
||||
this.reverbService.setEnabled(this.enabled)
|
||||
}
|
||||
|
||||
formatDryWetMixValue () {
|
||||
return Math.round(this.dryWetMix * 100)
|
||||
}
|
||||
|
||||
toggleVisibility () {
|
||||
this.hide = !this.hide
|
||||
this.visibilityToggled.emit()
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { EffectService } from '../effect.service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ReverbService extends EffectService {
|
||||
route = `${this.route}/reverb`
|
||||
|
||||
async getMix () {
|
||||
const resp = await this.request({ method: 'GET', endpoint: '/mix' })
|
||||
return resp.mix
|
||||
}
|
||||
|
||||
setMix (mix) {
|
||||
return this.request({ method: 'POST', endpoint: '/mix', data: { mix } })
|
||||
}
|
||||
|
||||
async getPresets () {
|
||||
return this.request({ method: 'GET', endpoint: '/presets' })
|
||||
}
|
||||
|
||||
async getSelectedPresetId () {
|
||||
const resp = await this.request({ method: 'GET', endpoint: '/preset' })
|
||||
return resp.id
|
||||
}
|
||||
|
||||
setPreset (id) {
|
||||
return this.request({ method: 'POST', endpoint: '/preset', data: { id } })
|
||||
}
|
||||
|
||||
onMixChanged (callback: (mix: number) => void) {
|
||||
this.on(`${this.route}/mix`, ({ mix }) => callback(mix))
|
||||
}
|
||||
|
||||
onPresetChanged (callback: (id: number) => void) {
|
||||
this.on(`${this.route}/preset`, ({ preset }) => callback(preset))
|
||||
}
|
||||
}
|
@ -50,7 +50,12 @@ export class OutputsComponent implements OnInit {
|
||||
}
|
||||
|
||||
setupEventListeners () {
|
||||
this.service.onChanged(() => this.sync())
|
||||
this.service.onDevicesChanged(() => this.sync())
|
||||
this.service.onSelectedChanged(this.sync.bind(this))
|
||||
this.service.onDevicesChanged(this.sync.bind(this))
|
||||
}
|
||||
|
||||
destroyEvents () {
|
||||
this.service.offSelectedChanged(this.sync)
|
||||
this.service.offDevicesChanged(this.sync)
|
||||
}
|
||||
}
|
||||
|
@ -40,11 +40,22 @@ export class OutputsService extends DataService {
|
||||
return this.request({ method: 'POST', endpoint: '/selected', data: { ...output } })
|
||||
}
|
||||
|
||||
onChanged (callback: (id: number) => void) {
|
||||
this.on('/selected', ({ id }) => callback(id))
|
||||
onSelectedChanged (callback: OutputsSelectedChangedEventCallback) {
|
||||
this.on('/selected', callback)
|
||||
}
|
||||
|
||||
onDevicesChanged (callback: (devices: Output[]) => void) {
|
||||
this.on('/devices', devices => callback(devices))
|
||||
offSelectedChanged (callback: OutputsSelectedChangedEventCallback) {
|
||||
this.off('/selected', callback)
|
||||
}
|
||||
|
||||
onDevicesChanged (callback: OutputsDevicesChangedEventCallback) {
|
||||
this.on('/devices', callback)
|
||||
}
|
||||
|
||||
offDevicesChanged (callback: OutputsDevicesChangedEventCallback) {
|
||||
this.off('/devices', callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type OutputsSelectedChangedEventCallback = (data: { id: number }) => void
|
||||
export type OutputsDevicesChangedEventCallback = (devices: Output[]) => void
|
||||
|
@ -7,6 +7,8 @@ import {
|
||||
UtilitiesService
|
||||
} from '../../../services/utilities.service'
|
||||
import {
|
||||
FilePlayingChangedEventCallback,
|
||||
FileProgressChangedEventCallback,
|
||||
FileService
|
||||
} from './file.service'
|
||||
import { ApplicationService } from '../../../services/app.service'
|
||||
@ -49,6 +51,7 @@ export class FileComponent implements OnInit, OnDestroy {
|
||||
if (this.progressProjectionInterval) {
|
||||
clearInterval(this.progressProjectionInterval)
|
||||
}
|
||||
this.destroyEvents()
|
||||
}
|
||||
|
||||
public setDefaultMeta () {
|
||||
@ -151,13 +154,23 @@ export class FileComponent implements OnInit, OnDestroy {
|
||||
}, 10)
|
||||
}
|
||||
|
||||
protected setupEvents () {
|
||||
this.fileService.onPlayingChanged(playing => {
|
||||
this.playing = playing
|
||||
})
|
||||
private onPlayingChangedEventCallback: FilePlayingChangedEventCallback
|
||||
private onProgressChangedEventCallback: FileProgressChangedEventCallback
|
||||
|
||||
this.fileService.onProgressChanged(progress => {
|
||||
protected setupEvents () {
|
||||
this.onPlayingChangedEventCallback = ({ playing }) => {
|
||||
this.playing = playing
|
||||
}
|
||||
this.fileService.onPlayingChanged(this.onPlayingChangedEventCallback)
|
||||
|
||||
this.onProgressChangedEventCallback = ({ progress }) => {
|
||||
this.progress = progress
|
||||
})
|
||||
}
|
||||
this.fileService.onProgressChanged(this.onProgressChangedEventCallback)
|
||||
}
|
||||
|
||||
private destroyEvents () {
|
||||
this.fileService.offPlayingChanged(this.onPlayingChangedEventCallback)
|
||||
this.fileService.offProgressChanged(this.onProgressChangedEventCallback)
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import { SourceService } from '../source.service'
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@Injectable()
|
||||
export class FileService extends SourceService {
|
||||
route = `${this.route}/file`
|
||||
|
||||
@ -45,11 +44,22 @@ export class FileService extends SourceService {
|
||||
return resp.playing
|
||||
}
|
||||
|
||||
onPlayingChanged (callback: (playing: boolean) => void) {
|
||||
this.on('/playing', ({ playing }) => callback(playing))
|
||||
onPlayingChanged (callback: FilePlayingChangedEventCallback) {
|
||||
this.on('/playing', callback)
|
||||
}
|
||||
|
||||
onProgressChanged (callback: (progress: number) => void) {
|
||||
this.on('/progress', ({ progress }) => callback(progress))
|
||||
offPlayingChanged (callback: FilePlayingChangedEventCallback) {
|
||||
this.off('/playing', callback)
|
||||
}
|
||||
|
||||
onProgressChanged (callback: FileProgressChangedEventCallback) {
|
||||
this.on('/progress', callback)
|
||||
}
|
||||
|
||||
offProgressChanged (callback: FileProgressChangedEventCallback) {
|
||||
this.off('/progress', callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type FilePlayingChangedEventCallback = (data: { playing: boolean }) => void
|
||||
export type FileProgressChangedEventCallback = (data: { progress: number }) => void
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { InputService } from './input.service'
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core'
|
||||
import { InputDeviceChangedEventCallback, InputService } from './input.service'
|
||||
|
||||
export interface InputDevice {
|
||||
deviceId: number
|
||||
@ -12,7 +12,7 @@ export interface InputDevice {
|
||||
templateUrl: './input.component.html',
|
||||
styleUrls: [ './input.component.scss' ]
|
||||
})
|
||||
export class InputComponent implements OnInit {
|
||||
export class InputComponent implements OnInit, OnDestroy {
|
||||
constructor (public inputService: InputService) { }
|
||||
|
||||
devices: InputDevice[] = []
|
||||
@ -38,10 +38,16 @@ export class InputComponent implements OnInit {
|
||||
await this.inputService.getDevice()
|
||||
}
|
||||
|
||||
private onDeviceChangedEventCallback: InputDeviceChangedEventCallback
|
||||
protected setupEvents () {
|
||||
this.inputService.onDeviceChanged((deviceId) => {
|
||||
this.onDeviceChangedEventCallback = ({ deviceId }) => {
|
||||
this.setDeviceById(deviceId)
|
||||
})
|
||||
}
|
||||
this.inputService.onDeviceChanged(this.onDeviceChangedEventCallback)
|
||||
}
|
||||
|
||||
private destroyEvents () {
|
||||
this.inputService.offDeviceChanged(this.onDeviceChangedEventCallback)
|
||||
}
|
||||
|
||||
deviceSelected (device) {
|
||||
@ -61,4 +67,8 @@ export class InputComponent implements OnInit {
|
||||
}
|
||||
this.selectedDevice = device
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.destroyEvents()
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,13 @@ export class InputService extends SourceService {
|
||||
return this.request({ method: 'POST', endpoint: '/device', data: { deviceId } })
|
||||
}
|
||||
|
||||
onDeviceChanged (callback: (deviceId: number) => void) {
|
||||
this.on(({ deviceId }) => callback(deviceId))
|
||||
onDeviceChanged (callback: InputDeviceChangedEventCallback) {
|
||||
this.on(callback)
|
||||
}
|
||||
|
||||
offDeviceChanged (callback: InputDeviceChangedEventCallback) {
|
||||
this.off(callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type InputDeviceChangedEventCallback = (data: { deviceId: number }) => void
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { SourceService, SourceType } from './source.service'
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core'
|
||||
import { SourceChangedEventCallback, SourceService, SourceType } from './source.service'
|
||||
|
||||
@Component({
|
||||
selector: 'eqm-source',
|
||||
templateUrl: './source.component.html',
|
||||
styleUrls: [ './source.component.scss' ]
|
||||
})
|
||||
export class SourceComponent implements OnInit {
|
||||
export class SourceComponent implements OnInit, OnDestroy {
|
||||
source: SourceType = 'File'
|
||||
constructor (public sourceService: SourceService) { }
|
||||
|
||||
@ -14,10 +14,16 @@ export class SourceComponent implements OnInit {
|
||||
this.setupEvents()
|
||||
}
|
||||
|
||||
private onSourceChangedEventCallback: SourceChangedEventCallback
|
||||
protected setupEvents () {
|
||||
this.sourceService.onSourceChanged(source => {
|
||||
this.onSourceChangedEventCallback = ({ source }) => {
|
||||
this.source = source
|
||||
})
|
||||
}
|
||||
this.sourceService.onSourceChanged(this.onSourceChangedEventCallback)
|
||||
}
|
||||
|
||||
private destroyEvents () {
|
||||
this.sourceService.offSourceChanged(this.onSourceChangedEventCallback)
|
||||
}
|
||||
|
||||
async setSource (source: SourceType) {
|
||||
@ -26,4 +32,8 @@ export class SourceComponent implements OnInit {
|
||||
this.sourceService.setSource(this.source)
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.destroyEvents()
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,13 @@ export class SourceService extends DataService {
|
||||
return this.request({ method: 'POST', endpoint: '', data: { source } })
|
||||
}
|
||||
|
||||
onSourceChanged (callback: (source: SourceType) => void) {
|
||||
this.on(({ source }) => callback(source))
|
||||
onSourceChanged (callback: SourceChangedEventCallback) {
|
||||
this.on(callback)
|
||||
}
|
||||
|
||||
offSourceChanged (callback: SourceChangedEventCallback) {
|
||||
this.off(callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type SourceChangedEventCallback = (data: { source: SourceType }) => void
|
||||
|
@ -1,16 +1,17 @@
|
||||
import { Component, OnInit, Input } from '@angular/core'
|
||||
import { BalanceService } from './balance.service'
|
||||
import { Component, OnInit, Input, OnDestroy } from '@angular/core'
|
||||
import { BalanceChangedEventCallback, BalanceService } from './balance.service'
|
||||
import { ApplicationService } from '../../../../services/app.service'
|
||||
import { KnobValueChangedEvent } from '../../../../modules/eqmac-components/components/knob/knob.component'
|
||||
import { FlatSliderValueChangedEvent } from '../../../../modules/eqmac-components/components/flat-slider/flat-slider.component'
|
||||
import { UIService } from '../../../../services/ui.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'eqm-balance',
|
||||
templateUrl: './balance.component.html',
|
||||
styleUrls: [ './balance.component.scss' ]
|
||||
})
|
||||
export class BalanceComponent implements OnInit {
|
||||
export class BalanceComponent implements OnInit, OnDestroy {
|
||||
balance = 0
|
||||
@Input() animationDuration = 500
|
||||
@Input() animationFps = 30
|
||||
@ -40,15 +41,24 @@ export class BalanceComponent implements OnInit {
|
||||
this.replaceKnobsWithSliders = uiSettings.replaceKnobsWithSliders
|
||||
}
|
||||
|
||||
private onBalanceChangedEventCallback: BalanceChangedEventCallback
|
||||
private onUISettingsChangedSubscription: Subscription
|
||||
protected setupEvents () {
|
||||
this.balanceService.onBalanceChanged((balance) => {
|
||||
this.onBalanceChangedEventCallback = ({ balance }) => {
|
||||
this.balance = balance
|
||||
})
|
||||
this.ui.settingsChanged.subscribe(uiSettings => {
|
||||
}
|
||||
this.balanceService.onBalanceChanged(this.onBalanceChangedEventCallback)
|
||||
|
||||
this.onUISettingsChangedSubscription = this.ui.settingsChanged.subscribe(uiSettings => {
|
||||
this.replaceKnobsWithSliders = uiSettings.replaceKnobsWithSliders
|
||||
})
|
||||
}
|
||||
|
||||
protected destroyEvents () {
|
||||
this.balanceService.offBalanceChanged(this.onBalanceChangedEventCallback)
|
||||
this.onUISettingsChangedSubscription?.unsubscribe()
|
||||
}
|
||||
|
||||
async getBalance () {
|
||||
this.balance = await this.balanceService.getBalance()
|
||||
}
|
||||
@ -62,4 +72,8 @@ export class BalanceComponent implements OnInit {
|
||||
this.app.haptic()
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.destroyEvents()
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,13 @@ export class BalanceService extends VolumeService {
|
||||
return this.request({ method: 'POST', endpoint: '/balance', data: { balance, transition } })
|
||||
}
|
||||
|
||||
onBalanceChanged (callback: (balance: number) => void) {
|
||||
this.on(({ balance }) => callback(balance))
|
||||
onBalanceChanged (callback: BalanceChangedEventCallback) {
|
||||
this.on(callback)
|
||||
}
|
||||
|
||||
offBalanceChanged (callback: BalanceChangedEventCallback) {
|
||||
this.off(callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type BalanceChangedEventCallback = (data: { balance: number }) => void
|
||||
|
@ -2,19 +2,21 @@ import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
ChangeDetectorRef
|
||||
ChangeDetectorRef,
|
||||
OnDestroy
|
||||
} from '@angular/core'
|
||||
|
||||
import { BoosterService } from './booster.service'
|
||||
import { BoosterGainChangedEventCallback, BoosterService } from './booster.service'
|
||||
import { ApplicationService } from '../../../../services/app.service'
|
||||
import { UIService } from '../../../../services/ui.service'
|
||||
import { UIService, UISettings } from '../../../../services/ui.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'eqm-booster',
|
||||
templateUrl: './booster.component.html',
|
||||
styleUrls: [ './booster.component.scss' ]
|
||||
})
|
||||
export class BoosterComponent implements OnInit {
|
||||
export class BoosterComponent implements OnInit, OnDestroy {
|
||||
gain = 1
|
||||
replaceKnobsWithSliders = false
|
||||
@Input() hide = false
|
||||
@ -40,18 +42,27 @@ export class BoosterComponent implements OnInit {
|
||||
|
||||
public ignoreUpdates = false
|
||||
public ignoreUpdatesDebouncer: NodeJS.Timer
|
||||
private onGainChangedEventCallback: BoosterGainChangedEventCallback
|
||||
private onUISettingsChangedEventSubscription: Subscription
|
||||
protected setupEvents () {
|
||||
this.boosterService.onGainChanged(gain => {
|
||||
this.onGainChangedEventCallback = ({ gain }) => {
|
||||
if (!this.ignoreUpdates) {
|
||||
this.gain = gain
|
||||
this.changeRef.detectChanges()
|
||||
}
|
||||
})
|
||||
this.ui.settingsChanged.subscribe(uiSettings => {
|
||||
}
|
||||
this.boosterService.onGainChanged(this.onGainChangedEventCallback)
|
||||
|
||||
this.onUISettingsChangedEventSubscription = this.ui.settingsChanged.subscribe(uiSettings => {
|
||||
this.replaceKnobsWithSliders = uiSettings.replaceKnobsWithSliders
|
||||
})
|
||||
}
|
||||
|
||||
protected destroyEvents () {
|
||||
this.boosterService.offGainChanged(this.onGainChangedEventCallback)
|
||||
this.onUISettingsChangedEventSubscription.unsubscribe()
|
||||
}
|
||||
|
||||
async syncUISettings () {
|
||||
const uiSettings = await this.ui.getSettings()
|
||||
this.replaceKnobsWithSliders = uiSettings.replaceKnobsWithSliders
|
||||
@ -76,4 +87,8 @@ export class BoosterComponent implements OnInit {
|
||||
this.app.haptic()
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.destroyEvents()
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,13 @@ export class BoosterService extends VolumeService {
|
||||
this.request({ method: 'POST', data: { gain, transition } })
|
||||
}
|
||||
|
||||
onGainChanged (callback: (gain: number) => void) {
|
||||
this.on(({ gain }) => callback(gain))
|
||||
onGainChanged (callback: BoosterGainChangedEventCallback) {
|
||||
this.on(callback)
|
||||
}
|
||||
|
||||
offGainChanged (callback: BoosterGainChangedEventCallback) {
|
||||
this.off(callback)
|
||||
}
|
||||
}
|
||||
|
||||
export type BoosterGainChangedEventCallback = (data: { gain: number }) => void
|
||||
|
@ -17,9 +17,12 @@ type CallHandlerCallback = (data?: BridgeResponseData) => void
|
||||
type RegisterHandler = (handler: string, cb: RegisterHandlerCallback) => void
|
||||
type RegisterHandlerCallback = (data: JSONData, cb: (data?: BridgeResponseData) => void) => void
|
||||
|
||||
type EventHandler = (data: JSONData, res: BridgeResponse) => void | Promise<void>
|
||||
|
||||
interface JSBridge {
|
||||
callHandler: CallHandler
|
||||
registerHandler: RegisterHandler
|
||||
disableJavscriptAlertBoxSafetyTimeout: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,6 +35,10 @@ interface JSBridge {
|
||||
export class BridgeService {
|
||||
public static bridgeLoadTimeout = 10000
|
||||
public static bridgeLoadPromise: Promise<JSBridge> = null
|
||||
private static didSpeedUp = false
|
||||
private static readonly handlers: {
|
||||
[event: string]: EventHandler[]
|
||||
} = {}
|
||||
|
||||
public get bridge () {
|
||||
if (BridgeService.bridgeLoadPromise) {
|
||||
@ -66,6 +73,10 @@ export class BridgeService {
|
||||
async call (handler: string, data?: JSONData): Promise<any> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const bridge = await this.bridge
|
||||
if (!BridgeService.didSpeedUp) {
|
||||
BridgeService.didSpeedUp = true
|
||||
bridge.disableJavscriptAlertBoxSafetyTimeout()
|
||||
}
|
||||
bridge.callHandler(handler, data, res => {
|
||||
const err = res.error
|
||||
return err ? reject(new Error(err)) : resolve(res.data)
|
||||
@ -73,14 +84,25 @@ export class BridgeService {
|
||||
})
|
||||
}
|
||||
|
||||
async on (event: string, handler: (data: JSONData, res: BridgeResponse) => void | Promise<void>) {
|
||||
async on (event: string, handler: EventHandler) {
|
||||
const bridge = await this.bridge
|
||||
let shouldRegister = false
|
||||
if (!(event in BridgeService.handlers)) {
|
||||
BridgeService.handlers[event] = []
|
||||
shouldRegister = true
|
||||
}
|
||||
|
||||
BridgeService.handlers[event].push(handler)
|
||||
|
||||
if (shouldRegister) {
|
||||
bridge.registerHandler(event, async (data, cb) => {
|
||||
const handleError = (err: string | Error) => {
|
||||
console.error(err)
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
cb({ error: err.toString() })
|
||||
}
|
||||
|
||||
for (const handler of BridgeService.handlers[event]) {
|
||||
try {
|
||||
await handler(data, {
|
||||
send: (data) => cb({ data }),
|
||||
@ -89,6 +111,21 @@ export class BridgeService {
|
||||
} catch (err) {
|
||||
handleError(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async off (event: string, handler: EventHandler) {
|
||||
if (!BridgeService.handlers[event]?.length) {
|
||||
console.error(`Trying to unsubscribe from event: "${event}" when there are no handlers registered`)
|
||||
return
|
||||
}
|
||||
const index = BridgeService.handlers[event]?.indexOf(handler)
|
||||
if (index > -1) {
|
||||
BridgeService.handlers[event].splice(index, 1)
|
||||
} else {
|
||||
console.error(`Trying to unsubscribe from event: "${event}" with a handler that is not registered`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +31,23 @@ export class DataService {
|
||||
return resp
|
||||
}
|
||||
|
||||
private normalizeEventCallback (eventOrCallback: string | EventCallback, callback?: EventCallback) {
|
||||
const event = typeof eventOrCallback === 'string' ? eventOrCallback : ''
|
||||
callback = typeof eventOrCallback === 'function' ? eventOrCallback : callback
|
||||
return { event, callback }
|
||||
}
|
||||
|
||||
async on (callback: EventCallback)
|
||||
async on (event: string, callback: EventCallback)
|
||||
async on (eventOrCallback: string | EventCallback, callback?: EventCallback) {
|
||||
const eventName = typeof eventOrCallback === 'string' ? eventOrCallback : ''
|
||||
callback = typeof eventOrCallback === 'function' ? eventOrCallback : callback
|
||||
this.bridge.on(`${this.route}${eventName}`, callback)
|
||||
async on (eventOrCallback: string | EventCallback, cb?: EventCallback) {
|
||||
const { event, callback } = this.normalizeEventCallback(eventOrCallback, cb)
|
||||
this.bridge.on(`${this.route}${event}`, callback)
|
||||
}
|
||||
|
||||
async off (callback: EventCallback)
|
||||
async off (event: string, callback: EventCallback)
|
||||
async off (eventOrCallback: string | EventCallback, cb?: EventCallback) {
|
||||
const { event, callback } = this.normalizeEventCallback(eventOrCallback, cb)
|
||||
this.bridge.off(`${this.route}${event}`, callback)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user