From 183d2738e0a064979be8b5c8a6fbbec492c7092f Mon Sep 17 00:00:00 2001 From: Sean Engelhardt Date: Tue, 19 Mar 2019 17:20:38 +0100 Subject: [PATCH] Add Countdowns in projector detail Adds Pretty countdown controls, detetion and edit in Projector template. Countdown list was removed --- .../countdown-time.component.html | 10 +- .../projector-button.component.scss | 5 - .../projector-button.component.ts | 21 +- .../countdown-controls.component.html | 83 ++++++- .../countdown-controls.component.scss | 62 +++++ .../countdown-controls.component.ts | 65 +++++- .../countdown-dialog.component.html | 45 ++++ .../countdown-dialog.component.scss | 3 + .../countdown-dialog.component.spec.ts | 40 ++++ .../countdown-dialog.component.ts | 79 +++++++ .../countdown-list.component.html | 137 ----------- .../countdown-list.component.scss | 41 ---- .../countdown-list.component.spec.ts | 27 --- .../countdown-list.component.ts | 218 ------------------ .../projector-detail.component.html | 18 +- .../projector-detail.component.scss | 12 + .../projector-detail.component.ts | 72 +++++- .../projector-list.component.html | 34 +-- .../projector/projector-routing.module.ts | 5 - .../app/site/projector/projector.module.ts | 9 +- .../styles/global-components-style.scss | 14 +- .../assets/styles/openslides-green-theme.scss | 6 +- client/src/styles.scss | 1 - 23 files changed, 513 insertions(+), 494 deletions(-) create mode 100644 client/src/app/site/projector/components/countdown-controls/countdown-controls.component.scss create mode 100644 client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.html create mode 100644 client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.scss create mode 100644 client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.spec.ts create mode 100644 client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.ts delete mode 100644 client/src/app/site/projector/components/countdown-list/countdown-list.component.html delete mode 100644 client/src/app/site/projector/components/countdown-list/countdown-list.component.scss delete mode 100644 client/src/app/site/projector/components/countdown-list/countdown-list.component.spec.ts delete mode 100644 client/src/app/site/projector/components/countdown-list/countdown-list.component.ts diff --git a/client/src/app/shared/components/contdown-time/countdown-time.component.html b/client/src/app/shared/components/contdown-time/countdown-time.component.html index 6ea9552c7..21d09512d 100644 --- a/client/src/app/shared/components/contdown-time/countdown-time.component.html +++ b/client/src/app/shared/components/contdown-time/countdown-time.component.html @@ -1,5 +1,9 @@ -
+
{{ time }}
diff --git a/client/src/app/shared/components/projector-button/projector-button.component.scss b/client/src/app/shared/components/projector-button/projector-button.component.scss index 545fa07d5..237a8084f 100644 --- a/client/src/app/shared/components/projector-button/projector-button.component.scss +++ b/client/src/app/shared/components/projector-button/projector-button.component.scss @@ -10,9 +10,4 @@ color: mat-color($contrast, A200) !important; background-color: mat-color($contrast, 500) !important; } - - .mat-menu-item.projector-active, - .projector-active > .mat-icon { - color: mat-color($primary) !important; - } } diff --git a/client/src/app/shared/components/projector-button/projector-button.component.ts b/client/src/app/shared/components/projector-button/projector-button.component.ts index 620839034..877b5b825 100644 --- a/client/src/app/shared/components/projector-button/projector-button.component.ts +++ b/client/src/app/shared/components/projector-button/projector-button.component.ts @@ -6,6 +6,7 @@ import { isProjectable, isProjectorElementBuildDeskriptor } from 'app/site/base/projectable'; +import { Projector } from 'app/shared/models/core/projector'; import { ProjectorService } from 'app/core/core-services/projector.service'; import { ProjectionDialogService } from 'app/core/ui-services/projection-dialog.service'; @@ -45,6 +46,12 @@ export class ProjectorButtonComponent implements OnInit { @Input() public menuItem = false; + /** + * Pre-define projection target + */ + @Input() + public projector: Projector; + /** * The constructor */ @@ -68,7 +75,19 @@ export class ProjectorButtonComponent implements OnInit { event.stopPropagation(); } if (this.object) { - this.projectionDialogService.openProjectDialogFor(this.object); + if (this.projector) { + // if the projection target was defines before + if (this.isProjected()) { + // remove the projected object + this.projectorService.removeFrom(this.projector, this.object); + } else { + // instantly project the object + this.projectorService.projectOn(this.projector, this.object); + } + } else { + // open the projection dialog + this.projectionDialogService.openProjectDialogFor(this.object); + } } } diff --git a/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.html b/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.html index c2313286e..af5e8355d 100644 --- a/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.html +++ b/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.html @@ -1,12 +1,71 @@ -
- - - - -
+ +
+
+ +
+ +
{{ countdown.getTitle() | translate }}
+ +
+ + + +
+ +
+ + +
+ + + +
+
+
+
diff --git a/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.scss b/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.scss new file mode 100644 index 000000000..963060064 --- /dev/null +++ b/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.scss @@ -0,0 +1,62 @@ +.grid-wrapper { + display: grid; + width: 100%; + grid-template-areas: + 'project title buttons' + 'project controls controls'; + grid-gap: 10px; + grid-template-columns: min-content auto auto; +} + +.projector-button { + grid-area: project; + margin: auto 10px auto 0; +} + +.title { + grid-area: title; + padding: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.action-buttons { + grid-area: buttons; + text-align: right; +} + +.timer { + grid-area: controls; + display: flex; +} + +.larger-countdown { + font-size: 150%; + min-width: 60px; + margin-right: 10px; +} + +// smaller and closer mat icon buttons. +// use on button-tags +// TODO: Somehow does not apply when in style.scss +.small-mat-icon-button { + $size: 20px; + margin: 0 5px; + position: relative; + width: $size; + height: $size; + + ::ng-deep .mat-icon { + position: absolute; + left: 0; + top: 0; + line-height: normal; + width: $size; + height: $size; + } + + .material-icons { + font-size: $size; + } +} diff --git a/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.ts b/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.ts index 23248e19d..4e9ab595c 100644 --- a/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.ts +++ b/client/src/app/site/projector/components/countdown-controls/countdown-controls.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { MatSnackBar } from '@angular/material'; @@ -8,26 +8,60 @@ import { BaseViewComponent } from '../../../base/base-view'; import { ViewCountdown } from '../../models/view-countdown'; import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service'; import { ConfigService } from 'app/core/ui-services/config.service'; +import { PromptService } from 'app/core/ui-services/prompt.service'; +import { Projector } from 'app/shared/models/core/projector'; +import { ProjectionDialogService } from 'app/core/ui-services/projection-dialog.service'; +/** + * + */ @Component({ selector: 'os-countdown-controls', - templateUrl: './countdown-controls.component.html' + templateUrl: './countdown-controls.component.html', + styleUrls: ['./countdown-controls.component.scss'] }) export class CountdownControlsComponent extends BaseViewComponent { + /** + * Countdown as input + */ @Input() public countdown: ViewCountdown; + /** + * Edit event + */ + @Output() + public editEvent = new EventEmitter(); + + /** + * Pre defined projection target (if any) + */ + @Input() + public projector: Projector; + /** * The time in seconds to make the countdown orange, is the countdown is below this value. */ public warningTime: number; + /** + * Constructor + * + * @param titleService + * @param translate + * @param matSnackBar + * @param repo + * @param configService + * @param promptService + */ public constructor( titleService: Title, translate: TranslateService, matSnackBar: MatSnackBar, private repo: CountdownRepositoryService, - private configService: ConfigService + private configService: ConfigService, + private promptService: PromptService, + private projectionDialogService: ProjectionDialogService ) { super(titleService, translate, matSnackBar); @@ -64,4 +98,29 @@ export class CountdownControlsComponent extends BaseViewComponent { public canStop(): boolean { return this.countdown.running || this.countdown.countdown_time !== this.countdown.default_time; } + + /** + * Fires an edit event + */ + public onEdit(): void { + this.editEvent.next(this.countdown); + } + + /** + * Brings the projection dialog + */ + public onBringDialog(): void { + this.projectionDialogService.openProjectDialogFor(this.countdown); + } + + /** + * On delete button + */ + public async onDelete(): Promise { + const content = + this.translate.instant('Delete countdown') + ` ${this.translate.instant(this.countdown.title)}?`; + if (await this.promptService.open('Are you sure?', content)) { + this.repo.delete(this.countdown).then(() => {}, this.raiseError); + } + } } diff --git a/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.html b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.html new file mode 100644 index 000000000..3f927610b --- /dev/null +++ b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.html @@ -0,0 +1,45 @@ +

+ Countdown +

+ +
+
+ + + + + + + + + + + + + + +
+
+ + + + + +
+
diff --git a/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.scss b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.scss new file mode 100644 index 000000000..ef0ee7122 --- /dev/null +++ b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.scss @@ -0,0 +1,3 @@ +.mat-form-field { + width: 100%; +} diff --git a/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.spec.ts b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.spec.ts new file mode 100644 index 000000000..0e1228c72 --- /dev/null +++ b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.spec.ts @@ -0,0 +1,40 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CountdownDialogComponent, CountdownData } from './countdown-dialog.component'; +import { E2EImportsModule } from 'e2e-imports.module'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; + +describe('CountdownDialogComponent', () => { + let component: CountdownDialogComponent; + let fixture: ComponentFixture; + + const dialogData: CountdownData = { + title: '', + description: '', + duration: '' + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [E2EImportsModule], + declarations: [CountdownDialogComponent], + providers: [ + { provide: MatDialogRef, useValue: {} }, + { + provide: MAT_DIALOG_DATA, + useValue: dialogData + } + ] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CountdownDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.ts b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.ts new file mode 100644 index 000000000..4c922e92d --- /dev/null +++ b/client/src/app/site/projector/components/countdown-dialog/countdown-dialog.component.ts @@ -0,0 +1,79 @@ +import { Component, OnInit, Inject } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { MatSnackBar, MAT_DIALOG_DATA } from '@angular/material'; +import { Title } from '@angular/platform-browser'; + +import { TranslateService } from '@ngx-translate/core'; + +import { BaseViewComponent } from 'app/site/base/base-view'; +import { ConfigService } from 'app/core/ui-services/config.service'; +import { DurationService } from 'app/core/ui-services/duration.service'; + +/** + * Countdown data for the form + */ +export interface CountdownData { + title: string; + description: string; + duration: string; + count?: number; +} + +/** + * Dialog component for countdowns + */ +@Component({ + selector: 'os-countdown-dialog', + templateUrl: './countdown-dialog.component.html', + styleUrls: ['./countdown-dialog.component.scss'] +}) +export class CountdownDialogComponent extends BaseViewComponent implements OnInit { + /** + * The form data + */ + public countdownForm: FormGroup; + + /** + * Holds the default time which was set in the config + */ + private defaultTime: number; + + /** + * Constructor + * + * @param title Title service. Required by parent + * @param matSnackBar Required by parent + * @param configService Read out config variables + * @param translate Required by parent + * @param formBuilder To build the form + * @param durationService Converts duration numbers to string + * @param data The mat dialog data, contains the values to display (if any) + */ + public constructor( + title: Title, + matSnackBar: MatSnackBar, + configService: ConfigService, + translate: TranslateService, + private formBuilder: FormBuilder, + private durationService: DurationService, + @Inject(MAT_DIALOG_DATA) public data: CountdownData + ) { + super(title, translate, matSnackBar); + this.defaultTime = configService.instant('projector_default_countdown'); + } + + /** + * Init. Creates the form + */ + public ngOnInit(): void { + const time = this.data.duration || this.durationService.durationToString(this.defaultTime, 'm'); + const title = this.data.title || `${this.translate.instant('Countdown')} ${this.data.count + 1}`; + + this.countdownForm = this.formBuilder.group({ + title: [title, Validators.required], + description: [this.data.description], + // TODO: custom form validation. This needs to be a valid minute duration + duration: [time, Validators.required] + }); + } +} diff --git a/client/src/app/site/projector/components/countdown-list/countdown-list.component.html b/client/src/app/site/projector/components/countdown-list/countdown-list.component.html deleted file mode 100644 index 80680dfe2..000000000 --- a/client/src/app/site/projector/components/countdown-list/countdown-list.component.html +++ /dev/null @@ -1,137 +0,0 @@ - - -
-

Countdowns

-
-
- -
- - New countdown - -
-

- - - - Required - - -

-

- - - -

-

- - - - Required - - -

-
-
- - - - -
- - - - - - -
-
- -
-
- {{ countdown.getTitle() | translate }} -
-
- -
-
-
-
-
-
Edit countdown
-

- - - - Required - - -

-

- - - -

-

- - - - Required - - -

-
- - - - - - -
-
- - - -
No countdowns
-
-
diff --git a/client/src/app/site/projector/components/countdown-list/countdown-list.component.scss b/client/src/app/site/projector/components/countdown-list/countdown-list.component.scss deleted file mode 100644 index cb1a8763e..000000000 --- a/client/src/app/site/projector/components/countdown-list/countdown-list.component.scss +++ /dev/null @@ -1,41 +0,0 @@ -.head-spacer { - width: 100%; - height: 60px; - line-height: 60px; - text-align: right; - background: white; /* TODO: remove this and replace with theme */ - border-bottom: 1px solid rgba(0, 0, 0, 0.12); -} - -mat-card { - margin-bottom: 20px; -} - -.header-container { - display: grid; - grid-template-rows: auto; - grid-template-columns: 40px 1fr 2fr; - width: 100%; - - > div { - grid-row-start: 1; - grid-row-end: span 1; - grid-column-end: span 2; - } - - .header-projector-button { - grid-column-start: 1; - grid-column-end: 2; - } - - .header-name { - grid-column-start: 2; - grid-column-end: 3; - padding: 10px; - } - - .header-controls { - grid-column-start: 3; - grid-column-end: 4; - } -} diff --git a/client/src/app/site/projector/components/countdown-list/countdown-list.component.spec.ts b/client/src/app/site/projector/components/countdown-list/countdown-list.component.spec.ts deleted file mode 100644 index b9b7a55f2..000000000 --- a/client/src/app/site/projector/components/countdown-list/countdown-list.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CountdownListComponent } from './countdown-list.component'; -import { E2EImportsModule } from 'e2e-imports.module'; -import { CountdownControlsComponent } from '../countdown-controls/countdown-controls.component'; - -describe('CountdownListComponent', () => { - let component: CountdownListComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [E2EImportsModule], - declarations: [CountdownListComponent, CountdownControlsComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(CountdownListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/site/projector/components/countdown-list/countdown-list.component.ts b/client/src/app/site/projector/components/countdown-list/countdown-list.component.ts deleted file mode 100644 index 9a7af5fcb..000000000 --- a/client/src/app/site/projector/components/countdown-list/countdown-list.component.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Title } from '@angular/platform-browser'; -import { MatSnackBar } from '@angular/material'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; - -import { TranslateService } from '@ngx-translate/core'; - -import { PromptService } from 'app/core/ui-services/prompt.service'; -import { BaseViewComponent } from '../../../base/base-view'; -import { ViewCountdown } from '../../models/view-countdown'; -import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service'; -import { Countdown } from 'app/shared/models/core/countdown'; -import { DurationService } from 'app/core/ui-services/duration.service'; - -/** - * List view for countdowns. - */ -@Component({ - selector: 'os-countdown-list', - templateUrl: './countdown-list.component.html', - styleUrls: ['./countdown-list.component.scss'] -}) -export class CountdownListComponent extends BaseViewComponent implements OnInit { - public countdownToCreate: Countdown | null; - - /** - * Source of the Data - */ - public countdowns: ViewCountdown[] = []; - - /** - * The current focussed formgroup - */ - public updateForm: FormGroup; - - public createForm: FormGroup; - - public openId: number | null; - public editId: number | null; - - public constructor( - titleService: Title, - protected translate: TranslateService, // protected required for ng-translate-extract - matSnackBar: MatSnackBar, - private repo: CountdownRepositoryService, - private formBuilder: FormBuilder, - private promptService: PromptService, - private durationService: DurationService - ) { - super(titleService, translate, matSnackBar); - - const form = { - description: [''], - default_time: ['', Validators.required], - title: ['', Validators.required] - }; - this.createForm = this.formBuilder.group(form); - this.updateForm = this.formBuilder.group(form); - } - - /** - * Init function. - * - * Sets the title and gets/observes countdowns from DataStore - */ - public ngOnInit(): void { - super.setTitle('Countdowns'); - this.repo.getViewModelListObservable().subscribe(newCountdowns => { - this.countdowns = newCountdowns; - }); - } - - /** - * Add a new countdown. - */ - public onPlusButton(): void { - if (!this.countdownToCreate) { - this.createForm.reset(); - this.createForm.setValue({ - description: '', - title: '', - default_time: '1:00 m' - }); - this.countdownToCreate = new Countdown(); - } - } - - /** - * Handler when clicking on create to create a new statute paragraph - */ - public create(): void { - if (this.createForm.valid) { - let default_time = this.durationService.stringToDuration(this.createForm.value.default_time, 'm'); - if (default_time === 0) { - default_time = 60; - } - - const newValues: Partial = { - description: this.createForm.value.description, - title: this.createForm.value.title, - default_time: default_time - }; - newValues.countdown_time = default_time; - this.countdownToCreate.patchValues(newValues); - this.repo.create(this.countdownToCreate).then(() => { - this.countdownToCreate = null; - }, this.raiseError); - } - } - - /** - * Executed on edit button - * @param countdown - */ - public onEditButton(countdown: ViewCountdown): void { - this.editId = countdown.id; - - this.updateForm.setValue({ - description: countdown.description, - title: this.translate.instant(countdown.title), - default_time: this.durationService.durationToString(countdown.default_time, 'm') - }); - } - - /** - * Saves the countdown - * @param countdown The countdown to save - */ - public onSaveButton(countdown: ViewCountdown): void { - if (this.updateForm.valid) { - let default_time = this.durationService.stringToDuration(this.updateForm.value.default_time, 'm'); - if (default_time === 0) { - default_time = 60; - } - const newValues: Partial = { - title: this.updateForm.value.title, - description: this.updateForm.value.description, - default_time: default_time - }; - if (!countdown.running) { - newValues.countdown_time = default_time; - } - this.repo.update(newValues, countdown).then(() => { - this.openId = this.editId = null; - }, this.raiseError); - } - } - - /** - * Is executed, when the delete button is pressed - * - * @param countdown The countdown to delete - */ - public async onDeleteButton(countdown: ViewCountdown): Promise { - const title = this.translate.instant('Are you sure you want to delete this countdown?'); - const content = countdown.title; - if (await this.promptService.open(title, content)) { - this.repo.delete(countdown).then(() => (this.openId = this.editId = null), this.raiseError); - } - } - - /** - * Is executed when a mat-extension-panel is closed - * - * @param countdown the statute paragraph in the panel - */ - public panelClosed(countdown: ViewCountdown): void { - this.openId = null; - if (this.editId) { - this.onSaveButton(countdown); - } - } - - /** - * clicking Shift and Enter will save automatically - * clicking Escape will cancel the process - * - * @param event has the code - */ - public onKeyDownCreate(event: KeyboardEvent): void { - if (event.key === 'Enter' && event.shiftKey) { - this.create(); - } - if (event.key === 'Escape') { - this.onCancelCreate(); - } - } - - /** - * Cancels the current form action - */ - public onCancelCreate(): void { - this.countdownToCreate = null; - } - - /** - * clicking Shift and Enter will save automatically - * clicking Escape will cancel the process - * - * @param event has the code - */ - public onKeyDownUpdate(event: KeyboardEvent): void { - if (event.key === 'Enter' && event.shiftKey) { - const countdown = this.countdowns.find(x => x.id === this.editId); - this.onSaveButton(countdown); - } - if (event.key === 'Escape') { - this.onCancelUpdate(); - } - } - - /** - * Cancels the current form action - */ - public onCancelUpdate(): void { - this.editId = null; - } -} diff --git a/client/src/app/site/projector/components/projector-detail/projector-detail.component.html b/client/src/app/site/projector/components/projector-detail/projector-detail.component.html index e176a155d..4becf4ecd 100644 --- a/client/src/app/site/projector/components/projector-detail/projector-detail.component.html +++ b/client/src/app/site/projector/components/projector-detail/projector-detail.component.html @@ -180,24 +180,28 @@ - + Countdowns - - {{ countdown.getTitle() | translate }} + - diff --git a/client/src/app/site/projector/components/projector-detail/projector-detail.component.scss b/client/src/app/site/projector/components/projector-detail/projector-detail.component.scss index 90ac81a4d..86ce82db0 100644 --- a/client/src/app/site/projector/components/projector-detail/projector-detail.component.scss +++ b/client/src/app/site/projector/components/projector-detail/projector-detail.component.scss @@ -121,3 +121,15 @@ .drop-list.cdk-drop-list-dragging .drop-list-entry:not(.cdk-drag-placeholder) { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } + +.larger-mat-list-item { + height: 90px; +} + +.larger-mat-list-item + .larger-mat-list-item { + margin-top: 15px; +} + +.dynamic-list-entry { + width: 100%; +} diff --git a/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts b/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts index 0e724b8af..1b3aa52e7 100644 --- a/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts +++ b/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; -import { MatSnackBar } from '@angular/material'; +import { MatSnackBar, MatDialog } from '@angular/material'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; @@ -11,6 +11,11 @@ import { } from 'app/core/repositories/projector/projector-repository.service'; import { ViewProjector } from '../../models/view-projector'; import { BaseViewComponent } from 'app/site/base/base-view'; +import { Countdown } from 'app/shared/models/core/countdown'; +import { CountdownDialogComponent, CountdownData } from '../countdown-dialog/countdown-dialog.component'; +import { CurrentListOfSpeakersSlideService } from '../../services/current-list-of-of-speakers-slide.service'; +import { CurrentSpeakerChyronSlideService } from '../../services/current-speaker-chyron-slide.service'; +import { DurationService } from 'app/core/ui-services/duration.service'; import { ProjectorService } from 'app/core/core-services/projector.service'; import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop'; import { ProjectorElement } from 'app/shared/models/core/projector'; @@ -20,8 +25,6 @@ import { ProjectorMessageRepositoryService } from 'app/core/repositories/project import { ViewProjectorMessage } from 'app/site/projector/models/view-projector-message'; import { ViewCountdown } from 'app/site/projector/models/view-countdown'; import { Projectable } from 'app/site/base/projectable'; -import { CurrentListOfSpeakersSlideService } from '../../services/current-list-of-of-speakers-slide.service'; -import { CurrentSpeakerChyronSlideService } from '../../services/current-speaker-chyron-slide.service'; /** * The projector detail view. @@ -61,6 +64,7 @@ export class ProjectorDetailComponent extends BaseViewComponent implements OnIni titleService: Title, translate: TranslateService, matSnackBar: MatSnackBar, + private dialog: MatDialog, private repo: ProjectorRepositoryService, private route: ActivatedRoute, private projectorService: ProjectorService, @@ -68,7 +72,8 @@ export class ProjectorDetailComponent extends BaseViewComponent implements OnIni private countdownRepo: CountdownRepositoryService, private messageRepo: ProjectorMessageRepositoryService, private currentListOfSpeakersSlideService: CurrentListOfSpeakersSlideService, - private currentSpeakerChyronService: CurrentSpeakerChyronSlideService + private currentSpeakerChyronService: CurrentSpeakerChyronSlideService, + private durationService: DurationService ) { super(titleService, translate, matSnackBar); @@ -170,4 +175,63 @@ export class ProjectorDetailComponent extends BaseViewComponent implements OnIni public toggleChyron(): void { this.currentSpeakerChyronService.toggleOn(this.projector); } + + /** + * Opens the countdown dialog + * + * @param viewCountdown optional existing countdown to edit + */ + public openCountdownDialog(viewCountdown?: ViewCountdown): void { + let countdownData: CountdownData = { + title: '', + description: '', + duration: '', + count: this.countdowns.length + }; + + if (viewCountdown) { + countdownData = { + title: viewCountdown.title, + description: viewCountdown.description, + duration: this.durationService.durationToString(viewCountdown.default_time, 'm') + }; + } + + const dialogRef = this.dialog.open(CountdownDialogComponent, { + data: countdownData, + maxHeight: '90vh', + width: '400px', + maxWidth: '90vw', + disableClose: true + }); + + dialogRef.afterClosed().subscribe(result => { + if (result) { + this.submitCountdown(result, viewCountdown); + } + }); + } + + /** + * Function to send a countdown + * + * @param data the countdown data to send + * @param viewCountdown optional existing countdown to update + */ + public submitCountdown(data: CountdownData, viewCountdown?: ViewCountdown): void { + const defaultTime = this.durationService.stringToDuration(data.duration, 'm'); + + const sendData = new Countdown({ + title: data.title, + description: data.description, + default_time: defaultTime, + countdown_time: viewCountdown && viewCountdown.running ? null : defaultTime + }); + + if (viewCountdown) { + this.countdownRepo.update(sendData, viewCountdown).then(() => {}, this.raiseError); + } else { + this.countdownRepo.create(sendData).then(() => {}, this.raiseError); + } + } } diff --git a/client/src/app/site/projector/components/projector-list/projector-list.component.html b/client/src/app/site/projector/components/projector-list/projector-list.component.html index e9ba048c1..9057399fc 100644 --- a/client/src/app/site/projector/components/projector-list/projector-list.component.html +++ b/client/src/app/site/projector/components/projector-list/projector-list.component.html @@ -16,10 +16,14 @@ - Reference projector for current list of speakers: -   + Reference projector for current list of speakers:   - + {{ projector.getTitle() | translate }} @@ -33,7 +37,7 @@

- + Required @@ -58,16 +62,16 @@ {{ projector.name | translate }} - - - - @@ -81,7 +85,7 @@ - + Required @@ -94,7 +98,13 @@ {{ ratio }} - + {{ updateForm.value.width }} @@ -160,8 +170,4 @@ note Projector messages - diff --git a/client/src/app/site/projector/projector-routing.module.ts b/client/src/app/site/projector/projector-routing.module.ts index 8de5de99e..1bd66de4c 100644 --- a/client/src/app/site/projector/projector-routing.module.ts +++ b/client/src/app/site/projector/projector-routing.module.ts @@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { ProjectorListComponent } from './components/projector-list/projector-list.component'; import { ProjectorDetailComponent } from './components/projector-detail/projector-detail.component'; -import { CountdownListComponent } from './components/countdown-list/countdown-list.component'; import { ProjectorMessageListComponent } from './components/projector-message-list/projector-message-list.component'; const routes: Routes = [ @@ -15,10 +14,6 @@ const routes: Routes = [ path: 'detail/:id', component: ProjectorDetailComponent }, - { - path: 'countdowns', - component: CountdownListComponent - }, { path: 'messages', component: ProjectorMessageListComponent diff --git a/client/src/app/site/projector/projector.module.ts b/client/src/app/site/projector/projector.module.ts index 571490314..3c884c8d2 100644 --- a/client/src/app/site/projector/projector.module.ts +++ b/client/src/app/site/projector/projector.module.ts @@ -5,18 +5,19 @@ import { ProjectorRoutingModule } from './projector-routing.module'; import { SharedModule } from '../../shared/shared.module'; import { ProjectorListComponent } from './components/projector-list/projector-list.component'; import { ProjectorDetailComponent } from './components/projector-detail/projector-detail.component'; -import { CountdownListComponent } from './components/countdown-list/countdown-list.component'; import { ProjectorMessageListComponent } from './components/projector-message-list/projector-message-list.component'; import { CountdownControlsComponent } from './components/countdown-controls/countdown-controls.component'; +import { CountdownDialogComponent } from './components/countdown-dialog/countdown-dialog.component'; @NgModule({ imports: [CommonModule, ProjectorRoutingModule, SharedModule], declarations: [ ProjectorListComponent, ProjectorDetailComponent, - CountdownListComponent, ProjectorMessageListComponent, - CountdownControlsComponent - ] + CountdownControlsComponent, + CountdownDialogComponent + ], + entryComponents: [CountdownDialogComponent] }) export class ProjectorModule {} diff --git a/client/src/assets/styles/global-components-style.scss b/client/src/assets/styles/global-components-style.scss index c35824b5b..ca569a513 100644 --- a/client/src/assets/styles/global-components-style.scss +++ b/client/src/assets/styles/global-components-style.scss @@ -11,7 +11,8 @@ $foreground: map-get($theme, foreground); $background: map-get($theme, background); - h1, h3.accent { + h1, + h3.accent { color: mat-color($primary); } @@ -19,7 +20,8 @@ color: mat-color($primary); } - .accent, .accent-text { + .accent, + .accent-text { color: mat-color($accent); } @@ -27,10 +29,6 @@ color: mat-color($primary); } - .projected .mat-icon { - color: mat-color($primary); - } - //custom table header for search button, filtering and more. Used in ListViews .custom-table-header { background: mat-color($background, background); @@ -42,7 +40,9 @@ font-size: 75%; display: block; } - .error, .warn { + + .error, + .warn { color: mat-color($warn); } diff --git a/client/src/assets/styles/openslides-green-theme.scss b/client/src/assets/styles/openslides-green-theme.scss index 456d9c13e..4db30c22a 100644 --- a/client/src/assets/styles/openslides-green-theme.scss +++ b/client/src/assets/styles/openslides-green-theme.scss @@ -35,8 +35,4 @@ $openslides-primary: mat-palette($openslides-green); $openslides-accent: mat-palette($mat-amber); $openslides-warn: mat-palette($mat-red); -$openslides-green-theme: mat-light-theme( - $openslides-primary, - $openslides-accent, - $openslides-warn -) +$openslides-green-theme: mat-light-theme($openslides-primary, $openslides-accent, $openslides-warn); diff --git a/client/src/styles.scss b/client/src/styles.scss index e93afef84..347f9609f 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -651,7 +651,6 @@ button.mat-menu-item.selected { z-index: 2; } - .queue { .mat-expansion-panel-body { padding: 0 !important;