From 4b931c06d80471db240a06b8b841566ed35b70cd Mon Sep 17 00:00:00 2001 From: smuddyx Date: Sun, 13 Jun 2021 00:00:26 +0200 Subject: [PATCH] better song sorting --- src/app/modules/guest/guest.component.ts | 16 ++- .../presentation/remote/remote.component.html | 5 +- .../presentation/remote/remote.component.less | 9 ++ .../presentation/remote/remote.component.ts | 18 ++- .../shows/services/show-song.service.ts | 5 +- src/app/modules/shows/services/show-song.ts | 1 - .../modules/shows/services/show.service.ts | 1 + src/app/modules/shows/services/show.ts | 1 + .../modules/shows/show/show.component.html | 22 ++-- .../modules/shows/show/show.component.less | 23 ++++ src/app/modules/shows/show/show.component.ts | 16 ++- .../shows/show/song/song.component.html | 20 +--- .../shows/show/song/song.component.less | 6 +- .../modules/shows/show/song/song.component.ts | 109 +++++++++--------- src/app/modules/shows/shows.module.ts | 2 + .../songs/services/transpose.service.ts | 9 +- .../components/add-song/add-song.component.ts | 13 ++- .../song-text/song-text.component.ts | 4 +- 18 files changed, 163 insertions(+), 117 deletions(-) diff --git a/src/app/modules/guest/guest.component.ts b/src/app/modules/guest/guest.component.ts index 1705ce8..d911684 100644 --- a/src/app/modules/guest/guest.component.ts +++ b/src/app/modules/guest/guest.component.ts @@ -5,6 +5,7 @@ import {Observable} from 'rxjs'; import {filter, map, switchMap} from 'rxjs/operators'; import {ShowSongService} from '../shows/services/show-song.service'; import {GlobalSettings} from '../../services/global-settings'; +import {ShowService} from '../shows/services/show.service'; @Component({ selector: 'app-guest', @@ -16,11 +17,16 @@ export class GuestComponent { filter(_ => !!_), map(_ => _ as GlobalSettings), map(_ => _.currentShow), - switchMap(_ => this.showSongService.list$(_)), - filter(_ => !!_), - map(_ => _), - map(_ => _.sort((x, y) => x.order - y.order).map(showSong => showSong.text)) + switchMap(_ => this.showSongService.list$(_).pipe(map(l => ({showSongs: l, currentShow: _})))), + switchMap(_ => this.showService.read$(_.currentShow).pipe(map(l => ({showSongs: _.showSongs, show: l})))), + filter(_ => !!_.showSongs), + map(_ => (_?.show ? _.show.order.map(o => _.showSongs.find(f => f.id === o) ?? _.showSongs[0]).map(m => m.text) : [])) ); - public constructor(private songService: SongService, private globalSettingsService: GlobalSettingsService, private showSongService: ShowSongService) {} + public constructor( + private songService: SongService, + private showService: ShowService, + private globalSettingsService: GlobalSettingsService, + private showSongService: ShowSongService + ) {} } diff --git a/src/app/modules/presentation/remote/remote.component.html b/src/app/modules/presentation/remote/remote.component.html index d6729de..16fad92 100644 --- a/src/app/modules/presentation/remote/remote.component.html +++ b/src/app/modules/presentation/remote/remote.component.html @@ -32,7 +32,7 @@ -
+
@@ -78,9 +79,9 @@ diff --git a/src/app/modules/presentation/remote/remote.component.less b/src/app/modules/presentation/remote/remote.component.less index 1d86479..ba091b6 100644 --- a/src/app/modules/presentation/remote/remote.component.less +++ b/src/app/modules/presentation/remote/remote.component.less @@ -72,3 +72,12 @@ .padding-bottom { padding-bottom: 20px; } + +a { + font-size: 30px; + padding: 10px; + transition: all 300ms ease-in-out; + &:hover { + color: #4286f4; + } +} diff --git a/src/app/modules/presentation/remote/remote.component.ts b/src/app/modules/presentation/remote/remote.component.ts index 70b8218..aa3e721 100644 --- a/src/app/modules/presentation/remote/remote.component.ts +++ b/src/app/modules/presentation/remote/remote.component.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {Observable} from 'rxjs'; +import {combineLatest, Observable} from 'rxjs'; import {Show} from '../../shows/services/show'; import {ShowSongService} from '../../shows/services/show-song.service'; import {SongService} from '../../songs/services/song.service'; @@ -40,6 +40,10 @@ export class RemoteComponent { public faDesktop = faDesktop; public showControl = new FormControl(); + public trackBy(index: number, item: PresentationSong): string { + return item.id; + } + public constructor( private showService: ShowService, private showSongService: ShowSongService, @@ -73,14 +77,18 @@ export class RemoteComponent { await this.showService.update$(change, {presentationSongId: 'title'}); } this.currentShowId = change; - this.showService.read$(change).subscribe(_ => (this.show = _)); - this.showSongService.list$(change).subscribe(_ => { - this.showSongs = _; - this.presentationSongs = _.map(song => ({ + this.showService.read$(change).subscribe(show => { + this.show = show; + }); + + combineLatest([this.showService.read$(change), this.showSongService.list$(change)]).subscribe(([show, list]) => { + this.showSongs = list; + const presentationSongs = list.map(song => ({ id: song.id, title: song.title, sections: this.textRenderingService.parse(song.text, null), })); + this.presentationSongs = show?.order.map(_ => presentationSongs.filter(f => f.id === _)[0]) ?? []; }); await delay(500); this.progress = false; diff --git a/src/app/modules/shows/services/show-song.service.ts b/src/app/modules/shows/services/show-song.service.ts index 6286913..7f7d3d1 100644 --- a/src/app/modules/shows/services/show-song.service.ts +++ b/src/app/modules/shows/services/show-song.service.ts @@ -12,14 +12,13 @@ import {UserService} from '../../../services/user/user.service'; export class ShowSongService { public constructor(private showSongDataService: ShowSongDataService, private songDataService: SongDataService, private userService: UserService) {} - public async new$(showId: string, songId: string, order: number, addedLive = false): Promise { + public async new$(showId: string, songId: string, addedLive = false): Promise { const song = await this.songDataService.read$(songId).pipe(take(1)).toPromise(); const user = await this.userService.user$.pipe(take(1)).toPromise(); if (!song || !user) return null; const data: Partial = { ...song, songId, - order, key: song.key, keyOriginal: song.key, chordMode: user.chordMode, @@ -31,7 +30,7 @@ export class ShowSongService { public read$ = (showId: string, songId: string): Observable => this.showSongDataService.read$(showId, songId); public read = (showId: string, songId: string): Promise => this.read$(showId, songId).pipe(first()).toPromise(); - public list$ = (showId: string): Observable => this.showSongDataService.list$(showId, _ => _.orderBy('order')); + public list$ = (showId: string): Observable => this.showSongDataService.list$(showId); public list = (showId: string): Promise => this.list$(showId).pipe(first()).toPromise(); public delete$ = (showId: string, songId: string): Promise => this.showSongDataService.delete(showId, songId); public update$ = async (showId: string, songId: string, data: Partial): Promise => await this.showSongDataService.update$(showId, songId, data); diff --git a/src/app/modules/shows/services/show-song.ts b/src/app/modules/shows/services/show-song.ts index 4de8be3..3f0961e 100644 --- a/src/app/modules/shows/services/show-song.ts +++ b/src/app/modules/shows/services/show-song.ts @@ -6,7 +6,6 @@ export interface ShowSong extends Song { songId: string; key: string; keyOriginal: string; - order: number; chordMode: ChordMode; addedLive: boolean; } diff --git a/src/app/modules/shows/services/show.service.ts b/src/app/modules/shows/services/show.service.ts index 4db0ae5..389da90 100644 --- a/src/app/modules/shows/services/show.service.ts +++ b/src/app/modules/shows/services/show.service.ts @@ -38,6 +38,7 @@ export class ShowService { const calculatedData: Partial = { ...data, owner: this.user.id, + order: [], public: ShowService.SHOW_TYPE_PUBLIC.indexOf(data.showType) !== -1, }; return await this.showDataService.add(calculatedData); diff --git a/src/app/modules/shows/services/show.ts b/src/app/modules/shows/services/show.ts index c977660..0e23b1a 100644 --- a/src/app/modules/shows/services/show.ts +++ b/src/app/modules/shows/services/show.ts @@ -10,6 +10,7 @@ export interface Show { reported: boolean; published: boolean; archived: boolean; + order: string[]; presentationSongId: string; presentationSection: number; diff --git a/src/app/modules/shows/show/show.component.html b/src/app/modules/shows/show/show.component.html index 6d772a2..34c270b 100644 --- a/src/app/modules/shows/show/show.component.html +++ b/src/app/modules/shows/show/show.component.html @@ -11,22 +11,20 @@

Text anzeigen

-
- +
+
+ +
diff --git a/src/app/modules/shows/show/show.component.less b/src/app/modules/shows/show/show.component.less index da87eac..138aaac 100644 --- a/src/app/modules/shows/show/show.component.less +++ b/src/app/modules/shows/show/show.component.less @@ -3,3 +3,26 @@ border-bottom: 1px solid #0002; } + +.cdk-drag-preview { + background-color: white; + box-sizing: border-box; + border-radius: 4px; + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} + +.cdk-drag-placeholder { + opacity: 0; +} + +.cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +.song-list:last-child { + border: none; +} + +.example-list.cdk-drop-list-dragging .song-list:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} diff --git a/src/app/modules/shows/show/show.component.ts b/src/app/modules/shows/show/show.component.ts index f87d46e..3b5f29f 100644 --- a/src/app/modules/shows/show/show.component.ts +++ b/src/app/modules/shows/show/show.component.ts @@ -16,6 +16,7 @@ import {faLock} from '@fortawesome/free-solid-svg-icons/faLock'; import {faFileDownload} from '@fortawesome/free-solid-svg-icons/faFileDownload'; import {faUser} from '@fortawesome/free-solid-svg-icons/faUser'; import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers'; +import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop'; @Component({ selector: 'app-show', @@ -57,7 +58,8 @@ export class ShowComponent implements OnInit { map(param => param as {showId: string}), map(param => param.showId), switchMap(showId => this.showSongService.list$(showId)), - filter(_ => !!_) + tap(_ => console.log(_)), + filter(_ => !!_ && _.length > 0) ) .subscribe(_ => (this.showSongs = _)); this.songService @@ -101,4 +103,16 @@ export class ShowComponent implements OnInit { copyright: true, }); } + + public async drop(event: CdkDragDrop, show: Show): Promise { + const order = [...show.order]; + moveItemInArray(order, event.previousIndex, event.currentIndex); + await this.showService.update$(show.id, {order}); + } + + public orderedShowSongs(show: Show): ShowSong[] { + const list = this.showSongs; + if (!list) return []; + return show.order.map(_ => list.filter(f => f.id === _)[0]); + } } diff --git a/src/app/modules/shows/show/song/song.component.html b/src/app/modules/shows/show/song/song.component.html index a5d15a4..3c9655a 100644 --- a/src/app/modules/shows/show/song/song.component.html +++ b/src/app/modules/shows/show/song/song.component.html @@ -1,21 +1,11 @@ -
+
{{ iSong.title }}
- - {{ iSong.title }} - {{ showSong.keyOriginal }} → {{ iSong.keyOriginal }} →  @@ -34,9 +24,9 @@
diff --git a/src/app/modules/shows/show/song/song.component.less b/src/app/modules/shows/show/song/song.component.less index 3ba9338..aa34d4b 100644 --- a/src/app/modules/shows/show/song/song.component.less +++ b/src/app/modules/shows/show/song/song.component.less @@ -2,11 +2,11 @@ .song { min-height: 28px; display: grid; - grid-template-columns: 20px 20px auto 70px 25px; + grid-template-columns: auto 70px 25px; @media screen and (max-width: 860px) { - grid-template-columns: 40px 40px auto 70px 45px; + grid-template-columns: auto 70px 45px; } - grid-template-areas: "up down title keys delete"; + grid-template-areas: "title keys delete"; & > * { display: flex; diff --git a/src/app/modules/shows/show/song/song.component.ts b/src/app/modules/shows/show/song/song.component.ts index 091181e..9ce8f86 100644 --- a/src/app/modules/shows/show/song/song.component.ts +++ b/src/app/modules/shows/show/song/song.component.ts @@ -1,5 +1,4 @@ import {Component, Input, OnInit} from '@angular/core'; -import {Song} from '../../../songs/services/song'; import {faTrash} from '@fortawesome/free-solid-svg-icons/faTrash'; import {faCaretUp} from '@fortawesome/free-solid-svg-icons/faCaretUp'; import {faCaretDown} from '@fortawesome/free-solid-svg-icons/faCaretDown'; @@ -17,8 +16,6 @@ import {Show} from '../../services/show'; }) export class SongComponent implements OnInit { @Input() public show: Show | null = null; - @Input() public showSong: ShowSong | null = null; - @Input() public showSongs: ShowSong[] | null = null; @Input() public showId: string | null = null; @Input() public showText: boolean | null = null; @@ -27,77 +24,77 @@ export class SongComponent implements OnInit { public faUp = faCaretUp; public faDown = faCaretDown; public keyFormControl: FormControl = new FormControl(); - public iSong: Song | null = null; + public iSong: ShowSong | null = null; public constructor(private showSongService: ShowSongService) {} @Input() - public set Song(song: Song) { + public set showSong(song: ShowSong) { this.iSong = song; this.keys = song ? getScale(song.key) : []; } public ngOnInit(): void { - if (!this.showSong) return; - this.keyFormControl = new FormControl(this.showSong.key); + if (!this.iSong) return; + this.keyFormControl = new FormControl(this.iSong.key); this.keyFormControl.valueChanges.subscribe((value: string) => { - if (!this.showId || !this.showSong) return; - void this.showSongService.update$(this.showId, this.showSong.id, {key: value}); + if (!this.showId || !this.iSong) return; + void this.showSongService.update$(this.showId, this.iSong.id, {key: value}); }); } public async onDelete(): Promise { - if (!this.showId || !this.showSong) return; - await this.showSongService.delete$(this.showId, this.showSong.id); + if (!this.showId || !this.iSong) return; + await this.showSongService.delete$(this.showId, this.iSong.id); } - public async reorder(up: boolean): Promise { - if (up) { - await this.reorderUp(); - } else { - await this.reorderDown(); - } - } - - public async reorderUp(): Promise { - if (!this.showSongs || !this.showId) return; - const index = this.showSongs.findIndex(_ => _.songId === this.iSong?.id); - if (index === 0) { - return; - } - - const song = this.showSongs[index]; - const toggleSong = this.showSongs[index - 1]; - - await this.showSongService.update$(this.showId, song.id, { - order: toggleSong.order, - }); - await this.showSongService.update$(this.showId, toggleSong.id, { - order: song.order, - }); - } - - public async reorderDown(): Promise { - if (!this.showSongs || !this.showId) return; - const index = this.showSongs.findIndex(_ => _.songId === this.iSong?.id); - if (index === this.showSongs.length - 1) { - return; - } - - const song = this.showSongs[index]; - const toggleSong = this.showSongs[index + 1]; - - await this.showSongService.update$(this.showId, song.id, { - order: toggleSong.order, - }); - await this.showSongService.update$(this.showId, toggleSong.id, { - order: song.order, - }); - } + // public async reorder(up: boolean): Promise { + // if (up) { + // await this.reorderUp(); + // } else { + // await this.reorderDown(); + // } + // } + // + // public async reorderUp(): Promise { + // if (!this.showSongs || !this.showId) return; + // const index = this.showSongs.findIndex(_ => _.songId === this.iSong?.id); + // if (index === 0) { + // return; + // } + // + // const song = this.showSongs[index]; + // const toggleSong = this.showSongs[index - 1]; + // + // await this.showSongService.update$(this.showId, song.id, { + // order: toggleSong.order, + // }); + // await this.showSongService.update$(this.showId, toggleSong.id, { + // order: song.order, + // }); + // } + // + // public async reorderDown(): Promise { + // if (!this.showSongs || !this.showId) return; + // const index = this.showSongs.findIndex(_ => _.songId === this.iSong?.id); + // if (index === this.showSongs.length - 1) { + // return; + // } + // + // const song = this.showSongs[index]; + // const toggleSong = this.showSongs[index + 1]; + // + // await this.showSongService.update$(this.showId, song.id, { + // order: toggleSong.order, + // }); + // await this.showSongService.update$(this.showId, toggleSong.id, { + // order: song.order, + // }); + // } public async onChordModeChanged(value: ChordMode): Promise { - if (!this.showId || !this.showSong) return; - await this.showSongService.update$(this.showId, this.showSong.id, { + if (!this.showId || !this.iSong) return; + await this.showSongService.update$(this.showId, this.iSong.id, { chordMode: value, }); } diff --git a/src/app/modules/shows/shows.module.ts b/src/app/modules/shows/shows.module.ts index f65692c..aef6167 100644 --- a/src/app/modules/shows/shows.module.ts +++ b/src/app/modules/shows/shows.module.ts @@ -28,6 +28,7 @@ import {ButtonModule} from '../../widget-modules/components/button/button.module import {OwnerModule} from '../../services/user/owner.module'; import {UserNameModule} from '../../services/user/user-name/user-name.module'; import {MatMenuModule} from '@angular/material/menu'; +import {DragDropModule} from '@angular/cdk/drag-drop'; @NgModule({ declarations: [NewComponent, ListComponent, ListItemComponent, ShowComponent, SongComponent], @@ -56,6 +57,7 @@ import {MatMenuModule} from '@angular/material/menu'; OwnerModule, UserNameModule, MatMenuModule, + DragDropModule, ], }) export class ShowsModule {} diff --git a/src/app/modules/songs/services/transpose.service.ts b/src/app/modules/songs/services/transpose.service.ts index ef30827..56c46f6 100644 --- a/src/app/modules/songs/services/transpose.service.ts +++ b/src/app/modules/songs/services/transpose.service.ts @@ -45,18 +45,13 @@ export class TransposeService { for (let i = 0; i < 12; i++) { const source = scale[0][i]; const mappedIndex = (i + difference + 12) % 12; - const mapped = scale[0][mappedIndex]; - console.log(mapped); - map[source] = mapped; + map[source] = scale[0][mappedIndex]; } for (let i = 0; i < 12; i++) { const source = scale[1][i]; const mappedIndex = (i + difference + 12) % 12; - const mapped = scale[1][mappedIndex]; - console.log(mapped); - map[source] = mapped; + map[source] = scale[1][mappedIndex]; } - console.log(map); return map; } diff --git a/src/app/widget-modules/components/add-song/add-song.component.ts b/src/app/widget-modules/components/add-song/add-song.component.ts index b4ef5c1..73a37f1 100644 --- a/src/app/widget-modules/components/add-song/add-song.component.ts +++ b/src/app/widget-modules/components/add-song/add-song.component.ts @@ -5,6 +5,8 @@ import {MatSelectChange} from '@angular/material/select'; import {Song} from '../../../modules/songs/services/song'; import {ShowSong} from '../../../modules/shows/services/show-song'; import {ShowSongService} from '../../../modules/shows/services/show-song.service'; +import {Show} from '../../../modules/shows/services/show'; +import {ShowService} from '../../../modules/shows/services/show.service'; @Component({ selector: 'app-add-song', @@ -14,11 +16,11 @@ import {ShowSongService} from '../../../modules/shows/services/show-song.service export class AddSongComponent { @Input() public songs: Song[] | null = null; @Input() public showSongs: ShowSong[] | null = null; - @Input() public showId: string | null = null; + @Input() public show: Show | null = null; @Input() public addedLive = false; public filteredSongsControl = new FormControl(); - public constructor(private showSongService: ShowSongService) {} + public constructor(private showSongService: ShowSongService, private showService: ShowService) {} public filteredSongs(): Song[] { if (!this.songs) return []; @@ -42,9 +44,10 @@ export class AddSongComponent { } public async onAddSongSelectionChanged(event: MatSelectChange): Promise { - if (!this.showSongs || !this.showId) return; - const order = this.showSongs.reduce((oa, u) => Math.max(oa, u.order), 0) + 1; - await this.showSongService.new$(this.showId, event.value, order, this.addedLive); + if (!this.showSongs) return; + if (!this.show) return; + const newId = await this.showSongService.new$(this.show?.id, event.value, this.addedLive); + await this.showService.update$(this.show?.id, {order: [...this.show.order, newId ?? '']}); event.source.value = null; } } diff --git a/src/app/widget-modules/components/song-text/song-text.component.ts b/src/app/widget-modules/components/song-text/song-text.component.ts index f5e199e..7ea0728 100644 --- a/src/app/widget-modules/components/song-text/song-text.component.ts +++ b/src/app/widget-modules/components/song-text/song-text.component.ts @@ -52,9 +52,9 @@ export class SongTextComponent implements OnInit { this.offset = 0; this.sections = []; if (this.fullscreen) { - setTimeout(() => (this.sections = this.textRenderingService.parse(this.iText, this.iTranspose).sort((a, b) => a.type - b.type)), 100); + setTimeout(() => (this.sections = this.textRenderingService.parse(this.iText, this.iTranspose)), 100); } else { - this.sections = this.textRenderingService.parse(this.iText, this.iTranspose).sort((a, b) => a.type - b.type); + this.sections = this.textRenderingService.parse(this.iText, this.iTranspose); //.sort((a, b) => a.type - b.type); } }