💥 Finished up controls for so far!

Yay!
This commit is contained in:
corner 2019-09-27 19:08:36 +02:00
parent 319104dee8
commit 29d8d978aa
9 changed files with 122 additions and 29 deletions

View File

@ -31,7 +31,7 @@
<button type="button" class="btn btn-outline-secondary" (click)="toggleNav();">
<fa-icon [icon]="this.navToggled ? faChevronLeft : faChevronRight" [fixedWidth]="true"></fa-icon>
</button>
<span class="navbar-brand">Route name here</span>
<span class="navbar-brand">{{ router.url }}</span>
<form class="form-inline" id="navbar-search">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>

View File

@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { faGlobeEurope, faMusic, faCompactDisc, faUsers, faCog, faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
import { Router, UrlSegment } from '@angular/router';
@Component({
selector: 'app-root',
@ -20,11 +21,10 @@ export class AppComponent implements OnInit {
faChevronRight = faChevronRight;
constructor() {
this.navToggled = false;
}
constructor(public router: Router) { }
ngOnInit() {
this.navToggled = false;
}
toggleNav() {

View File

@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@ -25,7 +26,8 @@ import { ControlsComponent } from './components/controls/controls.component';
BrowserModule,
AppRoutingModule,
HttpClientModule,
FontAwesomeModule
FontAwesomeModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]

View File

@ -26,6 +26,15 @@ export class Song {
// tslint:disable-next-line: no-use-before-declare
return new Artist(await this.data.getArtist(this.artist));
}
async getAlbum() {
// tslint:disable-next-line: no-use-before-declare
return new Album(await this.data.getAlbum(this.album));
}
async getDuration() {
return await this.data.getDuration(this.path);
}
}
/** This class represents one artist */

View File

@ -1,20 +1,24 @@
<div class="navbar navbar-light bg-light border-top controls-wrapper">
<span *ngIf="( currentSong | async ) as song" class="songInfo">
{{ song.name }}
</span>
<div class="figure-container">
<figure *ngIf="currentSong && currentArtist && currentAlbum" class="songInfo">
<img [src]="data.apiUrl + '/image/' + currentAlbum.image" [alt]="'Album art for ' + currentAlbum.name">
<figcaption>{{ currentSong.name }} by {{ currentArtist.name }}</figcaption>
</figure>
</div>
<span class="buttons">
<fa-icon (click)="audio.isCurrentlyPlaying ? audio.pause() : audio.play()" [icon]="audio.isCurrentlyPlaying ? faPause : faPlay"></fa-icon>
</span>
<span class="time">
<input type="range" class="form-control-range" id="song-range">
</span>
<div class="time">
<span class="currentTime">{{ audio.currentTime > 0 ? audio.formatTime(audio.currentTime) : '00:00' }}</span>
<input type="range" min="0" [max]="duration ? duration : 100" [(ngModel)]="audio.time" [value]="audio.currentTime" class="form-control-range" id="song-range">
<span class="duration">{{ duration > 0 ? audio.formatTime(duration) : '00:00' }}</span>
</div>
<span class="volume">
<fa-icon [icon]="faMusic" [fixedWidth]="true"></fa-icon>
<input 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>

View File

@ -2,9 +2,33 @@
width: 100%;
padding: 18px;
line-height: 1.5em;
display: grid;
grid-template-columns: 25% 10% 55% 10%
}
.form-control-range {
display: inline;
display: inline-block;
}
div.time {
display: grid;
grid-template-columns: min-content auto min-content;
span {
padding: 0 5px;
}
}
figure {
margin: 0;
img {
height: 2rem;
display: inline-block;
}
figcaption {
display: inline-block;
}
}
// #song-range {
// width: 50%;

View File

@ -1,8 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { faPlay, faPause, faVolumeMute, faVolumeDown, faVolumeUp } from '@fortawesome/free-solid-svg-icons';
import { faPlay, faPause, faVolumeMute, faVolumeDown, faVolumeUp, faMusic } from '@fortawesome/free-solid-svg-icons';
import { AudioService } from 'src/app/services/audio.service';
import { Song } from '../../classes/entities';
import { Song, Artist, Album } from '../../classes/entities';
import { ApiService } from 'src/app/services/api.service';
import { DataService } from 'src/app/services/data.service';
@Component({
selector: 'app-controls',
@ -17,17 +18,28 @@ export class ControlsComponent implements OnInit {
faVolumeMute = faVolumeMute;
faVolumeDown = faVolumeDown;
faVolumeUp = faVolumeUp;
faMusic = faMusic;
currentSong: Promise<Song>;
Math = Math;
NaN = NaN;
currentSong: Song;
currentArtist: Artist;
currentAlbum: Album;
duration: number;
constructor(
public audio: AudioService,
private api: ApiService
private api: ApiService,
public data: DataService
) { }
ngOnInit() {
this.audio.currentSong.subscribe(id => {
this.currentSong = this.api.getSong(id);
this.audio.currentSong.subscribe(async id => {
this.currentSong = await this.api.getSong(id);
this.currentArtist = await this.currentSong.getArtist();
this.currentAlbum = await this.currentSong.getAlbum();
this.duration = (await this.currentSong.getDuration()).data.result;
});
}

View File

@ -18,11 +18,22 @@ export class AudioService {
return !this.player.paused;
}
constructor(private data: DataService) { }
constructor(private data: DataService) {
// Make sure that the currentTime property is always up to date.
this.player.addEventListener('timeupdate', () => {
this.currentTime = this.player.currentTime;
});
}
player = new Audio();
currentSong = new Subject<number>();
currentTime: number;
// Use audio.time to set the time
set time(value: number) {
this.player.currentTime = value;
}
/**
* The play function sets the playstate of the player to playing.
@ -38,6 +49,33 @@ export class AudioService {
this.player.pause();
}
/**
* This function will format the number of seconds to a nices human-readable format.
* @param input The number of seconds.
* @returns a string like: '01:34', standing for 1 minute and 34 seconds.
*/
formatTime(input: number): string {
const minutes = Math.floor(input / 60);
const seconds = Math.floor(input % 60);
return this.addZero(minutes) + ':' + this.addZero(seconds);
}
/**
* This function prepends a 0 when the number is smaller than 10.
* @param input The number
* @returns a string with a 0 prepended if the number is smaller than 10.
*/
addZero(input: number): string {
if (input < 10) {
return '0' + String(input);
} else {
return String(input);
}
}
/**
* The setSong function set the song for the player.
* @param id The id of the song that needs to be played

View File

@ -37,6 +37,10 @@ export class DataService {
return this.axiosInstance.get(`${this.apiUrl}/get/${type}/${id}`);
}
getDuration(path: string): Promise<AxiosResponse<ApiData>> {
return this.axiosInstance.get(`${this.apiUrl}/duration/${path}`);
}
/**
* @param id The id of the artist. It can be a number representing the id, multiple numbers seperated by commas or the string 'all'.
* @returns A Promise<AxiosResponse<object>> containing the returned data from the API.