new song GUI
This commit is contained in:
@@ -21,9 +21,11 @@ import { TableComponent } from './components/songs/table/table.component';
|
|||||||
import { SongsComponent } from './components/songs/songs.component';
|
import { SongsComponent } from './components/songs/songs.component';
|
||||||
import { SongComponent } from './components/songs/song/song.component';
|
import { SongComponent } from './components/songs/song/song.component';
|
||||||
import { SongEditComponent } from './components/songs/song-edit/song-edit.component';
|
import { SongEditComponent } from './components/songs/song-edit/song-edit.component';
|
||||||
|
import { SongNewComponent } from './components/songs/song-new/song-new.component';
|
||||||
|
import { SongFormComponent } from './components/songs/song-form/song-form.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent, SongsComponent, TableComponent, SongComponent, SongEditComponent],
|
declarations: [AppComponent, SongsComponent, TableComponent, SongComponent, SongEditComponent, SongNewComponent, SongFormComponent],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
|
|||||||
@@ -1,61 +1,18 @@
|
|||||||
<div class="song-detail-container">
|
<div class="song-detail-container">
|
||||||
<mat-card class="mat-elevation-z8" [@blend] *ngIf="form">
|
<mat-card class="mat-elevation-z8" *ngIf="form">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<div mat-card-avatar>
|
<div mat-card-avatar>
|
||||||
<button mat-icon-button (click)="onBack()">
|
<button mat-icon-button (click)="onBack()" color="warn">
|
||||||
<fa-icon [icon]="faArrow"></fa-icon>
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<mat-card-title>Titel bearbeiten</mat-card-title>
|
<mat-card-title>Titel bearbeiten</mat-card-title>
|
||||||
<mat-card-subtitle>Daten werden nach der Eingabe automatisch gespeichert</mat-card-subtitle>
|
<mat-card-subtitle>
|
||||||
|
Daten werden nach der Eingabe automatisch gespeichert
|
||||||
|
</mat-card-subtitle>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<form>
|
<app-song-form [form]="form"></app-song-form>
|
||||||
<mat-form-field>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
placeholder="Titel"
|
|
||||||
[formControl]="form.controls.Name"
|
|
||||||
/>
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="row">
|
|
||||||
<mat-radio-group [formControl]="form.controls.SongType">
|
|
||||||
<mat-radio-button value="Praise">Lobpreis</mat-radio-button>
|
|
||||||
<mat-radio-button value="Worship">Anbetung</mat-radio-button>
|
|
||||||
</mat-radio-group>
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>Tonart</mat-label>
|
|
||||||
<mat-select [formControl]="form.controls.Key">
|
|
||||||
<mat-option *ngFor="let key of keys" [value]="key">
|
|
||||||
{{ key }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
placeholder="Tempo"
|
|
||||||
[formControl]="form.controls.Tempo"
|
|
||||||
/>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<mat-form-field>
|
|
||||||
<textarea
|
|
||||||
matInput
|
|
||||||
placeholder="Liedtext"
|
|
||||||
[formControl]="form.controls.Text"
|
|
||||||
[matTextareaAutosize]="true"
|
|
||||||
></textarea>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<textarea
|
|
||||||
matInput
|
|
||||||
placeholder="Kommentare"
|
|
||||||
[formControl]="form.controls.Comments"
|
|
||||||
[matTextareaAutosize]="true"
|
|
||||||
></textarea>
|
|
||||||
</mat-form-field>
|
|
||||||
</form>
|
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<!-- <mat-card-actions>
|
<!-- <mat-card-actions>
|
||||||
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
form {
|
:host {
|
||||||
display: flex;
|
display: block;
|
||||||
flex-direction: column;
|
}
|
||||||
.row {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 2fr 1fr 1fr;
|
|
||||||
grid-column-gap: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,56 +6,20 @@ import {
|
|||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef
|
ChangeDetectorRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { blend } from 'src/app/services/animation';
|
|
||||||
import { EditSongService } from 'src/app/data/edit-song.service';
|
import { EditSongService } from 'src/app/data/edit-song.service';
|
||||||
import { faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons';
|
import { faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { State } from 'src/app/data/state';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song-edit',
|
selector: 'app-song-edit',
|
||||||
templateUrl: './song-edit.component.html',
|
templateUrl: './song-edit.component.html',
|
||||||
styleUrls: ['./song-edit.component.less'],
|
styleUrls: ['./song-edit.component.less'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
animations: [blend]
|
|
||||||
})
|
})
|
||||||
export class SongEditComponent implements OnInit {
|
export class SongEditComponent implements OnInit {
|
||||||
public form: FormGroup = null;
|
public form: FormGroup = null;
|
||||||
public faArrow = faLongArrowAltLeft;
|
public faArrow = faLongArrowAltLeft;
|
||||||
public keys = [
|
|
||||||
'C',
|
|
||||||
'C#',
|
|
||||||
'Db',
|
|
||||||
'D',
|
|
||||||
'D#',
|
|
||||||
'Eb',
|
|
||||||
'E',
|
|
||||||
'F',
|
|
||||||
'F#',
|
|
||||||
'Gb',
|
|
||||||
'G',
|
|
||||||
'G#',
|
|
||||||
'Ab',
|
|
||||||
'A',
|
|
||||||
'A#',
|
|
||||||
'B',
|
|
||||||
'H',
|
|
||||||
'c',
|
|
||||||
'c#',
|
|
||||||
'db',
|
|
||||||
'd',
|
|
||||||
'd#',
|
|
||||||
'eb',
|
|
||||||
'e',
|
|
||||||
'f',
|
|
||||||
'f#',
|
|
||||||
'gb',
|
|
||||||
'g',
|
|
||||||
'g#',
|
|
||||||
'ab',
|
|
||||||
'a',
|
|
||||||
'A#',
|
|
||||||
'b',
|
|
||||||
'h'
|
|
||||||
];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private editSongService: EditSongService,
|
private editSongService: EditSongService,
|
||||||
@@ -64,11 +28,11 @@ export class SongEditComponent implements OnInit {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.form = this.editSongService.initEditForm();
|
this.form = this.editSongService.initEditForm(true);
|
||||||
this.change.markForCheck();
|
this.change.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onBack(): void {
|
public onBack(): void {
|
||||||
this.songsService.edit = false;
|
this.songsService.state = State.read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
WEB/src/app/components/songs/song-form/keys.ts
Normal file
36
WEB/src/app/components/songs/song-form/keys.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
export const keys = [
|
||||||
|
'C',
|
||||||
|
'C#',
|
||||||
|
'Db',
|
||||||
|
'D',
|
||||||
|
'D#',
|
||||||
|
'Eb',
|
||||||
|
'E',
|
||||||
|
'F',
|
||||||
|
'F#',
|
||||||
|
'Gb',
|
||||||
|
'G',
|
||||||
|
'G#',
|
||||||
|
'Ab',
|
||||||
|
'A',
|
||||||
|
'A#',
|
||||||
|
'B',
|
||||||
|
'H',
|
||||||
|
'c',
|
||||||
|
'c#',
|
||||||
|
'db',
|
||||||
|
'd',
|
||||||
|
'd#',
|
||||||
|
'eb',
|
||||||
|
'e',
|
||||||
|
'f',
|
||||||
|
'f#',
|
||||||
|
'gb',
|
||||||
|
'g',
|
||||||
|
'g#',
|
||||||
|
'ab',
|
||||||
|
'a',
|
||||||
|
'A#',
|
||||||
|
'b',
|
||||||
|
'h'
|
||||||
|
];
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<form>
|
||||||
|
<mat-form-field>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
placeholder="Titel"
|
||||||
|
[formControl]="form.controls.Name"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
|
<div class="row">
|
||||||
|
<mat-radio-group [formControl]="form.controls.SongType">
|
||||||
|
<mat-radio-button value="Praise">Lobpreis</mat-radio-button>
|
||||||
|
<mat-radio-button value="Worship">Anbetung</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
<mat-form-field>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
placeholder="Nummer"
|
||||||
|
[formControl]="form.controls.Number"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Tonart</mat-label>
|
||||||
|
<mat-select [formControl]="form.controls.Key">
|
||||||
|
<mat-option *ngFor="let key of keys" [value]="key">
|
||||||
|
{{ key }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
placeholder="Tempo"
|
||||||
|
[formControl]="form.controls.Tempo"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<mat-form-field>
|
||||||
|
<textarea
|
||||||
|
matInput
|
||||||
|
placeholder="Liedtext"
|
||||||
|
[formControl]="form.controls.Text"
|
||||||
|
[matTextareaAutosize]="true"
|
||||||
|
></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<textarea
|
||||||
|
matInput
|
||||||
|
placeholder="Kommentare"
|
||||||
|
[formControl]="form.controls.Comments"
|
||||||
|
[matTextareaAutosize]="true"
|
||||||
|
></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 3fr 1fr 1fr 1fr;
|
||||||
|
grid-column-gap: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { keys } from './keys';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-song-form',
|
||||||
|
templateUrl: './song-form.component.html',
|
||||||
|
styleUrls: ['./song-form.component.less']
|
||||||
|
})
|
||||||
|
export class SongFormComponent {
|
||||||
|
@Input() public form: FormGroup;
|
||||||
|
public keys = keys;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<div class="song-detail-container">
|
||||||
|
<mat-card class="mat-elevation-z8" *ngIf="form">
|
||||||
|
<mat-card-header>
|
||||||
|
<div mat-card-avatar>
|
||||||
|
<button mat-icon-button (click)="onBack()" color="warn">
|
||||||
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<mat-card-title>Neuen Titel anlegen</mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
</mat-card-subtitle>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<app-song-form [form]="form"></app-song-form>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
<button mat-button (click)="onClickEdit()">
|
||||||
|
<fa-icon [icon]="faSave"></fa-icon> Speichern
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
34
WEB/src/app/components/songs/song-new/song-new.component.ts
Normal file
34
WEB/src/app/components/songs/song-new/song-new.component.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { EditSongService } from './../../../data/edit-song.service';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { faLongArrowAltLeft, faSave } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { State } from 'src/app/data/state';
|
||||||
|
import { SongsService } from 'src/app/data/songs.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-song-new',
|
||||||
|
templateUrl: './song-new.component.html',
|
||||||
|
styleUrls: ['./song-new.component.less'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class SongNewComponent implements OnInit {
|
||||||
|
public faArrow = faLongArrowAltLeft;
|
||||||
|
public faSave = faSave;
|
||||||
|
public form: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private editSongService: EditSongService,
|
||||||
|
private songsService: SongsService,
|
||||||
|
private change: ChangeDetectorRef
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.form = this.editSongService.initEditForm(false);
|
||||||
|
this.change.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onBack(): void {
|
||||||
|
this.songsService.state = State.list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<div class="song-detail-container">
|
<div class="song-detail-container" *ngIf="song">
|
||||||
<mat-card class="mat-elevation-z8" [@blend] *ngIf="selectedSongId !== 0">
|
<mat-card class="mat-elevation-z8">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<div mat-card-avatar>
|
<div mat-card-avatar>
|
||||||
<button mat-icon-button (click)="onBack()">
|
<button mat-icon-button (click)="onBack()" color="warn">
|
||||||
<fa-icon [icon]="faArrow"></fa-icon>
|
<fa-icon [icon]="faArrow"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
<p *ngFor="let line of comments">{{ line }}</p>
|
<p *ngFor="let line of comments">{{ line }}</p>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions>
|
<mat-card-actions>
|
||||||
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
|
||||||
<button mat-button (click)="onClickEdit()">
|
<button mat-button (click)="onClickEdit()">
|
||||||
<fa-icon [icon]="faEdit"></fa-icon> Bearbeiten
|
<fa-icon [icon]="faEdit"></fa-icon> Bearbeiten
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: 10px;
|
min-height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ import {
|
|||||||
import { faLongArrowAltLeft, faEdit } from '@fortawesome/free-solid-svg-icons';
|
import { faLongArrowAltLeft, faEdit } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { Song } from 'src/app/models/song.model';
|
import { Song } from 'src/app/models/song.model';
|
||||||
import { DownloadService } from 'src/app/data/download.service';
|
import { DownloadService } from 'src/app/data/download.service';
|
||||||
import { blend } from 'src/app/services/animation';
|
import { State } from 'src/app/data/state';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-song',
|
selector: 'app-song',
|
||||||
templateUrl: './song.component.html',
|
templateUrl: './song.component.html',
|
||||||
styleUrls: ['./song.component.less'],
|
styleUrls: ['./song.component.less'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
animations: [blend]
|
|
||||||
})
|
})
|
||||||
export class SongComponent {
|
export class SongComponent {
|
||||||
public song: Song;
|
public song: Song;
|
||||||
@@ -48,14 +47,14 @@ export class SongComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onClickEdit(): void {
|
public onClickEdit(): void {
|
||||||
this.songService.edit = true;
|
this.songService.state = State.edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get text(): string[] {
|
public get text(): string[] {
|
||||||
return this.song.Text ? this.song.Text.split(/\r?\n/) : [];
|
return this.song && this.song.Text ? this.song.Text.split(/\r?\n/) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public get comments(): string[] {
|
public get comments(): string[] {
|
||||||
return this.song.Comments ? this.song.Comments.split(/\r?\n/) : [];
|
return this.song && this.song.Comments ? this.song.Comments.split(/\r?\n/) : [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
<app-table></app-table>
|
<app-table></app-table>
|
||||||
<app-song *ngIf="!songsService.edit"></app-song>
|
<app-song [@blend] *ngIf="songsService.state === State.read"></app-song>
|
||||||
<app-song-edit *ngIf="songsService.edit"></app-song-edit>
|
<app-song-edit [@blend] *ngIf="songsService.state === State.edit"></app-song-edit>
|
||||||
|
<app-song-new [@blend] *ngIf="songsService.state === State.new"></app-song-new>
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
|
import { blend } from 'src/app/services/animation';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { SongsService } from 'src/app/data/songs.service';
|
import { SongsService } from 'src/app/data/songs.service';
|
||||||
|
import { State } from 'src/app/data/state';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-songs',
|
selector: 'app-songs',
|
||||||
templateUrl: './songs.component.html',
|
templateUrl: './songs.component.html',
|
||||||
styleUrls: ['./songs.component.less']
|
styleUrls: ['./songs.component.less'],
|
||||||
|
animations: [blend]
|
||||||
})
|
})
|
||||||
export class SongsComponent {
|
export class SongsComponent {
|
||||||
|
public State = State;
|
||||||
constructor(public songsService: SongsService) {
|
constructor(public songsService: SongsService) {
|
||||||
songsService.loadSongList();
|
songsService.loadSongList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<div
|
<div
|
||||||
class="page-container mat-elevation-z8"
|
class="page-container mat-elevation-z8"
|
||||||
[class.pinned]="selectedSongId !== 0"
|
[class.pinned]="songsService.state !== State.list"
|
||||||
>
|
>
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
|
<button mat-icon-button (click)="onClickNew()" class="button-new"><fa-icon [icon]="faNew"></fa-icon></button>
|
||||||
<table
|
<table
|
||||||
mat-table
|
mat-table
|
||||||
[dataSource]="songsService.songs | async"
|
[dataSource]="songsService.songs | async"
|
||||||
|
|||||||
@@ -10,4 +10,16 @@ table {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-new {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 5px;
|
||||||
|
font-size: 2em;
|
||||||
|
z-index: 1000;
|
||||||
|
color: #aaa;
|
||||||
|
&:hover {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import {
|
|||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef
|
ChangeDetectorRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import { State } from 'src/app/data/state';
|
||||||
|
import { faFileMedical } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-table',
|
selector: 'app-table',
|
||||||
@@ -13,10 +15,12 @@ import {
|
|||||||
})
|
})
|
||||||
export class TableComponent {
|
export class TableComponent {
|
||||||
public selectedSongId = 0;
|
public selectedSongId = 0;
|
||||||
|
public State = State;
|
||||||
|
public faNew = faFileMedical;
|
||||||
public columnsFull = ['Number', 'Name', 'Key', 'SongType', 'Tempo'];
|
public columnsFull = ['Number', 'Name', 'Key', 'SongType', 'Tempo'];
|
||||||
public columnsPinned = ['Number', 'Name'];
|
public columnsPinned = ['Number', 'Name'];
|
||||||
public get columns(): string[] {
|
public get columns(): string[] {
|
||||||
return this.selectedSongId === 0 ? this.columnsFull : this.columnsPinned;
|
return this.songsService.state === State.list ? this.columnsFull : this.columnsPinned;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -42,4 +46,11 @@ export class TableComponent {
|
|||||||
this.songsService.selectSong(id);
|
this.songsService.selectSong(id);
|
||||||
this.change.detectChanges();
|
this.change.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onClickNew(): void {
|
||||||
|
this.songsService.selectSong(null);
|
||||||
|
this.songsService.state = State.new;
|
||||||
|
this.change.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { SongsService } from 'src/app/data/songs.service';
|
import { SongsService } from 'src/app/data/songs.service';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||||
import { switchMap, tap } from 'rxjs/operators';
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
import { Song } from '../models/song.model';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -10,7 +11,7 @@ export class EditSongService {
|
|||||||
constructor(private songsService: SongsService) {}
|
constructor(private songsService: SongsService) {}
|
||||||
|
|
||||||
public initEditForm(attachSync: boolean): FormGroup {
|
public initEditForm(attachSync: boolean): FormGroup {
|
||||||
const song = this.songsService.selectedSong.value;
|
const song = attachSync ? this.songsService.selectedSong.value : this.defaultValues();
|
||||||
const form = new FormGroup({
|
const form = new FormGroup({
|
||||||
Number: new FormControl(song.Number, {
|
Number: new FormControl(song.Number, {
|
||||||
updateOn: 'blur',
|
updateOn: 'blur',
|
||||||
@@ -25,7 +26,10 @@ export class EditSongService {
|
|||||||
updateOn: 'blur',
|
updateOn: 'blur',
|
||||||
validators: Validators.required
|
validators: Validators.required
|
||||||
}),
|
}),
|
||||||
Key: new FormControl(song.Key, { updateOn: 'blur' }),
|
Key: new FormControl(song.Key, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: Validators.required
|
||||||
|
}),
|
||||||
Tempo: new FormControl(song.Tempo, { updateOn: 'blur' }),
|
Tempo: new FormControl(song.Tempo, { updateOn: 'blur' }),
|
||||||
Comments: new FormControl(song.Comments, { updateOn: 'blur' }),
|
Comments: new FormControl(song.Comments, { updateOn: 'blur' }),
|
||||||
});
|
});
|
||||||
@@ -35,10 +39,33 @@ export class EditSongService {
|
|||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachSync(form: FormGroup, song: import("/Users/benjamin/src/wgenerator/WEB/src/app/models/song.model").Song) {
|
private attachSync(form: FormGroup, song: Song) {
|
||||||
const controls = Object.keys(form.controls);
|
const controls = Object.keys(form.controls);
|
||||||
controls.forEach(control => {
|
controls.forEach(control => {
|
||||||
form.controls[control].valueChanges.pipe(switchMap(value => this.songsService.patch(song.ID, control, value))).subscribe();
|
form.controls[control].valueChanges.pipe(switchMap(value => this.songsService.patch(song.ID, control, value))).subscribe();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private defaultValues(): Song {
|
||||||
|
const song: Song = {
|
||||||
|
ID: null,
|
||||||
|
Number: this.firstFreeNumber(),
|
||||||
|
Name: null,
|
||||||
|
Tempo: null,
|
||||||
|
Text: null,
|
||||||
|
SongType: null,
|
||||||
|
Key: null,
|
||||||
|
Comments: null,
|
||||||
|
Final: false
|
||||||
|
};
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
private firstFreeNumber(): number {
|
||||||
|
let number = 0;
|
||||||
|
const numbers = this.songsService.songs.value.map(_ => _.Number);
|
||||||
|
while (numbers.indexOf(++number) !== -1) { }
|
||||||
|
return number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import { OdataService } from './odata.service';
|
|||||||
import { Song } from '../models/song.model';
|
import { Song } from '../models/song.model';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
|
import { State } from './state';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class SongsService extends OdataService {
|
export class SongsService extends OdataService {
|
||||||
public edit = false;
|
public state = State.list;
|
||||||
|
|
||||||
public songs: BehaviorSubject<Song[]> = new BehaviorSubject<Song[]>([]);
|
public songs: BehaviorSubject<Song[]> = new BehaviorSubject<Song[]>([]);
|
||||||
public selectedSong: BehaviorSubject<Song> = new BehaviorSubject<Song>(null);
|
public selectedSong: BehaviorSubject<Song> = new BehaviorSubject<Song>(null);
|
||||||
@@ -24,7 +25,7 @@ export class SongsService extends OdataService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public selectSong(id: number): void {
|
public selectSong(id: number): void {
|
||||||
this.edit = false;
|
this.state = State.read;
|
||||||
const filter = this.songs.value.filter(_ => _.ID === id);
|
const filter = this.songs.value.filter(_ => _.ID === id);
|
||||||
const song = filter.length === 1 ? filter[0] : null;
|
const song = filter.length === 1 ? filter[0] : null;
|
||||||
if (!song) {
|
if (!song) {
|
||||||
@@ -39,6 +40,7 @@ export class SongsService extends OdataService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public resetSelectedSong() {
|
public resetSelectedSong() {
|
||||||
|
this.state = State.list;
|
||||||
this.selectedSong.next(null);
|
this.selectedSong.next(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
WEB/src/app/data/state.ts
Normal file
6
WEB/src/app/data/state.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export enum State {
|
||||||
|
read,
|
||||||
|
edit,
|
||||||
|
new,
|
||||||
|
list
|
||||||
|
}
|
||||||
@@ -2,12 +2,12 @@ import { trigger, transition, style, animate } from '@angular/animations';
|
|||||||
|
|
||||||
export const blend = trigger('blend', [
|
export const blend = trigger('blend', [
|
||||||
transition(':enter', [
|
transition(':enter', [
|
||||||
style({ opacity: 0 }),
|
style({ opacity: 0, display: 'none' }),
|
||||||
animate('200ms', style({ opacity: 0 })),
|
animate('400ms', style({ opacity: 0 , display: 'none'})),
|
||||||
animate('300ms', style({ opacity: 1 }))
|
animate('300ms', style({ opacity: 1, display: 'block' }))
|
||||||
]),
|
]),
|
||||||
transition(':leave', [
|
transition(':leave', [
|
||||||
style({ opacity: 1 }),
|
style({ opacity: 1, display: 'block' }),
|
||||||
animate('300ms', style({ opacity: 0 }))
|
animate('300ms', style({ opacity: 0, display: 'none' }))
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -36,18 +36,20 @@ html {
|
|||||||
transition: all 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.selected {
|
tbody {
|
||||||
background-color: #0002;
|
tr.selected {
|
||||||
}
|
background-color: #0002;
|
||||||
tr:hover {
|
}
|
||||||
cursor: pointer;
|
tr:hover {
|
||||||
background-color: #0001;
|
cursor: pointer;
|
||||||
td {
|
background-color: #0001;
|
||||||
color: #ff9900;
|
td {
|
||||||
|
color: #ff9900;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
td.mat-cell {
|
||||||
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
td.mat-cell {
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.pinned {
|
&.pinned {
|
||||||
|
|||||||
Reference in New Issue
Block a user