Merge pull request #4585 from FinnStutzenstein/projectorListCleanup
Put projector cards in own components in the listview
This commit is contained in:
commit
e7624c0d1e
@ -0,0 +1,113 @@
|
|||||||
|
<os-meta-text-block showActionRow="false" *ngIf="projector">
|
||||||
|
<ng-container class="meta-text-block-title">
|
||||||
|
{{ projector.getTitle() | translate }}
|
||||||
|
</ng-container>
|
||||||
|
<ng-container class="meta-text-block-action-row" *ngIf="canManage">
|
||||||
|
<button mat-icon-button *ngIf="!isEditing" (click)="onEditButton()">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button *ngIf="isEditing" (click)="onCancelButton()">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button *ngIf="isEditing" (click)="onSaveButton()">
|
||||||
|
<mat-icon>save</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button color="warn" (click)="onDeleteButton()">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container class="meta-text-block-content">
|
||||||
|
<a class="no-markup" [routerLink]="['/projectors/detail', projector.id]">
|
||||||
|
<div class="projector">
|
||||||
|
<os-projector [projector]="projector"></os-projector>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<ng-container *ngIf="isEditing">
|
||||||
|
<form [formGroup]="updateForm" (keydown)="keyDownFunction($event, projector)">
|
||||||
|
<!-- Name field -->
|
||||||
|
<mat-form-field>
|
||||||
|
<input formControlName="name" matInput placeholder="{{ 'Name' | translate }}" required />
|
||||||
|
<mat-hint *ngIf="!updateForm.controls.name.valid">
|
||||||
|
<span translate>Required</span>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
{{ ratio }}
|
||||||
|
</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
<mat-slider
|
||||||
|
[thumbLabel]="true"
|
||||||
|
min="800"
|
||||||
|
max="3840"
|
||||||
|
step="10"
|
||||||
|
(change)="widthSliderValueChanged($event)"
|
||||||
|
></mat-slider>
|
||||||
|
{{ updateForm.value.width }}
|
||||||
|
|
||||||
|
<!-- projection defaults -->
|
||||||
|
<h3 translate>Projection defaults</h3>
|
||||||
|
<mat-select formControlName="projectiondefaults_id" placeholder="{{ 'Projection defaults' | translate }}" [multiple]="true">
|
||||||
|
<mat-option *ngFor="let pd of projectionDefaults" [value]="pd.id">
|
||||||
|
{{ pd.getTitle() | translate }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
|
||||||
|
<!-- colors -->
|
||||||
|
<mat-form-field>
|
||||||
|
<span translate>Background color</span>
|
||||||
|
<input matInput formControlName="background_color" type="color" />
|
||||||
|
<mat-hint *ngIf="!updateForm.controls.background_color.valid">
|
||||||
|
<span translate>Required</span>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<span translate>Header background color</span>
|
||||||
|
<input matInput formControlName="header_background_color" type="color" />
|
||||||
|
<mat-hint *ngIf="!updateForm.controls.header_background_color.valid">
|
||||||
|
<span translate>Required</span>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<span translate>Header font color</span>
|
||||||
|
<input matInput formControlName="header_font_color" type="color" />
|
||||||
|
<mat-hint *ngIf="!updateForm.controls.header_font_color.valid">
|
||||||
|
<span translate>Required</span>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<span translate>Headline color</span>
|
||||||
|
<input matInput formControlName="header_h1_color" type="color" />
|
||||||
|
<mat-hint *ngIf="!updateForm.controls.header_h1_color.valid">
|
||||||
|
<span translate>Required</span>
|
||||||
|
</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<!-- checkboxes -->
|
||||||
|
<div>
|
||||||
|
<mat-checkbox formControlName="show_header_footer">
|
||||||
|
<span translate>Show header and footer</span>
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox formControlName="show_title">
|
||||||
|
<span translate>Show title</span>
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox formControlName="show_logo">
|
||||||
|
<span translate>Show logo</span>
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox formControlName="clock">
|
||||||
|
<span translate>Show clock</span>
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</os-meta-text-block>
|
@ -0,0 +1,19 @@
|
|||||||
|
.projector {
|
||||||
|
width: 320px;
|
||||||
|
color: black;
|
||||||
|
border: 1px solid lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep mat-card {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-markup {
|
||||||
|
/* Do not let the a tag ruin the projector */
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { E2EImportsModule } from '../../../../../e2e-imports.module';
|
||||||
|
import { ProjectorModule } from '../../projector.module';
|
||||||
|
import { ProjectorListEntryComponent } from './projector-list-entry.component';
|
||||||
|
|
||||||
|
describe('ProjectorListEntryComponent', () => {
|
||||||
|
let component: ProjectorListEntryComponent;
|
||||||
|
let fixture: ComponentFixture<ProjectorListEntryComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule, ProjectorModule]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ProjectorListEntryComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,229 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
import { MatSnackBar, MatSliderChange } from '@angular/material';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-repository.service';
|
||||||
|
import { ViewProjector } from '../../models/view-projector';
|
||||||
|
import { Projector } from 'app/shared/models/core/projector';
|
||||||
|
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||||
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
|
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';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All supported aspect rations for projectors.
|
||||||
|
*/
|
||||||
|
const aspectRatios: { [ratio: string]: number } = {
|
||||||
|
'4:3': 4 / 3,
|
||||||
|
'16:9': 16 / 9,
|
||||||
|
'16:10': 16 / 10
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List for all projectors.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'os-projector-list-entry',
|
||||||
|
templateUrl: './projector-list-entry.component.html',
|
||||||
|
styleUrls: ['./projector-list-entry.component.scss']
|
||||||
|
})
|
||||||
|
export class ProjectorListEntryComponent extends BaseViewComponent implements OnInit {
|
||||||
|
/**
|
||||||
|
* The update form. Will be refreahed for each projector. Just one update
|
||||||
|
* form can be shown per time.
|
||||||
|
*/
|
||||||
|
public updateForm: FormGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves, if this projector currently is edited.
|
||||||
|
*/
|
||||||
|
public isEditing = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All ProjectionDefaults to select from.
|
||||||
|
*/
|
||||||
|
public projectionDefaults: ViewProjectionDefault[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All aspect ratio keys/strings for the UI.
|
||||||
|
*/
|
||||||
|
public aspectRatiosKeys: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The projector shown by this entry.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
public projector: ViewProjector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to check manage permissions
|
||||||
|
*
|
||||||
|
* @returns true if the user can manage projectors
|
||||||
|
*/
|
||||||
|
public get canManage(): boolean {
|
||||||
|
return this.operator.hasPerms('core.can_manage_projector');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. Initializes the update form.
|
||||||
|
*
|
||||||
|
* @param titleService
|
||||||
|
* @param translate
|
||||||
|
* @param matSnackBar
|
||||||
|
* @param repo
|
||||||
|
* @param formBuilder
|
||||||
|
* @param promptService
|
||||||
|
* @param clockSlideService
|
||||||
|
* @param operator OperatorService
|
||||||
|
*/
|
||||||
|
public constructor(
|
||||||
|
titleService: Title,
|
||||||
|
protected translate: TranslateService, // protected required for ng-translate-extract
|
||||||
|
matSnackBar: MatSnackBar,
|
||||||
|
private repo: ProjectorRepositoryService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private promptService: PromptService,
|
||||||
|
private clockSlideService: ClockSlideService,
|
||||||
|
private operator: OperatorService,
|
||||||
|
private projectionDefaultRepo: ProjectionDefaultRepositoryService
|
||||||
|
) {
|
||||||
|
super(titleService, translate, matSnackBar);
|
||||||
|
|
||||||
|
this.aspectRatiosKeys = Object.keys(aspectRatios);
|
||||||
|
|
||||||
|
this.updateForm = this.formBuilder.group({
|
||||||
|
name: ['', Validators.required],
|
||||||
|
aspectRatio: ['', Validators.required],
|
||||||
|
width: [0, Validators.required],
|
||||||
|
projectiondefaults_id: [[]],
|
||||||
|
clock: [true],
|
||||||
|
background_color: ['', Validators.required],
|
||||||
|
header_background_color: ['', Validators.required],
|
||||||
|
header_font_color: ['', Validators.required],
|
||||||
|
header_h1_color: ['', Validators.required],
|
||||||
|
show_header_footer: [],
|
||||||
|
show_title: [],
|
||||||
|
show_logo: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches all projectiondefaults.
|
||||||
|
*/
|
||||||
|
public ngOnInit(): void {
|
||||||
|
this.projectionDefaults = this.projectionDefaultRepo.getViewModelList();
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.projectionDefaultRepo.getViewModelListObservable().subscribe(pds => (this.projectionDefaults = pds))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event on Key Down in update form.
|
||||||
|
*
|
||||||
|
* @param event the keyboard event
|
||||||
|
* @param the current view in scope
|
||||||
|
*/
|
||||||
|
public keyDownFunction(event: KeyboardEvent): void {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
this.onSaveButton();
|
||||||
|
}
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
this.onCancelButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the aspect ratio of the given projector.
|
||||||
|
* If no matching ratio is found, the first ratio is returned.
|
||||||
|
*
|
||||||
|
* @param projector The projector to check
|
||||||
|
* @returns the found ratio key.
|
||||||
|
*/
|
||||||
|
public getAspectRatioKey(): string {
|
||||||
|
const ratio = this.projector.width / this.projector.height;
|
||||||
|
const RATIO_ENVIRONMENT = 0.05;
|
||||||
|
const foundRatioKey = Object.keys(aspectRatios).find(key => {
|
||||||
|
const value = aspectRatios[key];
|
||||||
|
return value >= ratio - RATIO_ENVIRONMENT && value <= ratio + RATIO_ENVIRONMENT;
|
||||||
|
});
|
||||||
|
if (!foundRatioKey) {
|
||||||
|
return Object.keys(aspectRatios)[0];
|
||||||
|
} else {
|
||||||
|
return foundRatioKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts editing for the given projector.
|
||||||
|
*/
|
||||||
|
public onEditButton(): void {
|
||||||
|
if (this.isEditing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.isEditing = true;
|
||||||
|
this.updateForm.reset();
|
||||||
|
|
||||||
|
this.updateForm.patchValue(this.projector.projector);
|
||||||
|
this.updateForm.patchValue({
|
||||||
|
name: this.translate.instant(this.projector.name),
|
||||||
|
aspectRatio: this.getAspectRatioKey(),
|
||||||
|
clock: this.clockSlideService.isProjectedOn(this.projector)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the current editing.
|
||||||
|
*/
|
||||||
|
public onCancelButton(): void {
|
||||||
|
this.isEditing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the projector
|
||||||
|
*
|
||||||
|
* @param projector The projector to save.
|
||||||
|
*/
|
||||||
|
public async onSaveButton(): Promise<void> {
|
||||||
|
const updateProjector: Partial<Projector> = this.updateForm.value;
|
||||||
|
updateProjector.height = Math.round(
|
||||||
|
this.updateForm.value.width / aspectRatios[this.updateForm.value.aspectRatio]
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.clockSlideService.setProjectedOn(this.projector, this.updateForm.value.clock);
|
||||||
|
await this.repo.update(updateProjector, this.projector);
|
||||||
|
this.isEditing = false;
|
||||||
|
} catch (e) {
|
||||||
|
this.raiseError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the projector.
|
||||||
|
*/
|
||||||
|
public async onDeleteButton(): Promise<void> {
|
||||||
|
const title = this.translate.instant('Are you sure you want to delete this projector?');
|
||||||
|
if (await this.promptService.open(title, this.projector.name)) {
|
||||||
|
this.repo.delete(this.projector).then(null, this.raiseError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eventhandler for slider changes. Directly saves the new aspect ratio.
|
||||||
|
*
|
||||||
|
* @param event The slider value
|
||||||
|
*/
|
||||||
|
public widthSliderValueChanged(event: MatSliderChange): void {
|
||||||
|
const aspectRatio = this.getAspectRatioKey();
|
||||||
|
const updateProjector: Partial<Projector> = {
|
||||||
|
width: event.value
|
||||||
|
};
|
||||||
|
updateProjector.height = Math.round(event.value / aspectRatios[aspectRatio]);
|
||||||
|
this.repo.update(updateProjector, this.projector).then(null, this.raiseError);
|
||||||
|
}
|
||||||
|
}
|
@ -45,120 +45,7 @@
|
|||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
||||||
<div id="card-wrapper">
|
<div id="card-wrapper">
|
||||||
<div class="projector-card" *ngFor="let projector of projectors">
|
<div class="projector-card" *ngFor="let projector of projectors; trackBy: trackByIndex">
|
||||||
<os-meta-text-block showActionRow="false">
|
<os-projector-list-entry [projector]="projector"></os-projector-list-entry>
|
||||||
<ng-container class="meta-text-block-title">
|
|
||||||
{{ projector.name | translate }}
|
|
||||||
</ng-container>
|
|
||||||
<ng-container class="meta-text-block-action-row" *ngIf="canManage">
|
|
||||||
<button mat-icon-button *ngIf="editId !== projector.id" (click)="onEditButton(projector)">
|
|
||||||
<mat-icon>edit</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button *ngIf="editId === projector.id" (click)="onCancelButton(projector)">
|
|
||||||
<mat-icon>close</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button *ngIf="editId === projector.id" (click)="onSaveButton(projector)">
|
|
||||||
<mat-icon>save</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button color="warn" (click)="onDeleteButton(projector)">
|
|
||||||
<mat-icon>delete</mat-icon>
|
|
||||||
</button>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container class="meta-text-block-content">
|
|
||||||
<a class="no-markup" [routerLink]="['/projectors/detail', projector.id]">
|
|
||||||
<div class="projector">
|
|
||||||
<os-projector [projector]="projector"></os-projector>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<ng-container *ngIf="editId === projector.id">
|
|
||||||
<form [formGroup]="updateForm" (keydown)="keyDownFunction($event, projector)">
|
|
||||||
<!-- Name field -->
|
|
||||||
<mat-form-field>
|
|
||||||
<input formControlName="name" matInput placeholder="{{ 'Name' | translate }}" required />
|
|
||||||
<mat-hint *ngIf="!updateForm.controls.name.valid">
|
|
||||||
<span translate>Required</span>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<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">
|
|
||||||
{{ ratio }}
|
|
||||||
</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
<mat-slider
|
|
||||||
[thumbLabel]="true"
|
|
||||||
formControlName="width"
|
|
||||||
min="800"
|
|
||||||
max="3840"
|
|
||||||
step="10"
|
|
||||||
(change)="widthSliderValueChanged(projector, $event)"
|
|
||||||
></mat-slider>
|
|
||||||
{{ updateForm.value.width }}
|
|
||||||
|
|
||||||
<!-- projection defaults -->
|
|
||||||
<h3 translate>Projection defaults</h3>
|
|
||||||
<mat-select formControlName="projectiondefaults_id" placeholder="{{ 'Projection defaults' | translate }}" [multiple]="true">
|
|
||||||
<mat-option *ngFor="let pd of projectionDefaults" [value]="pd.id">
|
|
||||||
{{ pd.getTitle() | translate }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
|
|
||||||
<!-- colors -->
|
|
||||||
<mat-form-field>
|
|
||||||
<span translate>Background color</span>
|
|
||||||
<input matInput formControlName="background_color" type="color" />
|
|
||||||
<mat-hint *ngIf="!updateForm.controls.background_color.valid">
|
|
||||||
<span translate>Required</span>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<span translate>Header background color</span>
|
|
||||||
<input matInput formControlName="header_background_color" type="color" />
|
|
||||||
<mat-hint *ngIf="!updateForm.controls.header_background_color.valid">
|
|
||||||
<span translate>Required</span>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<span translate>Header font color</span>
|
|
||||||
<input matInput formControlName="header_font_color" type="color" />
|
|
||||||
<mat-hint *ngIf="!updateForm.controls.header_font_color.valid">
|
|
||||||
<span translate>Required</span>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<span translate>Headline color</span>
|
|
||||||
<input matInput formControlName="header_h1_color" type="color" />
|
|
||||||
<mat-hint *ngIf="!updateForm.controls.header_h1_color.valid">
|
|
||||||
<span translate>Required</span>
|
|
||||||
</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<!-- checkboxes -->
|
|
||||||
<div>
|
|
||||||
<mat-checkbox formControlName="show_header_footer">
|
|
||||||
<span translate>Show header and footer</span>
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-checkbox formControlName="show_title">
|
|
||||||
<span translate>Show title</span>
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-checkbox formControlName="show_logo">
|
|
||||||
<span translate>Show logo</span>
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-checkbox formControlName="clock">
|
|
||||||
<span translate>Show clock</span>
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</ng-container>
|
|
||||||
</ng-container>
|
|
||||||
</os-meta-text-block>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -6,25 +6,5 @@
|
|||||||
width: 350px;
|
width: 350px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
float: left;
|
float: left;
|
||||||
|
|
||||||
.projector {
|
|
||||||
width: 320px;
|
|
||||||
color: black;
|
|
||||||
border: 1px solid lightgrey;
|
|
||||||
}
|
|
||||||
|
|
||||||
form {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::ng-deep mat-card {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-markup {
|
|
||||||
/* Do not let the a tag ruin the projector */
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { MatSnackBar, MatSelectChange, MatSliderChange } from '@angular/material';
|
import { MatSnackBar, MatSelectChange } from '@angular/material';
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
@ -9,20 +9,7 @@ import { ProjectorRepositoryService } from 'app/core/repositories/projector/proj
|
|||||||
import { ViewProjector } from '../../models/view-projector';
|
import { ViewProjector } from '../../models/view-projector';
|
||||||
import { Projector } from 'app/shared/models/core/projector';
|
import { Projector } from 'app/shared/models/core/projector';
|
||||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
|
||||||
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 { ProjectionDefaultRepositoryService } from 'app/core/repositories/projector/projection-default-repository.service';
|
|
||||||
import { ViewProjectionDefault } from '../../models/view-projection-default';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All supported aspect rations for projectors.
|
|
||||||
*/
|
|
||||||
const aspectRatios: { [ratio: string]: number } = {
|
|
||||||
'4:3': 4 / 3,
|
|
||||||
'16:9': 16 / 9,
|
|
||||||
'16:10': 16 / 10
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List for all projectors.
|
* List for all projectors.
|
||||||
@ -43,17 +30,6 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
|||||||
*/
|
*/
|
||||||
public createForm: FormGroup;
|
public createForm: FormGroup;
|
||||||
|
|
||||||
/**
|
|
||||||
* The update form. Will be refreahed for each projector. Just one update
|
|
||||||
* form can be shown per time.
|
|
||||||
*/
|
|
||||||
public updateForm: FormGroup;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the currently edited projector.
|
|
||||||
*/
|
|
||||||
public editId: number | null = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All aspect ratio keys/strings for the UI.
|
* All aspect ratio keys/strings for the UI.
|
||||||
*/
|
*/
|
||||||
@ -64,8 +40,6 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
|||||||
*/
|
*/
|
||||||
public projectors: ViewProjector[];
|
public projectors: ViewProjector[];
|
||||||
|
|
||||||
public projectionDefaults: ViewProjectionDefault[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to check manage permissions
|
* Helper to check manage permissions
|
||||||
*
|
*
|
||||||
@ -93,32 +67,13 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
|||||||
matSnackBar: MatSnackBar,
|
matSnackBar: MatSnackBar,
|
||||||
private repo: ProjectorRepositoryService,
|
private repo: ProjectorRepositoryService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private promptService: PromptService,
|
private operator: OperatorService
|
||||||
private clockSlideService: ClockSlideService,
|
|
||||||
private operator: OperatorService,
|
|
||||||
private projectionDefaultRepo: ProjectionDefaultRepositoryService
|
|
||||||
) {
|
) {
|
||||||
super(titleService, translate, matSnackBar);
|
super(titleService, translate, matSnackBar);
|
||||||
|
|
||||||
this.aspectRatiosKeys = Object.keys(aspectRatios);
|
|
||||||
|
|
||||||
this.createForm = this.formBuilder.group({
|
this.createForm = this.formBuilder.group({
|
||||||
name: ['', Validators.required]
|
name: ['', Validators.required]
|
||||||
});
|
});
|
||||||
this.updateForm = this.formBuilder.group({
|
|
||||||
name: ['', Validators.required],
|
|
||||||
aspectRatio: ['', Validators.required],
|
|
||||||
width: [0, Validators.required],
|
|
||||||
projectiondefaults_id: [[]],
|
|
||||||
clock: [true],
|
|
||||||
background_color: ['', Validators.required],
|
|
||||||
header_background_color: ['', Validators.required],
|
|
||||||
header_font_color: ['', Validators.required],
|
|
||||||
header_h1_color: ['', Validators.required],
|
|
||||||
show_header_footer: [],
|
|
||||||
show_title: [],
|
|
||||||
show_logo: []
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,8 +83,6 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
|||||||
super.setTitle('Projectors');
|
super.setTitle('Projectors');
|
||||||
this.projectors = this.repo.getViewModelList();
|
this.projectors = this.repo.getViewModelList();
|
||||||
this.repo.getViewModelListObservable().subscribe(projectors => (this.projectors = projectors));
|
this.repo.getViewModelListObservable().subscribe(projectors => (this.projectors = projectors));
|
||||||
this.projectionDefaults = this.projectionDefaultRepo.getViewModelList();
|
|
||||||
this.projectionDefaultRepo.getViewModelListObservable().subscribe(pds => (this.projectionDefaults = pds));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,112 +112,15 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
|||||||
* Event on Key Down in update or create form.
|
* Event on Key Down in update or create form.
|
||||||
*
|
*
|
||||||
* @param event the keyboard event
|
* @param event the keyboard event
|
||||||
* @param the current view in scope
|
|
||||||
*/
|
*/
|
||||||
public keyDownFunction(event: KeyboardEvent, projector?: ViewProjector): void {
|
public keyDownFunction(event: KeyboardEvent): void {
|
||||||
if (event.key === 'Enter' && event.shiftKey) {
|
if (event.key === 'Enter') {
|
||||||
if (projector) {
|
|
||||||
this.onSaveButton(projector);
|
|
||||||
} else {
|
|
||||||
this.create();
|
this.create();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
if (projector) {
|
|
||||||
this.onCancelButton(projector);
|
|
||||||
} else {
|
|
||||||
this.projectorToCreate = null;
|
this.projectorToCreate = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the aspect ratio of the given projector.
|
|
||||||
* If no matching ratio is found, the first ratio is returned.
|
|
||||||
*
|
|
||||||
* @param projector The projector to check
|
|
||||||
* @returns the found ratio key.
|
|
||||||
*/
|
|
||||||
public getAspectRatioKey(projector: ViewProjector): string {
|
|
||||||
const ratio = projector.width / projector.height;
|
|
||||||
const RATIO_ENVIRONMENT = 0.05;
|
|
||||||
const foundRatioKey = Object.keys(aspectRatios).find(key => {
|
|
||||||
const value = aspectRatios[key];
|
|
||||||
return value >= ratio - RATIO_ENVIRONMENT && value <= ratio + RATIO_ENVIRONMENT;
|
|
||||||
});
|
|
||||||
if (!foundRatioKey) {
|
|
||||||
return Object.keys(aspectRatios)[0];
|
|
||||||
} else {
|
|
||||||
return foundRatioKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts editing for the given projector.
|
|
||||||
*
|
|
||||||
* @param projector The projector to edit
|
|
||||||
*/
|
|
||||||
public onEditButton(projector: ViewProjector): void {
|
|
||||||
if (this.editId !== null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.editId = projector.id;
|
|
||||||
this.updateForm.reset();
|
|
||||||
|
|
||||||
this.updateForm.patchValue(projector.projector);
|
|
||||||
this.updateForm.patchValue({
|
|
||||||
name: this.translate.instant(projector.name),
|
|
||||||
aspectRatio: this.getAspectRatioKey(projector),
|
|
||||||
clock: this.clockSlideService.isProjectedOn(projector)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels the current editing.
|
|
||||||
* @param projector the projector
|
|
||||||
*/
|
|
||||||
public onCancelButton(projector: ViewProjector): void {
|
|
||||||
if (projector.id !== this.editId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.editId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the projector
|
|
||||||
*
|
|
||||||
* @param projector The projector to save.
|
|
||||||
*/
|
|
||||||
public async onSaveButton(projector: ViewProjector): Promise<void> {
|
|
||||||
if (projector.id !== this.editId || !this.updateForm.valid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const updateProjector: Partial<Projector> = this.updateForm.value;
|
|
||||||
updateProjector.height = Math.round(
|
|
||||||
this.updateForm.value.width / aspectRatios[this.updateForm.value.aspectRatio]
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.clockSlideService.setProjectedOn(projector, this.updateForm.value.clock);
|
|
||||||
await this.repo.update(updateProjector, projector);
|
|
||||||
this.editId = null;
|
|
||||||
} catch (e) {
|
|
||||||
this.raiseError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the projector.
|
|
||||||
*
|
|
||||||
* @param projector The projector to delete
|
|
||||||
*/
|
|
||||||
public async onDeleteButton(projector: ViewProjector): Promise<void> {
|
|
||||||
const title = this.translate.instant('Are you sure you want to delete this projector?');
|
|
||||||
const content = projector.name;
|
|
||||||
if (await this.promptService.open(title, content)) {
|
|
||||||
this.repo.delete(projector).then(null, this.raiseError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public onSelectReferenceProjector(change: MatSelectChange): void {
|
public onSelectReferenceProjector(change: MatSelectChange): void {
|
||||||
const update: Partial<Projector> = {
|
const update: Partial<Projector> = {
|
||||||
@ -275,13 +131,4 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
|||||||
});
|
});
|
||||||
Promise.all(promises).then(null, this.raiseError);
|
Promise.all(promises).then(null, this.raiseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
public widthSliderValueChanged(projector: ViewProjector, event: MatSliderChange): void {
|
|
||||||
const aspectRatio = this.getAspectRatioKey(projector);
|
|
||||||
const updateProjector: Partial<Projector> = {
|
|
||||||
width: event.value
|
|
||||||
};
|
|
||||||
updateProjector.height = Math.round(event.value / aspectRatios[aspectRatio]);
|
|
||||||
this.repo.update(updateProjector, projector).then(null, this.raiseError);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,13 @@ import { CountdownControlsComponent } from './components/countdown-controls/coun
|
|||||||
import { CountdownDialogComponent } from './components/countdown-dialog/countdown-dialog.component';
|
import { CountdownDialogComponent } from './components/countdown-dialog/countdown-dialog.component';
|
||||||
import { MessageControlsComponent } from './components/message-controls/message-controls.component';
|
import { MessageControlsComponent } from './components/message-controls/message-controls.component';
|
||||||
import { MessageDialogComponent } from './components/message-dialog/message-dialog.component';
|
import { MessageDialogComponent } from './components/message-dialog/message-dialog.component';
|
||||||
|
import { ProjectorListEntryComponent } from './components/projector-list-entry/projector-list-entry.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, ProjectorRoutingModule, SharedModule],
|
imports: [CommonModule, ProjectorRoutingModule, SharedModule],
|
||||||
declarations: [
|
declarations: [
|
||||||
ProjectorListComponent,
|
ProjectorListComponent,
|
||||||
|
ProjectorListEntryComponent,
|
||||||
ProjectorDetailComponent,
|
ProjectorDetailComponent,
|
||||||
CountdownControlsComponent,
|
CountdownControlsComponent,
|
||||||
CountdownDialogComponent,
|
CountdownDialogComponent,
|
||||||
|
Loading…
Reference in New Issue
Block a user