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 { Observable, BehaviorSubject } from 'rxjs';
|
||||
import { Observable, BehaviorSubject, Subject } from 'rxjs';
|
||||
|
||||
import { WebsocketService } from 'app/core/core-services/websocket.service';
|
||||
import { ProjectorElement, Projector } from 'app/shared/models/core/projector';
|
||||
import { auditTime } from 'rxjs/operators';
|
||||
|
||||
export interface SlideData<T = { error?: string }, P extends ProjectorElement = ProjectorElement> {
|
||||
data: T;
|
||||
@ -36,12 +37,19 @@ export class ProjectorDataService {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param websocketService
|
||||
*/
|
||||
public constructor(private websocketService: WebsocketService) {
|
||||
// Dispatch projector data.
|
||||
this.websocketService.getOberservable('projector').subscribe((update: AllProjectorData) => {
|
||||
Object.keys(update).forEach(_id => {
|
||||
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());
|
||||
|
||||
// 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 {
|
||||
const allActiveProjectorIds = Object.keys(this.openProjectorInstances)
|
||||
.map(id => parseInt(id, 10))
|
||||
.filter(id => this.openProjectorInstances[id] > 0);
|
||||
this.websocketService.send('listenToProjectors', { projector_ids: allActiveProjectorIds });
|
||||
this.updateProjectorDataDebounceSubject.next();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,11 +1,11 @@
|
||||
<div id="container" [osResized]="resizeSubject" [ngStyle]="containerStyle" #container>
|
||||
<div id="projector" [ngStyle]="projectorStyle">
|
||||
<div id="container" class="projector-container" [osResized]="resizeSubject" #container>
|
||||
<div id="projector" class="projector">
|
||||
<div id="offline-indicator" *ngIf="isOffline()">
|
||||
<mat-icon>
|
||||
fiber_manual_record
|
||||
</mat-icon>
|
||||
</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 -->
|
||||
<img *ngIf="projector.show_logo && projectorLogo" src="{{ projectorLogo }}" class="projector-logo-main" />
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
></os-slide-container>
|
||||
</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">
|
||||
<span *ngIf="eventDate"> {{ eventDate }} </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 {
|
||||
background-color: lightgoldenrodyellow;
|
||||
position: relative;
|
||||
@ -31,11 +25,6 @@
|
||||
font-size: 22px !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 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -53,12 +53,12 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
||||
) {
|
||||
this.updateScaling();
|
||||
}
|
||||
this.projectorStyle['background-color'] = projector.background_color;
|
||||
this.headerFooterStyle.color = projector.header_font_color;
|
||||
this.headerFooterStyle['background-color'] = projector.header_background_color;
|
||||
|
||||
// alter the local scope css variable with the header_h1_color
|
||||
document.documentElement.style.setProperty('--header-h1-color', this.projector.header_h1_color);
|
||||
this.css.projector.color = projector.color;
|
||||
this.css.projector.backgroundColor = projector.background_color;
|
||||
this.css.projector.H1Color = this.projector.header_h1_color;
|
||||
this.css.headerFooter.color = projector.header_font_color;
|
||||
this.css.headerFooter.backgroundColor = projector.header_background_color;
|
||||
this.updateCSS();
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,33 +85,54 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
||||
private containerElement: ElementRef;
|
||||
|
||||
/**
|
||||
* Dynamic style attributes for the projector.
|
||||
* The css class assigned to this projector.
|
||||
*/
|
||||
public projectorStyle: {
|
||||
transform?: string;
|
||||
private projectorClass: 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;
|
||||
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',
|
||||
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
|
||||
*/
|
||||
@ -161,9 +182,21 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
||||
private projectorDataService: ProjectorDataService,
|
||||
private projectorRepository: ProjectorRepositoryService,
|
||||
private configService: ConfigService,
|
||||
private offlineService: OfflineService
|
||||
private offlineService: OfflineService,
|
||||
private elementRef: ElementRef
|
||||
) {
|
||||
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
|
||||
this.configService.get<{ path?: string }>('logo_projector_main').subscribe(val => {
|
||||
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 => {
|
||||
if (val && val.path) {
|
||||
this.headerFooterStyle['background-image'] = "url('" + val.path + "')";
|
||||
this.css.headerFooter.backgroundImage = "url('" + val.path + "')";
|
||||
} else {
|
||||
this.headerFooterStyle['background-image'] = 'none';
|
||||
this.css.headerFooter.backgroundImage = 'none';
|
||||
}
|
||||
this.updateCSS();
|
||||
});
|
||||
|
||||
// event data
|
||||
@ -218,10 +252,39 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
||||
if (isNaN(scale)) {
|
||||
return;
|
||||
}
|
||||
this.projectorStyle.transform = 'scale(' + scale + ')';
|
||||
this.projectorStyle.width = this.currentProjectorSize.width + 'px';
|
||||
this.projectorStyle.height = this.currentProjectorSize.height + 'px';
|
||||
this.containerStyle.height = Math.round(scale * this.currentProjectorSize.height) + 'px';
|
||||
this.css.projector.transform = 'scale(' + scale + ')';
|
||||
this.css.projector.width = this.currentProjectorSize.width + 'px';
|
||||
this.css.projector.height = 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) {
|
||||
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 reference_projector_id: number;
|
||||
public projectiondefaults_id: number[];
|
||||
public color: string;
|
||||
public background_color: string;
|
||||
public header_background_color: string;
|
||||
public header_font_color: string;
|
||||
|
@ -35,14 +35,14 @@
|
||||
<h3 translate>Resolution and size</h3>
|
||||
<!-- Aspect ratio field -->
|
||||
<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 }}
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
<div class="spacer-top-20">
|
||||
<mat-slider
|
||||
[thumbLabel]="true"
|
||||
min="800"
|
||||
[min]="getMinWidth()"
|
||||
max="2000"
|
||||
step="10"
|
||||
value="{{ updateForm.value.width }}"
|
||||
@ -60,6 +60,23 @@
|
||||
</mat-select>
|
||||
|
||||
<!-- 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="form">
|
||||
<mat-form-field>
|
||||
|
@ -15,6 +15,7 @@ import { ClockSlideService } from '../../services/clock-slide.service';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { ViewProjectionDefault } from '../../models/view-projection-default';
|
||||
import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projector/projection-default-repository.service';
|
||||
import { MatRadioChange } from '@angular/material';
|
||||
|
||||
/**
|
||||
* All supported aspect rations for projectors.
|
||||
@ -22,9 +23,12 @@ import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projec
|
||||
const aspectRatios: { [ratio: string]: number } = {
|
||||
'4:3': 4 / 3,
|
||||
'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.
|
||||
*/
|
||||
@ -59,7 +63,16 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
||||
* The projector shown by this entry.
|
||||
*/
|
||||
@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
|
||||
@ -103,6 +116,7 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
||||
width: [0, Validators.required],
|
||||
projectiondefaults_id: [[]],
|
||||
clock: [true],
|
||||
color: ['', Validators.required],
|
||||
background_color: ['', Validators.required],
|
||||
header_background_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.
|
||||
*/
|
||||
@ -222,11 +254,14 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
||||
* @param event The slider value
|
||||
*/
|
||||
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> = {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,10 @@ export class ViewProjector extends BaseViewModel<Projector> {
|
||||
return this.projector.reference_projector_id;
|
||||
}
|
||||
|
||||
public get color(): string {
|
||||
return this.projector.color;
|
||||
}
|
||||
|
||||
public get background_color(): string {
|
||||
return this.projector.background_color;
|
||||
}
|
||||
|
@ -131,75 +131,6 @@ def get_config_variables():
|
||||
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
|
||||
|
||||
yield ConfigVariable(
|
||||
@ -218,7 +149,8 @@ def get_config_variables():
|
||||
{"value": "ru", "display_name": "русский"},
|
||||
),
|
||||
weight=150,
|
||||
group="Projector",
|
||||
group="General",
|
||||
subgroup="Projector",
|
||||
)
|
||||
|
||||
yield ConfigVariable(
|
||||
@ -226,21 +158,81 @@ def get_config_variables():
|
||||
default_value=60,
|
||||
input_type="integer",
|
||||
label="Predefined seconds of new countdowns",
|
||||
weight=185,
|
||||
group="Projector",
|
||||
weight=152,
|
||||
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(
|
||||
name="projector_currentListOfSpeakers_reference",
|
||||
default_value=1,
|
||||
input_type="integer",
|
||||
label="Projector reference for list of speakers",
|
||||
weight=201,
|
||||
group="Projector",
|
||||
hidden=True,
|
||||
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=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(
|
||||
name="logos_available",
|
||||
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)
|
||||
height = models.PositiveIntegerField(default=768)
|
||||
|
||||
color = models.CharField(max_length=7, default="#000000")
|
||||
background_color = models.CharField(max_length=7, default="#ffffff")
|
||||
header_background_color = models.CharField(max_length=7, default="#317796")
|
||||
header_font_color = models.CharField(max_length=7, default="#f5f5f5")
|
||||
|
@ -106,6 +106,7 @@ class ProjectorSerializer(ModelSerializer):
|
||||
"height",
|
||||
"reference_projector",
|
||||
"projectiondefaults",
|
||||
"color",
|
||||
"background_color",
|
||||
"header_background_color",
|
||||
"header_font_color",
|
||||
|
Loading…
Reference in New Issue
Block a user