The Space For App Developers

Beyond Plain Old HTML Objects

Archive for January, 2010

Secure sockets with Adobe AIR 2.0

with 2 comments

During my journey of discovering the goodness of AIR 2.0 I wanted to try the new secure sockets functionality. AIR 2 comes with a new class, SecureSocket, which actually extends the standard Socket class. The easiest way for me to test it was to try to connect to GMail’s IMAP server. I was actually inspired by very cool example built by Christian Cantrell called MenuMail available here to download from Adobe Labs. I think the code below is self explaining; when you click Connect button you should see following trace output in the console:
onConnect [Event type="connect" bubbles=false cancelable=false eventPhase=2]
onSocketData [ProgressEvent type="socketData" bubbles=false cancelable=false eventPhase=2 bytesLoaded=66 bytesTotal=0]
* OK Gimap ready for requests from x.x.x.x n12if410166gve.29

Below is the source code:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
					   xmlns:s="library://ns.adobe.com/flex/spark" 
					   xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:halo="library://ns.adobe.com/flex/halo">
 
	<fx:Script>
		<![CDATA[
			import flash.events.Event;
			import flash.events.IOErrorEvent;
			import flash.events.MouseEvent;
			import flash.events.ProgressEvent;
			import flash.events.SecurityErrorEvent;
			import flash.net.SecureSocket;
			import flash.net.Socket;
 
			protected var secureSocket:SecureSocket;
 
			protected function btnConnect_clickHandler(event:MouseEvent):void
			{
				secureSocket = new SecureSocket();
				secureSocket.addEventListener(Event.CONNECT, onConnect);
				secureSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
				secureSocket.addEventListener(IOErrorEvent.IO_ERROR, onIoError);
				secureSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
				secureSocket.connect(txtServerAdress.text, parseInt(txtServerPort.text));
			}
 
			/**
			 * Handles Event.CONNECT event when successful connection is established
			 */
			protected function onConnect(event:Event):void 
			{
				trace("onConnect", event);
			}
 
			/**
			 * Handles ProgressEvent.SOCKET_DATA when data is received through the SecureSocket
			 */
			protected function onSocketData(event:ProgressEvent):void 
			{
				trace("onSocketData", event);
 
				var socket:Socket = event.target as Socket;
				trace(socket.readUTFBytes(event.bytesLoaded));
			}
 
			/**
			 * Handles IOErrorEvent.IO_ERROR when IO error happens during the connection
			 */
			protected function onIoError(event:IOErrorEvent):void 
			{
				trace("onIoError", event);
			}
 
			/**
			 * Handles SecurityErrorEvent.SECURITY_ERROR event on any security errors
			 */
			protected function onSecurityError(event:SecurityErrorEvent):void 
			{
				trace("onSecurityError", event);
			}
 
		]]>
	</fx:Script>
 
	<halo:Form horizontalCenter="0" verticalCenter="0">
		<halo:FormHeading label="Connection info"/>
		<halo:FormItem label="Server adress:">
			<s:TextInput id="txtServerAdress" text="imap.gmail.com" />
		</halo:FormItem>
		<halo:FormItem label="Server port:">
			<s:TextInput id="txtServerPort" text="993"/>
		</halo:FormItem>
		<halo:FormItem>
			<s:Button id="btnConnect" label="Connect" click="btnConnect_clickHandler(event)" />
		</halo:FormItem>
	</halo:Form>
 
</s:WindowedApplication>

Written by Piotr Walczyszyn

January 29th, 2010 at 4:06 pm

Posted in Examples

Tagged with

File promises with Adobe AIR 2.0

with 6 comments

File promises is one of the new AIR 2.0 features already available in beta on Adobe Labs. “A file promise is a drag-and-drop clipboard format that allows a user to drag a file that does not yet exist out of an AIR application. AIR uses the methods and properties defined by the IFilePromise interface to access the data to be written when the file promise is dropped.” To check out how it works, I built a sample application that allows you drag an AIR icon out of the app and drop it somewhere in your system (e.g. on your desktop). Dropping it will initiate a download of the current stable AIR runtime installer (at this point in time it is AIR 1.5.3). The downloaded file containing the runtime will be appropriate for your operating system. This logic is implemented in the fileUrl function and it uses the Capablities.os property with a simple regexp search for “win”, “lin”, or “mac” patterns.

Here is how the application looks:

Below is the source code:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
					   xmlns:s="library://ns.adobe.com/flex/spark" 
					   xmlns:mx="library://ns.adobe.com/flex/mx"
					   xmlns:halo="library://ns.adobe.com/flex/halo"
					   currentState="START_STATE" height="200" width="300" viewSourceURL="srcview/index.html">
 
	<s:layout>
		<s:VerticalLayout horizontalAlign="center" gap="15"/>
	</s:layout>
 
	<fx:Script>
		<![CDATA[
			import flash.events.Event;
			import flash.events.MouseEvent;
			import flash.system.Capabilities;
 
			protected var filePromise:URLFilePromise;
 
			protected function imgAirIcon_mouseDownHandler(event:MouseEvent):void
			{
				// Instantiating new file promise
				filePromise = new URLFilePromise();
				// Registering OPEN event listener, to switch to 
				// DOWNLOAD_STATE when downloading starts
				filePromise.addEventListener(Event.OPEN, onOpen);
 
				// Setting URLRequest pointing to remote file
				filePromise.request = new URLRequest(fileUrl);
				// Setting relativePath with fileName to be saved locally
				filePromise.relativePath = fileName;
 
				// Array of promises with single promise in this case
				var promises:Array = new Array();
				promises.push(filePromise);
 
				// Instantiating clipboard object pointing to the promise
				var clipboard:Clipboard = new Clipboard();
				clipboard.setData(ClipboardFormats.FILE_PROMISE_LIST_FORMAT, promises);
 
				// Dragging with NativeDragManager
				NativeDragManager.doDrag(imgAirIcon, clipboard);
			}
 
			protected function onOpen(event:Event):void
			{
				currentState = "DOWNLOAD_STATE";
				prgBar.source = filePromise;
			}
 
			protected function get fileUrl():String
			{
				// Returns remote file URL based on current operating system
				if (Capabilities.os.search(/mac/i) > -1)
					return "http://airdownload.adobe.com/air/mac/download/latest/AdobeAIR.dmg";
				else if (Capabilities.os.search(/win/i) > -1)
					return "http://airdownload.adobe.com/air/win/download/latest/AdobeAIRInstaller.exe";
				else 
					return "http://airdownload.adobe.com/air/lin/download/latest/AdobeAIRInstaller.bin";
			}
 
			protected function get fileName():String
			{
				var fileUrl:String = fileUrl;
				return fileUrl.slice(fileUrl.lastIndexOf("/") + 1);
			}
		]]>
	</fx:Script>
 
	<s:states>
		<s:State name="START_STATE"/>
		<s:State name="DOWNLOAD_STATE"/>
	</s:states>
 
	<halo:Image id="imgAirIcon" source="assets/air_icon_special.gif" mouseDown="imgAirIcon_mouseDownHandler(event)" toolTip="{fileUrl}" />
 
	<s:Label text="(Drag it out to start download)" />
 
	<halo:ProgressBar id="prgBar" bottom="10" horizontalCenter="0"  visible="false" visible.DOWNLOAD_STATE="true" label="Downloading {int(prgBar.percentComplete)}%"/>
 
</s:WindowedApplication>

Written by Piotr Walczyszyn

January 26th, 2010 at 5:37 pm

Posted in Examples

Tagged with

Flerry: Flex-Java bridge for Adobe AIR 2.0

with 106 comments

Today I published Flerry on Google Code, a Flex-Java bridge that uses NativeProcess API from Adobe AIR 2.0. Using it is very simple and similar to RemoteObject API in Flex. In fact I reused libraries from BlazeDS to do AMF de/serialization on Java side and on Flex side classes like AsyncToken, RemotingMessage, AcknowledgeMessage and ResultEvent/FaultEvent for eventing.

Here is short snippet how you can use it directly in MXML:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="300" minHeight="200" xmlns:flerry="net.riaspace.flerry.*">
    <fx:Script>
        <![CDATA[
            import flash.events.MouseEvent;
 
            import mx.controls.Alert;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
 
            protected function nativeObject_faultHandler(event:FaultEvent):void
            {
              Alert.show(event.message.toString());
            }
 
            protected function addMethod_resultHandler(event:ResultEvent):void
            {
              txtResult.text = event.result.toString();
            }
 
            protected function btnAdd_clickHandler(event:MouseEvent):void
            {
              nativeObject.add(parseInt(txtValue1.text), parseInt(txtValue2.text));
            }
            ]]>
    </fx:Script>
    <fx:Declarations>
 
    <!-- Declaring NativeObject that points to 
            net.riaspace.flerrydemo.MyJavaObject class in ./jars/flerry-demo.jar -->
    <flerry:NativeObject id="nativeObject" binPath="./jars/flerry-demo.jar" 
            source="net.riaspace.flerrydemo.MyJavaObject"
            fault="nativeObject_faultHandler(event)">
 
      <!-- Declaring NativeMethod with custom result handler, for this example 
              actually result from NativeObject could be used -->
      <flerry:NativeMethod id="addMethod" name="add" 
            result="addMethod_resultHandler(event)" />
 
    </flerry:NativeObject> 
 
  </fx:Declarations>
 
  <s:HGroup verticalAlign="middle" textAlign="center" horizontalCenter="0" verticalCenter="0">
    <s:TextInput id="txtValue1" text="2" width="30" />
    <s:Label text="+" width="30" />
    <s:TextInput id="txtValue2" text="3" width="30" />
    <s:Button id="btnAdd" label="=" width="30" click="btnAdd_clickHandler(event)" />
    <s:TextInput id="txtResult" width="30" editable="false" />
  </s:HGroup>
 
</s:WindowedApplication>

Some NativeObject properties:

  • binPath – points to jar file with your Java application
  • source – points to java class that this NativeObject maps to
  • singleton – sets source class object as singleton
  • startupInfoProvider – custom implementation of net.riaspace.flerry.IStartupInfoProvider, by default Flerry comes with JavaStartupInfoProvider that tries to detect where Java is installed on users machine, in other case Error is thrown

In following posts I will explain in details how it all works, for now you can download flerry Flash Builder project with all the source code from here.

Written by Piotr Walczyszyn

January 13th, 2010 at 7:32 pm

Posted in Examples,Releases

Tagged with , ,

Simple Flex 4 components styling (part 2)

with 2 comments

In my previous post I gave few hints about styling Flex 4 applications using default Spark theme. This time I extended it to additional MX containers and also wanted to explain what particular CSS properties mean.

  • chrome-color (chromeColor, it was renamed from baseColor after Flex 4 Beta 2) – The main color for a component
  • content-background-color (contentBackgroundColor) – Color of the fill of an item renderer
  • symbol-color (symbolColor) – Color of any symbol of a component. Examples include the check mark of a CheckBox or the arrow of a scroll button
  • selection-color (selectionColor) – The color of text when the component is enabled and has focus
  • focus-color (focusColor) – Color of focus ring when the component is in focus
  • roll-over-color (rollOverColor) – Color of the highlights when the mouse is over the component
  • color – Color of the text
  • text-roll-over-color (textRollOverColor) – Color of the text highlights when the mouse is over the component, used in old MX components.
  • accent-color (accentColor) – Additional color used for accent. This color is used by “emphasized” buttons (default button in Alert box), and the slider track highlight.
/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
 
global
{
	chrome-color: #333333;
	content-background-color: #333333;
	symbol-color: #FFFFFF;
	selection-color: #FFB129;
	focus-color: #FF7F29;
	roll-over-color: #F7DCAD;
 
	color: #D7D6D6;
	text-roll-over-color: #D7D6D6;
 
	accent-color: #FFB129;
}
 
s|Panel
{
	background-color: #333333;
}
 
mx|Alert
{
	background-color: #333333;
}
 
mx|TabNavigator
{
	background-color: #333333;
}
 
mx|ToolTip
{
	color: #000000;
}

This it the result of applying this style sheet (same as in previous post):

This movie requires Flash Player 10

Written by Piotr Walczyszyn

January 6th, 2010 at 1:45 pm

Posted in Examples

Tagged with

Simple Flex 4 components styling (part 1)

with 6 comments

As you probably know, the upcoming Flex 4 (Gumbo) release was built with design in mind to let developers easily and quickly skin and style their applications. In particular, skinning can be realized with the use of a new component architecture called Spark that comes with two built-in themes, one also called Spark (the default) and the second one called Wireframe (very useful when prototyping). In addition to the skinning capabilities, new CSS properties were also introduced that make it even simpler to style existing components and quickly achieve really good looking results without needing new custom themes.

As an example I came up with a set of styles that you can apply to default Spark components to get a nice looking dark theme. Here is the example (with the source code here):

This movie requires Flash Player 10

Example above uses only following CSS properties:

/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
 
global
{
	chrome-color: #333333;
	content-background-color: #333333;
	symbol-color: #FFFFFF;
	selection-color: #FFB129;
	focus-color: #FF7F29;
	roll-over-color: #F7DCAD;
	color: #D7D6D6;
}
 
s|Panel
{
	backgroundColor: #333333;
}

To make it even simpler to style your application theme there was a new Appearance panel introduced in Flash Builder 4. It is available in the design view for your main MXML component.

Appearance Panel

Written by Piotr Walczyszyn

January 5th, 2010 at 6:11 pm

Posted in Examples

Tagged with

Twitter-like syntax formatter with smart truncation

without comments

Recently I needed to format a Twitter-like input string, replacing the @UserName, #Tag and http://some.url syntax with an html a tag and adding the proper event: prefix to the href content so that it could dispatch a Flex link event (more info about link events Listening for the link event in a Flex Label control). Additionally I wanted to intelligently truncate the input string to the specified maximum length. I used RegExp for syntax parsing and also extended mx.formatters.Formatter. I guess RegExp expression might be more elegant but this way was good enough for my purposes.

Formatter code:

package net.riaspace
{
	import mx.formatters.Formatter;
 
	public class TwitterFormatter extends Formatter
	{		
 
		public var truncate:Number = NaN;
 
		protected var regExp:RegExp = /((@|#)\w+)|((ht|f)tp(s?):\/\/)(\S+)/ig;
 
		public function TwitterFormatter()
		{
			super();
		}
 
		override public function format(value:Object):String
		{
			if (value != null)
			{
				var str:String = String(value);
 
				if (!isNaN(truncate) && str.length > truncate - 3)
				{
					var index:int = lastWhiteSpaceIndex(str.substr(0, truncate - 2)); // truncate - 2 checks if after last char there is no white-space
					if (index > 0)
						str = str.substring(0, index); // truncates after last white-space
					else
						str = str.substr(0, truncate - 3); // truncates at specified truncate index -3 for ...
 
					str = str + "...";
				}
 
				return str.replace(regExp, "<u><a href='event:$&'>$&</a></u>");
			}
			return null;
		}
 
		protected function lastWhiteSpaceIndex(str:String):int
		{
			return Math.max(
				str.lastIndexOf(" "), 
				str.lastIndexOf("\n"), 
				str.lastIndexOf("\r"), 
				str.lastIndexOf("\t"));
		}
	}
}

Usage example:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="1024" minHeight="768" xmlns:riaspace="net.riaspace.*">
 
	<fx:Script>
		<![CDATA[
			import mx.controls.Alert;
			protected function txt_linkHandler(event:TextEvent):void
			{
				Alert.show("Clicked: " + event.text);
			}
		]]>
	</fx:Script>
 
	<fx:Declarations>
 
		<riaspace:TwitterFormatter id="formatter" truncate="100" />
 
		<fx:String id="twitterString">
			#Lorem @ipsum http://dolor sit amet, consectetur adipiscing elit. In vehicula mollis velit a lobortis. Vivamus quis turpis non odio aliquet mattis. Proin vel nisi in nisi condimentum ornare eget porttitor tortor. Phasellus et nulla est, sit amet cursus nunc. Maecenas sit amet nisi augue, in euismod mauris. Nulla facilisi. Curabitur hendrerit aliquam magna, facilisis pellentesque justo semper eget. Quisque eleifend nisi non risus elementum ut feugiat urna ultricies. Morbi elementum augue non velit tempus tempus hendrerit sit amet diam. Mauris eleifend odio sit amet tellus luctus pellentesque. Curabitur nec massa dui, at imperdiet purus. 
		</fx:String>
 
	</fx:Declarations>
 
	<mx:Text id="txt" link="txt_linkHandler(event)" htmlText="{formatter.format(twitterString)}" 
			 width="100%" height="100%" />
 
</s:Application>

Written by Piotr Walczyszyn

January 4th, 2010 at 6:20 pm

Posted in Examples

Tagged with