Posts Tagged ‘flex’

Adobe Air MP3 Shaker (Shuffle)

Sunday, February 7th, 2010

I like iTunes, it’s a good media player. But I got some MP3s that are not part of my iTunes library, an old backup. I don’t want ALL of them to be automatically imported into my iTunes library just so I can listen to them. And There is a lot, over 1000. I wanted to select the directory, and hit play and have it go through so I can listen. If any that caught my attention and were not already in my library I could import it. On Windows, I would just use WINAMP. But I could not find a Mac version of WINAMP. I wanted something light, simple, just to play a directory of MP3s.

A few years ago, my first Adobe AIR project was an MP3 player. It was pretty much full featured: volume control, track progress, skinning, etc. I wanted something a little simpler, cleaner. I had a free Saturday, and I made a new one. Based it off of the Apple iPod Shuffle, 2nd generation. It is very simple to use. When it opens, select a directory of MP3s (it only plays MP3s), and be patient if its a directory with thousands of MP3s it will take a moment to load. A window will come up with a list of all the MP3s, double click one to play, or hit the play button, or next. You can close the windows and just have the player up, it shows the name of the song if ID3 tags are available. The reason I call it “MP3 Shaker”: if you shake it (drag it left and right really fast) it will shuffle to another song (just like the new iPods). Click the green light on the top right to close.

As always, its open source. Right click anywhere on the player and select view source. Enjoy!

Please upgrade your Flash Player This is the content that would be shown if the user does not have Flash Player 9.0.115 or higher installed.

AIR/Flex URLRequest: Sending Authentication Headers

Wednesday, June 17th, 2009

If the request requires authentication and URLRequest.authenticate is set to true (the default) the operating systems login window will popup asking for credentials. These will be automatically sent in the request. To manually set the username and password there are a few ways:

URL Request Defaults:

URLRequestDefaults.setLoginCredentialsForHost("www.domain.com",username,password);

Headers:

var encAuth:Base64Encoder = new Base64Encoder();
encAuth.encode(username+":"+password);
var header:URLRequestHeader = new URLRequestHeader("Authorization","Basic "+ encAuth.toString() );
var request:URLRequest = new URLRequest(url);
request.requestHeaders.push(header);

Under both ways, once a successful login occurs the credentials are remembered while the application is open and the user is not asked for username and password again.

BreakTimer – an AIR app to remind you to take a break from the computer

Monday, May 4th, 2009

My current career path has me sittign on my ass infront of a computer for most of the daylight hours. I have back issues, and sometimes I get too involved in my work and forget to move.  Combine that with years of volleyball and tight muscles I got a herniated disc.  So I made a simple AIR application that will block out the screen and tell you to take a break after a proscribed period of time (30 minutes).  This can be set from 0 to 180 minutes (no person should be sitting for 180 minutes straight though!).  If you have multiple monitores it will block all your monitors.

The source is there for you to tweak, right click on the app and view source.

Reading and Writing Files in AIR – using a simple text editor

Monday, January 26th, 2009

Monstagon asked me if I ever saved or opened files in Adobe AIR. Yes. I have. I made a simple text editor to demonstrate the basics of reading files in (letting the user browse for a file on their machine) and writing a save (also letting the user specify where to save the new file).

Some issues I encountered with making the text editor were the different FileModes (READ, WRITE, UPDATE, and APPEND). UPDATE and APPEND basically just add whatever you write to the FileStream to the end of the file. WRITE deletes the destination and writes only what is sent to the FileStream. READ only opens the file for reading. After erasing some files accidentally by opening it with WRITE, I realized for the text editor to work, first READ the file in, close the FileStream. When the user hits Save, open the file in WRITE mode, and send the contents of the editor to the FileStream.

I also had to removeEventListener from the FileStream because it was listening for two Event.SELECT’s: user selects which file to open, and user selects where to save. This was throwing errors when the user selects where to save and the program tries to open a file that doesn’t exist.

If you just want to know how to read a file, look at private function Open() and follow the code. For writing, private function Save(). Note that in ActionScript, its all about event listeners. So reading the file contents into the TextArea is 3 function, because we have to wait until each step is ready. Else, if you don’t setup the Event Listeners nothing will happen.

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.events.FileEvent;
private var stream:FileStream;
private var file:File = File.documentsDirectory;
private var newFile:Boolean = true;
private function New():void
{
	newFile = true;
	editor.text = '';
}
private function Open():void
{
	try
	{
	    file.browseForOpen("Open");
	    file.addEventListener(Event.SELECT, LoadFile);
	}
	catch (error:Error)
	{
	    trace("Failed:", error.message);
	}
}
private function LoadFile(evt:Event):void
{
	file.removeEventListener(Event.SELECT, LoadFile);
	file = evt.currentTarget as File;
	stream = new FileStream();
	stream.addEventListener(Event.COMPLETE, ReadFile);
	stream.openAsync(file,FileMode.READ);
}
private function ReadFile(evt:Event):void
{
	stream.removeEventListener(Event.COMPLETE,ReadFile);
	var str:String = stream.readUTFBytes(stream.bytesAvailable);
	editor.text = str;
	newFile = false;
	stream.close();
}
private function Save():void
{
	if(!newFile)
	{
		stream = new FileStream();
		stream.openAsync(file,FileMode.WRITE);
		stream.writeUTFBytes(editor.text);
		stream.close();
	}else
	{
		file.browseForSave("Save");
		file.addEventListener(Event.SELECT, SaveFile);
	}
}
private function SaveFile(evt:Event):void
{
	file.removeEventListener(Event.SELECT, SaveFile);
	var file:File = evt.currentTarget as File;
	stream = new FileStream();
	stream.openAsync(file,FileMode.WRITE);
	stream.writeUTFBytes(editor.text);
	stream.close();
	newFile = false;
}
]]>
</mx:Script>
<mx:VBox width="100%" height="100%">
<mx:HBox>
	<mx:Button label="New" click="New();" />
	<mx:Button label="Open" click="Open();" />
	<mx:Button label="Save" click="Save();" />
</mx:HBox>
	<mx:TextArea id="editor" width="100%" height="100%" />
</mx:VBox>
</mx:WindowedApplication>

Detecting Screen Resolution in Flex/AIR

Saturday, January 10th, 2009

Monstagon asked me how to scale and AIR application to the users screen resolution. There are
a few ways to achieve this: maximize(), StageDisplayState.FULLSCREEN, or Capabilities.screenResolutionX/Y.
Here is a little tutorial/sample of resizing a chomeless window to fit the screen
using all 3 methods.

Go open Flex Builder 3, and create a new AIR project. First, lest go chromeless.
Open the app.xml file to edit the application settings. We need to set
systemChrome and transparent to none and true
respectively.

<!-- Thetype of system chrome to use (either "standard" or "none"). Optional. Default standard. -->
<systemChrome>none</systemChrome>

<!-- Whether the window is transparent. Only applicable when systemChrome is none. Optional. Default false. -->
<transparent>true</transparent>

And now we need to set up the WindowedApplication properties showStatusBar,
showTitleBar, and just for effect backgroundAlpha to false,
false, and 0.5. Also set applicationComplete to the
startup function, in this case Init();. (I ran into some trouble accessing the stage
in the startup function when I was listening for the creationComplete event. We need to listen
for applicationComplete if we want to access stage and stage items, because when this event
is fired, everything is drawn and ready to go.
Understanding The Flex Application Startup Event Order)

	<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="Init();"
		showStatusBar="false" showTitleBar="false" backgroundAlpha="0.5" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#000000, #5D7B68]">

Enough jabber, here is are the functions source code. Layout some buttons to activate which options you want to see.

<mx:Script>
	<![CDATA[
	import mx.events.FlexEvent;
	private function Init():void
	{
		addEventListener(MouseEvent.MOUSE_DOWN,InitMove);
	}
	private function CapabilitiesMax():void
	{
		width = Capabilities.screenResolutionX;
		height = Capabilities.screenResolutionY;
	}
	private function FullScreen():void
	{
		stage.displayState = StageDisplayState.FULL_SCREEN;
	}
	/* MOVE */
	private function InitMove(evt:MouseEvent):void
	{
		stage.nativeWindow.startMove();
	}
	]]>
</mx:Script>
<mx:VBox horizontalCenter="0" verticalCenter="0" horizontalAlign="center">
	<mx:Button label="stage.nativeWindow.maximize()" click="stage.nativeWindow.maximize();" />
	<mx:Button label="Resize to Screen Resolution" click="CapabilitiesMax();" />
	<mx:Button label="stage.nativeWindow.restore()" click="stage.nativeWindow.restore();" />
	<mx:Button label="Full Screen" click="FullScreen();" />
	<mx:Button label="Close" click="close();" />
</mx:VBox>

And that is the entire source code to demostrate how each option works. A thing to note,
when using the “Resize to Screen Resolution” the window is not centered, but stretched
from its current screen position. In most cases, I maximize(); would be the function
to use, or set it to full screen. And if you want to manually resize it to the screen resolution
and have the window centered, set the x and y of stage.nativeWindow to 0.
Here is the new CapabilitiesMax() function.

private function CapabilitiesMax():void
{
	width = Capabilities.screenResolutionX;
	height = Capabilities.screenResolutionY;
	stage.nativeWindow.x = 0;
	stage.nativeWindow.y = 0;
}

Hope that helps Monsta. And I would enjoy working on a project, and I want chocolate.

KatanaPG Bug Fix / Update

Thursday, June 12th, 2008

I noticed that the max upload allowed was really 100KB and not 100MB, so I fixed the calculations and also added an address location in the browser. Hopefully the next update will have some basic photo editing features, like cropping, brightness, contrast. Maybe even add a feature that will email the link to the group. I will have to get with Nick, but it would also be cool to upload directly to a group and do some more managing in the air app, like moving pictures from group to group, etc.

Here is the new version: katanapg-v101-beta.air.zip

Non Standard (Custom) Window in AIR

Tuesday, May 27th, 2008

Monstagon was wanting to create a custom window for an AIR application at work and could not figure out how to do it. I had found a tutorial that used an apple shaped window, but I seem to have lost the bookmark. So I figured I’ll just post my own tutorial. Since that is what this dang blog is for!

First, create a new AIR application in Flex Builder. I called mine NonStandardGUI, but you can call it “whatever.” Then, open up the app-XML file (“NonStandardGUI-app.xml”) and we will edit the properties here first. This file is loaded automatically and contains all of the basic application properties. Set these properties to


systemChrome = none
transparent = true
visible = false
width = 800
height = 600
x = 100
y = 100

in the “initialWindow” section. The width, height, x and y are optional; you just need to make sure the size is big enough for the background image and the location on the screen allows you to see the whole window.

Now we will edit the NonStandardGUI.mxml (the main application file). To the WindowedApplication, add these attributes

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
        showTitleBar="false" showStatusBar="false"
        backgroundAlpha="0.0" borderThickness="0" >

This gets rid of the window. If you were to save and run the app now it would display nothing.

To add your image as the background, simply an Image tag with the source pointing to the actual image file. For better performance, we want to embed these static images. This could be a PNG, JPG, SWF… So the background can be anything you can create.

<mx:Image id="background" source="@Embed(source='nonStandard_GUI_test.png')" />

With the image in place a a background, you can add all the content you like to it. Due to the nonstandard shape of the new window, laying content out might be a little more time consuming since the Flex Builder Design view doesn’t load the image for you. I have attached the source code for my NonStandard GUI for you to dissect.

Source code: nonstandardgui.zip

Flex Image Resampling

Tuesday, May 6th, 2008

While working on KatanaPG (picture uploader) I ran into a memory issue. Pictures, especially those taken with 6+MP cameras, are HUGE. When I was creating the thumbnails for them in the TileList was was simply resizing them. This kept all that 6MP of data in memory just loooked smaller. I needed to resample it at a lower resolution and then dispose of the original. I tried it multiple ways, first using an Image and setting the source and then the width and height.  Then using a bitmap and scaleX and scaleY (as well as ImageSnapshop, but never go that to even work).  After posting a question to flexcoders a very kind replier said: “Use bitmap.draw.”  That method worked great.  Below is a chart of the Flex Profile peak memory for each method. Pictures imported: 23 Photo Booth pictures 640 x 480 and about 150KB on disk each.

Method Peak Memory (KB)
image.width/height 33,351
bitmap.scaleX/scaleY 61,837
bitmap.draw 7,107

I don’t know exactly why the first two methods take up almost as much memory as Firefox, but I am glad I managed to reduce the memory significantly. Now for he part you all have been waiting for, CODE. I used this code for a TileList.itemRenderer.

	<?xml version="1.0" encoding="utf-8"?>
	<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100" height="100" initialize="init();" creationComplete="created();" dataChange="init()">
	    <mx:Script>
	        <![CDATA[
	            import mx.graphics.ImageSnapshot;
	            import mx.core.UIComponent;

	       		private var _created:Boolean = false;

		        private function created():void
		        {
		            _created = true;
		            init();
		        }
		        private var contentLoader:Loader;
		        private function init():void
		        {
		            if(!_created)
		                return;
		            removeAllChildren();
		            contentLoader = new Loader();
		            contentLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, LoadComplete);
		            contentLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, IOErrorHandler);

		            var request:URLRequest = new URLRequest(data.url);
		            contentLoader.load(request);
		        }

		        //When image loaded, create scaled bitmap
		        private function LoadComplete(evt:Event):void
		        {
		            evt.stopImmediatePropagation();
		            var loader:Loader = Loader(evt.target.loader);
		            var image:Bitmap = Bitmap(loader.content);

		            var sxy:Number = (image.width > image.height)?(95/image.width):(95/image.height);
		            var scaleMatrix:Matrix = new Matrix();
		            scaleMatrix.scale(sxy,sxy);

		            var container:UIComponent = new UIComponent();
		            addChild(container);

		            var scaledImage:Bitmap = new Bitmap(new BitmapData(95,95,true,0));
		            scaledImage.bitmapData.draw(image,scaleMatrix);

		            container.addChild(scaledImage);
		            contentLoader = null;
		            image.bitmapData.dispose();
		        }
		        private function IOErrorHandler(evt:IOErrorEvent):void
		        {
		            trace("Error loading",data.url);
		        }
		    ]]>
		</mx:Script>
	</mx:Canvas>

KatanaPG AIR Pic Uploader

Wednesday, April 30th, 2008

I made a simple AIR app to upload pictures to my buddy’s online photo gallery, Katana Photo Groups.  The AIR app is very basic (first workign version released); but it does in fact work.  So this is what you do:

  1. Select directory to upload pictures from.
    OR
  2. Drag and Drop files onto app.
  3. Slecect the pictures you would like to upload.
  4. Login to KatanaPG.
  5. Click upload to upload pictures.

The above order clearly isn’t set in stone, but it gives you a basic idea of how the application works.

After that your pictures will be uploaded into your Inbox. You will need to already have a KatanaPG account for this to work.

It uses FZip (Actionscript zipping library) to compress the images into a zip and then uploads the zip to Katana.  I hope to had some basic images editing, drag and drop support, and it also needs some optimization.

Here is the package: katanapgair.zip

You will need Adobe AIR to run this.

UPDATE:

Added drag and drop from the PC and also fixed some memory issues.