Archive for the ‘UI’ Category

Flex / Twitter App Take 2

Thursday, June 14th, 2007

If you think this looks like any fun and don’t know anything about WPF go check out Kurt Brockett’s blog for an interesting challenge.

Thanks to a great tip from Matt Chotin, from Adobe, in the comments of my previous post I take a massive step forward in the UI department.  Again, the Open Source gods ( is this open source? ) work their magic to give me an even more useful component:  SpringGraph from another Adobe Engineer ( seeing a pattern are we ) named Mark Shepard.  He hasn’t blogged in some time, so I’m not sure he is still doing stuff with Adobe/Flex or blogging but, his component totally rules and fits my needs pretty closely.  Here is the original SpringGraph Demo and the Roamer Demo which is like the SpringGraph just with nodes hidden or collapsed ( which may be the final component I use ).  Well onto, what I’m trying to do:

Shiny New Object

First things first, time to see what makes the SpringGraph tick.  Given my limited knowledge of all things Flash, I had to piece together how the main body of his MXML file even worked. 

<fc:SpringGraph id="s" backgroundColor="#ffffff" lineColor="#333388" left="0" right="0" top="0" bottom="0" itemRenderer="AmazonItemView" repulsionFactor="{rep.value}" > </fc:SpringGraph>

It took me a few minutes to understand the beauty of the itemRenderer system built into Flex.  If you check out the other source objects in Mark’s project you will notice AmazonItem.as and AmazonItemView.as.  Think of this as a mini MVC subsystem.  With a collection of AmazonItem-s being the model, the SpringGraph control being the controller and the AmazonItemView obviously being the view.   This is made clearer when you add the following AS3 snippet to the mix

private var items: Graph; public function addItem(id: String, name: String, linkTo: AmazonItem): AmazonItem { var newItem: AmazonItem = new AmazonItem(id, name); items.add(newItem); if(linkTo != null) items.link(newItem, linkTo); s.dataProvider = items; return newItem; }

What is happening here?  Well as you call the addItem function an instance of the model, AmazonItem is created and added to collection.  This collection is then bound to the dataProvider of the SpringGraph.  When SpringGraph is drawn on the stage it loops at this dataProvider and instantiates a view object named itemRenderer for each item in the dataProvider.  So this allows you to completely change what the SpringGrid is rendering on your behalf — pretty cool, huh?

My “Model”

Now that I think I understand how that component works I need a place to store some data about a Twitter user.  Normally, you could just create a basic class and use that but, in the case of this component it seems you need to subclass the delivered Item class.  Once again, no big deal.  Created a new class called TwitterPerson.  That class has a few attributes:

public class TwitterPerson extends Item { [Bindable]public var screenName:String; [Bindable]public var name:String; [Bindable]public var profile_image:String;

These will store the data returned from the API, I’ve named the attributes nearly the same as the API to make it easier to follow.  The attributes are bindable so that as I fill in the information the “view” will update automatically.  The constructor is uber-simple:

public function TwitterPerson(xml:XML){ screenName = xml.screen_name; name = xml.name; profile_image = xml.profile_image_url; }

To make it as easy as possible to construct the TwitterPerson I just pass in an XML node and map the parameters myself.  If you check out the API you will see that the two services I use “statuses/friends/” and  ”users/show/” return different data but have the same information about each person with the same attribute names ( thanks for the consistency Twitter guys! ).

My “View”

The other piece I need to construct is the view that the SpringGraph will call to render the data stored in the model.  For right now all I want to do is put the picture of the person being rendered up there and give a tool tip for their name.  Flex makes something like this so easy it’s barely worth mentioning but for completeness:

<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Image source="{data.profile_image}" scaleX="1" scaleY="1" toolTip="{data.name}"/> </mx:VBox>

Two Heads are better then one but One’s a start

Back in the main MXML of our application things have changed a bit:

<mx:HTTPService id="myInfoService" url="http://twitter.com/users/show/dan_mcweeney.xml" resultFormat="e4x" result="onMyInfoServiceResult(event)" fault="onMyInfoServiceFailed(event)" /> <fc:SpringGraph id="springLayout" backgroundColor="#ffffff" lineColor="#333388" left="0" right="0" top="0" bottom="0" itemRenderer="TwitterPersonView" repulsionFactor=".80" canDragNodes="false" />

You can see how nice and clean the SpringGraph is to use it was basically a one for one swap of other component.  Another change here is method used to fetch the data.  As you will see in the next section I leave it up to the Model class itself to determine how their friends are, hopefully this will be a good decision architecturally, so the start of the application is to just call the send method of the myInfoService HTTPService.  The result event is then triggered and that’s where everything gets stuck back together again.

At this point if you are following along, which I’m fairly certain no one is, you should get one head floating in the middle of a big white background, yay!  Although the astute observer will notice that I snuck a new method into that last snippet of code: “person.getFriends()”. 

 One head

 

Model^2 Math.pow(Model,2)

As I mentioned eariler I have now moved the getting of friends into the Model.  I did this to hopefully make it easier for some ideas I have in the long run but also to see how to make a HTTPService entirely in AS.  All this method does is ask the Twitter API to for the user’s list of friends:

1 public function getFriends():void{ 2 var friendsService:HTTPService = new HTTPService(); 3 var friends:Array = new Array(); 4 friendsService.url = 5 "http://twitter.com/statuses/friends/" + 6 screenName + ".xml"; 7 friendsService.resultFormat = "e4x"; 8 friendsService.addEventListener(FaultEvent.FAULT, 9 friendsFault); 10 friendsService.addEventListener("result", 11 friendsResult); 12 friendsService.send(); 13 }

The only remaining mystery is what happens in the friendsResult method which gets bound to the “result” event on line 10-11. 

private function friendsResult(result:ResultEvent):void{ var friendsArray:Array = new Array(); for each (var userEntry:XML in result.result.user){ friendsArray.push(new TwitterPerson(userEntry)); } sevenDegress_2(Application.application). onAddFriends(this, friendsArray); }

When the friends HTTPService returns it has a list of all the user’s friends and their current status.  The method just pushes these newly minted TwitterPerson(s) into an array and then calls another mysterious method from the application that contains it.  I don’t know if this is the best way to do this or not — seems like a bad case of statically linking these two objects but it seemed like the easiest way at the time.  This line of code gets the root Application object’s attribute called application and invokes a method on it.  For this to work at compile time though you need to cast that application attribute over to to the specific type of your application hence that funky, sevenDegrees_2 thing you see there.  The source code to that one extra method is also pretty straightforward thanks once again to Mark’s Graph class:

public function onAddFriends(node:TwitterPerson, friendsList:Array):void{ for each (var person:TwitterPerson in friendsList){ people.add(person); people.link(person, node); } }

When the friends HTTPService gets a result it passes it back up to the application which in turn modifies the data provider by adding the new nodes ( via the add() method ) and then linking them to each other ( via the link() method ).  This should now produce the pretty little Poof ball like below:

Poof

 

Hatchet Attack

This control is actually a little too useful for my needs, I don’t really want anyone to be able to drag folks around once they have been placed on the screen so, I have to delve into Mark’s control and get rid of that functionality.  This turned out to be a fairly straightforward:

1 private function mouseDownEvent 2 (event: MouseEvent):void { 3 var now: int = getTimer(); 4 if((now - lastMouseDownTime) < 300) { 5 // it’s a double-click 6 var node: GraphNode = _dataProvider.findNode( 7 UIComponent(event.currentTarget)); 8 if(node != null) { 9 dragEnd(event); 10 if(Object(node.view). 11 hasOwnProperty("doubleClick")) 12 Object(node.view).doubleClick(event); 13 } 14 return; 15 } 16 lastMouseDownTime = now; 17 if (_canDragNodes) 18 dragBegin(event); 19 event.stopImmediatePropagation(); 20 }

Beyond the addition of line 17, the only other thing I needed to add was one parameter _canDragNodes ( and its’ getter and setter methods ).  Although it is truly tons of fun to drag the seed member of the graph around and watch all their Twitter Friends fly after them — it’s not really useful.

If you want to see it running live, meaning you really think I’m a liar, here is a link to the Current Version of 7DegreesOfTwitter.

Extreme Programming to the Max

Tuesday, June 12th, 2007

I’ve always thought it would be interesting for people to see what a programmer goes through when creating a new system.  Telling the world where you are getting stuck so others can learn from and/or laugh at your mistakes.  It might also be interesting for people who create languages or frameworks to see a blow by blow of someone learning a new programming language / toolkit — how many times do you get to see that!

I also have wanted to build a Twitter ( hanger-on ) application that shows you your web friends and their friends and their friends and so on — think 6 Degrees of Kevin Bacon but, for Twitter.  I’ve thought about the visualizations for this and feel that Flex/Flash is the only way to go, which I luckily no nothing about!  So, tonight is the first episode of stuff I wish I knew about Flex while building 7DegreesOfTwitter.

I will only be working on this at night and on the weekends so, progress will be slow and sometimes painful.  I may even try and post nightly “builds” somewhere so people can see what I’m up to help give me pointers where required.

A Plan

Here is what i think the visualization should look like ( yes this was done in MS Paint, hopefully I am a better programmer then artist ):

 7degrees

Basically, you should see all your friends circled around your portrait then as you click on a friend it will shift the view so that your friend is now the focus on the screen, and you can move along your web of friends exploring other people’s connection.  Obviously, this whole visualization is rife with opportunity.  Adding some cool like the Mac doc magnify feature would be pretty cool, or even maybe have the whole thing look like a horizon instead of a flat web of people.

First Day 

First thing to do is get two chunks of data out of Twitter using the Twitter API.  The first bit is your list of friends:

<mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; public var myInfo:XML; public var friends:XML; private function onFriendsResult(result:ResultEvent):void{ friends = XML(result.result); } private function onFriendsFault(result:FaultEvent):void{ var error:XML; error = XML(result.fault); } ]]> </mx:Script> <mx:HTTPService id="friendsService" url="http://twitter.com/statuses/friends/dan_mcweeney.xml" resultFormat="e4x" result="onFriendsResult(event)" fault="onFriendsFault(event)"/>

So basically, this is all it takes in Flex to get data from a web service and parse it into an XML document that is easily traversable.  If you don’t know what E4X is neither did I — go read the Wikipedia entry about E4X then have a look at the W3Schools Tutorial on E4X.  Just remember it’s actually a lot easier then you think, no big scary XSLTs here.  The next thing to do was the other piece of data I need, in this case it’s your mug shot associated with your Twitter account:

 

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="friendsService.send()"> <mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; public var myInfo:XML; public var friends:XML; private function onFriendsResult(result:ResultEvent):void{ friends = XML(result.result); myInfoService.send(); } private function onFriendsFault(result:FaultEvent):void{ var error:XML; error = XML(result.fault); } private function onMyInfoServiceResult(result:ResultEvent):void{ myInfo = XML(result.result); myMug.source = myInfo.profile_image_url; } private function onMyInfoServiceFailed(result:FaultEvent):void{ var error:XML; error = XML(result.fault); } ]]> </mx:Script> <mx:HTTPService id="friendsService" url="http://twitter.com/statuses/friends/dan_mcweeney.xml" resultFormat="e4x" result="onFriendsResult(event)" fault="onFriendsFault(event)"/> <mx:HTTPService id="myInfoService" url="http://twitter.com/users/show/dan_mcweeney.xml" resultFormat="e4x" result="onMyInfoServiceResult(event)" fault="onMyInfoServiceFailed(event)"/> <mx:Image id="myMug" source="" horizontalCenter="0" verticalCenter="0" width="48" height="48"/> </mx:Application>

Major additions here are a a new HTTPService to grab my information and also a small slight of hand to keep the two asynchronous services at least somewhat in sync.  In the onFriendsResult function I call the next HTTPService.  This is an easy way to create simple dependencies among asynchronous requests.

The Layout

I started tonight to try and write this myself — and I soon realized I was probably in over my head.  I got up to the point where I am able to calculate the correct radius for a circle to easily hold all of the objects and then where their positions should be in radians around the circle.  The thought of having to write this in Flex made me want to jump out a window, so I thought to myself — maybe someone has already done this. Just then the Red Sea was parted and the open source gods smiled upon me.  Circle Layout was created by Sho Kuwamoto, an Adobe Engineer, it does exactly what I want in terms of layout and some other snazzy stuff with drag and drop.  Here is a demo of the Circle Layout for Flex just press the “Change to Circle” button to see what I am talking about.  It’s a pretty impressive bit of code for my needs though I need to get rid of the drag and drop bits but, for right now I will leave all that in.

So here is the the running code for Iteration 1 of the 7DegreesOfTwitter.  If you want the source just right-click the movie and use the “View Source” menu option.  When asked for a username and password just use your Twitter Log-in info.

Current issues:

  • Only works for me!
  • No clue what will happen when you have lots of friends

Next time?

  • Create a hover over for the images to at least show the name
  • Come up with a way of Clicking on a person then moving to their “circle”

If you find more issues in the code just post a comment — if I’m doing something totally silly please tell me that too!

Once again big thanks to Sho Kuwamoto for saving me having to do any real programming :-)

SAPTube

Tuesday, April 24th, 2007

Hasso Keynote
View from the cheap seats :-)

If you believe SAP’s vision of the future, the next version of the enterprise will be most certainly be YouTubed. Yesterday, Hasso worked off a set of great blackboard styled slides (anyone have that font?) and even brought one of his classes to the keynote. In his usual way, Hasso cut to the chase about the shifts occurring in enterprise software due to technology and the advent of the social web. Building off Thomas Otter’s live notes and Cote’s mind map here are some thoughts about the keynotes viewed as a whole.

New Idea

His solution to these shifts is his “New Idea” an architectural change focused more on “clouds” that could be used as raw computing power and potentially house enterprise services. The new architecture needs to be event based, must focus on the end user of the application, should be model based and expose little to no code. Probably, the most interesting point here is the idea of event driven thinking.

The “information worker” does not do the same transition repeatedly. They seek out exceptions they look for trends. Part of refocusing on the user will have to allow these users to more affectively locate these fringe events and resolve them. I would also love to see SAP start tracking the root cause of the error — what series of events occurred prior to this issue? Next time could we prevent it? We of course first have to come up with a way of attaching all these systems and getting them talking.

The answer of course is SOA! Hasso does add another interesting spin to this through higher degrees of abstraction allowing a fully model based architecture to enable user to model everything. Obviously, all this is probably still only on the blackboard but, one can see a time with these standardized clouds of services available at will and the ability to have a crowd sourced documentation scheme maybe capable business users could really start to remodel their own enterprise.

Community

Around the community topic Hasso said, “Without a community there is no product,” which is a great hat tip to the folks on SDN /BPX and certainly an important focus for the company moving forward. The idea of using this community to create feature requests is an obvious next step. SAP is only just starting to use their BPX communities to create ES, imagine a time where the users were modeling processes and even changing UI constructs to suit a particular need or usage pattern. This is sort of the holy grail of adaptive UI but uses a crowd sourced to determine the layout and functionality, no need for complex coding!

SAP software generally overlooks the casual users. Hasso argues that these people need to have the UI adapt to their needs as they progress from casual to expert. I’m not sure what this interaction model would look like certainly the hidden menu items in MS Office(before Vista) is not the best way. The idea is great if you can come up with a way to have the UI flex to the user based upon their own knowledge level.

UI

Not all of this appears to be blackboard magic; during Henning’s keynote he “demoed” a prototype of a Web 2.0-ey workspace for business users. This was also shown on the floor also, it has many more features, such as connections to mobile users via Blackberry and having them email into the space to contribute to the project. The general idea of the UI is to allow users to bring people in the space to solve a particular problem. You can add a user to the space, assign users to a task, and use a wiki to help organize the new ad hoc team. The framework supports the notion of templating so you can branch off to do a repetitive transactional type task injecting a good flavor of “best-practice.”

Finding others to help in these new ad hoc teams is easy with Harmony. Harmony is a mySpace/LinkedIn kind of application for the enterprise. It is already running at SAP and I’ve already had some hands on time with it. The interface is very good, has a consistent UI and well done graphics – the whole package looks highly, well unSAPish. The current version only has the mySpace component but I hope they plans to add the other components, wikis, blogs, social bookmarking, etc. This is SAP’s first foray into the social computing side of web 2.0 so no surprise the offer is limited. On the live SAP site you already have started to see interesting groups form like Basketball leagues and Live Music Lovers, not a huge value to the enterprise’s bottom line but happy workers are more productive workers.

Harmony UI

With the addition of a social computing slant, you really start to see the underlying strategy of the user-generated enterprise, at least that was my take on the whole thing.