Ionic Music Player
- Fire Focus
- Oct 10, 2020
- 6 min read
Introduction
In this lesson you will learn about how you can create a music player app using Ionic Framework.First of all, we have to create a songs array with title, subtitle and thumnail image in songs.page.ts.
songs.page.ts
songs = [
{
title: "Believer",
subtitle: "Imagine Dragons"
,img: "/assets/believer.jpg",
path: "/assets/songs/believer.mp3"
},
{
title: "Fifa 2010",
subtitle: "FIFA 2010 Theme Song",
img: "/assets/fifa.png",
path: "/assets/songs/fifa_2010.mp3"
},
{title: "Thunder",
subtitle: "Imagine Dragons",
img: "/assets/thunder.jpg",
path: "/assets/songs/thunder.mp3"
}
];
Display Songs
Next, we display songs from the songs array.
songs.page.html
<ion-item lines="none" *ngFor="let song of songs" (click)="playSong(song.title,song.subtitle,song.img,song.path)">
<ion-thumbnail slot="start">
<img src="{{song.img}}" />
</ion-thumbnail>
<ion-label>
<h2>{{song.title}}</h2>
<p>{{song.subtitle}}</p>
</ion-label>
</ion-item>
Full Player UI
Next, we create a UI for the music player.Here we have variables like
currImage - to keep track of current song thumbnail
currTitle - to keep track of current song title
currSubtitle - to keep track of current song subtitle
Song Progress
Then, we can create a song progress bar using ion-range (we don't use ion-progress-bar here because we should be able to drag the progress bar forward & backward).
maxRangeValue - maximum value for ion-range
currRangeTime - current range value.It changes as song plays on
Here, we have two more variables
currSecsText - to display song current time in seconds
durationText - to display song total duration in seconds
Buttons
Here, we have four ion-buttons
Previous Song Button - to play previous song
Play Button - to play the song (*ngIf="!isPlaying" is used.If song is not playing the show this button)
Pause Button - to pause the song (*ngIf="isPlaying" is used.If song is playing the show this button)
Next Song Button - to play next song
Up Next Song
Here, we have some variables that hold the data about next song
upNextImg - to keep track of next song thumbnail
upNextTitle - to keep track of next songtitle
upNextSubtitle - to keep track of nextsong subtitle
Full Player HTML
Below we have the full player html markup.
songs.page.html
<div class="ion-text-center" id="fullPlayer">
<!-- Minimize Icon -->
<ion-toolbar>
<ion-buttons slot="end">
<ion-button (click)="minimize()">
<ion-icon name="chevron-down-outline" slot="icon-only"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
<img src="{{currImage}}" alt="" id="currImg">
<h2>
{{currTitle}}
</h2>
<p>
{{currSubtitle}}
</p>
<ion-item lines="none">
<ion-range #range (touchmove)="touchMove()" (touchend)="touchEnd()" (touchstart)="touchStart()"
max="{{maxRangeValue}}" [(ngModel)]="currRangeTime">
<ion-label slot="start">
<ion-text>
<b>
{{currSecsText}}
</b>
</ion-text>
</ion-label>
<ion-label slot="end">
<ion-text>
<b>
{{durationText}}
</b>
</ion-text>
</ion-label>
</ion-range>
</ion-item>
<!-- Play Previous Button -->
<ion-button fill="clear" mode="ios" (click)="playPrev()">
<ion-icon name="play-skip-back-outline" style="font-size: 30px;"></ion-icon>
</ion-button>
<!-- Play Button -->
<ion-button fill="clear" mode="ios" *ngIf="!isPlaying" (click)="play()">
<ion-icon name="play" style="font-size: 40px;"></ion-icon>
</ion-button>
<!-- Pause Button -->
<ion-button fill="clear" mode="ios" *ngIf="isPlaying" (click)="pause()">
<ion-icon name="pause" style="font-size: 40px;"></ion-icon>
</ion-button>
<!-- Play Next Button -->
<ion-button fill="clear" mode="ios" (click)="playNext()">
<ion-icon name="play-skip-forward-outline" style="font-size: 30px;"></ion-icon>
</ion-button>
<ion-list-header>
Up Next
</ion-list-header>
<!-- Up Next Song -->
<ion-item>
<ion-thumbnail slot="start">
<img src="{{upNextImg}}" />
</ion-thumbnail>
<ion-label>
<h2>
{{upNextTitle}}
</h2>
<p>
{{upNextSubtitle}}
</p>
</ion-label>
</ion-item>
</div>
Minimize Player UI
This is the content that will be displayed while minimizing the full player view.It contains the same variables and has same buttons as in full player view except it has close button that closes the currently playing song.It uses ion-progress bar to keep the song progress and has progress variable.
songs.page.html
<ion-toolbar id="miniPlayer">
<ion-item>
<ion-thumbnail slot="start" (click)="maximize()">
<img src="{{currImage}}" />
</ion-thumbnail>
<ion-label (click)="maximize()">
<h2>{{currTitle}}</h2>
<p>{{currSubtitle}}</p>
</ion-label>
<!-- Play Button -->
<ion-button (click)="play()" mode="ios" fill="clear" *ngIf="!isPlaying">
<ion-icon name="play" style="font-size: x-large;"></ion-icon>
</ion-button>
<!-- Pause Button -->
<ion-button (click)="pause()" mode="ios" fill="clear" *ngIf="isPlaying">
<ion-icon name="pause" style="font-size: x-large;"></ion-icon>
</ion-button>
<!-- Cancel Song Button -->
<ion-button (click)="cancel()" mode="ios" fill="clear">
<ion-icon name="close" style="font-size: x-large;"></ion-icon>
</ion-button>
</ion-item>
<!-- Song Progress Bar -->
<ion-progress-bar value="{{progress}}"></ion-progress-bar>
</ion-toolbar>
CSS Styles
The styles for the full player view and minimize player view.
songs.page.scss
* {
font-weight: bold;
}
ion-item {
ion-thumbnail {
img {
border-radius: 10px;
}
}
ion-label {
h2,
p {
font-weight: bold;
}
}
}
#miniPlayer {
box-shadow: 0px -4px 10px rgba(0, 0, 0, 0.1);
border-radius: 10px 10px 0 0;
transition: 0.5s;
//hide by default by setting bottom value in negative
bottom: -100px;
ion-progress-bar {
z-index: 10;
}
}
#fullPlayer {
transition: 0.5s;
position: fixed;
width: 100%;
height: 100%;
left: 0;
background: #fff;
z-index: 20;
//Hide by default by setting bottom value in negative
bottom: -1000px;
//Current Song Image
#currImg {
margin-top: 30px;
width: 200px;
height: 200px;
border-radius: 10px;
}
p {
color: #8c8c8c;
margin: 0;
}
ion-text {
font-size: medium;
}
}
Scripts
Let's come to the most interesting part Scripting.Import IonRange that will be used to keep track of ion-range value.
songs.page.ts
import { IonRange } from "@ionic/angular";
Declare Variables
Declare all necessary variables.
songs.page.ts
@ViewChild("range", { static: false }) range: IonRange;
//Current song details
currTitle:string;
currSubtitle:string;
currImage:string;
//progress bar value
progress:number = 0;
//toggle for play/pause button
isPlaying:booleab = false;
//track of ion-range touch
isTouched:boolean = false;
//ion range texts
currSecsText:string;
durationText:string;
//ion range value
currRangeTime:number;
maxRangeValue:number;
//Current song
currSong: HTMLAudioElement;
//Upnext song details
upNextImg:string;
upNextTitle:string;
upNextSubtitle:string;
Format Number to Seconds
Before continue,use the below method to convert a number to seconds ie., convert 59 => 00:59.
songs.page.ts
sToTime(t) {
return this.padZero(parseInt(String((t / (60)) % 60))) + ":" +
this.padZero(parseInt(String((t) % 60)));
}
padZero(v) {
return (v < 10) ? "0" + v : v;
}
Play the Song
We move to the main part.Here we play a song that is clicked from list of songs in songs.page.html.On clicking on a item, that trigger playSong() method that has song title,subtitle,thumbnail image and path for the song as arguments.
songs.page.ts
playSong(title, subTitle, img, song) {
if (this.currSong != null) {
this.currSong.pause(); //If a song plays,stop that
}
//open full player view
document.getElementById("fullPlayer").style.bottom = "0px";
//set current song details
this.currTitle = title;
this.currSubtitle = subTitle;
this.currImage = img;
//Current song audio
this.currSong = new Audio(song);
this.currSong.play().then(() => {
//Total song duration
this.durationText = this.sToTime(this.currSong.duration);
//set max range value (important to show proress in ion-range)
this.maxRangeValue = Number(this.currSong.duration.toFixed(2).toString().substring(0, 5));
//set upnext song
//get current song index
var index = this.songs.findIndex(x => x.title == this.currTitle);
//if current song is the last one then set first song info for upnext song
if ((index + 1) == this.songs.length) {
this.upNextImg = this.songs[0].img;
this.upNextTitle = this.songs[0].title;
this.upNextSubtitle = this.songs[0].subtitle;
}
//else set next song info for upnext song
else {
this.upNextImg = this.songs[index + 1].img;
this.upNextTitle = this.songs[index + 1].title;
this.upNextSubtitle = this.songs[index + 1].subtitle;
}
this.isPlaying = true;
})
this.currSong.addEventListener("timeupdate", () => {
//update some infos as song plays on
//if ion-range not touched the do update
if (!this.isTouched) {
//update ion-range value
this.currRangeTime = Number(this.currSong.currentTime.toFixed(2).toString().substring(0, 5));
//update current seconds text
this.currSecsText = this.sToTime(this.currSong.currentTime);
//update progress bar (in miniize view)
this.progress = (Math.floor(this.currSong.currentTime) / Math.floor(this.currSong.duration));
//if song ends,play next song
if (this.currSong.currentTime == this.currSong.duration) {
this.playNext();
}
}
});
}
Play Next Song
For playing next song, we get the index of current song from songs array.
We have two conditions
If current song is last song of the array, then play first song
Otherwise play next song in the list
songs.page.ts
playNext() {
var index = this.songs.findIndex(x => x.title == this.currTitle);
if ((index + 1) == this.songs.length) {
this.playSong(this.songs[0].title, this.songs[0].subtitle, this.songs[0].img, this.songs[0].path);
}
else {
var nextIndex = index + 1;
this.playSong(this.songs[nextIndex].title, this.songs[nextIndex].subtitle, this.songs[nextIndex].img, this.songs[nextIndex].path);
}
}
Play Previous Song
For playing previous song, we get the index of current song from songs array.
We have two conditions
If current song is first song of the array, then play last song
Otherwise play previous song in the list
songs.page.ts
playPrev() {
var index = this.songs.findIndex(x => x.title == this.currTitle);
if (index == 0) {
var lastIndex = this.songs.length - 1;
this.playSong(this.songs[lastIndex].title, this.songs[lastIndex].subtitle, this.songs[lastIndex].img, this.songs[lastIndex].path);
}
else {
var prevIndex = index - 1;
this.playSong(this.songs[prevIndex].title, this.songs[prevIndex].subtitle, this.songs[prevIndex].img, this.songs[prevIndex].path);
}
}
Drag Events
This part contains the code and details about ion-range drag events(drag the ion-range forward and backward and play song from the release point of the ion-range) It includes three methods
touchStart() - fires on start touching ion-range
touchMove() - fires on moving over ion-range
touchEnd() - fires on releasing the touch of ion-range
On start touching, we set isTouched value to true to prevent the updation on seconds text that are updated as song plays in playSong() method.
On dragging the ion-range, we are updating the currSecsText value.
On releasing the ion-range, we update the isTouched value to flase, set current song currentTime to current ion-range value ,currSecsText and currRangeTime value.
songs.page.ts
touchStart() {
this.isTouched = true;
this.currRangeTime = Number(this.range.value);
}
touchMove() {
this.currSecsText = this.sToTime(this.range.value);
}
touchEnd() {
this.isTouched = false;
this.currSong.currentTime = Number(this.range.value);
this.currSecsText = this.sToTime(this.currSong.currentTime)
this.currRangeTime = Number(this.currSong.currentTime.toFixed(2).toString().substring(0, 5));
if (this.isPlaying) {
this.currSong.play();
}
}
Maximize the player
The method maximize() hides the mini song player if visible and shows full song player.
songs.page.ts
maximize() {
document.getElementById("fullPlayer").style.bottom = "0px";
document.getElementById("miniPlayer").style.bottom = "-100px";
}
Minimize the player
The method minimize() hides the full song player if visible and shows mini song player.
songs.page.ts
minimize() {
document.getElementById("fullPlayer").style.bottom = "-1000px";
document.getElementById("miniPlayer").style.bottom = "0px";
}
Pause Play Close
There are three methods
pause() - It pauses the currently playing song
play() - It plays the currently paused song
close() - It hides the player,resets all value and stops the currently playing song
songs.page.ts
pause() {
this.currSong.pause();
this.isPlaying = false;
}
play() {
this.currSong.play();
this.isPlaying = true;
}
cancel() {
document.getElementById("miniPlayer").style.bottom = "-100px";
this.currImage = "";
this.currTitle = "";
this.currSubtitle = "";
this.progress = 0;
this.currSong.pause();
this.isPlaying = false;
}
I hope you understand the lesson.Please leave your feedback in comments.Cheers!
Comments