Merge pull request #4441 from FinnStutzenstein/closReference
One global clos reference. More projector buttons for the clos view
This commit is contained in:
commit
c8c55ce597
@ -43,7 +43,7 @@ export class ProjectorRepositoryService extends BaseRepository<ViewProjector, Pr
|
||||
private http: HttpService,
|
||||
private translate: TranslateService
|
||||
) {
|
||||
super(DS, mapperService, viewModelStoreService, Projector);
|
||||
super(DS, mapperService, viewModelStoreService, Projector, [Projector]);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -3,14 +3,14 @@
|
||||
[ngClass]="isProjected() ? 'projector-active' : 'projector-inactive'">
|
||||
<mat-icon>videocam</mat-icon>
|
||||
</button>
|
||||
<button type="button" *ngIf="menuItem" mat-menu-item (click)="onClick()"
|
||||
[ngClass]="isProjected() ? 'projector-active' : 'projector-inactive'">
|
||||
<mat-icon>videocam</mat-icon>
|
||||
<span translate>Project</span>
|
||||
</button>
|
||||
<button type="button" *ngIf="text && !menuItem" mat-button (click)="onClick($event)"
|
||||
[ngClass]="isProjected() ? 'projector-active' : 'projector-inactive'">
|
||||
<mat-icon>videocam</mat-icon>
|
||||
{{ text | translate }}
|
||||
</button>
|
||||
<button type="button" *ngIf="menuItem" mat-menu-item (click)="onClick()"
|
||||
[ngClass]="isProjected() ? 'projector-active' : 'projector-inactive'">
|
||||
<mat-icon>videocam</mat-icon>
|
||||
{{ (text || 'Project') | translate }}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
@ -11,20 +11,6 @@
|
||||
</div>
|
||||
</os-head-bar>
|
||||
|
||||
<!-- Select projector -->
|
||||
<mat-card *ngIf="currentListOfSpeakers">
|
||||
<h3 translate>
|
||||
Manage the list of speakers for...
|
||||
</h3>
|
||||
<mat-form-field *ngIf="projectors && projectors.length > 0">
|
||||
<mat-select [value]="projectors[0]" (selectionChange)="onSelectProjector($event)">
|
||||
<mat-option *ngFor="let projector of projectors" [value]="projector">
|
||||
{{ projector.name | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</mat-card>
|
||||
|
||||
<h1 class="title on-transition-fade" *ngIf="viewItem">{{ viewItem.contentObject.getTitle() }}</h1>
|
||||
|
||||
<mat-card class="speaker-card" *ngIf="viewItem">
|
||||
@ -131,10 +117,25 @@
|
||||
</mat-card>
|
||||
|
||||
<mat-menu #speakerMenu="matMenu">
|
||||
<os-projector-button
|
||||
*ngIf="viewItem && projectors && projectors.length > 1"
|
||||
[object]="getClosSlide()"
|
||||
[menuItem]="true"
|
||||
text="Current list of speakers (as slide)"
|
||||
></os-projector-button>
|
||||
|
||||
<os-projector-button
|
||||
*ngIf="viewItem"
|
||||
[object]="viewItem.listOfSpeakersSlide"
|
||||
[menuItem]="true"
|
||||
text="List of speakers"
|
||||
></os-projector-button>
|
||||
|
||||
<os-projector-button
|
||||
*ngIf="viewItem"
|
||||
[object]="viewItem.contentObject"
|
||||
[menuItem]="true"
|
||||
[text]="getContentObjectProjectorButtonText()"
|
||||
></os-projector-button>
|
||||
|
||||
<button mat-menu-item *ngIf="closedList" (click)="openSpeakerList()">
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormControl } from '@angular/forms';
|
||||
import { MatSnackBar, MatSelectChange } from '@angular/material';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
@ -21,6 +21,9 @@ import { UserRepositoryService } from 'app/core/repositories/users/user-reposito
|
||||
import { DurationService } from 'app/core/ui-services/duration.service';
|
||||
import { CurrentAgendaItemService } from 'app/site/projector/services/current-agenda-item.service';
|
||||
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CurrentListOfSpeakersSlideService } from 'app/site/projector/services/current-list-of-of-speakers-slide.service';
|
||||
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
||||
|
||||
/**
|
||||
* The list of speakers for agenda items.
|
||||
@ -92,6 +95,13 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
return this.activeSpeaker ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to detect changes in the projector reference.
|
||||
*/
|
||||
private closReferenceProjectorId: number | null;
|
||||
|
||||
private closItemSubscription: Subscription | null;
|
||||
|
||||
/**
|
||||
* Constructor for speaker list component. Generates the forms and subscribes
|
||||
* to the {@link currentListOfSpeakers}
|
||||
@ -121,7 +131,9 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
private promptService: PromptService,
|
||||
private currentAgendaItemService: CurrentAgendaItemService,
|
||||
private durationService: DurationService,
|
||||
private userRepository: UserRepositoryService
|
||||
private userRepository: UserRepositoryService,
|
||||
private collectionStringMapper: CollectionStringMapperService,
|
||||
private currentListOfSpeakersSlideService: CurrentListOfSpeakersSlideService
|
||||
) {
|
||||
super(title, translate, snackBar);
|
||||
this.isCurrentListOfSpeakers();
|
||||
@ -129,9 +141,10 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
|
||||
if (this.currentListOfSpeakers) {
|
||||
this.projectors = projectorRepo.getViewModelList();
|
||||
this.showClosOfProjector(this.projectors[0]);
|
||||
this.updateClosProjector();
|
||||
projectorRepo.getViewModelListObservable().subscribe(newProjectors => {
|
||||
this.projectors = newProjectors;
|
||||
this.updateClosProjector();
|
||||
});
|
||||
} else {
|
||||
this.getItemByUrl();
|
||||
@ -172,29 +185,26 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed by selecting projectors
|
||||
*
|
||||
* @param event Holds the selected projector
|
||||
*/
|
||||
public onSelectProjector(event: MatSelectChange): void {
|
||||
this.showClosOfProjector(event.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the current list of speakers (CLOS) of a given projector.
|
||||
* Triggers after mat-select-change
|
||||
*
|
||||
* @param event Mat select change event, holds the projector in value
|
||||
*/
|
||||
private showClosOfProjector(projector: ViewProjector): void {
|
||||
private updateClosProjector(): void {
|
||||
if (!this.projectors.length) {
|
||||
return;
|
||||
}
|
||||
const referenceProjector = this.projectors[0].referenceProjector;
|
||||
if (!referenceProjector || referenceProjector.id === this.closReferenceProjectorId) {
|
||||
return;
|
||||
}
|
||||
this.closReferenceProjectorId = referenceProjector.id;
|
||||
|
||||
if (this.projectorSubscription) {
|
||||
this.projectorSubscription.unsubscribe();
|
||||
this.viewItem = null;
|
||||
}
|
||||
|
||||
this.projectorSubscription = this.currentAgendaItemService
|
||||
.getAgendaItemObservable(projector)
|
||||
.getAgendaItemObservable(referenceProjector)
|
||||
.subscribe(item => {
|
||||
if (item) {
|
||||
this.setSpeakerList(item.id);
|
||||
@ -202,6 +212,13 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the CLOS slide build descriptor
|
||||
*/
|
||||
public getClosSlide(): ProjectorElementBuildDeskriptor {
|
||||
return this.currentListOfSpeakersSlideService.getSlide(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the ID from the url
|
||||
* Determine whether the speaker list belongs to a motion or a topic
|
||||
@ -217,7 +234,11 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
* @param item the item to use as List of Speakers
|
||||
*/
|
||||
private setSpeakerList(id: number): void {
|
||||
this.itemRepo.getViewModelObservable(id).subscribe(newAgendaItem => {
|
||||
if (this.closItemSubscription) {
|
||||
this.closItemSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
this.closItemSubscription = this.itemRepo.getViewModelObservable(id).subscribe(newAgendaItem => {
|
||||
if (newAgendaItem) {
|
||||
this.viewItem = newAgendaItem;
|
||||
const allSpeakers = this.repo.createSpeakerList(newAgendaItem.item);
|
||||
@ -228,6 +249,17 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the verbose name of the model of the content object from viewItem.
|
||||
* If a motion is the current content object, "Motion" will be the returned value.
|
||||
*/
|
||||
public getContentObjectProjectorButtonText(): string {
|
||||
const verboseName = this.collectionStringMapper
|
||||
.getRepository(this.viewItem.item.content_object.collection)
|
||||
.getVerboseName();
|
||||
return verboseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a speaker out of an id
|
||||
*
|
||||
|
@ -14,6 +14,19 @@
|
||||
</div>
|
||||
</os-head-bar>
|
||||
|
||||
<mat-card *ngIf="!projectorToCreate && projectors">
|
||||
<span translate>
|
||||
Reference projector for current list of speakers:
|
||||
</span>
|
||||
<mat-form-field>
|
||||
<mat-select [disabled]="!!editId" [value]="projectors[0].reference_projector_id" (selectionChange)="onSelectReferenceProjector($event)">
|
||||
<mat-option *ngFor="let projector of projectors" [value]="projector.id">
|
||||
{{ projector.getTitle() | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</mat-card>
|
||||
|
||||
<mat-card *ngIf="projectorToCreate">
|
||||
<mat-card-title translate>New Projector</mat-card-title>
|
||||
<mat-card-content>
|
||||
@ -74,19 +87,6 @@
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Reference projector for the current list of speakers -->
|
||||
<h3 translate>Current list of 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">
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { MatSnackBar, MatSelectChange } from '@angular/material';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@ -105,7 +105,6 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
aspectRatio: ['', Validators.required],
|
||||
width: [0, Validators.required],
|
||||
clock: [true],
|
||||
reference_projector_id: [],
|
||||
background_color: ['', Validators.required],
|
||||
header_background_color: ['', Validators.required],
|
||||
header_font_color: ['', Validators.required],
|
||||
@ -140,11 +139,12 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
public create(): void {
|
||||
if (this.createForm.valid && this.projectorToCreate) {
|
||||
this.projectorToCreate.patchValues(this.createForm.value as Projector);
|
||||
// TODO: the server shouldn't want to have this data..
|
||||
// TODO: the server shouldn't want to have element data..
|
||||
this.projectorToCreate.patchValues({
|
||||
elements: [{ name: 'core/clock', stable: true }],
|
||||
elements_preview: [],
|
||||
elements_history: []
|
||||
elements_history: [],
|
||||
reference_projector_id: this.projectors[0].reference_projector_id
|
||||
});
|
||||
this.repo.create(this.projectorToCreate).then(() => (this.projectorToCreate = null), this.raiseError);
|
||||
}
|
||||
@ -206,25 +206,11 @@ 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),
|
||||
reference_projector_id: reference_projector_id,
|
||||
background_color: projector.background_color,
|
||||
show_header_footer: projector.show_header_footer,
|
||||
show_title: projector.show_title,
|
||||
show_logo: projector.show_logo
|
||||
});*/
|
||||
this.updateForm.patchValue(projector.projector);
|
||||
this.updateForm.patchValue({
|
||||
name: this.translate.instant(projector.name),
|
||||
aspectRatio: this.getAspectRatioKey(projector),
|
||||
clock: this.clockSlideService.isProjectedOn(projector),
|
||||
reference_projector_id: reference_projector_id
|
||||
clock: this.clockSlideService.isProjectedOn(projector)
|
||||
});
|
||||
}
|
||||
|
||||
@ -249,16 +235,6 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
return;
|
||||
}
|
||||
const updateProjector: Partial<Projector> = this.updateForm.value;
|
||||
/*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]),
|
||||
reference_projector_id: this.updateForm.value.reference_projector_id,
|
||||
background_color: this.updateForm.value.background_color,
|
||||
show_header_footer: this.updateForm.value.show_header_footer,
|
||||
show_title: this.updateForm.value.show_title,
|
||||
show_logo: this.updateForm.value.show_logo
|
||||
};*/
|
||||
updateProjector.height = Math.round(
|
||||
this.updateForm.value.width / aspectRatios[this.updateForm.value.aspectRatio]
|
||||
);
|
||||
@ -284,13 +260,13 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
public onSelectReferenceProjector(change: MatSelectChange): void {
|
||||
const update: Partial<Projector> = {
|
||||
reference_projector_id: change.value
|
||||
};
|
||||
const promises = this.projectors.map(projector => {
|
||||
return this.repo.update(update, projector);
|
||||
});
|
||||
Promise.all(promises).then(null, this.raiseError);
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,20 @@ export class ViewProjector extends BaseViewModel {
|
||||
public static COLLECTIONSTRING = Projector.COLLECTIONSTRING;
|
||||
|
||||
private _projector: Projector;
|
||||
private _referenceProjector: ViewProjector;
|
||||
|
||||
public get projector(): Projector {
|
||||
return this._projector;
|
||||
}
|
||||
|
||||
public get referenceProjector(): ViewProjector {
|
||||
if (!this.reference_projector_id) {
|
||||
return this;
|
||||
} else {
|
||||
return this._referenceProjector;
|
||||
}
|
||||
}
|
||||
|
||||
public get id(): number {
|
||||
return this.projector.id;
|
||||
}
|
||||
@ -87,14 +96,19 @@ export class ViewProjector extends BaseViewModel {
|
||||
*/
|
||||
public getVerboseName;
|
||||
|
||||
public constructor(projector?: Projector) {
|
||||
public constructor(projector: Projector, referenceProjector?: ViewProjector) {
|
||||
super(Projector.COLLECTIONSTRING);
|
||||
this._projector = projector;
|
||||
this._referenceProjector = referenceProjector;
|
||||
}
|
||||
|
||||
public getTitle = () => {
|
||||
return this.name;
|
||||
};
|
||||
|
||||
public updateDependencies(update: BaseViewModel): void {}
|
||||
public updateDependencies(update: BaseViewModel): void {
|
||||
if (update instanceof ViewProjector && this.reference_projector_id === update.id) {
|
||||
this._referenceProjector = update;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { Injectable } from '@angular/core';
|
||||
import { ProjectorService } from 'app/core/core-services/projector.service';
|
||||
import { ViewProjector } from '../models/view-projector';
|
||||
import { IdentifiableProjectorElement } from 'app/shared/models/core/projector';
|
||||
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
||||
|
||||
/**
|
||||
* Handles the curent list of speakers slide. Manages the projection and provides
|
||||
@ -29,6 +30,18 @@ export class CurrentListOfSpeakersSlideService {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the slide build descriptor for the overlay or slide
|
||||
*/
|
||||
public getSlide(overlay: boolean): ProjectorElementBuildDeskriptor {
|
||||
return {
|
||||
getBasicProjectorElement: options => this.getCurrentListOfSpeakersProjectorElement(overlay),
|
||||
slideOptions: [],
|
||||
projectionDefaultName: 'agenda_current_list_of_speakers',
|
||||
getDialogTitle: () => 'Current list of speakers'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries, if the slide/overlay is projected on the given projector.
|
||||
*
|
||||
|
34
openslides/core/migrations/0020_set_reference_projector.py
Normal file
34
openslides/core/migrations/0020_set_reference_projector.py
Normal file
@ -0,0 +1,34 @@
|
||||
# Generated by Finn Stutzenstein on 2019-03-01 10:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def set_reference_projector(apps, schema_editor):
|
||||
"""
|
||||
Sets all references to one projector. Tries to get the id from the former
|
||||
config value. If there is no config or the id is invalid, the first projector
|
||||
will be taken
|
||||
"""
|
||||
ConfigStore = apps.get_model("core", "ConfigStore")
|
||||
Projector = apps.get_model("core", "Projector")
|
||||
|
||||
try:
|
||||
config = ConfigStore.objects.get(
|
||||
key="projector_currentListOfSpeakers_reference"
|
||||
)
|
||||
reference_id = config.value
|
||||
config.delete() # cleanup. this config is not needed anymore
|
||||
reference_projector = Projector.objects.get(pk=reference_id)
|
||||
except (ConfigStore.DoesNotExist, Projector.DoesNotExist):
|
||||
reference_projector = Projector.objects.first()
|
||||
|
||||
for projector in Projector.objects.all():
|
||||
projector.reference_projector = reference_projector
|
||||
projector.save(skip_autoupdate=True)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0019_countdown_title_2")]
|
||||
|
||||
operations = [migrations.RunPython(set_reference_projector)]
|
Loading…
Reference in New Issue
Block a user