Projector reference for CLOS
This commit is contained in:
parent
7b4ea753c1
commit
582d4d7c4a
@ -56,6 +56,7 @@ export class Projector extends BaseModel<Projector> {
|
||||
public name: string;
|
||||
public width: number;
|
||||
public height: number;
|
||||
public reference_projector_id: number;
|
||||
public projectiondefaults: ProjectionDefault[];
|
||||
|
||||
public constructor(input?: any) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
|
||||
import { OpenSlidesComponent } from '../../openslides.component';
|
||||
import { BaseViewModel } from './base-view-model';
|
||||
@ -24,6 +24,11 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
*/
|
||||
protected readonly viewModelListSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>([]);
|
||||
|
||||
/**
|
||||
* Observable subject for any changes of view models.
|
||||
*/
|
||||
protected readonly generalViewModelSubject: Subject<V> = new Subject<V>();
|
||||
|
||||
/**
|
||||
* Construction routine for the base repository
|
||||
*
|
||||
@ -149,6 +154,13 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
return this.viewModelListSubject.asObservable().pipe(auditTime(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* This observable fires every time an object is changed in the repository.
|
||||
*/
|
||||
public getGeneralViewModelObservable(): Observable<V> {
|
||||
return this.generalViewModelSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ViewModel observable using a ViewModel corresponding to the id
|
||||
*/
|
||||
@ -156,6 +168,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
if (this.viewModelSubjects[id]) {
|
||||
this.viewModelSubjects[id].next(this.viewModelStore[id]);
|
||||
}
|
||||
this.generalViewModelSubject.next(this.viewModelStore[id]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,6 +73,20 @@
|
||||
<span translate>Required</span>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Reference projector for the current list of speakers -->
|
||||
<h3 translate>Current list fo speakers reference</h3>
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="reference_projector_id" placeholder="{{ 'Reference projector' | translate }}">
|
||||
<mat-option [value]="projector.id">
|
||||
<span translate>self</span>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let refProjector of getReferenceProjectorsFor(projector)" [value]="refProjector.id">
|
||||
<span>{{ refProjector.getTitle() | translate }}</span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<h3 translate>Resolution and size</h3>
|
||||
<!-- Aspect ratio field -->
|
||||
<mat-radio-group formControlName="aspectRatio" [name]="projector.id">
|
||||
@ -82,6 +96,8 @@
|
||||
</mat-radio-group>
|
||||
<mat-slider [thumbLabel]="true" formControlName="width" min="800" max="3840" step="10"></mat-slider>
|
||||
{{ updateForm.value.width }}
|
||||
|
||||
<!-- Clock -->
|
||||
<div>
|
||||
<mat-checkbox formControlName="clock">
|
||||
<span translate>Show clock</span>
|
||||
|
@ -91,7 +91,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
name: ['', Validators.required],
|
||||
aspectRatio: ['', Validators.required],
|
||||
width: [0, Validators.required],
|
||||
clock: [true]
|
||||
clock: [true],
|
||||
reference_projector_id: []
|
||||
});
|
||||
}
|
||||
|
||||
@ -184,11 +185,16 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
}
|
||||
this.editId = projector.id;
|
||||
this.updateForm.reset();
|
||||
|
||||
const reference_projector_id = projector.reference_projector_id
|
||||
? projector.reference_projector_id
|
||||
: projector.id;
|
||||
this.updateForm.patchValue({
|
||||
name: projector.name,
|
||||
aspectRatio: this.getAspectRatioKey(projector),
|
||||
width: projector.width,
|
||||
clock: this.clockSlideService.isProjectedOn(projector)
|
||||
clock: this.clockSlideService.isProjectedOn(projector),
|
||||
reference_projector_id: reference_projector_id
|
||||
});
|
||||
}
|
||||
|
||||
@ -215,7 +221,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
const updateProjector: Partial<Projector> = {
|
||||
name: this.updateForm.value.name,
|
||||
width: this.updateForm.value.width,
|
||||
height: Math.round(this.updateForm.value.width / aspectRatios[this.updateForm.value.aspectRatio])
|
||||
height: Math.round(this.updateForm.value.width / aspectRatios[this.updateForm.value.aspectRatio]),
|
||||
reference_projector_id: this.updateForm.value.reference_projector_id
|
||||
};
|
||||
try {
|
||||
await this.clockSlideService.setProjectedOn(projector, this.updateForm.value.clock);
|
||||
@ -237,4 +244,14 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
this.repo.delete(projector).then(null, this.raiseError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available reference projectors for the given projector. These
|
||||
* projectors are all existing projectors exluding the given projector
|
||||
*
|
||||
* @returns all available reference projectors
|
||||
*/
|
||||
public getReferenceProjectorsFor(projector: ViewProjector): ViewProjector[] {
|
||||
return this.repo.getViewModelList().filter(p => p.id !== projector.id);
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,10 @@ export class ViewProjector extends BaseViewModel {
|
||||
return this.projector ? this.projector.scroll : null;
|
||||
}
|
||||
|
||||
public get reference_projector_id(): number {
|
||||
return this.projector ? this.projector.reference_projector_id : null;
|
||||
}
|
||||
|
||||
public constructor(projector?: Projector) {
|
||||
super();
|
||||
this._projector = projector;
|
||||
|
@ -2,6 +2,10 @@ import { Injectable } from '@angular/core';
|
||||
import { ProjectorService } from 'app/core/services/projector.service';
|
||||
import { ViewProjector } from '../models/view-projector';
|
||||
import { IdentifiableProjectorElement } from 'app/shared/models/core/projector';
|
||||
import { ProjectorRepositoryService } from './projector-repository.service';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
||||
import { AgendaBaseModel } from 'app/shared/models/base/agenda-base-model';
|
||||
|
||||
/**
|
||||
*/
|
||||
@ -9,8 +13,28 @@ import { IdentifiableProjectorElement } from 'app/shared/models/core/projector';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CurrentListOfSpeakersSlideService {
|
||||
public constructor(private projectorService: ProjectorService) {}
|
||||
private currentItemIds: { [projectorId: number]: BehaviorSubject<number | null> } = {};
|
||||
|
||||
public constructor(
|
||||
private projectorService: ProjectorService,
|
||||
private projectorRepo: ProjectorRepositoryService,
|
||||
private slideManager: SlideManager
|
||||
) {
|
||||
this.projectorRepo.getGeneralViewModelObservable().subscribe(projector => {
|
||||
const itemId = this.getCurrentAgendaItemIdForProjector(projector);
|
||||
if (this.currentItemIds[projector.id]) {
|
||||
this.currentItemIds[projector.id].next(itemId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the basic projector element for the CLOS slide. If overlay=True, the projector element
|
||||
* will be the overlay instead of the slide.
|
||||
*
|
||||
* @param overlay Wether to have a slide or overlay
|
||||
* @returns the identifiable CLOS projector element.
|
||||
*/
|
||||
private getCurrentListOfSpeakersProjectorElement(overlay: boolean): IdentifiableProjectorElement {
|
||||
return {
|
||||
name: overlay ? 'agenda/current-list-of-speakers-overlay' : 'agenda/current-list-of-speakers',
|
||||
@ -19,6 +43,51 @@ export class CurrentListOfSpeakersSlideService {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable for the agenda item id of the currently projected element on the
|
||||
* given projector.
|
||||
*
|
||||
* @param projector The projector to observe.
|
||||
* @returns An observalbe for the agenda item id. Null, if no element with an agenda item is shown.
|
||||
*/
|
||||
public getAgendaItemIdObservable(projector: ViewProjector): Observable<number | null> {
|
||||
if (!this.currentItemIds[projector.id]) {
|
||||
const itemId = this.getCurrentAgendaItemIdForProjector(projector);
|
||||
this.currentItemIds[projector.id] = new BehaviorSubject<number | null>(itemId);
|
||||
}
|
||||
return this.currentItemIds[projector.id].asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the agenda item id for one non stable element on the projector.
|
||||
*
|
||||
* @param projector The projector
|
||||
* @returns The agenda item id or null, if there is no such projector element.
|
||||
*/
|
||||
private getCurrentAgendaItemIdForProjector(projector: ViewProjector): number | null {
|
||||
const nonStableElements = projector.elements.filter(element => !element.stable);
|
||||
if (nonStableElements.length > 0) {
|
||||
const nonStableElement = this.slideManager.getIdentifialbeProjectorElement(nonStableElements[0]); // The normal case is just one non stable slide
|
||||
try {
|
||||
const model = this.projectorService.getModelFromProjectorElement(nonStableElement);
|
||||
if (model instanceof AgendaBaseModel) {
|
||||
// TODO: Use repositories associated to models
|
||||
return (<any>model).agenda_item_id;
|
||||
}
|
||||
} catch (e) {
|
||||
// make TypeScript silent.
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries, if the slide/overlay is projected on the given projector.
|
||||
*
|
||||
* @param projector The projector
|
||||
* @param overlay True, if we query for an overlay instead of the slide
|
||||
* @returns if the slide/overlay is projected on the projector
|
||||
*/
|
||||
public isProjectedOn(projector: ViewProjector, overlay: boolean): boolean {
|
||||
return this.projectorService.isProjectedOn(
|
||||
this.getCurrentListOfSpeakersProjectorElement(overlay),
|
||||
@ -26,6 +95,12 @@ export class CurrentListOfSpeakersSlideService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the projection state of the slide/overlay on the given projector
|
||||
*
|
||||
* @param projector The projector
|
||||
* @param overlay Slide or overlay
|
||||
*/
|
||||
public async toggleOn(projector: ViewProjector, overlay: boolean): Promise<void> {
|
||||
const isClosProjected = this.isProjectedOn(projector, overlay);
|
||||
if (isClosProjected) {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { HttpService } from 'app/core/services/http.service';
|
||||
import { AgendaCurrentListOfSpeakersSlideData } from '../base/agenda-current-list-of-speakers-slide-data';
|
||||
|
||||
@Component({
|
||||
@ -9,15 +8,10 @@ import { AgendaCurrentListOfSpeakersSlideData } from '../base/agenda-current-lis
|
||||
templateUrl: './agenda-current-list-of-speakers-overlay-slide.component.html',
|
||||
styleUrls: ['./agenda-current-list-of-speakers-overlay-slide.component.scss']
|
||||
})
|
||||
export class AgendaCurrentListOfSpeakersOverlaySlideComponent
|
||||
extends BaseSlideComponent<AgendaCurrentListOfSpeakersSlideData>
|
||||
implements OnInit {
|
||||
public constructor(private http: HttpService) {
|
||||
export class AgendaCurrentListOfSpeakersOverlaySlideComponent extends BaseSlideComponent<
|
||||
AgendaCurrentListOfSpeakersSlideData
|
||||
> {
|
||||
public constructor() {
|
||||
super();
|
||||
console.log(this.http);
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
console.log('Hello from current list of speakers overlay');
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,5 @@ export class AgendaCurrentListOfSpeakersSlideComponent extends BaseSlideComponen
|
||||
super();
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
console.log('Hello from current list of speakers slide');
|
||||
}
|
||||
public ngOnInit(): void {}
|
||||
}
|
||||
|
@ -1,20 +1,14 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { CoreCountdownSlideData } from './core-countdown-slide-data';
|
||||
import { HttpService } from 'app/core/services/http.service';
|
||||
|
||||
@Component({
|
||||
selector: 'os-core-countdown-slide',
|
||||
templateUrl: './core-countdown-slide.component.html',
|
||||
styleUrls: ['./core-countdown-slide.component.scss']
|
||||
})
|
||||
export class CoreCountdownSlideComponent extends BaseSlideComponent<CoreCountdownSlideData> implements OnInit {
|
||||
public constructor(private http: HttpService) {
|
||||
export class CoreCountdownSlideComponent extends BaseSlideComponent<CoreCountdownSlideData> {
|
||||
public constructor() {
|
||||
super();
|
||||
console.log(this.http);
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
console.log('Hello from countdown slide');
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { MotionsMotionSlideData } from './motions-motion-slide-data';
|
||||
|
||||
@ -7,12 +7,8 @@ import { MotionsMotionSlideData } from './motions-motion-slide-data';
|
||||
templateUrl: './motions-motion-slide.component.html',
|
||||
styleUrls: ['./motions-motion-slide.component.scss']
|
||||
})
|
||||
export class MotionsMotionSlideComponent extends BaseSlideComponent<MotionsMotionSlideData> implements OnInit {
|
||||
export class MotionsMotionSlideComponent extends BaseSlideComponent<MotionsMotionSlideData> {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
console.log('Hello from motion slide');
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { UsersUserSlideData } from './users-user-slide-data';
|
||||
|
||||
@ -7,12 +7,8 @@ import { UsersUserSlideData } from './users-user-slide-data';
|
||||
templateUrl: './users-user-slide.component.html',
|
||||
styleUrls: ['./users-user-slide.component.scss']
|
||||
})
|
||||
export class UsersUserSlideComponent extends BaseSlideComponent<UsersUserSlideData> implements OnInit {
|
||||
export class UsersUserSlideComponent extends BaseSlideComponent<UsersUserSlideData> {
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
console.log('Hello from user slide');
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
# Generated by Django 2.1.5 on 2019-01-31 10:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
import openslides.utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0015_auto_20190122_1216")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="projector",
|
||||
name="reference_projector",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=openslides.utils.models.SET_NULL_AND_AUTOUPDATE,
|
||||
related_name="references",
|
||||
to="core.Projector",
|
||||
),
|
||||
)
|
||||
]
|
@ -84,6 +84,14 @@ class Projector(RESTModelMixin, models.Model):
|
||||
|
||||
name = models.CharField(max_length=255, unique=True, blank=True)
|
||||
|
||||
reference_projector = models.ForeignKey(
|
||||
"self",
|
||||
on_delete=SET_NULL_AND_AUTOUPDATE,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="references",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
Contains general permissions that can not be placed in a specific app.
|
||||
|
@ -97,6 +97,7 @@ class ProjectorSerializer(ModelSerializer):
|
||||
"name",
|
||||
"width",
|
||||
"height",
|
||||
"reference_projector",
|
||||
"projectiondefaults",
|
||||
)
|
||||
read_only_fields = ("scale", "scroll")
|
||||
|
Loading…
Reference in New Issue
Block a user