Work on the presentation controls
This commit is contained in:
parent
efbce9b645
commit
469084a1b6
@ -5,9 +5,9 @@ import { Observable, BehaviorSubject } from 'rxjs';
|
|||||||
import { WebsocketService } from 'app/core/core-services/websocket.service';
|
import { WebsocketService } from 'app/core/core-services/websocket.service';
|
||||||
import { ProjectorElement, Projector } from 'app/shared/models/core/projector';
|
import { ProjectorElement, Projector } from 'app/shared/models/core/projector';
|
||||||
|
|
||||||
export interface SlideData<T = { error?: string }> {
|
export interface SlideData<T = { error?: string }, P extends ProjectorElement = ProjectorElement> {
|
||||||
data: T;
|
data: T;
|
||||||
element: ProjectorElement;
|
element: P;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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, ...
|
||||||
|
}
|
@ -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 { BaseViewModelWithListOfSpeakers } from 'app/site/base/base-view-model-with-list-of-speakers';
|
||||||
import { ViewListOfSpeakers } from 'app/site/agenda/models/view-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 {
|
export interface MediafileTitleInformation {
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ViewMediafile extends BaseViewModelWithListOfSpeakers<Mediafile>
|
export class ViewMediafile extends BaseViewModelWithListOfSpeakers<Mediafile>
|
||||||
implements MediafileTitleInformation, Searchable {
|
implements MediafileTitleInformation, Searchable {
|
||||||
|
|
||||||
public static COLLECTIONSTRING = Mediafile.COLLECTIONSTRING;
|
public static COLLECTIONSTRING = Mediafile.COLLECTIONSTRING;
|
||||||
|
|
||||||
private _uploader: ViewUser;
|
private _uploader: ViewUser;
|
||||||
@ -110,7 +115,7 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers<Mediafile>
|
|||||||
* @returns true or false
|
* @returns true or false
|
||||||
*/
|
*/
|
||||||
public isImage(): boolean {
|
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<Mediafile>
|
|||||||
* @returns true or false
|
* @returns true or false
|
||||||
*/
|
*/
|
||||||
public isFont(): boolean {
|
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<Mediafile>
|
|||||||
* @returns true or false
|
* @returns true or false
|
||||||
*/
|
*/
|
||||||
public isPdf(): boolean {
|
public isPdf(): boolean {
|
||||||
return ['application/pdf'].includes(this.type);
|
return PDF_MIMETYPES.includes(this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
<h5 *ngIf="elements.length" translate>Presentation control</h5>
|
<mat-expansion-panel *ngIf="elements.length">
|
||||||
<div *ngFor="let element of elements">
|
<mat-expansion-panel-header>
|
||||||
|
<span translate>Media controls</span>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<h5 translate>Presentation control</h5>
|
||||||
|
<div *ngFor="let element of elements">
|
||||||
{{ getMediafile(element).getTitle() }}
|
{{ getMediafile(element).getTitle() }}
|
||||||
<span *ngIf="getMediafile(element).isImage()">
|
<span *ngIf="getMediafile(element).isImage()">
|
||||||
<button type="button" mat-icon-button (click)="imageFullscreen(element)">
|
<button type="button" *ngIf="!element.fullscreen" mat-icon-button (click)="fullscreen(element)">
|
||||||
<mat-icon>fullscreen</mat-icon>
|
<mat-icon>fullscreen</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" mat-icon-button (click)="imageRotate(element)">
|
<button type="button" *ngIf="!!element.fullscreen" mat-icon-button (click)="fullscreen(element)">
|
||||||
|
<mat-icon>fullscreen_exit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button type="button" mat-icon-button (click)="rotate(element)">
|
||||||
<mat-icon>refresh</mat-icon>
|
<mat-icon>refresh</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
@ -18,17 +25,18 @@
|
|||||||
</button>
|
</button>
|
||||||
<!-- TODO: Use form for page number; use pdfSetPage then. -->
|
<!-- TODO: Use form for page number; use pdfSetPage then. -->
|
||||||
Page {{ getPage(element) }}/{{ getMediafile(element).pages }}
|
Page {{ getPage(element) }}/{{ getMediafile(element).pages }}
|
||||||
<button type="button" mat-icon-button (click)="pdfRotate(element)">
|
<button type="button" mat-icon-button (click)="rotate(element)">
|
||||||
<mat-icon>refresh</mat-icon>
|
<mat-icon>refresh</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" mat-icon-button (click)="pdfZoom(element, 'in')">
|
<button type="button" mat-icon-button (click)="zoom(element, 'in')">
|
||||||
<mat-icon>zoom_in</mat-icon>
|
<mat-icon>zoom_in</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" mat-icon-button (click)="pdfZoom(element, 'reset')">
|
<button type="button" mat-icon-button (click)="zoom(element, 'reset')">
|
||||||
<mat-icon>replay</mat-icon>
|
<mat-icon>replay</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" mat-icon-button (click)="pdfZoom(element, 'out')">
|
<button type="button" mat-icon-button (click)="zoom(element, 'out')">
|
||||||
<mat-icon>zoom_out</mat-icon>
|
<mat-icon>zoom_out</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
@ -7,11 +7,11 @@ import { TranslateService } from '@ngx-translate/core';
|
|||||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
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 { ProjectorService } from 'app/core/core-services/projector.service';
|
||||||
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
||||||
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
import { ViewProjector } from '../../models/view-projector';
|
import { ViewProjector } from '../../models/view-projector';
|
||||||
|
import { MediafileProjectorElement } from 'app/site/mediafiles/models/mediafile-projector-element';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The presentation controls.
|
* The presentation controls.
|
||||||
@ -38,7 +38,7 @@ export class PresentationControlComponent extends BaseViewComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// All mediafile elements.
|
// All mediafile elements.
|
||||||
public elements: ProjectorElements = [];
|
public elements: MediafileProjectorElement[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -66,7 +66,7 @@ export class PresentationControlComponent extends BaseViewComponent {
|
|||||||
*/
|
*/
|
||||||
private updateElements(): void {
|
private updateElements(): void {
|
||||||
this.elements = this.projector.elements.filter(element => {
|
this.elements = this.projector.elements.filter(element => {
|
||||||
if (element.name !== Mediafile.COLLECTIONSTRING && !element.id) {
|
if (element.name !== Mediafile.COLLECTIONSTRING || !element.id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const mediafile = this.mediafileRepo.getViewModel(element.id);
|
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);
|
return this.mediafileRepo.getViewModel(element.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns the currently used page number (1 in case of unnumbered elements)
|
* @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;
|
return element.page || 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ export class PresentationControlComponent extends BaseViewComponent {
|
|||||||
*
|
*
|
||||||
* @param element
|
* @param element
|
||||||
*/
|
*/
|
||||||
public pdfForward(element: ProjectorElement): void {
|
public pdfForward(element: MediafileProjectorElement): void {
|
||||||
if (this.getPage(element) < this.getMediafile(element).pages) {
|
if (this.getPage(element) < this.getMediafile(element).pages) {
|
||||||
this.pdfSetPage(element, this.getPage(element) + 1);
|
this.pdfSetPage(element, this.getPage(element) + 1);
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ export class PresentationControlComponent extends BaseViewComponent {
|
|||||||
*
|
*
|
||||||
* @param element
|
* @param element
|
||||||
*/
|
*/
|
||||||
public pdfBackward(element: ProjectorElement): void {
|
public pdfBackward(element: MediafileProjectorElement): void {
|
||||||
if (this.getPage(element) > 1) {
|
if (this.getPage(element) > 1) {
|
||||||
this.pdfSetPage(element, this.getPage(element) - 1);
|
this.pdfSetPage(element, this.getPage(element) - 1);
|
||||||
}
|
}
|
||||||
@ -114,19 +114,47 @@ export class PresentationControlComponent extends BaseViewComponent {
|
|||||||
* @param element
|
* @param element
|
||||||
* @param page
|
* @param page
|
||||||
*/
|
*/
|
||||||
public pdfSetPage(element: ProjectorElement, page: number): void {
|
public pdfSetPage(element: MediafileProjectorElement, page: number): void {
|
||||||
const idElement = this.slideManager.getIdentifialbeProjectorElement(element);
|
|
||||||
if (this.getMediafile(element).pages >= page) {
|
if (this.getMediafile(element).pages >= page) {
|
||||||
idElement.page = page;
|
element.page = page;
|
||||||
|
this.updateElement(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 fullscreen(element: MediafileProjectorElement): void {
|
||||||
|
element.fullscreen = !element.fullscreen;
|
||||||
|
this.updateElement(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateElement(element: MediafileProjectorElement): void {
|
||||||
|
const idElement = this.slideManager.getIdentifialbeProjectorElement(element);
|
||||||
this.projectorService.updateElement(this.projector.projector, idElement).then(null, this.raiseError);
|
this.projectorService.updateElement(this.projector.projector, idElement).then(null, this.raiseError);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public pdfZoom(element: ProjectorElement, direction: 'in' | 'out' | 'reset'): void {}
|
|
||||||
|
|
||||||
public pdfRotate(element: ProjectorElement): void {}
|
|
||||||
|
|
||||||
public imageFullscreen(element: ProjectorElement): void {}
|
|
||||||
|
|
||||||
public imageRotate(element: ProjectorElement): void {}
|
|
||||||
}
|
}
|
||||||
|
@ -264,13 +264,16 @@
|
|||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
|
|
||||||
<!-- File display controls -->
|
<!-- File display controls -->
|
||||||
<mat-expansion-panel>
|
<!--<mat-expansion-panel>
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<span translate>Media controls</span>
|
<span translate>Media controls</span>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<os-presentation-control [projector]="projector">
|
<os-presentation-control [projector]="projector">
|
||||||
</os-presentation-control>
|
</os-presentation-control>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>-->
|
||||||
|
|
||||||
|
<os-presentation-control [projector]="projector">
|
||||||
|
</os-presentation-control>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,17 +2,18 @@ import { Input } from '@angular/core';
|
|||||||
|
|
||||||
import { ViewProjector } from 'app/site/projector/models/view-projector';
|
import { ViewProjector } from 'app/site/projector/models/view-projector';
|
||||||
import { SlideData } from 'app/core/core-services/projector-data.service';
|
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
|
* Every slide has to extends this base class. It forces the slides
|
||||||
* to have an input for the slidedata.
|
* to have an input for the slidedata.
|
||||||
*/
|
*/
|
||||||
export abstract class BaseSlideComponent<T extends object> {
|
export abstract class BaseSlideComponent<T extends object, P extends ProjectorElement = ProjectorElement> {
|
||||||
/**
|
/**
|
||||||
* Each slide must take slide data.
|
* Each slide must take slide data.
|
||||||
*/
|
*/
|
||||||
@Input()
|
@Input()
|
||||||
public data: SlideData<T>;
|
public data: SlideData<T, P>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The projector where this slide is projected on.
|
* The projector where this slide is projected on.
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
<div *ngIf="data">
|
<div *ngIf="data">
|
||||||
<div *ngIf="data.data.type == 'image/png'">
|
<div *ngIf="isImage">
|
||||||
<img [src]="url" alt=""/>
|
<img [src]="url" alt="" [ngClass]="'rotate' + (data.element.rotation || 0)"/>
|
||||||
|
{{ data.element.fullscreen || false }}
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="data.data.type == 'image/jpeg'">
|
<div *ngIf="isPdf">
|
||||||
<img [src]="url" alt=""/>
|
{{ data.element.rotation || 0 }}
|
||||||
</div>
|
|
||||||
<div *ngIf="data.data.type == 'application/pdf'">
|
|
||||||
<pdf-viewer
|
<pdf-viewer
|
||||||
[show-all]="false"
|
[show-all]="false"
|
||||||
[original-size]="false"
|
[original-size]="false"
|
||||||
|
[fit-to-page]="true"
|
||||||
[autoresize]="true"
|
[autoresize]="true"
|
||||||
[page]="page"
|
[page]="data.element.page || 1"
|
||||||
|
[zoom]="zoom"
|
||||||
|
[rotation]="data.element.rotation || 0"
|
||||||
[src]="url"
|
[src]="url"
|
||||||
style="display: block;"></pdf-viewer>
|
style="display: block;"></pdf-viewer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
.rotate0 {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
.rotate90 {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
.rotate180 {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
.rotate270 {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
@ -2,22 +2,32 @@ import { Component } from '@angular/core';
|
|||||||
|
|
||||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||||
import { MediafileSlideData } from './mediafile-slide-data';
|
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({
|
@Component({
|
||||||
selector: 'os-mediafile-slide',
|
selector: 'os-mediafile-slide',
|
||||||
templateUrl: './mediafile-slide.component.html',
|
templateUrl: './mediafile-slide.component.html',
|
||||||
styleUrls: ['./mediafile-slide.component.scss']
|
styleUrls: ['./mediafile-slide.component.scss']
|
||||||
})
|
})
|
||||||
export class MediafileSlideComponent extends BaseSlideComponent<MediafileSlideData> {
|
export class MediafileSlideComponent extends BaseSlideComponent<MediafileSlideData, MediafileProjectorElement> {
|
||||||
public constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public get page(): string {
|
|
||||||
return this.data.element.page;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get url(): string {
|
public get url(): string {
|
||||||
return `${this.data.data.media_url_prefix}/${this.data.data.path}`;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,8 +54,8 @@ export class SlideManager {
|
|||||||
return this.loadedSlideConfigurations[slideName];
|
return this.loadedSlideConfigurations[slideName];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getIdentifialbeProjectorElement(element: ProjectorElement): IdentifiableProjectorElement {
|
public getIdentifialbeProjectorElement<P extends ProjectorElement>(element: P): IdentifiableProjectorElement & P {
|
||||||
const identifiableElement: IdentifiableProjectorElement = element as IdentifiableProjectorElement;
|
const identifiableElement: IdentifiableProjectorElement & P = element as IdentifiableProjectorElement & P;
|
||||||
const identifiers = this.getManifest(element.name).elementIdentifiers.map(x => x); // map to copy.
|
const identifiers = this.getManifest(element.name).elementIdentifiers.map(x => x); // map to copy.
|
||||||
identifiableElement.getIdentifiers = () => identifiers;
|
identifiableElement.getIdentifiers = () => identifiers;
|
||||||
return identifiableElement;
|
return identifiableElement;
|
||||||
|
Loading…
Reference in New Issue
Block a user