From 469084a1b6329e012c0b1718118b514653b09abd Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Mon, 29 Apr 2019 13:39:02 +0200 Subject: [PATCH] Work on the presentation controls --- .../core-services/projector-data.service.ts | 4 +- .../models/mediafile-projector-element.ts | 13 ++++ .../site/mediafiles/models/view-mediafile.ts | 11 ++- .../presentation-control.component.html | 76 ++++++++++--------- .../presentation-control.component.ts | 58 ++++++++++---- .../projector-detail.component.html | 7 +- client/src/app/slides/base-slide-component.ts | 5 +- .../mediafile/mediafile-slide.component.html | 28 +++---- .../mediafile/mediafile-slide.component.scss | 12 +++ .../mediafile/mediafile-slide.component.ts | 28 ++++--- .../slides/services/slide-manager.service.ts | 4 +- 11 files changed, 164 insertions(+), 82 deletions(-) create mode 100644 client/src/app/site/mediafiles/models/mediafile-projector-element.ts diff --git a/client/src/app/core/core-services/projector-data.service.ts b/client/src/app/core/core-services/projector-data.service.ts index 7b3a2358d..9600e20d2 100644 --- a/client/src/app/core/core-services/projector-data.service.ts +++ b/client/src/app/core/core-services/projector-data.service.ts @@ -5,9 +5,9 @@ import { Observable, BehaviorSubject } from 'rxjs'; import { WebsocketService } from 'app/core/core-services/websocket.service'; import { ProjectorElement, Projector } from 'app/shared/models/core/projector'; -export interface SlideData { +export interface SlideData { data: T; - element: ProjectorElement; + element: P; error?: string; } diff --git a/client/src/app/site/mediafiles/models/mediafile-projector-element.ts b/client/src/app/site/mediafiles/models/mediafile-projector-element.ts new file mode 100644 index 000000000..98670520e --- /dev/null +++ b/client/src/app/site/mediafiles/models/mediafile-projector-element.ts @@ -0,0 +1,13 @@ +import { ProjectorElement } from 'app/shared/models/core/projector'; + +export interface MediafileProjectorElement extends ProjectorElement { + // Images and Pdf + rotation?: 0 | 90 | 180 | 270; + + // Images + fullscreen?: boolean; + + // Pdf + page?: number; + zoom?: number; // 0 is normal, then +-1, +-2, ... +} diff --git a/client/src/app/site/mediafiles/models/view-mediafile.ts b/client/src/app/site/mediafiles/models/view-mediafile.ts index bc4cc4fb0..fa12cac5f 100644 --- a/client/src/app/site/mediafiles/models/view-mediafile.ts +++ b/client/src/app/site/mediafiles/models/view-mediafile.ts @@ -7,12 +7,17 @@ import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable'; import { BaseViewModelWithListOfSpeakers } from 'app/site/base/base-view-model-with-list-of-speakers'; import { ViewListOfSpeakers } from 'app/site/agenda/models/view-list-of-speakers'; +export const IMAGE_MIMETYPES = ['image/png', 'image/jpeg', 'image/gif']; +export const FONT_MIMETYPES = ['font/ttf', 'font/woff', 'application/font-woff', 'application/font-sfnt']; +export const PDF_MIMETYPES = ['application/pdf']; + export interface MediafileTitleInformation { title: string; } export class ViewMediafile extends BaseViewModelWithListOfSpeakers implements MediafileTitleInformation, Searchable { + public static COLLECTIONSTRING = Mediafile.COLLECTIONSTRING; private _uploader: ViewUser; @@ -110,7 +115,7 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers * @returns true or false */ public isImage(): boolean { - return ['image/png', 'image/jpeg', 'image/gif'].includes(this.type); + return IMAGE_MIMETYPES.includes(this.type); } /** @@ -119,7 +124,7 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers * @returns true or false */ public isFont(): boolean { - return ['font/ttf', 'font/woff', 'application/font-woff', 'application/font-sfnt'].includes(this.type); + return FONT_MIMETYPES.includes(this.type); } /** @@ -128,7 +133,7 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers * @returns true or false */ public isPdf(): boolean { - return ['application/pdf'].includes(this.type); + return PDF_MIMETYPES.includes(this.type); } /** diff --git a/client/src/app/site/projector/components/presentation-control/presentation-control.component.html b/client/src/app/site/projector/components/presentation-control/presentation-control.component.html index 93b737280..41e285865 100644 --- a/client/src/app/site/projector/components/presentation-control/presentation-control.component.html +++ b/client/src/app/site/projector/components/presentation-control/presentation-control.component.html @@ -1,34 +1,42 @@ -
Presentation control
-
- {{ getMediafile(element).getTitle() }} - - - - - - - - - Page {{ getPage(element) }}/{{ getMediafile(element).pages }} - - - - - -
+ + + Media controls + +
Presentation control
+
+ {{ getMediafile(element).getTitle() }} + + + + + + + + + + Page {{ getPage(element) }}/{{ getMediafile(element).pages }} + + + + + +
+
diff --git a/client/src/app/site/projector/components/presentation-control/presentation-control.component.ts b/client/src/app/site/projector/components/presentation-control/presentation-control.component.ts index 695892b2a..5618204ff 100644 --- a/client/src/app/site/projector/components/presentation-control/presentation-control.component.ts +++ b/client/src/app/site/projector/components/presentation-control/presentation-control.component.ts @@ -7,11 +7,11 @@ import { TranslateService } from '@ngx-translate/core'; import { BaseViewComponent } from 'app/site/base/base-view'; import { Mediafile } from 'app/shared/models/mediafiles/mediafile'; import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service'; -import { ProjectorElements, ProjectorElement } from 'app/shared/models/core/projector'; import { ProjectorService } from 'app/core/core-services/projector.service'; import { SlideManager } from 'app/slides/services/slide-manager.service'; import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile'; import { ViewProjector } from '../../models/view-projector'; +import { MediafileProjectorElement } from 'app/site/mediafiles/models/mediafile-projector-element'; /** * The presentation controls. @@ -38,7 +38,7 @@ export class PresentationControlComponent extends BaseViewComponent { } // All mediafile elements. - public elements: ProjectorElements = []; + public elements: MediafileProjectorElement[] = []; /** * Constructor @@ -66,7 +66,7 @@ export class PresentationControlComponent extends BaseViewComponent { */ private updateElements(): void { this.elements = this.projector.elements.filter(element => { - if (element.name !== Mediafile.COLLECTIONSTRING && !element.id) { + if (element.name !== Mediafile.COLLECTIONSTRING || !element.id) { return false; } const mediafile = this.mediafileRepo.getViewModel(element.id); @@ -74,14 +74,14 @@ export class PresentationControlComponent extends BaseViewComponent { }); } - public getMediafile(element: ProjectorElement): ViewMediafile { + public getMediafile(element: MediafileProjectorElement): ViewMediafile { return this.mediafileRepo.getViewModel(element.id); } /** * @returns the currently used page number (1 in case of unnumbered elements) */ - public getPage(element: ProjectorElement): number { + public getPage(element: MediafileProjectorElement): number { return element.page || 1; } @@ -90,7 +90,7 @@ export class PresentationControlComponent extends BaseViewComponent { * * @param element */ - public pdfForward(element: ProjectorElement): void { + public pdfForward(element: MediafileProjectorElement): void { if (this.getPage(element) < this.getMediafile(element).pages) { this.pdfSetPage(element, this.getPage(element) + 1); } @@ -101,7 +101,7 @@ export class PresentationControlComponent extends BaseViewComponent { * * @param element */ - public pdfBackward(element: ProjectorElement): void { + public pdfBackward(element: MediafileProjectorElement): void { if (this.getPage(element) > 1) { this.pdfSetPage(element, this.getPage(element) - 1); } @@ -114,19 +114,47 @@ export class PresentationControlComponent extends BaseViewComponent { * @param element * @param page */ - public pdfSetPage(element: ProjectorElement, page: number): void { - const idElement = this.slideManager.getIdentifialbeProjectorElement(element); + public pdfSetPage(element: MediafileProjectorElement, page: number): void { if (this.getMediafile(element).pages >= page) { - idElement.page = page; - this.projectorService.updateElement(this.projector.projector, idElement).then(null, this.raiseError); + element.page = page; + this.updateElement(element); } } - public pdfZoom(element: ProjectorElement, direction: 'in' | 'out' | 'reset'): void {} + public zoom(element: MediafileProjectorElement, direction: 'in' | 'out' | 'reset'): void { + if (direction === 'reset') { + element.zoom = 0; + } else if (direction === 'in') { + element.zoom = (element.zoom || 0) + 1; + } else if (direction === 'out') { + element.zoom = (element.zoom || 0) - 1; + } + this.updateElement(element); + } - public pdfRotate(element: ProjectorElement): void {} + public fullscreen(element: MediafileProjectorElement): void { + element.fullscreen = !element.fullscreen; + this.updateElement(element); + } - public imageFullscreen(element: ProjectorElement): void {} + public rotate(element: MediafileProjectorElement): void { + let rotation: 0 | 90 | 180 | 270 = element.rotation || 0; + if (rotation === 0) { + rotation = 90; + } else if (rotation === 90) { + rotation = 180; + } else if (rotation === 180) { + rotation = 270; + } else { + // 270 + rotation = 0; + } + element.rotation = rotation; + this.updateElement(element); + } - public imageRotate(element: ProjectorElement): void {} + private updateElement(element: MediafileProjectorElement): void { + const idElement = this.slideManager.getIdentifialbeProjectorElement(element); + this.projectorService.updateElement(this.projector.projector, idElement).then(null, this.raiseError); + } } diff --git a/client/src/app/site/projector/components/projector-detail/projector-detail.component.html b/client/src/app/site/projector/components/projector-detail/projector-detail.component.html index 7b0b2bfc2..1296de599 100644 --- a/client/src/app/site/projector/components/projector-detail/projector-detail.component.html +++ b/client/src/app/site/projector/components/projector-detail/projector-detail.component.html @@ -264,13 +264,16 @@ - + + + + diff --git a/client/src/app/slides/base-slide-component.ts b/client/src/app/slides/base-slide-component.ts index 29d1e2eec..f83515b7f 100644 --- a/client/src/app/slides/base-slide-component.ts +++ b/client/src/app/slides/base-slide-component.ts @@ -2,17 +2,18 @@ import { Input } from '@angular/core'; import { ViewProjector } from 'app/site/projector/models/view-projector'; import { SlideData } from 'app/core/core-services/projector-data.service'; +import { ProjectorElement } from 'app/shared/models/core/projector'; /** * Every slide has to extends this base class. It forces the slides * to have an input for the slidedata. */ -export abstract class BaseSlideComponent { +export abstract class BaseSlideComponent { /** * Each slide must take slide data. */ @Input() - public data: SlideData; + public data: SlideData; /** * The projector where this slide is projected on. diff --git a/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.html b/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.html index 74d3f4245..225838d5b 100644 --- a/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.html +++ b/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.html @@ -1,17 +1,19 @@
-
- +
+ + {{ data.element.fullscreen || false }}
-
- -
-
- +
+ {{ data.element.rotation || 0 }} +
diff --git a/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.scss b/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.scss index e69de29bb..53fc4c228 100644 --- a/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.scss +++ b/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.scss @@ -0,0 +1,12 @@ +.rotate0 { + transform: rotate(0deg); +} +.rotate90 { + transform: rotate(90deg); +} +.rotate180 { + transform: rotate(180deg); +} +.rotate270 { + transform: rotate(270deg); +} diff --git a/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.ts b/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.ts index ec60bcdcb..5a31c04e5 100644 --- a/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.ts +++ b/client/src/app/slides/mediafiles/mediafile/mediafile-slide.component.ts @@ -2,22 +2,32 @@ import { Component } from '@angular/core'; import { BaseSlideComponent } from 'app/slides/base-slide-component'; import { MediafileSlideData } from './mediafile-slide-data'; +import { IMAGE_MIMETYPES, PDF_MIMETYPES } from 'app/site/mediafiles/models/view-mediafile'; +import { MediafileProjectorElement } from 'app/site/mediafiles/models/mediafile-projector-element'; @Component({ selector: 'os-mediafile-slide', templateUrl: './mediafile-slide.component.html', styleUrls: ['./mediafile-slide.component.scss'] }) -export class MediafileSlideComponent extends BaseSlideComponent { - public constructor() { - super(); - } - - public get page(): string { - return this.data.element.page; - } - +export class MediafileSlideComponent extends BaseSlideComponent { public get url(): string { return `${this.data.data.media_url_prefix}/${this.data.data.path}`; } + + public get zoom(): number { + return Math.pow(1.1, this.data.element.zoom || 0); + } + + public get isImage(): boolean { + return IMAGE_MIMETYPES.includes(this.data.data.type); + } + + public get isPdf(): boolean { + return PDF_MIMETYPES.includes(this.data.data.type); + } + + public constructor() { + super(); + } } diff --git a/client/src/app/slides/services/slide-manager.service.ts b/client/src/app/slides/services/slide-manager.service.ts index f2ef6a768..5ed340c1b 100644 --- a/client/src/app/slides/services/slide-manager.service.ts +++ b/client/src/app/slides/services/slide-manager.service.ts @@ -54,8 +54,8 @@ export class SlideManager { return this.loadedSlideConfigurations[slideName]; } - public getIdentifialbeProjectorElement(element: ProjectorElement): IdentifiableProjectorElement { - const identifiableElement: IdentifiableProjectorElement = element as IdentifiableProjectorElement; + public getIdentifialbeProjectorElement

(element: P): IdentifiableProjectorElement & P { + const identifiableElement: IdentifiableProjectorElement & P = element as IdentifiableProjectorElement & P; const identifiers = this.getManifest(element.name).elementIdentifiers.map(x => x); // map to copy. identifiableElement.getIdentifiers = () => identifiers; return identifiableElement;