🚸 Added SongList component for consistent song visuals everywhere.

This commit is contained in:
corner 2019-09-28 17:35:25 +02:00
parent 29d8d978aa
commit 91a0cdfd57
17 changed files with 117 additions and 66 deletions

View File

@ -3,15 +3,13 @@ import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './components/home/home.component'; import { HomeComponent } from './components/home/home.component';
import { ArtistsComponent } from './components/artists/artists.component'; import { ArtistsComponent } from './components/artists/artists.component';
import { AlbumsComponent } from './components/albums/albums.component'; import { AlbumsComponent } from './components/albums/albums.component';
import { SongComponent } from './components/song/song.component';
const routes: Routes = [ const routes: Routes = [
{ path: '', component: HomeComponent }, { path: '', component: HomeComponent },
{ path: 'artists/:id', component: ArtistsComponent }, { path: 'artists/:id', component: ArtistsComponent },
{ path: 'artists', component: ArtistsComponent }, { path: 'artists', component: ArtistsComponent },
{ path: 'albums/:id', component: AlbumsComponent }, { path: 'albums/:id', component: AlbumsComponent },
{ path: 'albums', component: AlbumsComponent }, { path: 'albums', component: AlbumsComponent }
{ path: 'songs', component: SongComponent }
]; ];
@NgModule({ @NgModule({

View File

@ -8,19 +8,19 @@ import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { HomeComponent } from './components/home/home.component'; import { HomeComponent } from './components/home/home.component';
import { SongComponent } from './components/song/song.component';
import { ArtistsComponent } from './components/artists/artists.component'; import { ArtistsComponent } from './components/artists/artists.component';
import { AlbumsComponent } from './components/albums/albums.component'; import { AlbumsComponent } from './components/albums/albums.component';
import { ControlsComponent } from './components/controls/controls.component'; import { ControlsComponent } from './components/controls/controls.component';
import { SonglistComponent } from './components/songlist/songlist.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
HomeComponent, HomeComponent,
SongComponent,
ArtistsComponent, ArtistsComponent,
AlbumsComponent, AlbumsComponent,
ControlsComponent ControlsComponent,
SonglistComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

View File

@ -32,8 +32,9 @@ export class Song {
return new Album(await this.data.getAlbum(this.album)); return new Album(await this.data.getAlbum(this.album));
} }
async getDuration() { async getDuration(): Promise<number> {
return await this.data.getDuration(this.path); const apiData = await this.data.getDuration(this.path);
return apiData.data.result;
} }
} }

View File

@ -10,26 +10,16 @@
<ng-template #artistInfo> <ng-template #artistInfo>
<div *ngIf="( artistData | async ) as data"> <h2>{{ artistData.name }}'s profile</h2>
<h1>{{ data.name }}'s profile</h1> <hr>
<h4>{{ artistData.name }}'s songs</h4>
<h4>{{ data.name }}'s albums</h4>
<ul> <ul>
<li *ngFor="let album of data.albums"> <li *ngFor="let song of songs">
{{ album }} {{ song.name }}
</li> </li>
</ul> </ul>
<h4>{{ data.name }}'s songs</h4>
<ul>
<li *ngFor="let song of data.songs">
{{ song }}
</li>
</ul>
{{ data | json}}
</div>
</ng-template> </ng-template>

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { ApiService } from 'src/app/services/api.service'; import { ApiService } from 'src/app/services/api.service';
import { Artist, Song } from '../../classes/entities';
@Component({ @Component({
selector: 'app-artists', selector: 'app-artists',
@ -9,8 +10,9 @@ import { ApiService } from 'src/app/services/api.service';
}) })
export class ArtistsComponent implements OnInit { export class ArtistsComponent implements OnInit {
artistData; artistData: Artist;
artists; artists: Promise<Array<Artist>>;
songs: Array<Song>;
constructor( constructor(
private api: ApiService, private api: ApiService,
@ -25,7 +27,10 @@ export class ArtistsComponent implements OnInit {
if (params.has('id')) { if (params.has('id')) {
// ... then get artist data ... // ... then get artist data ...
this.artistData = this.api.getArtist(Number(params.get('id'))); this.api.getArtist(Number(params.get('id'))).then(async res => {
this.artistData = res;
this.songs = await this.api.getSong(res.songs.join());
});
} else { } else {

View File

@ -17,8 +17,9 @@
<span class="duration">{{ duration > 0 ? audio.formatTime(duration) : '00:00' }}</span> <span class="duration">{{ duration > 0 ? audio.formatTime(duration) : '00:00' }}</span>
</div> </div>
<span class="volume"> <div class="volume">
<fa-icon [icon]="audio.player.volume === 0 ? faVolumeMute : ( audio.player.volume > 0.5 ? faVolumeUp : faVolumeDown )"></fa-icon>
<input min="0" max="1" step="0.05" [(ngModel)]="audio.player.volume" type="range" class="form-control-range" id="volume-range"> <input min="0" max="1" step="0.05" [(ngModel)]="audio.player.volume" type="range" class="form-control-range" id="volume-range">
</span> </div>
</div> </div>

View File

@ -3,7 +3,7 @@
padding: 18px; padding: 18px;
line-height: 1.5em; line-height: 1.5em;
display: grid; display: grid;
grid-template-columns: 25% 10% 55% 10% grid-template-columns: 25% 5% 55% 15%
} }
.form-control-range { .form-control-range {
display: inline-block; display: inline-block;
@ -18,6 +18,16 @@ div.time {
} }
} }
div.volume {
display: grid;
grid-template-columns: auto auto;
text-align: center;
input {
width: 90%;
}
}
figure { figure {
margin: 0; margin: 0;

View File

@ -39,7 +39,7 @@ export class ControlsComponent implements OnInit {
this.currentSong = await this.api.getSong(id); this.currentSong = await this.api.getSong(id);
this.currentArtist = await this.currentSong.getArtist(); this.currentArtist = await this.currentSong.getArtist();
this.currentAlbum = await this.currentSong.getAlbum(); this.currentAlbum = await this.currentSong.getAlbum();
this.duration = (await this.currentSong.getDuration()).data.result; this.duration = await this.currentSong.getDuration();
}); });
} }

View File

@ -1,3 +1 @@
<div *ngIf="songs && artists"> <app-songlist *ngIf="( songs | async ) as songs" [songs]="songs"></app-songlist>
<p *ngFor="let song of songs; let i=index" (click)="audio.setSong(song)">{{ song.name }} by <span *ngIf="artists[i]">{{ artists[i].name }}</span></p>
</div>

View File

@ -10,7 +10,7 @@ import { ApiService } from 'src/app/services/api.service';
}) })
export class HomeComponent implements OnInit { export class HomeComponent implements OnInit {
songs: Song[]; songs: Promise<Song[]>;
artists: Artist[] = []; artists: Artist[] = [];
constructor( constructor(
@ -21,12 +21,7 @@ export class HomeComponent implements OnInit {
ngOnInit() { ngOnInit() {
// Load the first song from the API // Load the first song from the API
// Removing the async / await from the .then() callback will load the artists async from the songs. // Removing the async / await from the .then() callback will load the artists async from the songs.
this.api.getSong('all').then(async res => { this.songs = this.api.getSong('all');
this.songs = res;
await res.forEach(async (song: Song) => {
this.artists.push(await song.getArtist());
});
});
} }
} }

View File

@ -1 +0,0 @@
<p>song works!</p>

View File

@ -1,15 +0,0 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-song',
templateUrl: './song.component.html',
styleUrls: ['./song.component.scss']
})
export class SongComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,23 @@
<table class="table">
<thead>
<th scope="col">#</th>
<th scope="col"></th>
<th scope="col">Song name</th>
<th scope="col">Artist name</th>
<th scope="col">Album name</th>
<th scope="col">Duration</th>
</thead>
<tbody *ngIf="songsInfo">
<tr *ngFor="let song of songsInfo; let i = index">
<th scope="row">{{ i + 1 }}</th>
<th><fa-icon (click)="audio.setSong(songs[i])" [icon]="faPlay"></fa-icon></th>
<td>{{ song.name }}</td>
<td *ngIf="song.artistInfo">{{ song.artistInfo.name }}</td>
<td *ngIf="song.albumInfo">{{ song.albumInfo.name }}</td>
<td *ngIf="song.duration">{{ audio.formatTime(song.duration) }}</td>
</tr>
</tbody>
</table>

View File

@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SongComponent } from './song.component'; import { SonglistComponent } from './songlist.component';
describe('SongComponent', () => { describe('SonglistComponent', () => {
let component: SongComponent; let component: SonglistComponent;
let fixture: ComponentFixture<SongComponent>; let fixture: ComponentFixture<SonglistComponent>;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SongComponent ] declarations: [ SonglistComponent ]
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(SongComponent); fixture = TestBed.createComponent(SonglistComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@ -0,0 +1,46 @@
import { Component, OnInit, Input } from '@angular/core';
import { Song, Artist, Album } from '../../classes/entities';
import { faPlay } from '@fortawesome/free-solid-svg-icons';
import { AudioService } from 'src/app/services/audio.service';
@Component({
selector: 'app-songlist',
templateUrl: './songlist.component.html',
styleUrls: ['./songlist.component.scss']
})
export class SonglistComponent implements OnInit {
@Input() songs: Song[];
songsInfo = [];
// ? fontAwesome imports
faPlay = faPlay;
constructor(public audio: AudioService) { }
ngOnInit() {
this.songs.forEach(song => {
const index = this.songsInfo.push({}) - 1;
const result = {
...song,
artistInfo: null as Artist,
albumInfo: null as Album,
duration: null as number
};
song.getArtist().then((artist: Artist) => {
result.artistInfo = artist;
song.getAlbum().then((album: Album) => {
result.albumInfo = album;
song.getDuration().then((duration: number) => {
result.duration = duration;
this.songsInfo[index] = result;
});
});
});
});
}
}

View File

@ -78,7 +78,7 @@ export class AudioService {
/** /**
* The setSong function set the song for the player. * The setSong function set the song for the player.
* @param id The id of the song that needs to be played * @param song The song object
*/ */
setSong(song: Song) { setSong(song: Song) {
this.player.src = this.data.apiUrl + '/play/' + song.path; this.player.src = this.data.apiUrl + '/play/' + song.path;