Day 5: Nearing the End

Getting closer now. It is really just finding solutions at this point. For example, the old issue of having one of something is not the same as having an Array of 1 item, bit me. I had to use the ever-trusty ArrayUtil class:

var ac:ArrayCollection = new ArrayCollection(  ArrayUtil.toArray( tags ) );

I spent a number of hours getting the ImageView and ImageInfo screens to work again. I found myself not really looking at the Flex 1.5 version code and just re-coded in the spirit of Flex 2. Sometimes I did reach over for an algorithm or technique, but mostly I just wrote new code. I guess I like typing. When you are thinking of using Flex 2 on an existing Flex 1.5 project, bear in mind that you will have to change code in some places, so approaching the application from a fresh perspective may turn out to be a better strategy in the long run.

ImageViewer and ImageInfo

The ImageViewer is the TitleWindow that pops up when you click on an image in either the Favorites Panel or the Photo Gallery. You’ll definitely want to use the itemClick event instead of change on any list you intend to use with drag and drop. Remember: change signifies a change in the selection state of the list.

The ImageViewer works like this: a Thumbnail is clicked which causes a itemClick to be raised by the TileList. This is caught by the PhotoSearch component. If the ImageViewer is not already in existance, a new one is created via the PopUpManager. A number of events are registered for the ImageViewer (more on that below) and the ImageViewer is displayed.

Just before the click event handler exits, it makes a request to the Flickr service to get the image details. When those details arrive, they are given to the ImageViewer via its photoInfo property (a setter function).

When the ImageViewer first appears there is no image and no extra information (remember, that just went off to Flickr). So the ImageViewer is in its base state which shows the word “Loading…” in the lower right corner. As soon as the image information is given to it (via the photoInfo property), the ImageViewer shifts into the “loadedState”.

The user can click on the Info icon to see more details. I decided this would be another opportunity to use States. The ImageInfo panel would be displayed in the ImageViewer’s “infoState” which would be based upon the “loadedState”. Here are a couple of benefits to doing that:

  • I do not have to write any code to make the ImageInfo appear; the state-change mechanism does that
  • If I am viewing image information and I click on another image in the gallery, this causes the ImageViewer to go to the base state and the ImageInfo is taken down – and – the owner’s name is replaced with “Loading…”

This is all very neat and clean. And while you may have been thinking that you could just use a ViewStack instead of States, what I just described cannot be done with a ViewStack. Plus, having written this out the long way in Flex 1.5, I definitely think States have provided a very useful alternative.

Events

I was originally going to title this section, Death by One Thousand Events but that was too dramatic, even for me. Truth is, Events are our friends. Our very good friends. In Flex 2, it is just finding the right event.

Since this is an exploration of what is new with Flex 2, I decided that it was time I bubbled an event. That means I want a lower component to dispatch an event that a higher component (in the child-parent heirarchy) will catch, but without needing to involve any of the components in between.

For example, when you pick the info button on the ImageViewer, you see in the ImageInfo component a list of tags for an image. A search is kicked off if you click one of those tags. So how to do this?

The tags which appear in the ImageInfo window are Links. When a link is clicked, its click event handler dispatchs a com.macromedia.flickr.SearchEvent which contains the tag.

I want the SearchEvent to be caught by the PhotoSearch component, not ImageInfo’s parent, ImageViewer. In Flex 1.5 you have to intercept the event in ImageViewer, then dispatch it again so PhotoSearch can receive it. In Flex 2, I just have PhotoSearch listen for a SearchEvent on ImageViewer. Very simple. Very loosely coupled. We like that.

Another cool thing I did, which is not specific to Flex 2, is have other components handle events. For example, on the ImageViewer you can click the Next Image button and the next image in the gallery (Favorites or Photo) will appear. The ImageViewer dispatches the nextImage event.

In the PhotoSearch class, I set up the event listener like this:

imageViewer.addEventListener("nextImage",gallery.nextImage);
imageViewer.addEventListener("nextImage",favorites.nextImage);

Now PhotoSearch isn’t even involved with these events as only the Gallery and Favorites care about them. What this means however, is that both components will receive the same event – it is up to the components to know if they should handle it or not.

To make that happen, the ImageViewer is told for which TileList it is displaying images. That is, whenever an image is clicked, not only is that image’s information given to the ImageViewer, that image’s TileList is given, too.

Both the Gallery and Favorites, in their nextImage event handler, ask the event target (the ImageViewer) what gallery it is showing and if it is themselves, that gallery dispatches an imageClick event as if the user click on the image.

Again, loosely coupled, re-used event handling code.

Problems

Well, it would not be interesting without some problems to solve. Here’s today’s list of things I either could not figure out or have determined are missing in the Flex 2 Alpha 1 release.

  • Effects for state changes. I was able to, with the help of a Flex 2 Forum member, make the ImageInfo window appear to Fade in, but I cannot get it to Fade out. I believe this is due in part to how children added by a State are removed (rather unceremoniously, no double) so there is no time for an effect to take place. We should see effects for States appear in a later release.
  • Some of the image information descriptions contain HTML, specifically hyper-links. In Flex 1.5 I used a StyleSheet object to make any links appear blue and have an underline when you hover the mouse over them. That appears to be broken in Flex 2. So the link is there and it works, you just don’t know it until the mouse pointer changes to a hand. I’m sure this will get fixed.
  • It took me the longest time to figure out how to create the Links for the tags in ActionScript. I don’t know why, it is so easy – it is just different from Flex 1.5. For example, in Flex 1.5 you used one of the create methods like, createChild( datatype, undefined, initprops ). In Flex 2, it is easier. See the code snippet below.
  • Drag and drop are easy, to a point. Since I am using TileList instead of Tile, I can have the TileList handle the initiation of a drag operation simply by coding dragEnabled="true" on their definitions. The problem is, I cannot tell how started a drag operation. For example, you are supposed to be able to drag a Favorite over the Trashcan to delete it, but you are not supposed to be able to drag a Thumbnail from the Gallery. Only a drag out of Favorites should light up the Trashcan. But I cannot tell who started the drag, so the Trashcan cannot tell the difference. The jury is out on this one.

Here’s how to create a Link using ActionScript. You’ll find this in the ImageInfo component code when I put the code up on the weblog server.

import mx.controls.Link;
...
var link:Link = new Link();
link.label = tagName;
link.addEventListener( "click", handleLinkClick );
addChild(link);

Conslusion

Well, I’m almost ready to publish this code. I have to put in more comments, clean up some debug code, and hope that I can get drag and drop to work.

Stay tuned…