Merge pull request #4419 from MaximilianKrambach/countdown

countdown: new title field, description made optional
This commit is contained in:
Finn Stutzenstein 2019-03-01 12:02:50 +01:00 committed by GitHub
commit 69fe4632f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 125 additions and 37 deletions

View File

@ -8,7 +8,8 @@ export class Countdown extends BaseModel<Countdown> {
public static COLLECTIONSTRING = 'core/countdown'; public static COLLECTIONSTRING = 'core/countdown';
public id: number; public id: number;
public description: string; public description?: string;
public title: string;
public default_time: number; public default_time: number;
public countdown_time: number; public countdown_time: number;
public running: boolean; public running: boolean;

View File

@ -64,7 +64,7 @@ export class ViewTopic extends BaseAgendaViewModel {
} }
public getTitle = () => { public getTitle = () => {
if (this.agendaItem) { if (this.agendaItem && this.agendaItem.itemNumber) {
return this.agendaItem.itemNumber + ' · ' + this.title; return this.agendaItem.itemNumber + ' · ' + this.title;
} else { } else {
return this.title; return this.title;

View File

@ -9,18 +9,23 @@
<mat-card *ngIf="countdownToCreate"> <mat-card *ngIf="countdownToCreate">
<mat-card-title translate>New countdown</mat-card-title> <mat-card-title translate>New countdown</mat-card-title>
<mat-card-content> <mat-card-content>
<form [formGroup]="createForm" <form [formGroup]="createForm" (keydown)="onKeyDownCreate($event)">
(keydown)="onKeyDownCreate($event)">
<p> <p>
<mat-form-field> <mat-form-field>
<input formControlName="description" matInput placeholder="{{'Description' | translate}}" required> <input formControlName="title" matInput placeholder="{{ 'Title' | translate }}" required />
<mat-hint *ngIf="!createForm.controls.description.valid"> <mat-hint *ngIf="!createForm.controls.title.valid">
<span translate>Required</span> <span translate>Required</span>
</mat-hint> </mat-hint>
</mat-form-field> </mat-form-field>
</p><p> </p>
<p>
<mat-form-field> <mat-form-field>
<input formControlName="default_time" matInput placeholder="{{ 'Time' | translate}}" required> <input formControlName="description" matInput placeholder="{{ 'Description' | translate }}" />
</mat-form-field>
</p>
<p>
<mat-form-field>
<input formControlName="default_time" matInput placeholder="{{ 'Time' | translate }}" required />
<mat-hint *ngIf="!createForm.controls.default_time.valid"> <mat-hint *ngIf="!createForm.controls.default_time.valid">
<span translate>Required</span> <span translate>Required</span>
</mat-hint> </mat-hint>
@ -39,9 +44,13 @@
</mat-card> </mat-card>
<mat-accordion class="os-card"> <mat-accordion class="os-card">
<mat-expansion-panel *ngFor="let countdown of countdowns" (opened)="openId = countdown.id" <mat-expansion-panel
(closed)="panelClosed(countdown)" [expanded]="openId === countdown.id" multiple="false"> *ngFor="let countdown of countdowns"
(opened)="openId = countdown.id"
(closed)="panelClosed(countdown)"
[expanded]="openId === countdown.id"
multiple="false"
>
<!-- Projector button and countdown description--> <!-- Projector button and countdown description-->
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
@ -50,7 +59,7 @@
<os-projector-button [object]="countdown"></os-projector-button> <os-projector-button [object]="countdown"></os-projector-button>
</div> </div>
<div class="header-name"> <div class="header-name">
{{ countdown.description }} {{ countdown.getTitle() | translate }}
</div> </div>
<div class="header-controls"> <div class="header-controls">
<os-countdown-controls [countdown]="countdown"></os-countdown-controls> <os-countdown-controls [countdown]="countdown"></os-countdown-controls>
@ -58,20 +67,28 @@
</div> </div>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<form [formGroup]="updateForm" <form [formGroup]="updateForm" *ngIf="editId === countdown.id" (keydown)="onKeyDownUpdate($event)">
*ngIf="editId === countdown.id"
(keydown)="onKeyDownUpdate($event)">
<h5 translate>Edit countdown</h5> <h5 translate>Edit countdown</h5>
<p> <p>
<mat-form-field> <mat-form-field>
<input formControlName="description" matInput placeholder="{{ 'Description' | translate}}" required> <input formControlName="title" matInput placeholder="{{ 'Title' | translate }}" required />
<mat-hint *ngIf="!updateForm.controls.description.valid"> <mat-hint *ngIf="!updateForm.controls.title.valid">
<span translate>Required</span> <span translate>Required</span>
</mat-hint> </mat-hint>
</mat-form-field> </mat-form-field>
</p><p> </p>
<p>
<mat-form-field> <mat-form-field>
<input formControlName="default_time" matInput placeholder="{{ 'Time' | translate}}" required> <input
formControlName="description"
matInput
placeholder="{{ 'Description' | translate }}"
/>
</mat-form-field>
</p>
<p>
<mat-form-field>
<input formControlName="default_time" matInput placeholder="{{ 'Time' | translate }}" required />
<mat-hint *ngIf="!updateForm.controls.default_time.valid"> <mat-hint *ngIf="!updateForm.controls.default_time.valid">
<span translate>Required</span> <span translate>Required</span>
</mat-hint> </mat-hint>
@ -79,19 +96,34 @@
</p> </p>
</form> </form>
<mat-action-row> <mat-action-row>
<button *ngIf="editId !== countdown.id" mat-button class="on-transition-fade" (click)="onEditButton(countdown)" <button
mat-icon-button> *ngIf="editId !== countdown.id"
mat-button
class="on-transition-fade"
(click)="onEditButton(countdown)"
mat-icon-button
>
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
<button *ngIf="editId === countdown.id" mat-button class="on-transition-fade" (click)="onCancelUpdate()" <button
mat-icon-button> *ngIf="editId === countdown.id"
mat-button
class="on-transition-fade"
(click)="onCancelUpdate()"
mat-icon-button
>
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
<button *ngIf="editId === countdown.id" mat-button class="on-transition-fade" (click)="onSaveButton(countdown)" <button
mat-icon-button> *ngIf="editId === countdown.id"
mat-button
class="on-transition-fade"
(click)="onSaveButton(countdown)"
mat-icon-button
>
<mat-icon>save</mat-icon> <mat-icon>save</mat-icon>
</button> </button>
<button mat-button class='on-transition-fade' (click)=onDeleteButton(countdown) mat-icon-button> <button mat-button class="on-transition-fade" (click)="onDeleteButton(countdown)" mat-icon-button>
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
</mat-action-row> </mat-action-row>

View File

@ -50,8 +50,9 @@ export class CountdownListComponent extends BaseViewComponent implements OnInit
super(titleService, translate, matSnackBar); super(titleService, translate, matSnackBar);
const form = { const form = {
description: ['', Validators.required], description: [''],
default_time: ['', Validators.required] default_time: ['', Validators.required],
title: ['', Validators.required]
}; };
this.createForm = this.formBuilder.group(form); this.createForm = this.formBuilder.group(form);
this.updateForm = this.formBuilder.group(form); this.updateForm = this.formBuilder.group(form);
@ -77,6 +78,7 @@ export class CountdownListComponent extends BaseViewComponent implements OnInit
this.createForm.reset(); this.createForm.reset();
this.createForm.setValue({ this.createForm.setValue({
description: '', description: '',
title: '',
default_time: '1:00 m' default_time: '1:00 m'
}); });
this.countdownToCreate = new Countdown(); this.countdownToCreate = new Countdown();
@ -95,6 +97,7 @@ export class CountdownListComponent extends BaseViewComponent implements OnInit
const newValues: Partial<Countdown> = { const newValues: Partial<Countdown> = {
description: this.createForm.value.description, description: this.createForm.value.description,
title: this.createForm.value.title,
default_time: default_time default_time: default_time
}; };
newValues.countdown_time = default_time; newValues.countdown_time = default_time;
@ -114,6 +117,7 @@ export class CountdownListComponent extends BaseViewComponent implements OnInit
this.updateForm.setValue({ this.updateForm.setValue({
description: countdown.description, description: countdown.description,
title: this.translate.instant(countdown.title),
default_time: this.durationService.durationToString(countdown.default_time, 'm') default_time: this.durationService.durationToString(countdown.default_time, 'm')
}); });
} }
@ -129,6 +133,7 @@ export class CountdownListComponent extends BaseViewComponent implements OnInit
default_time = 60; default_time = 60;
} }
const newValues: Partial<Countdown> = { const newValues: Partial<Countdown> = {
title: this.updateForm.value.title,
description: this.updateForm.value.description, description: this.updateForm.value.description,
default_time: default_time default_time: default_time
}; };
@ -147,7 +152,7 @@ export class CountdownListComponent extends BaseViewComponent implements OnInit
* @param countdown The countdown to delete * @param countdown The countdown to delete
*/ */
public async onDeleteButton(countdown: ViewCountdown): Promise<void> { public async onDeleteButton(countdown: ViewCountdown): Promise<void> {
const content = this.translate.instant('Delete countdown') + ` ${countdown.description}?`; const content = this.translate.instant('Delete countdown') + ` ${this.translate.instant(countdown.title)}?`;
if (await this.promptService.open('Are you sure?', content)) { if (await this.promptService.open('Are you sure?', content)) {
this.repo.delete(countdown).then(() => (this.openId = this.editId = null), this.raiseError); this.repo.delete(countdown).then(() => (this.openId = this.editId = null), this.raiseError);
} }

View File

@ -14,7 +14,6 @@
</a> </a>
<!-- Controls under the projector preview --> <!-- Controls under the projector preview -->
<div class="control-group projector-controls"> <div class="control-group projector-controls">
<!-- scale up --> <!-- scale up -->
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Up)"> <button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Up)">
<mat-icon>zoom_in</mat-icon> <mat-icon>zoom_in</mat-icon>
@ -44,7 +43,6 @@
</button> </button>
<!-- scroll indicator --> <!-- scroll indicator -->
<div class="button-size" [ngClass]="projector.scroll != 0 ? 'warn' : ''">{{ projector.scroll }}</div> <div class="button-size" [ngClass]="projector.scroll != 0 ? 'warn' : ''">{{ projector.scroll }}</div>
</div> </div>
</div> </div>
<div class="column-right" *osPerms="'core.can_manage_projector'"> <div class="column-right" *osPerms="'core.can_manage_projector'">
@ -73,7 +71,10 @@
<div> <div>
<div *ngIf="projector.non_stable_elements.length"> <div *ngIf="projector.non_stable_elements.length">
<mat-list> <mat-list>
<mat-list-item *ngFor="let element of projector.non_stable_elements" class="currentElement backgroundColorAccent"> <mat-list-item
*ngFor="let element of projector.non_stable_elements"
class="currentElement backgroundColorAccent"
>
<button type="button" mat-icon-button (click)="unprojectCurrent(element)"> <button type="button" mat-icon-button (click)="unprojectCurrent(element)">
<mat-icon>videocam</mat-icon> <mat-icon>videocam</mat-icon>
</button> </button>
@ -96,7 +97,6 @@
<mat-expansion-panel-header> <mat-expansion-panel-header>
<span translate>Queue</span> <span translate>Queue</span>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div <div
cdkDropList cdkDropList
class="drop-list" class="drop-list"
@ -161,7 +161,7 @@
<button type="button" mat-icon-button (click)="project(countdown)"> <button type="button" mat-icon-button (click)="project(countdown)">
<mat-icon>videocam</mat-icon> <mat-icon>videocam</mat-icon>
</button> </button>
{{ countdown.description }} {{ countdown.getTitle() | translate }}
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>
<mat-action-row> <mat-action-row>

View File

@ -29,7 +29,11 @@ export class ViewCountdown extends BaseProjectableViewModel {
} }
public get description(): string { public get description(): string {
return this.countdown.description; return this.countdown.description || '';
}
public get title(): string {
return this.countdown.title;
} }
/** /**
@ -42,8 +46,12 @@ export class ViewCountdown extends BaseProjectableViewModel {
this._countdown = countdown; this._countdown = countdown;
} }
/**
* @returns a title for the countdown, consisting of the title and additional
* text info that may be displayed on the projector
*/
public getTitle = () => { public getTitle = () => {
return this.description; return this.description ? `${this.title} (${this.description})` : this.title;
}; };
public updateDependencies(update: BaseViewModel): void {} public updateDependencies(update: BaseViewModel): void {}

View File

@ -423,6 +423,7 @@ class Speaker(RESTModelMixin, models.Model):
pk=1, pk=1,
defaults={ defaults={
"default_time": config["projector_default_countdown"], "default_time": config["projector_default_countdown"],
"title": "Default countdown",
"countdown_time": config["projector_default_countdown"], "countdown_time": config["projector_default_countdown"],
}, },
) )

View File

@ -0,0 +1,15 @@
# Generated by Django 2.1.5 on 2019-02-27 11:17
from django.db import migrations
def delete_old_countdowns(apps, schema_editor):
Countdowns = apps.get_model("core", "countdown")
Countdowns.objects.all().delete()
class Migration(migrations.Migration):
dependencies = [("core", "0018_auto_20190222_1209")]
operations = [migrations.RunPython(delete_old_countdowns)]

View File

@ -0,0 +1,16 @@
# Generated by Django 2.1.5 on 2019-02-27 11:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [("core", "0019_countdown_title_1")]
operations = [
migrations.AddField(
model_name="countdown",
name="title",
field=models.CharField(max_length=256, unique=True),
)
]

View File

@ -232,6 +232,8 @@ class Countdown(RESTModelMixin, models.Model):
access_permissions = CountdownAccessPermissions() access_permissions = CountdownAccessPermissions()
title = models.CharField(max_length=256, unique=True, default="")
description = models.CharField(max_length=256, blank=True) description = models.CharField(max_length=256, blank=True)
running = models.BooleanField(default=False) running = models.BooleanField(default=False)

View File

@ -165,7 +165,15 @@ class CountdownSerializer(ModelSerializer):
class Meta: class Meta:
model = Countdown model = Countdown
fields = ("id", "description", "default_time", "countdown_time", "running") fields = (
"id",
"title",
"description",
"default_time",
"countdown_time",
"running",
)
unique_together = ("title",)
class HistorySerializer(ModelSerializer): class HistorySerializer(ModelSerializer):