diff --git a/src/app/components/chord-view/chord-view.component.ts b/src/app/components/chord-view/chord-view.component.ts index b3a253a..4b46f7e 100644 --- a/src/app/components/chord-view/chord-view.component.ts +++ b/src/app/components/chord-view/chord-view.component.ts @@ -16,14 +16,53 @@ export class ChordViewComponent extends StageViewComponent { songTransposeMap = new Map(); // current songs transpose level transposeLevel = 0; + currentSlide = 0; + useNewTransposeEndpoint = this.openlpService.assertApiVersionMinimum(2, 2); + updateCurrentSlides(serviceItemId: string, currentSlide: number): void { + this.currentSlide = currentSlide; + this.useNewTransposeEndpoint = this.openlpService.assertApiVersionMinimum(2, 2); + this.serviceItemSubscription$?.unsubscribe(); + const newServiceItemTransposeLevel = this.songTransposeMap.get(serviceItemId); - setNewSlides(slides: Slide[]): void { - super.setNewSlides(slides); + if (this.useNewTransposeEndpoint && newServiceItemTransposeLevel && (newServiceItemTransposeLevel !== 0)) { + this.serviceItemSubscription$ = this.openlpService + .transposeSong(newServiceItemTransposeLevel, 'service_item') + .subscribe(serviceItem => { + this.serviceItem = serviceItem; + if (serviceItem instanceof Array) { + this.setNewSlides(serviceItem, currentSlide); + } + else { + this.setNewSlides(serviceItem.slides, currentSlide); + this.setNotes(serviceItem.notes); + } + }); + } else { + if (this.useNewTransposeEndpoint) { + this.songTransposeMap.set(serviceItemId, 0); + this.transposeLevel = 0; + } + super.updateCurrentSlides(serviceItemId, currentSlide); + } + } + + setNewSlides(slides: Slide[], currentSlide: number): void { + super.setNewSlides(slides, currentSlide); + if (this.openlpService.assertApiVersionExact(2, 2)) { + // API Version 2.2 released on OpenLP 3.0.2 contains a bug on which 'selected' is not set correctly + // on Transponse Service Item response. + if (slides[currentSlide]) { + slides[currentSlide].selected = true; + } + } // if this song is already known if (this.songTransposeMap.has(this.serviceItem.id)) { - if (this.songTransposeMap.get(this.serviceItem.id) !== 0) { - this.transposeChords(); + const transposeLevel = this.songTransposeMap.get(this.serviceItem.id); + if (transposeLevel) { + if (!this.useNewTransposeEndpoint) { + this.transposeChords(); + } } else { this.transposeLevel = this.songTransposeMap.get(this.serviceItem.id); } @@ -57,7 +96,15 @@ export class ChordViewComponent extends StageViewComponent { transposeChords(): void { const tmpTranspose = this.songTransposeMap.get(this.serviceItem.id); this.transposeLevel = tmpTranspose; - this.openlpService.transposeSong(tmpTranspose).subscribe(transposedLyrics => { + if (this.useNewTransposeEndpoint) { + this.updateCurrentSlides(this.serviceItem.id, this.currentSlide); + } else { + this.transposeChordsLegacy(tmpTranspose); + } + } + + transposeChordsLegacy(transposeLevel): void { + this.openlpService.transposeSong(transposeLevel).subscribe(transposedLyrics => { // Replace the chords in the currentSlides with the returned transposed chords if (transposedLyrics instanceof Array) { for (let i = 0; i < transposedLyrics.length; ++i) { diff --git a/src/app/components/stage-view/stage-view.component.ts b/src/app/components/stage-view/stage-view.component.ts index bf35ad4..b1ed8cb 100644 --- a/src/app/components/stage-view/stage-view.component.ts +++ b/src/app/components/stage-view/stage-view.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subscription } from 'rxjs'; import { OpenLPService } from '../../openlp.service'; import { ServiceItem, Slide } from '../../responses'; @@ -21,24 +22,26 @@ export class StageViewComponent implements OnInit { tags: Tag[] = []; time = new Date(); showNotes = true; + serviceItemSubscription$: Subscription = null; constructor(public openlpService: OpenLPService) { setInterval(() => this.time = new Date(), 1000); } ngOnInit() { - this.updateCurrentSlides(); - this.openlpService.stateChanged$.subscribe(item => this.updateCurrentSlides()); + this.updateCurrentSlides(null, null); + this.openlpService.stateChanged$.subscribe(item => this.updateCurrentSlides(item.item, item.slide)); } - updateCurrentSlides(): void { - this.openlpService.getServiceItem().subscribe(serviceItem => { + updateCurrentSlides(serviceItemId: string, currentSlide: number): void { + this.serviceItemSubscription$?.unsubscribe(); + this.serviceItemSubscription$ = this.openlpService.getServiceItem().subscribe(serviceItem => { this.serviceItem = serviceItem; if (serviceItem instanceof Array) { - this.setNewSlides(serviceItem); + this.setNewSlides(serviceItem, currentSlide); } else { - this.setNewSlides(serviceItem.slides); + this.setNewSlides(serviceItem.slides, currentSlide); this.setNotes(serviceItem.notes); } }); @@ -48,7 +51,7 @@ export class StageViewComponent implements OnInit { return this.currentSlides.slice(this.activeSlide + 1); } - setNewSlides(slides: Slide[]): void { + setNewSlides(slides: Slide[], currentSlide: number): void { if (slides.length === 0) { return; } diff --git a/src/app/openlp.service.ts b/src/app/openlp.service.ts index a3b7ff4..5f4a23c 100644 --- a/src/app/openlp.service.ts +++ b/src/app/openlp.service.ts @@ -1,7 +1,7 @@ import { Injectable, EventEmitter } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable, Subscription } from 'rxjs'; -import { finalize, shareReplay } from 'rxjs/operators'; +import { finalize, shareReplay, tap } from 'rxjs/operators'; import { PluginDescription, @@ -44,6 +44,8 @@ export enum WebSocketStatus { @Injectable() export class OpenLPService { private apiURL: string; + public apiVersion: number | null; + public apiRevision: number | null; private host: string; public stateChanged$: EventEmitter; public webSocketStateChanged$: EventEmitter; @@ -69,6 +71,14 @@ export class OpenLPService { this.createWebSocket(); } + assertApiVersionExact(version: number, revision: number) { + return version === this.apiVersion && revision === this.apiRevision; + } + + assertApiVersionMinimum(version: number, revision: number) { + return version >= this.apiVersion && revision >= this.apiRevision; + } + setAuthToken(token: string): void { httpOptions.headers = httpOptions.headers.set('Authorization', token); } @@ -78,7 +88,13 @@ export class OpenLPService { } retrieveSystemInformation(): Observable { - return this.doGet(`${this.apiURL}/core/system`); + return this.doGet(`${this.apiURL}/core/system`) + .pipe(tap(systemInfo => { + if (systemInfo.api_version) { + this.apiVersion = systemInfo.api_version; + this.apiRevision = systemInfo.api_revision; + } + })); } getMainImage(): Observable { @@ -185,8 +201,8 @@ export class OpenLPService { return this.doPost(`${this.apiURL}/plugins/${plugin}/add`, {id}); } - transposeSong(transpose_value): Observable { - return this.doGet(`${this.apiURL}/plugins/songs/transpose-live-item/${transpose_value}`); + transposeSong(transpose_value, return_format = 'default'): Observable { + return this.doGet(`${this.apiURL}/plugins/songs/transpose-live-item/${transpose_value}?response_format=${return_format}`); } login(credentials: Credentials): Observable { diff --git a/src/app/responses.ts b/src/app/responses.ts index 826dd1e..19c3332 100644 --- a/src/app/responses.ts +++ b/src/app/responses.ts @@ -12,6 +12,7 @@ export class State { blank: boolean; twelve: boolean; theme: boolean; + item: string; live = () => !(this.blank || this.display || this.theme); @@ -68,6 +69,8 @@ export interface MainView { export interface SystemInformation { websocket_port: number; login_required: boolean; + api_version?: number; + api_revision?: number; } export interface Credentials {