Projector improvements
- Moved projector configs to group "General" - Removed unused projector config related to CLOS - debounce projector data requests for many projectors - add (foreground) color - custom, modifiable CSS classes per projector to cascade dynamic styles into slides
This commit is contained in:
parent
8cb9892426
commit
23c704b5da
@ -1,9 +1,10 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { Observable, BehaviorSubject } from 'rxjs';
|
import { Observable, BehaviorSubject, Subject } 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';
|
||||||
|
import { auditTime } from 'rxjs/operators';
|
||||||
|
|
||||||
export interface SlideData<T = { error?: string }, P extends ProjectorElement = ProjectorElement> {
|
export interface SlideData<T = { error?: string }, P extends ProjectorElement = ProjectorElement> {
|
||||||
data: T;
|
data: T;
|
||||||
@ -36,12 +37,19 @@ export class ProjectorDataService {
|
|||||||
*/
|
*/
|
||||||
private currentProjectorData: { [id: number]: BehaviorSubject<ProjectorData | null> } = {};
|
private currentProjectorData: { [id: number]: BehaviorSubject<ProjectorData | null> } = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When multiple projectory are requested, debounce these requests to just issue
|
||||||
|
* one request, with all the needed projectors.
|
||||||
|
*/
|
||||||
|
private readonly updateProjectorDataDebounceSubject = new Subject<void>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param websocketService
|
* @param websocketService
|
||||||
*/
|
*/
|
||||||
public constructor(private websocketService: WebsocketService) {
|
public constructor(private websocketService: WebsocketService) {
|
||||||
|
// Dispatch projector data.
|
||||||
this.websocketService.getOberservable('projector').subscribe((update: AllProjectorData) => {
|
this.websocketService.getOberservable('projector').subscribe((update: AllProjectorData) => {
|
||||||
Object.keys(update).forEach(_id => {
|
Object.keys(update).forEach(_id => {
|
||||||
const id = parseInt(_id, 10);
|
const id = parseInt(_id, 10);
|
||||||
@ -51,7 +59,16 @@ export class ProjectorDataService {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The service need to re-register, if the websocket connection was lost.
|
||||||
this.websocketService.generalConnectEvent.subscribe(() => this.updateProjectorDataSubscription());
|
this.websocketService.generalConnectEvent.subscribe(() => this.updateProjectorDataSubscription());
|
||||||
|
|
||||||
|
// With a bit of debounce, update the needed projectors.
|
||||||
|
this.updateProjectorDataDebounceSubject.pipe(auditTime(10)).subscribe(() => {
|
||||||
|
const allActiveProjectorIds = Object.keys(this.openProjectorInstances)
|
||||||
|
.map(id => parseInt(id, 10))
|
||||||
|
.filter(id => this.openProjectorInstances[id] > 0);
|
||||||
|
this.websocketService.send('listenToProjectors', { projector_ids: allActiveProjectorIds });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,13 +111,10 @@ export class ProjectorDataService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets initial data and keeps reuesting data.
|
* Requests to update the data subscription to the server.
|
||||||
*/
|
*/
|
||||||
private updateProjectorDataSubscription(): void {
|
private updateProjectorDataSubscription(): void {
|
||||||
const allActiveProjectorIds = Object.keys(this.openProjectorInstances)
|
this.updateProjectorDataDebounceSubject.next();
|
||||||
.map(id => parseInt(id, 10))
|
|
||||||
.filter(id => this.openProjectorInstances[id] > 0);
|
|
||||||
this.websocketService.send('listenToProjectors', { projector_ids: allActiveProjectorIds });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<div id="container" [osResized]="resizeSubject" [ngStyle]="containerStyle" #container>
|
<div id="container" class="projector-container" [osResized]="resizeSubject" #container>
|
||||||
<div id="projector" [ngStyle]="projectorStyle">
|
<div id="projector" class="projector">
|
||||||
<div id="offline-indicator" *ngIf="isOffline()">
|
<div id="offline-indicator" *ngIf="isOffline()">
|
||||||
<mat-icon>
|
<mat-icon>
|
||||||
fiber_manual_record
|
fiber_manual_record
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
</div>
|
</div>
|
||||||
<div id="header" [ngStyle]="headerFooterStyle" *ngIf="projector && projector.show_header_footer">
|
<div id="header" class="headerFooter" *ngIf="projector && projector.show_header_footer">
|
||||||
<!-- projector logo -->
|
<!-- projector logo -->
|
||||||
<img *ngIf="projector.show_logo && projectorLogo" src="{{ projectorLogo }}" class="projector-logo-main" />
|
<img *ngIf="projector.show_logo && projectorLogo" src="{{ projectorLogo }}" class="projector-logo-main" />
|
||||||
|
|
||||||
@ -29,7 +29,7 @@
|
|||||||
></os-slide-container>
|
></os-slide-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="footer" [ngStyle]="headerFooterStyle" *ngIf="projector && projector.show_header_footer">
|
<div id="footer" class="headerFooter" *ngIf="projector && projector.show_header_footer">
|
||||||
<div class="footertext">
|
<div class="footertext">
|
||||||
<span *ngIf="eventDate"> {{ eventDate }} </span>
|
<span *ngIf="eventDate"> {{ eventDate }} </span>
|
||||||
<span *ngIf="eventDate && eventLocation"> | </span>
|
<span *ngIf="eventDate && eventLocation"> | </span>
|
||||||
|
@ -1,9 +1,3 @@
|
|||||||
// should be better using @host binding, but does not work
|
|
||||||
// https://github.com/angular/angular/issues/9343
|
|
||||||
:host-context(.os-slide-container) {
|
|
||||||
--header-h1-color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
background-color: lightgoldenrodyellow;
|
background-color: lightgoldenrodyellow;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -31,11 +25,6 @@
|
|||||||
font-size: 22px !important;
|
font-size: 22px !important;
|
||||||
line-height: 24px !important;
|
line-height: 24px !important;
|
||||||
|
|
||||||
// shadow pierce all children of projector to overwrite the h1 color
|
|
||||||
::ng-deep h1 {
|
|
||||||
color: var(--header-h1-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -53,12 +53,12 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
) {
|
) {
|
||||||
this.updateScaling();
|
this.updateScaling();
|
||||||
}
|
}
|
||||||
this.projectorStyle['background-color'] = projector.background_color;
|
this.css.projector.color = projector.color;
|
||||||
this.headerFooterStyle.color = projector.header_font_color;
|
this.css.projector.backgroundColor = projector.background_color;
|
||||||
this.headerFooterStyle['background-color'] = projector.header_background_color;
|
this.css.projector.H1Color = this.projector.header_h1_color;
|
||||||
|
this.css.headerFooter.color = projector.header_font_color;
|
||||||
// alter the local scope css variable with the header_h1_color
|
this.css.headerFooter.backgroundColor = projector.header_background_color;
|
||||||
document.documentElement.style.setProperty('--header-h1-color', this.projector.header_h1_color);
|
this.updateCSS();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,33 +85,54 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
private containerElement: ElementRef;
|
private containerElement: ElementRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dynamic style attributes for the projector.
|
* The css class assigned to this projector.
|
||||||
*/
|
*/
|
||||||
public projectorStyle: {
|
private projectorClass: string;
|
||||||
transform?: string;
|
|
||||||
|
/**
|
||||||
|
* The styleelement for setting projector-specific styles.
|
||||||
|
*/
|
||||||
|
private styleElement?: HTMLStyleElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All current css rules for the projector. when updating this, call `updateCSS()` afterwards.
|
||||||
|
*/
|
||||||
|
public css: {
|
||||||
|
container: {
|
||||||
|
height: string;
|
||||||
|
};
|
||||||
|
projector: {
|
||||||
|
transform: string;
|
||||||
width: string;
|
width: string;
|
||||||
height: string;
|
height: string;
|
||||||
'background-color': string;
|
color: string;
|
||||||
|
backgroundColor: string;
|
||||||
|
H1Color: string;
|
||||||
|
};
|
||||||
|
headerFooter: {
|
||||||
|
color: string;
|
||||||
|
backgroundColor: string;
|
||||||
|
backgroundImage: string;
|
||||||
|
};
|
||||||
} = {
|
} = {
|
||||||
|
container: {
|
||||||
|
height: '0px'
|
||||||
|
},
|
||||||
|
projector: {
|
||||||
|
transform: 'none',
|
||||||
width: '0px',
|
width: '0px',
|
||||||
height: '0px',
|
height: '0px',
|
||||||
'background-color': 'white'
|
color: 'black',
|
||||||
|
backgroundColor: 'white',
|
||||||
|
H1Color: '#317796'
|
||||||
|
},
|
||||||
|
headerFooter: {
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: '#317796',
|
||||||
|
backgroundImage: 'none'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Dynamic style attributes for the header and footer.
|
|
||||||
*/
|
|
||||||
public headerFooterStyle: { 'background-image': string; 'background-color': string; color: string } = {
|
|
||||||
'background-image': 'none',
|
|
||||||
'background-color': 'blue',
|
|
||||||
color: 'white'
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dynamic style attributes for the container.
|
|
||||||
*/
|
|
||||||
public containerStyle: { height?: string } = {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All slides to show on this projector
|
* All slides to show on this projector
|
||||||
*/
|
*/
|
||||||
@ -161,9 +182,21 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
private projectorDataService: ProjectorDataService,
|
private projectorDataService: ProjectorDataService,
|
||||||
private projectorRepository: ProjectorRepositoryService,
|
private projectorRepository: ProjectorRepositoryService,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
private offlineService: OfflineService
|
private offlineService: OfflineService,
|
||||||
|
private elementRef: ElementRef
|
||||||
) {
|
) {
|
||||||
super(titleService, translate);
|
super(titleService, translate);
|
||||||
|
|
||||||
|
this.projectorClass =
|
||||||
|
'projector-' +
|
||||||
|
Math.random()
|
||||||
|
.toString(36)
|
||||||
|
.substring(4);
|
||||||
|
this.elementRef.nativeElement.classList.add(this.projectorClass);
|
||||||
|
this.styleElement = document.createElement('style');
|
||||||
|
this.styleElement.appendChild(document.createTextNode('')); // Hack for WebKit to trigger update
|
||||||
|
document.head.appendChild(this.styleElement);
|
||||||
|
|
||||||
// projector logo / background-image
|
// projector logo / background-image
|
||||||
this.configService.get<{ path?: string }>('logo_projector_main').subscribe(val => {
|
this.configService.get<{ path?: string }>('logo_projector_main').subscribe(val => {
|
||||||
if (val && val.path) {
|
if (val && val.path) {
|
||||||
@ -174,10 +207,11 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
});
|
});
|
||||||
this.configService.get<{ path?: string }>('logo_projector_header').subscribe(val => {
|
this.configService.get<{ path?: string }>('logo_projector_header').subscribe(val => {
|
||||||
if (val && val.path) {
|
if (val && val.path) {
|
||||||
this.headerFooterStyle['background-image'] = "url('" + val.path + "')";
|
this.css.headerFooter.backgroundImage = "url('" + val.path + "')";
|
||||||
} else {
|
} else {
|
||||||
this.headerFooterStyle['background-image'] = 'none';
|
this.css.headerFooter.backgroundImage = 'none';
|
||||||
}
|
}
|
||||||
|
this.updateCSS();
|
||||||
});
|
});
|
||||||
|
|
||||||
// event data
|
// event data
|
||||||
@ -218,10 +252,39 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
if (isNaN(scale)) {
|
if (isNaN(scale)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.projectorStyle.transform = 'scale(' + scale + ')';
|
this.css.projector.transform = 'scale(' + scale + ')';
|
||||||
this.projectorStyle.width = this.currentProjectorSize.width + 'px';
|
this.css.projector.width = this.currentProjectorSize.width + 'px';
|
||||||
this.projectorStyle.height = this.currentProjectorSize.height + 'px';
|
this.css.projector.height = this.currentProjectorSize.height + 'px';
|
||||||
this.containerStyle.height = Math.round(scale * this.currentProjectorSize.height) + 'px';
|
this.css.container.height = Math.round(scale * this.currentProjectorSize.height) + 'px';
|
||||||
|
this.updateCSS();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the css element with the current css settings in `this.css`.
|
||||||
|
*/
|
||||||
|
private updateCSS(): void {
|
||||||
|
if (!this.styleElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.styleElement.innerHTML = `
|
||||||
|
.${this.projectorClass} .projector-container {
|
||||||
|
height: ${this.css.container.height};
|
||||||
|
}
|
||||||
|
.${this.projectorClass} .projector {
|
||||||
|
transform: ${this.css.projector.transform};
|
||||||
|
width: ${this.css.projector.width};
|
||||||
|
height: ${this.css.projector.height};
|
||||||
|
background-color: ${this.css.projector.backgroundColor};
|
||||||
|
color: ${this.css.projector.color};
|
||||||
|
}
|
||||||
|
.${this.projectorClass} .projector h1 {
|
||||||
|
color: ${this.css.projector.H1Color};
|
||||||
|
}
|
||||||
|
.${this.projectorClass} .headerFooter {
|
||||||
|
color: ${this.css.headerFooter.color};
|
||||||
|
background-color: ${this.css.headerFooter.backgroundColor};
|
||||||
|
background-image: ${this.css.headerFooter.backgroundImage};
|
||||||
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,5 +325,7 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
if (this.projectorId > 0) {
|
if (this.projectorId > 0) {
|
||||||
this.projectorDataService.projectorClosed(this.projectorId);
|
this.projectorDataService.projectorClosed(this.projectorId);
|
||||||
}
|
}
|
||||||
|
document.head.removeChild(this.styleElement);
|
||||||
|
this.styleElement = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ export class Projector extends BaseModel<Projector> {
|
|||||||
public height: number;
|
public height: number;
|
||||||
public reference_projector_id: number;
|
public reference_projector_id: number;
|
||||||
public projectiondefaults_id: number[];
|
public projectiondefaults_id: number[];
|
||||||
|
public color: string;
|
||||||
public background_color: string;
|
public background_color: string;
|
||||||
public header_background_color: string;
|
public header_background_color: string;
|
||||||
public header_font_color: string;
|
public header_font_color: string;
|
||||||
|
@ -35,14 +35,14 @@
|
|||||||
<h3 translate>Resolution and size</h3>
|
<h3 translate>Resolution and size</h3>
|
||||||
<!-- Aspect ratio field -->
|
<!-- Aspect ratio field -->
|
||||||
<mat-radio-group formControlName="aspectRatio" [name]="projector.id">
|
<mat-radio-group formControlName="aspectRatio" [name]="projector.id">
|
||||||
<mat-radio-button *ngFor="let ratio of aspectRatiosKeys" [value]="ratio">
|
<mat-radio-button *ngFor="let ratio of aspectRatiosKeys" [value]="ratio" (change)="aspectRatioChanged($event)">
|
||||||
{{ ratio }}
|
{{ ratio }}
|
||||||
</mat-radio-button>
|
</mat-radio-button>
|
||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
<div class="spacer-top-20">
|
<div class="spacer-top-20">
|
||||||
<mat-slider
|
<mat-slider
|
||||||
[thumbLabel]="true"
|
[thumbLabel]="true"
|
||||||
min="800"
|
[min]="getMinWidth()"
|
||||||
max="2000"
|
max="2000"
|
||||||
step="10"
|
step="10"
|
||||||
value="{{ updateForm.value.width }}"
|
value="{{ updateForm.value.width }}"
|
||||||
@ -60,6 +60,23 @@
|
|||||||
</mat-select>
|
</mat-select>
|
||||||
|
|
||||||
<!-- colors -->
|
<!-- colors -->
|
||||||
|
<div class="color-field-wrapper">
|
||||||
|
<div class="form">
|
||||||
|
<mat-form-field>
|
||||||
|
<span translate>Foreground color</span>
|
||||||
|
<input matInput formControlName="color" type="color" />
|
||||||
|
<mat-hint *ngIf="!updateForm.controls.color.valid">
|
||||||
|
<span translate>Required</span>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="reset-button">
|
||||||
|
<button mat-icon-button matTooltip="{{ 'Reset' | translate }}" (click)="resetField('color', '#000000')">
|
||||||
|
<mat-icon>replay</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="color-field-wrapper">
|
<div class="color-field-wrapper">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
|
@ -15,6 +15,7 @@ import { ClockSlideService } from '../../services/clock-slide.service';
|
|||||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||||
import { ViewProjectionDefault } from '../../models/view-projection-default';
|
import { ViewProjectionDefault } from '../../models/view-projection-default';
|
||||||
import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projector/projection-default-repository.service';
|
import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projector/projection-default-repository.service';
|
||||||
|
import { MatRadioChange } from '@angular/material';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All supported aspect rations for projectors.
|
* All supported aspect rations for projectors.
|
||||||
@ -22,9 +23,12 @@ import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projec
|
|||||||
const aspectRatios: { [ratio: string]: number } = {
|
const aspectRatios: { [ratio: string]: number } = {
|
||||||
'4:3': 4 / 3,
|
'4:3': 4 / 3,
|
||||||
'16:9': 16 / 9,
|
'16:9': 16 / 9,
|
||||||
'16:10': 16 / 10
|
'16:10': 16 / 10,
|
||||||
|
'30:9': 30 / 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const aspectRatio_30_9_MinWidth = 1150;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List for all projectors.
|
* List for all projectors.
|
||||||
*/
|
*/
|
||||||
@ -59,7 +63,16 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
|||||||
* The projector shown by this entry.
|
* The projector shown by this entry.
|
||||||
*/
|
*/
|
||||||
@Input()
|
@Input()
|
||||||
public projector: ViewProjector;
|
public set projector(value: ViewProjector) {
|
||||||
|
this._projector = value;
|
||||||
|
this.updateForm.patchValue({ width: value.width });
|
||||||
|
}
|
||||||
|
|
||||||
|
public get projector(): ViewProjector {
|
||||||
|
return this._projector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _projector: ViewProjector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to check manage permissions
|
* Helper to check manage permissions
|
||||||
@ -103,6 +116,7 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
|||||||
width: [0, Validators.required],
|
width: [0, Validators.required],
|
||||||
projectiondefaults_id: [[]],
|
projectiondefaults_id: [[]],
|
||||||
clock: [true],
|
clock: [true],
|
||||||
|
color: ['', Validators.required],
|
||||||
background_color: ['', Validators.required],
|
background_color: ['', Validators.required],
|
||||||
header_background_color: ['', Validators.required],
|
header_background_color: ['', Validators.required],
|
||||||
header_font_color: ['', Validators.required],
|
header_font_color: ['', Validators.required],
|
||||||
@ -206,6 +220,24 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public aspectRatioChanged(event: MatRadioChange): void {
|
||||||
|
let width: number;
|
||||||
|
if (event.value === '30:9' && this.updateForm.value.width < aspectRatio_30_9_MinWidth) {
|
||||||
|
width = aspectRatio_30_9_MinWidth;
|
||||||
|
} else {
|
||||||
|
width = this.updateForm.value.width;
|
||||||
|
}
|
||||||
|
this.updateProjectorDimensions(width, event.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMinWidth(): number {
|
||||||
|
if (this.updateForm.value.aspectRatio === '30:9') {
|
||||||
|
return aspectRatio_30_9_MinWidth;
|
||||||
|
} else {
|
||||||
|
return 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the projector.
|
* Delete the projector.
|
||||||
*/
|
*/
|
||||||
@ -222,11 +254,14 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
|||||||
* @param event The slider value
|
* @param event The slider value
|
||||||
*/
|
*/
|
||||||
public widthSliderValueChanged(event: MatSliderChange): void {
|
public widthSliderValueChanged(event: MatSliderChange): void {
|
||||||
const aspectRatio = this.getAspectRatioKey();
|
this.updateProjectorDimensions(event.value, this.updateForm.value.aspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateProjectorDimensions(width: number, aspectRatioKey: string): void {
|
||||||
const updateProjector: Partial<Projector> = {
|
const updateProjector: Partial<Projector> = {
|
||||||
width: event.value
|
width: width
|
||||||
};
|
};
|
||||||
updateProjector.height = Math.round(event.value / aspectRatios[aspectRatio]);
|
updateProjector.height = Math.round(width / aspectRatios[aspectRatioKey]);
|
||||||
this.repo.update(updateProjector, this.projector).then(null, this.raiseError);
|
this.repo.update(updateProjector, this.projector).then(null, this.raiseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,10 @@ export class ViewProjector extends BaseViewModel<Projector> {
|
|||||||
return this.projector.reference_projector_id;
|
return this.projector.reference_projector_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get color(): string {
|
||||||
|
return this.projector.color;
|
||||||
|
}
|
||||||
|
|
||||||
public get background_color(): string {
|
public get background_color(): string {
|
||||||
return this.projector.background_color;
|
return this.projector.background_color;
|
||||||
}
|
}
|
||||||
|
@ -131,75 +131,6 @@ def get_config_variables():
|
|||||||
subgroup="System",
|
subgroup="System",
|
||||||
)
|
)
|
||||||
|
|
||||||
# General export settings
|
|
||||||
|
|
||||||
yield ConfigVariable(
|
|
||||||
name="general_csv_separator",
|
|
||||||
default_value=",",
|
|
||||||
label="Separator used for all csv exports and examples",
|
|
||||||
weight=142,
|
|
||||||
group="General",
|
|
||||||
subgroup="Export",
|
|
||||||
)
|
|
||||||
|
|
||||||
yield ConfigVariable(
|
|
||||||
name="general_csv_encoding",
|
|
||||||
default_value="utf-8",
|
|
||||||
input_type="choice",
|
|
||||||
label="Default encoding for all csv exports",
|
|
||||||
choices=(
|
|
||||||
{"value": "utf-8", "display_name": "UTF-8"},
|
|
||||||
{"value": "iso-8859-15", "display_name": "ISO-8859-15"},
|
|
||||||
),
|
|
||||||
weight=143,
|
|
||||||
group="General",
|
|
||||||
subgroup="Export",
|
|
||||||
)
|
|
||||||
|
|
||||||
yield ConfigVariable(
|
|
||||||
name="general_export_pdf_pagenumber_alignment",
|
|
||||||
default_value="center",
|
|
||||||
input_type="choice",
|
|
||||||
label="Page number alignment in PDF",
|
|
||||||
choices=(
|
|
||||||
{"value": "left", "display_name": "Left"},
|
|
||||||
{"value": "center", "display_name": "Center"},
|
|
||||||
{"value": "right", "display_name": "Right"},
|
|
||||||
),
|
|
||||||
weight=144,
|
|
||||||
group="General",
|
|
||||||
subgroup="Export",
|
|
||||||
)
|
|
||||||
|
|
||||||
yield ConfigVariable(
|
|
||||||
name="general_export_pdf_fontsize",
|
|
||||||
default_value="10",
|
|
||||||
input_type="choice",
|
|
||||||
label="Standard font size in PDF",
|
|
||||||
choices=(
|
|
||||||
{"value": "10", "display_name": "10"},
|
|
||||||
{"value": "11", "display_name": "11"},
|
|
||||||
{"value": "12", "display_name": "12"},
|
|
||||||
),
|
|
||||||
weight=146,
|
|
||||||
group="General",
|
|
||||||
subgroup="Export",
|
|
||||||
)
|
|
||||||
|
|
||||||
yield ConfigVariable(
|
|
||||||
name="general_export_pdf_pagesize",
|
|
||||||
default_value="A4",
|
|
||||||
input_type="choice",
|
|
||||||
label="Standard page size in PDF",
|
|
||||||
choices=(
|
|
||||||
{"value": "A4", "display_name": "DIN A4"},
|
|
||||||
{"value": "A5", "display_name": "DIN A5"},
|
|
||||||
),
|
|
||||||
weight=147,
|
|
||||||
group="General",
|
|
||||||
subgroup="Export",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Projector
|
# Projector
|
||||||
|
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
@ -218,7 +149,8 @@ def get_config_variables():
|
|||||||
{"value": "ru", "display_name": "русский"},
|
{"value": "ru", "display_name": "русский"},
|
||||||
),
|
),
|
||||||
weight=150,
|
weight=150,
|
||||||
group="Projector",
|
group="General",
|
||||||
|
subgroup="Projector",
|
||||||
)
|
)
|
||||||
|
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
@ -226,21 +158,81 @@ def get_config_variables():
|
|||||||
default_value=60,
|
default_value=60,
|
||||||
input_type="integer",
|
input_type="integer",
|
||||||
label="Predefined seconds of new countdowns",
|
label="Predefined seconds of new countdowns",
|
||||||
weight=185,
|
weight=152,
|
||||||
group="Projector",
|
group="General",
|
||||||
|
subgroup="Projector",
|
||||||
|
)
|
||||||
|
|
||||||
|
# General export settings
|
||||||
|
|
||||||
|
yield ConfigVariable(
|
||||||
|
name="general_csv_separator",
|
||||||
|
default_value=",",
|
||||||
|
label="Separator used for all csv exports and examples",
|
||||||
|
weight=160,
|
||||||
|
group="General",
|
||||||
|
subgroup="Export",
|
||||||
)
|
)
|
||||||
|
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
name="projector_currentListOfSpeakers_reference",
|
name="general_csv_encoding",
|
||||||
default_value=1,
|
default_value="utf-8",
|
||||||
input_type="integer",
|
input_type="choice",
|
||||||
label="Projector reference for list of speakers",
|
label="Default encoding for all csv exports",
|
||||||
weight=201,
|
choices=(
|
||||||
group="Projector",
|
{"value": "utf-8", "display_name": "UTF-8"},
|
||||||
hidden=True,
|
{"value": "iso-8859-15", "display_name": "ISO-8859-15"},
|
||||||
|
),
|
||||||
|
weight=162,
|
||||||
|
group="General",
|
||||||
|
subgroup="Export",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Logos.
|
yield ConfigVariable(
|
||||||
|
name="general_export_pdf_pagenumber_alignment",
|
||||||
|
default_value="center",
|
||||||
|
input_type="choice",
|
||||||
|
label="Page number alignment in PDF",
|
||||||
|
choices=(
|
||||||
|
{"value": "left", "display_name": "Left"},
|
||||||
|
{"value": "center", "display_name": "Center"},
|
||||||
|
{"value": "right", "display_name": "Right"},
|
||||||
|
),
|
||||||
|
weight=164,
|
||||||
|
group="General",
|
||||||
|
subgroup="Export",
|
||||||
|
)
|
||||||
|
|
||||||
|
yield ConfigVariable(
|
||||||
|
name="general_export_pdf_fontsize",
|
||||||
|
default_value="10",
|
||||||
|
input_type="choice",
|
||||||
|
label="Standard font size in PDF",
|
||||||
|
choices=(
|
||||||
|
{"value": "10", "display_name": "10"},
|
||||||
|
{"value": "11", "display_name": "11"},
|
||||||
|
{"value": "12", "display_name": "12"},
|
||||||
|
),
|
||||||
|
weight=166,
|
||||||
|
group="General",
|
||||||
|
subgroup="Export",
|
||||||
|
)
|
||||||
|
|
||||||
|
yield ConfigVariable(
|
||||||
|
name="general_export_pdf_pagesize",
|
||||||
|
default_value="A4",
|
||||||
|
input_type="choice",
|
||||||
|
label="Standard page size in PDF",
|
||||||
|
choices=(
|
||||||
|
{"value": "A4", "display_name": "DIN A4"},
|
||||||
|
{"value": "A5", "display_name": "DIN A5"},
|
||||||
|
),
|
||||||
|
weight=168,
|
||||||
|
group="General",
|
||||||
|
subgroup="Export",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Logos
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
name="logos_available",
|
name="logos_available",
|
||||||
default_value=[
|
default_value=[
|
||||||
|
16
openslides/core/migrations/0025_projector_color.py
Normal file
16
openslides/core/migrations/0025_projector_color.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Generated by Django 2.2.3 on 2019-07-10 10:12
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("core", "0024_auto_20190605_1105")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="projector",
|
||||||
|
name="color",
|
||||||
|
field=models.CharField(default="#000000", max_length=7),
|
||||||
|
)
|
||||||
|
]
|
@ -77,6 +77,7 @@ class Projector(RESTModelMixin, models.Model):
|
|||||||
width = models.PositiveIntegerField(default=1024)
|
width = models.PositiveIntegerField(default=1024)
|
||||||
height = models.PositiveIntegerField(default=768)
|
height = models.PositiveIntegerField(default=768)
|
||||||
|
|
||||||
|
color = models.CharField(max_length=7, default="#000000")
|
||||||
background_color = models.CharField(max_length=7, default="#ffffff")
|
background_color = models.CharField(max_length=7, default="#ffffff")
|
||||||
header_background_color = models.CharField(max_length=7, default="#317796")
|
header_background_color = models.CharField(max_length=7, default="#317796")
|
||||||
header_font_color = models.CharField(max_length=7, default="#f5f5f5")
|
header_font_color = models.CharField(max_length=7, default="#f5f5f5")
|
||||||
|
@ -106,6 +106,7 @@ class ProjectorSerializer(ModelSerializer):
|
|||||||
"height",
|
"height",
|
||||||
"reference_projector",
|
"reference_projector",
|
||||||
"projectiondefaults",
|
"projectiondefaults",
|
||||||
|
"color",
|
||||||
"background_color",
|
"background_color",
|
||||||
"header_background_color",
|
"header_background_color",
|
||||||
"header_font_color",
|
"header_font_color",
|
||||||
|
Loading…
Reference in New Issue
Block a user