# Create a Drag and Drop MP3 Player with Adobe AIR

In this tutorial, we’ll create an AIR drag and drop mp3 player. We’ll work with the NativeDragManager class to handle the drag and drop, the NativeWindow class for the playlist, and some SQLLite to store information about our mp3 files to build a playlist.

Please upgrade your Flash Player

## Step 1: Create a New AIR Document

Start Flash, create a new Adobe AIR document and save the document as “drag_drop_mp3.fla”.

If you already have a blank Actionscript 3.0 document open, simply go to Commands > AIR – Application and Installer Settings. Flash will give an alert saying that it will target all the appropriate files for you. Click “Ok” at the prompt, Flash will then show the application publish settings. Click “Ok” again and we’re ready to start.

## Step 2: Setting up the Stage and Document Class

Go to File > New and create a new ActionScript file. Save the blank file as “drag_drop_mp3.as”. In the “Properties” panel, resize the stage to 210 x 110 pixels. Next, in the “Document class” text box, type in the name of the newly created actionscript file; leaving out the file extension.

## Step 3: Creating the Player Background

Select the rectangle tool. In the rectangle tool options of the “Properties” panel, click the lock to unlock the rounded corners option. Enter 5 for the top corners and 0 for the bottom corners. Also, make the fill color black and give the stroke a color of #CCCCCC.

Next, draw a rectangle that is 200 x 100 pixels. Make sure nothing is selected. Select the bottom line of the stroke and delete it. Now, there should be a rectangle with rounded corners at the top, square corners at the bottom and a stroke that wraps around the top of the rectangle but not the bottom. If the stroke is hanging down past the bottom of the black square, simply double click on the stroke. With the stroke selected, in the “Properties” panel, click on “Cap:” and select “None”. Select the square and stroke, then place them at an x position of 5 and a y position of 2.5.

## Step 4: Giving the Background its Look and Feel

Select the entire rectangle and stroke, then hit F8 to convert it into a symbol. Turn it into a Movieclip and give it a name of “background”. In the “Properties” panel, give the newly created movieclip an instance name of background.

Double-click on the movieclip to go into edit mode. Select the stroke and go to Edit > Cut to cut the stroke out. Then go to Insert > Timeline > Layer to create a new layer. When the new layer is created, go to Edit > Paste in Place. This will put the stroke on the top layer. Lock the stroke layer. Next, create a new layer and place it between the stroke layer and rectangle layer. Now, select the rectangle, go to Edit > Copy. Select the empty middle layer and “Paste in Place” a copy of the rectangle. With the new rectangle selected, change its color to something bright (I use bright green) to remind us that we need to change this color at some point.

## Step 5: Continuing with the Background

Now we need to add another layer ontop of the green rectangle layer. In this layer, create a black 5 x 5 circle with no stroke. Hit “Ctrl-k” to bring up the align options. With the stage icon selected, align the circle to the top-left corner of the movieclips stage. With the circle selected, hold down “Alt” and drag out another instance of the circle. Place the cirlce at 10 for x and 0 for y. Continue to drag new copies of the circle out, placing them 10 pixels apart from each other until you reach the end of the green rectangle.

Now select all the circles, hold down “Alt” and drag down new copies. Offset the x postion of the new circles by 5px and give them a y position of 5. Continue to do this copy/paste technique until the whole green movieclip is covered. Delete any circles that aren’t covering the green rectangle.

Next, select all the circles in the layer. With all the circles selected, cut them out of the layer. In the green rectangle layer, “Paste in Place” all the circles and deselect everything. This will turn the entire layer into one shape. Now click the keyframe in the green rectangle layer to select everything. With everything selected, hold down “Shift” on the keyboard and click the green shape. This will deselect the green rectangle; leaving only the black circles selected. Then hit “Delete” to delete the black circles. We now have the top layer of our grate look. To view this, you can turn off the visibility of the black layer underneath.

## Step 6: Finishing the Background

The next step is to select the green rectangle. Copy the green rectangle, and “Paste in Place” on the bottom black rectangle layer. When you paste the layer, you’ll probably get some weird empty holes. Just fill in those holes with black using the paint bucket tool.

When all the black holes are filled, once again make sure nothing is selected, so that the layer will turn everything into one shape. Click on the green part of the layer and delete. Now we should have a bottom layer of holes and the layer above should have the fill.

Next, select the green rectangle in the layer above the black circles. In the “Color” panel, select the fill color picker and select the black-to-white circular gradient. Change the color of the white end to #5E5E5E and give it an alpha of 60%. Next, select the black end and give it an alpha of 88% and turn it into a movieclip. Give it an instance name of “winBack”. Now in the “Filters” panel, click the plus sign and assign it a new bevel filter. Give the bevel 1 for the blur x and y, a strength of 50%, a quality of high, an angle of 210 and a distance of 1. Delete all the empty layers, lock the rest and exit the movieclips editing mode.

On the stage of the main file, select the movieclip and go to the “Filters” panel. In the filters panel, give the movieclip a dropshadow. Give the dropshadow 4 for the blur x and y, a strength of 66%, a quality of high, an angle of 90 and a distance of 4.

## Step 7: Building the Playback Buttons

Next, select the rectangle tool. In the “Properties” panel, make sure that all the rounded corners are locked together with a value of 2.5. Draw out a rectangle that is approximately 28.5 pixels wide and 19.5 pixels in height without any stroke. In the “Color” panel, select the linear black-to-white gradient. With the shape selected, hit “f” on the keyboard to bring up the “Gradient Transform Tool”. Rotate the gradient 90 degrees, so that the white is at the top of the shape. Adjust the color sliders, so that each color is about half way. Now double-click on the little black square and enter in #BFBFBF as the color.

Select the rectangle shape and convert it to a movieclip. Give it a name of “buttonBackground”. Now create a new layer above the background layer. Drag out three instances of the “buttonBackground” movieclip. Give the first one an x position of 41.2 and a y position of 76.8. Give the second one an x position of 42.8 and a y position of 76.8. Give the third one an x position of 72.8 and a y position of 76.8. This will align all the buttons to the same y position and slightly space them out.

Next with “Webdings” font, the static text tool, and on top of the “buttonBackground” movieclip, give the first one the symbol for “Previous”. The middle button has the symbol for “Play” and the last button has the symbol for “Next”. Select all the newly created text boxes, and hit “Ctrl-b” until the text is broken into shapes. Select the first “buttonBackground” movieclip and the “Previous” shape and convert them into a movieclip. Do the same for the other two. Give the left movieclip an instance name of “prevBtn”. Next, select the movieclip in the middle and give it an instance name of ‘”playBtn”. Finally, select the button on the right and give it an instance name of “nextBtn”.

## Step 8: The Playlist Button

The next step is to create the playlist button. Select the rectangle tool. Give it a rounded corner of 5 and make a shape that is 80.5 pixels in width and 19.9 pixels in height. Give the shape the same fill color as the previously created buttons. Place the shape at 108.2 for x and 76.8 for y. Select the shape and convert it to a movieclip. Inside the new movieclip, select the type tool and create a dynamic text box over the shape that says “Show Playlist”. Make the text box 80.3 in width and 16.2 in height with an x position of 0.0 and a y position of 1.8.

Give the text box an instance name of “ty”. Give the movieclip an instance name of “playToggle”.

## Step 9: The Volume Slider

Now we’ll create the volume slider. Select the line tool, make sure that the color is set to #999999 and the stroke thickness is 1. Draw a line out that is 45 pixels tall. Select the line and convert it into a movieclip with an instance name of “volControl”. Next, double-click the movieclip to enter its edit mode. Copy/paste the line and change the color to white. Move the line over 1 pixel. Next select the rectangle tool and make sure that the rounded corners are set to 0. Draw a rectangle that is 10 pixels wide and 5 pixels in height. Place the rectangle at -4.5 for x and 0 for y. Select the rectangle, convert it into a movieclip and give it an instance name of “slider”.

With the “slider” movieclip selected, go to the “Filters” panel and give it a dropshadow with a 1 for the blur x and y, 66% for its strength, a quality of high, an angle of 90 and a distance of 1. Finally, exit the edit mode of the movieclip and on the stage of the main file, place the “volControl” movieclip at 195.6 for x and 45.4 for y.

## Step 10: Finalizing the Top Half of the App

The next step is to create two buttons. The first button is for minimizing the application, and the second is for closing it.

Select the rectangle tool, give the rounded corners a value of 2, and create a square that is 10.9 pixels. Apply the same fill settings as the other buttons on the stage and convert it to a movieclip. Drag out two instances for the new movieclip onto the stage. With the “Webdings” font, place the minimize character over one of the movieclips. Break apart the font until it becomes a shape, select both the new shape and the movieclip below it, and convert it to a Button. Give the new button an instance name of ‘mini,’ a x position of 178.4 and a y position of 5.5. Do the same process for the second movieclip, only give it a close character, an x position of 190.4 and a y position of 5.5.

Finally, create a blank dynamic text field on the stage. Give the textfield an instance name of “tf”, a color of #0000FF, a width of 188, a height of 14.1, a font size of 9, an alignment of center, an x value of 11 and a y value of 20.3.

## Step 11: Setting up the Play Button

Next we’re going to set up the ability to toggle the play button. Double click on the “playBtn” movieclip to enter its edit mode. Make sure that the “Play” character is on a separate layer. Go to frame 6 on the “Play” characters layer and hit F6 to create a new keyframe. Delete the “Play” character, and, using the “Webdings” font, place a “Stop” character there. Break the character apart until it becomes a shape.

Next, click to frame ten and hit F5 on both layers. Now add two more layers above the character layer. On the layer directly above the character layer, place a keyframe on frame 6 and extend it to frame 10. Click back to frame 1, and in the “Frame” text box, give it a label of “play”. Now click to frame six and give it a label of “stop”. Finally, on the top most layer, hit “F9″ on the keyboard to bring up the actions panel. In the actions panel, type:

stop();


Now, we’ll be able to toggle back and forth depending on whether a song is playing or not.

## Step 12: The Playlist Window

Let’s create the playlist window. We’ll be able to control this window later from actionscript. Go to Insert > New Symbol… to create a new symbol. Select “Movie clip” and give it a name of “window”. Next, under “Linkage”, check “Export for ActionScript” and give it a class name of “Window”. Click “Ok”, this will bring up a blank stage.

Next, select the rectangle tool. Now, make sure to unlock the rounded corners. Give the rectangle top corners a value of 0 and the bottom corners 5. Make sure the fill color is black and the stroke color is #CCCCCC. Draw out a rectangle that is 200 pixels wide and 400 pixels tall. Select the rectangle and its stroke, then convert them to a movieclip. Give the movieclip an instance name of “windowBackground”. Now double-click on the movieclip to enter its editing mode. Inside the movieclip, go through steps 3 – 6 again until the movieclip is similar to the main player’s background movieclip. Also, just like the first one, make sure to give the movieclip with the bevel an instance name of “winBack”.

So now, to clarify, inside the “Window” class, there should be one movieclip with an instance name of “windowBackground”. Inside “windowBackground”, there should be a movieclip with an instance name of “winBack”. Finally, there should be no instance of the “Window” class on the stage at all. This will all be controlled dynamically.

## Step 13: Adding the Datagrid Component

We’ll use the datagrid component to control our playlist. In the “Window” movieclip class, add a new layer. From the components panel, drag out an instance of the Datagrid. Give it an instance name of “grid” and an x position of 10.8 and a y position of 42.5. Resize the datagrid component to a width of 178 and a height of 314.9. Finally, in a new layer under the grid component, create a white rectangle the same size as the datagrid component. This is helpful with any transparency issues that the component has without having to reskin it.

## Step 14: Finalizing the Design

The last thing we need to add to the Window is the ability to delete items from out playlist. Drag out a copy of the “Show Playlist” button. Give the movieclip an instance name of “deli”, an x position of 108.6 and a y position of 366.9. Don’t worry about the text box saying “Show Playlist”, we’ll control that via actionscript.

## Step 15: The Document Skeleton

Open up the blank actionscript file that we created. Here’s the skeleton for the document class we’ll be using.

package {

public class drag_drop_mp3 extends Sprite {

public function drag_drop_mp3()
{

}
}
}


## Step 16: The Imports

Here are the import statements that we’ll be using..

	import fl.controls.DataGrid;
import fl.data.DataProvider;

import flash.data.SQLConnection;
import flash.data.SQLStatement;
import flash.desktop.Clipboard;
import flash.desktop.ClipboardFormats;
import flash.desktop.NativeDragManager;
import flash.display.MovieClip;
import flash.display.NativeWindow;
import flash.display.NativeWindowInitOptions;
import flash.display.NativeWindowSystemChrome;
import flash.display.NativeWindowType;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.NativeDragEvent;
import flash.events.TimerEvent;
import flash.filesystem.File;
import flash.filters.DropShadowFilter;
import flash.media.ID3Info;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundMixer;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.utils.Timer;


## Step 17: The Variables

..and here’s a list of the variables that we’ll be using. We’ll be using an SQLConnection to feed information about our mp3′s into the SQLLite database. Also, we’ll be using a sound object to track which song we’re currently playing. There is also a variable for us to create a NativeWindow object for our playlist. That way we can move the window anywhere on the screen we want, as well as have it be independent of the main window. We also create a tracer variable. This will help keep track of which song is playing.

private var connect:SQLConnection;
private var currentSound:Sound;
private var yOffset:Number;
private var st:SoundTransform;
private var nw:NativeWindow;
private var window:MovieClip;
private var tracer:int;
private var channel:SoundChannel;
private var tfText:String;
private var len:int;


## Step 18: The Init Functions

When the app launches, it’ll call these two functions: init and listeners. The init function calls for the database to be set up, as well as creates the new window instance. Finally, it calls the function that sets buttonModes and visibilty of objects. After the init function, the listeners function is called which adds the event listeners to everything. Most importantly, it calls the NativeDragEvent. This allows us to drag mp3′s from our desktop (from anywhere really) to the app.

public function drag_drop_mp3()
{
init();
listeners();
}
private function init():void
{
initDB();
buildWindow();
initObjects();
}
private function listeners():void
{
closer.addEventListener(MouseEvent.CLICK, handleWindow);
mini.addEventListener(MouseEvent.CLICK, handleWindow);
background.addEventListener(MouseEvent.MOUSE_DOWN, moveWindow);
playToggle.addEventListener(MouseEvent.CLICK, togglePlayList);
volControl.slider.addEventListener(MouseEvent.MOUSE_DOWN, sliderDown);
prevBtn.addEventListener(MouseEvent.CLICK, buttonClick);
playBtn.addEventListener(MouseEvent.CLICK, buttonClick);
nextBtn.addEventListener(MouseEvent.CLICK, buttonClick);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, dragEnter);
}


## Step 19: The Secondary Init Functions

Here are the functions that will set up the database, the properties of the objects on the stage and the function that creates a new NativeWindow.

The initObject is fairly self explanatory. I use a try/catch statement just in case the database is empty. In the initDB function, the database file is created, if it doesn’t already exsist. It then creates a table called “Playlist” with three columns; one for the artist, one for the song and the last is for the url of the song. Finally, we create a new instance of the “Window” object that we created earlier. The text of the delete button is changed. A dropshadow to match the top portion of the app is created as well. The window is chromeless and it creates a lightweight type of window. That means that the playlist window won’t have any system chrome and when it’s opened, there won’t be any option for it in the toolbar.

private function initObjects():void
{
background.winBack.mouseEnabled = false;
playToggle.buttonMode = true;
playToggle.mouseChildren = false;
tf.background = true;
tf.backgroundColor = 0x000000;
tf.mouseEnabled = false;
tf.text = "Drag and Drop an MP3 File Here";
prevBtn.buttonMode = true;
playBtn.buttonMode = true;
nextBtn.buttonMode = true;
st = new SoundTransform(1, 0);
channel = new SoundChannel();
try
{
currentSound = new Sound(new URLRequest(window.grid.getItemAt(0).Location));
}
catch(event:Error)
{
//
}
}
private function initDB():void
{
var file:File = File.applicationStorageDirectory.resolvePath("playlist.db");
connect = new SQLConnection();
connect.open(file);
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = connect;
statement.text = "CREATE TABLE IF NOT EXISTS PLAYLIST (Artist TEXT, Song TEXT, Location TEXT)";
statement.execute();
}
private function buildWindow():void
{
var nwo:NativeWindowInitOptions = new NativeWindowInitOptions();
nwo.maximizable = false;
nwo.resizable = false;
nwo.transparent = true;
nwo.systemChrome = NativeWindowSystemChrome.NONE
nwo.type = NativeWindowType.LIGHTWEIGHT;
nw = new NativeWindow(nwo);
nw.title = "Playlist";
window = new Window();
window.deli.ty.text = "Delete";
window.windowBackground.winBack.mouseEnabled = false;
window.windowBackground.addEventListener(MouseEvent.MOUSE_DOWN, moveNatWin);
nw.stage.stageWidth = window.width+10;
nw.stage.stageHeight = window.height+10;
nw.stage.scaleMode = StageScaleMode.NO_SCALE;
nw.stage.align = StageAlign.TOP_LEFT;
window.filters = [new DropShadowFilter(4, 90, 0x000000, 1, 4 ,4, 0.66, 3)];
window.x = 5;
window.y = 0;
nw.stage.addChild(window);
setCoords();
window.grid.addEventListener(Event.CHANGE, gridChange);
window.deli.addEventListener(MouseEvent.CLICK, deliClick);
loadData();
}


## Step 20: The Other Functions

The setCoords function is called when showing the playlist window. It resets the x and y of the playlist window, so that it’s easier to find when you toggle the visibility. The loadData function selects all the information from the database and populates the datagrid component.

private function setCoords():void
{
nw.x = stage.nativeWindow.x;
var theY:Number = (stage.nativeWindow.y + stage.nativeWindow.height)
nw.y = theY;
}
private function loadData():void
{
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = connect;
statement.text = "SELECT * FROM PLAYLIST";
statement.execute();
try
{
var dp:DataProvider = new DataProvider(statement.getResult().data);
window.grid.dataProvider = dp;
}
catch(event:Error)
{
//
}
len = window.grid.length;
}


## Step 21: Handling the Drag and Drop

The first function, dragEnter, is called when someone tries to drag a file onto the stage. The file checks to see if the extension is correct. If it is, the drag is accepted. If someone decides that they don’t want to drag a file, the dragExit function is called. It resets the text on the main window of the application. However, if the user picks the right file format and decides that they want to add the file to their playlist, the dragDrop function is called and the sound is loaded.

private function dragEnter(event:NativeDragEvent):void
{
this.removeEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, dragEnter);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, dragDrop);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_EXIT, dragExit);
var clip:Clipboard = event.clipboard;
var object:Object = clip.getData(ClipboardFormats.FILE_LIST_FORMAT);
tfText = tf.text;
if (object[0].extension.toLowerCase() == "mp3")
{
NativeDragManager.acceptDragDrop(this);

tf.text = "GIVE IT TO ME BABY...";
}
else
{
tf.text = "EWW...GET THAT AWAY FROM ME!";
}
}
private function dragExit(event:NativeDragEvent):void
{
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, dragEnter);
this.removeEventListener(NativeDragEvent.NATIVE_DRAG_EXIT, dragExit);
tf.text = tfText;
}
private function dragDrop(event:NativeDragEvent):void
{
this.removeEventListener(NativeDragEvent.NATIVE_DRAG_EXIT, dragExit);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, dragEnter);
this.removeEventListener(NativeDragEvent.NATIVE_DRAG_DROP, dragDrop);
var clip:Clipboard = event.clipboard;
var object:Object = clip.getData(ClipboardFormats.FILE_LIST_FORMAT);
var req:URLRequest = new URLRequest(object[0].url);
var sound:Sound = new Sound();
sound.addEventListener(Event.COMPLETE, soundLoaded);
sound.load(req);
tf.text = "LOADING...";
}


## Step 22: Loading the Sound

After the sound is loaded, we take the artist and song information from the ID3Info object. We then insert it into the database, as well as the url of the song we just loaded. We then reload the datagrid with the new sound data.

private function soundLoaded(event:Event):void
{
currentSound = event.target as Sound;
var id:ID3Info = currentSound.id3;
var artist:String = id.artist;
var song:String = id.songName;
var url:String = currentSound.url
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = connect;
statement.text = "INSERT INTO PLAYLIST (Artist, Song, Location) VALUES (?, ?, ?)";
statement.parameters[0] = artist;
statement.parameters[1] = song;
statement.parameters[2] = url;
statement.execute();
loadData();
window.grid.selectedIndex = len-1;
tracer = -1;
tf.text = "THANK YOU!";
var timer:Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, onTimer);
timer.start();
}
private function onTimer(event:TimerEvent):void
{
if(tf.text == "THANK YOU!")
{
tf.text = tfText;
}
var timer:Timer = event.target as Timer;
timer.stop();
}


## Step 23: Working with the Button Controls

We’ll control the song control buttons with one function. We check to see if the “playBtn” was clicked, if so, we check to see which label the button is currently on and, if the currentSound object isn’t null, we call the playSong function. If one of the other buttons was clicked, we call the appropriate function.

private function buttonClick(event:MouseEvent):void
{
var mc:MovieClip = event.target as MovieClip;
var string:String = mc.name;
switch(string)
{
case "playBtn" :
if(mc.currentLabel == "play")
{
try
{
playSong(currentSound.url);
}
catch(event:Error)
{
//
}
}
else
{
mc.gotoAndStop("play");
SoundMixer.stopAll();
}
break;
case "nextBtn" :
playNextSong();
break;
case "prevBtn" :
playPrevSong();
break;
}
}


## Step 24: The Song Functions

Here are the functions for working with the sound. Both the playNextSong and playPrevSong functions call the handleNextPrev function. This function uses the tracer variable to keep track of which song is playing. The handleNextPrev function then assigns the selected sound to the currentSound object. After that, we call the playSong function. In the playSong function, we tell the datagrid to highlight which song is playing, we set the text field to show the artist and song information from the database, and we listen for the SOUND_COMPLETE event. When the sound is complete, we load the next song.

private function playNextSong():void
{
if(tracer == len)
{
tracer = 0;
}
else
{
tracer++;
}
handleNextPrev();
}
private function playPrevSong():void
{
if(tracer == 0)
{
tracer = len;
}
tracer--;
handleNextPrev();
}
private function handleNextPrev():void
{
var string:String;
try
{
string = window.grid.getItemAt(tracer).Location;
currentSound = new Sound(new URLRequest(string));
SoundMixer.stopAll();
playSong(string);
}
catch(event:Error)
{
string = window.grid.getItemAt(0).Location;
currentSound = new Sound(new URLRequest(string));
SoundMixer.stopAll();
playSong(string);
}
}
private function playSong(string:String):void
{
try {
playBtn.gotoAndStop("stop");
for(var i:int; i<len; i++)
{
if(string == window.grid.getItemAt(i).Location)
{
tracer = i;
window.grid.selectedIndex = i;
}
}
var object:Object = window.grid.getItemAt(tracer);
if(object.Artist == null)
{
object.Artist = "";
}
if(object.Song == null)
{
object.Song = "";
}
tf.text = object.Artist + " - " + object.Song;
channel = currentSound.play();
channel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete);
}
catch(event:Error)
{
//
}
}
private function onSoundComplete(event:Event):void
{
playNextSong();
}


## Step 25: Volume Control

What good would an mp3 player be without the ability to control the volume? Here we set up the slider to control the volume. We pass the value of the slider to the updateVolume function which updates the volume.

private function sliderDown(event:MouseEvent):void
{
volControl.slider.removeEventListener(MouseEvent.MOUSE_DOWN, sliderDown);
stage.addEventListener(MouseEvent.MOUSE_MOVE, sliderMove);
stage.addEventListener(MouseEvent.MOUSE_UP, sliderUp);
yOffset = mouseY - event.target.y;
}
private function sliderMove(event:MouseEvent):void
{
var mc:MovieClip = volControl.slider;
mc.y = mouseY - yOffset;
if(mc.y <= 0)
{
mc.y = 0;
}
else if(mc.y >= (50))
{
mc.y = (50);
}
updateVolume(mc.y);
event.updateAfterEvent();
}
private function sliderUp(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, sliderMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, sliderUp);
volControl.slider.addEventListener(MouseEvent.MOUSE_DOWN, sliderDown);
}
private function updateVolume(num:Number):void
{
var vol:Number = (100 - (num*2))/100;
SoundMixer.soundTransform = st;
st.volume = vol;
}


## Step 26: Handling the Main Window

Here is the functions for controlling the main window. When the mouse is down on the “background” movieclip, we call the startMove method of the nativeWindow object. This is why we had to give our grate movieclip an instance name of “winBack”; we had to set the mouseEnabled property to false, eliminating any confusion. If we hadn’t done that, we would only be able to drag on the black circles, not the whole movieclip. The handleWindow function handles both the minimize and close buttons. Also, when we call thaose function, we set some control for our playlist window.

private function moveWindow(event:MouseEvent):void
{
stage.nativeWindow.startMove();
}
private function handleWindow(event:MouseEvent):void
{
if(event.target == closer)
{
stage.nativeWindow.close();
nw.close();
}
else
{
stage.nativeWindow.minimize();
nw.minimize();
}
}


## Step 27: The Final Functions

Here are final functions for our player. When we decide that we no longer want a song on our playlist, we can simply press the delete button to remove the song. When we press the “deli” button, we call the deliClick function. The function removes the item from the database, as well as lining up another song if the deleted song was the next song to play. The gridChange function is called everytime we add or remove an item from the database. This way the playlist will always stay up-to-date.

Finally, we need to be able to move the playlist around as well. We can call the moveNatWin function which works the same way as the functions for moving the main player window. Now the playlist can move all over screen without any limitation set by the stage of the main player window.

private function deliClick(event:MouseEvent):void
{
try
{
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = connect;
statement.text = "DELETE FROM PLAYLIST WHERE Location = ?";
statement.parameters[0] = window.grid.selectedItem.Location;
var string:String = window.grid.selectedItem.Location;
var item:int = window.grid.selectedIndex;
statement.execute();
loadData();
if(currentSound.url == string)
{
currentSound = new Sound(new URLRequest(window.grid.getItemAt(0).Location));
}
len = window.grid.length;
try
{
window.grid.selectedItem = window.grid.getItemAt(item-1);
}
catch(event:Error)
{
window.grid.selectedItem = window.grid.getItemAt(0);
}
} catch (event:Error) {
//
}
}
private function gridChange(event:Event):void
{
var dg:DataGrid = event.target as DataGrid;
currentSound = new Sound(new URLRequest(dg.selectedItem.Location));
}
private function moveNatWin(event:MouseEvent):void
{
var mc:MovieClip = event.target as MovieClip;
var st:Stage = mc.parent.parent as Stage;
st.nativeWindow.startMove();
}


## Step 28: Publishing the Application

The final step to this tutorial is to publish your application. Once it is tested and you’re satisfied with it, go to Commands > AIR – Application and Installer Settings. Make sure to set the “Window style” to “Custom Chrome (transparent)”. This way, we can see our dropshadows and the alpha we applied to the window backgrounds.

Once all your settings are applied, click the publish button, sign the application with our certificate and your new AIR mp3 player is ready to be installed.

## Conclusion

We covered quite a few new techniques in this tutorial. Each one can be applied in its own way or combined to produce something completely different. I hope this tutorial has sparked some ideas. Read up on AIR in the Adobe LiveDocs and don’t forget to subscribe to the Tuts+ feed. Thanks for reading!

• joseph ruano

only play mp3 format?

• I Put out Flames

Why dont YOU adapt it if thats what you want? Are you going to pay the man for his efforts?

• http://labs.dariux.com Dario Gutierrez

Very nice Jeremy, the code are amazing because is develop with classes and the final result are excellent! Congratulations!

• http://www.extremestudio.ro/blog Danny

Great MP3 Player mate! Nice work!

• boombox

very nice

• http://www.cbesslabs.com Sebastian Bratu

Cool, definitely cool !

Anybody up for a DJ-ing application ? I am for sure !

• raack

Me 2 :)

working on it

• Franco Rojas

Excelente tutorial, muy bueno

• http://www.omerercan.com Omer

very nice i like the drag and drop!

• http://www.flashmint.com flash templates

great drag’n'drop feature. how about the other type of file to play?

• IGor

That’s just great tut!!! Thank’s a lot!!!

• Phenomen

yeah, nice code, but no multiply files d’n'd support.

• RP

Gostei muito mesmo. Muito bom

• Ashish Tank

Good work man…

• John

where is the function for togglePlayList ?

• Pingback: 35个air教程 - zneil

• vamsi

It’s simply amazing.. Great tutorial and clear description about the file.. I really like it…. thanks a lot

• Carl Leiner

Great player and tut. I love the background and would love to use it in other apps but the thought of all those circles just made it impossible for me especiall with resizing, so I wrote a class which is an approximation of your background but totally actionscript. You can just set the parameters and let it draw

I thought I’d share it in case anyone would think it helpful

package
{
import flash.display.GradientType;
import flash.display.InterpolationMethod;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.filters.BevelFilter;
import flash.filters.DropShadowFilter;
import flash.geom.Matrix;

/**
* …draws mesh of circles over a radial gradient
* @author Carl E. Leiner
*/
public class MeshBackground extends Sprite
{
private var h=300
private var w=300
private var rc=0
private var xPos=0
private var yPos = 0
private var rad = 3
private var colors:Array = [0x6D6D6D, 0x0]
private var holeColor:uint=0;
private var holes:Sprite
private var backgroundGradient:Sprite
private var masker:Sprite
private var bf=new BevelFilter()
private var ds=new DropShadowFilter()

public function MeshBackground(width:Number=300,height:Number=300,colors:Array=null,holeColor:uint=0):void
{
bf.blurX=bf.blurY=-1
bf.distance=-1
bf.angle=210
bf.strength=.55
bf.quality = 3
ds.strength=.66
ds.quality=3
ds.angle=90
ds.blurX=ds.blurY=ds.distance=4
w = width
h = height
if (colors)this.colors = colors
this.holeColor=holeColor
holes=new Sprite()
backgroundGradient = new Sprite();
addChildAt(backgroundGradient, 0);
drawBack()
addChild(holes)
drawHoles()
masker = new Sprite()
addChild(masker = new Sprite())
addMask()
this.mask=masker
this.filters=[ds]
}

private function drawHoles():void
{
while (yPos<=h)
{
while(xPos<=w)
{
holes.graphics.beginFill(holeColor)
holes.graphics.drawCircle(xPos,yPos,rad)
holes.graphics.endFill()
xPos+=rad*4
}
rc++
xPos=rc%2?-(rad*2):0
yPos+=rad*3
}
holes.filters=[bf]
}

private function addMask():void
{
masker.graphics.beginFill(0)
masker.graphics.drawRect(0,0,w,h)
masker.graphics.endFill()
}

private function drawBack():void{
var alphas:Array = [.60,.88 ];
var ratios:Array = [0, 0xFF];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(w, h, (3 * Math.PI / 2));
with(backgroundGradient.graphics){
clear();
beginGradientFill(GradientType.RADIAL, colors, alphas, ratios, matrix, SpreadMethod.PAD, InterpolationMethod.RGB);
drawRect(0, 0, w, h);
endFill();
}
}
}

}

• Catalin

Hi all,

I’m so happy I found this code… I looked for it a lot and I was hoping to be more simple but I’m still happy… But, after I’ve fixed the errors generated from my bad copy/paste ability, I still got this error and I don’t know what to do… please help me!

“1037: Packages cannot be nested”

What did I do wrong? anybody can help? I really appreciate! Thanks!

• Ankit

Its really awesome… I follow this tutorial and created my first Air App :)…. I have tested it on Air 2.6 and playlist is not visible fully??? any1 know what is causing here…

once again thank you so much for gr8 tutorial :)

• Ankit

Ok Finally I got the solution

under buildWindow() function end we have loadData(); just above tat add

nw.width = 210;

then publish… after that you can see playlist :)…