Tcoz Tech Wire

Discoursing on trends and technologies interesting to Tim Consolazio, sole proprietor of Tcoz Tech Services, specializing in Flash/Flex/Air, iPhone, Facebook, Twitter, and related technologies.

"Technology from an indie software developer's perspective".

Friday, June 12, 2009

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 5 : Multiple views, control bar, and Mate wishlist item

This is a continuation of a series of articles on my experiments with writing a Twitter desktop client using the Twitter API, the Mate Framework for Flex, and Adobe Air. Previous blog posts are here at Day 1, Day 2, Day 3, and Day 4.

This time around, I decided to get two views working: the public timeline, and my own @tcoz_tweet timeline, the latter of which is made up of my own tweets, and tweets by the members I follow.

To accomplish this, clearly I needed a way to organize different list views, and a way to switch between them. From a UI perspective, naturally a control bar seemed to be the way to go. Anticipating this, I'd already left some space at the top of the application above where tweets appear, and it turned out to be just enough; 35 pixels to be precise.

A quick look at the current state:



Starting to finally look like something isn't it? This might not be my final design, but it serves the current purpose, and doesn't look all that bad. Notice the "next" button, which currently doesn't do anything--there's nothing to go "Next" to yet--but from a forward-looking perspective, I plan on integrating search, profile views, that sort of thing. It seemed like a good idea to assume I'll need more room than what's in that one strip.

If you're curious how I'm doing the skinning, note that there are no embedded or static images of any kind being used as backgrounds for the tweets, the buttons, or any other such thing; everything is done with the AS3 drawing API. The matrix object makes gradient fills very easy--well, compared to how they used to be--with the createGradientBox utility method. Here's a sample of how I put together gradient fills:


var matrix : Matrix = new Matrix ( );
matrix.createGradientBox ( width, height, Math.PI / 2 );
graphics.beginGradientFill ( GradientType.LINEAR, Model_Config.getInstance ( )._tweetColors, [ 1, 1 ], [ 128, 255 ], matrix );
graphics.drawRect ( 0, 0, width, height );
graphics.endFill ( );


Note that I'm pulling the colors for the gradient off of my Model_Config object and applying it to the graphics object of my view. In my coding style, Models are frequently singletons, and if you recall from a previous article, I populate this model with data from an XML file, which the user can edit to alter the appearance of certain UI elements, like the background colors of tweets (again, thanks for the inadvertent feature request iJustine). Some may say that I should be accessing the data through a proxy, and that accessing Models directly is evil, and in a larger effort, I'd tend to agree. But the deeper I get into this app, the simpler I think it is. Writing a twitter client with even some semi-advanced features isn't all that difficult.

Now, you notice that I have two buttons that matter at this point: My Timeline, and Public Timeline. Click one, see one, click the other, see the other. Again, from a previous article, you know that I'm pulling collections of objects from the Twitter API, and binding them into lists. To toggle these list views, I decided to use a flex ViewStack, and it works like a charm.

If you're not familiar with ViewStack, it's a component that makes it easy to swap the currently visible view. All you do is set the selectedItem property on it to bring the desired view to the top: 0 is the first item in the stack, and so on. Here's the code:


<mx:ViewStack id="timelineViewStack" width="100%" height="100%" creationPolicy="all">

<mx:Canvas label="My Timeline" width="100%" height="100%" backgroundAlpha="0">
<mx:TileList id="userAndFriendsList" backgroundAlpha="0" borderStyle="none"
height="100%" width="100%"
itemRenderer="com.tcoz.twitterclient.renderers.Renderer_Tweetr"
paddingBottom="0" paddingTop="0" paddingLeft="0" paddingRight="0" />
</mx:Canvas>

<mx:Canvas label="Public Timeline" width="100%" height="100%" backgroundAlpha="0">
<mx:TileList id="publicList" backgroundAlpha="0" borderStyle="none"
height="100%" width="100%"
itemRenderer="com.tcoz.twitterclient.renderers.Renderer_Tweet"
paddingBottom="0" paddingTop="0" paddingLeft="0" paddingRight="0" />
</mx:Canvas>

</mx:ViewStack>


Pretty simple; the ViewStack is a top-level MXML wrapper. In it, I've got a stack of canvases which act as the swappable views. Inside those canvases, I have my TileList components, which is what I bind my data object arrays to. The TileList takes that array of objects, creates a specified ItemRenderer for each one, and passes it one of the data objects, which has properties that map to a tweet, like name, thumbnail url, etc. The specified item renderer receives that object, which is automatically available as instance name "data", and binds the properties to the UI elements where I specify. Here's the internal of my ItemRenderer, which will power all of the TileLists that display tweets (properties like x/y and such omitted for clarity):


<mx:Image source="{ data.user.profileImageUrl }" />
<mx:Text text="{ data.user.name }" />
<mx:TextArea text="{ data.text }" />


That's it! The Flex framework makes this pretty easy. It's completely extensible: I make a new API call, like search for tweets, I get back an array of objects from the Tweetr, or my own (I'm currently using both) library. I drop another TileList into the ViewStack, and bind the data to it. I put up a button, which when clicked, sets the selectedItem property of the viewstack, which makes the desired view appear.

Now, onto something I discovered about Mate. First of all, I have found myself really liking that when I need to dispatch an event from anywhere at all, all I need to do is either do it from a view or from a Mate GlobalEventDispatcher, set it to bubble, and add the handler to my EventMap, which directs it as needed.

But...there's something missing. Take a look at this code from my evolving EventMap:


<mate:EventHandlers type="{ Event_ControlBar.SELECTED_MY_TIMELINE }" debug="true">
<mate:MethodInvoker generator="{ Manager_States }" method="changeTimelineState" arguments="{ someComputedArg }" />
</mate:EventHandlers>

<mate:EventHandlers type="{ Event_ControlBar.SELECTED_PUBLIC_TIMELINE }" debug="true">
<mate:MethodInvoker generator="{ Manager_States }" method="changeTimelineState" arguments="{ someComputedArg }" />
</mate:EventHandlers>


Note that both of these event handlers call the same method on the same Manager object.

I would very much like to have been able to do something like this:


<mate:EventHandlers type="{ Event_ControlBar.SELECTED_PUBLIC_TIMELINE | Event.ControlBar.SELECTED_PUBLIC_TIMELINE }" debug="true">
<mate:MethodInvoker generator="{ Manager_States }" method="changeTimelineState" arguments="{ ( someComputedArg ) }" />
</mate:EventHandlers>


The difference here is, I've set the event handler to accept two events as the trigger with a bitwise OR. So, if either of those events are received, the argument can be determined and passed along to the Manager. This would also be useful for bitwise exclusions, and so forth.

As far as I can tell, there is no way to do this directly in the EventMap in Mate. Every time you need to receive a different kind of event, even if it's the same arguments, same Manager, same method, etc., you have to create an entirely new MXML fragment and place it in the EventMap.

In AS3, I'd typically do something like this:


myObj.addEventListener ( MyEventClass.EVENTONE, onMyEventClassEvent );
myObj.addEventListener ( MyEventClass.EVENTTWO, onMyEventClassEvent );

private function onMyEventClassEvent ( event : MyEventClass ) : void
{
if ( event.type == MyEventClass.EVENTONE )
// do something
else if ( event.type == MyEventClass.EVENTTWO )
// do something else
}


I'm looking further into this, but so far, after searching through the docs and such, I've found no indication that you can use a common handler for multiple event types. It might be possible with a standard if statement or some such, but I was really hoping for the elegance of bitwise operators.

This is one of my misgivings about Mate, and MXML in general; it's VERBOSE. WAY more verbose than straight code. I suppose that might just be a point of view; some people may prefer the hierarchy of nested markup. At this point in time though, I don't.

Anyway, that's it this time around. As always, thanks for visiting.

Next up: refreshing Tweet lists, ensuring I only add the most recent tweets, which means, either issuing a request based on the time of the last received tweet, or just receiving the bulk and trimming off the ones that I've already got in my list.

Labels: , , , , , , ,

Wednesday, June 3, 2009

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 4 : Getting into Authentication

This is a continuation of a series of articles on my experiments with writing a Twitter desktop client using the Twitter API, the Mate Framework for Flex, and Adobe Air. Previous blog posts are here at Day 1, Day 2, and Day 3.

This time around, I started researching the dreaded topic, "Authentication". That is, in order to do anything really meaningful on behalf of a user, an application has to ask for your username and password, and one way or another, send it to Twitter for processing so that they can tell you "this is a known user, here's access to their stuff".

This is an interesting conundrum, since once you've installed a custom application and started using it, there's very little to prevent the application from taking your account information and sending it to a non-Twitter service. After all, you're just filling out a username and password form that isn't on the Twitter site, and clicking a button saying "sign in". The application could be sending that data anywhere. More tech-savvy users will know to use bad credentials first and monitor http calls carefully; if you see something not going to Twitter, something could be fishy.

There are social network apps and widgets out there that do this: IMHO YOU SHOULD NOT USE THEM. You are essentially giving your username and password to an unknown entity. Assurances aside, why take the risk? There is a better way...keep reading.

Let's assume that I'm not going to do anything nefarious with my own credentials. Unless I develop full-blown paranoia of some kind, I'm relatively certain that me-the-developer isn't going to compromise my Twitter account.

A visit to the Twitter API Wiki to review Twitter authentication reveals that there are two ways for an application to go about authenticating a user for access to their account-specific info: OAuth, and Basic Authentication. In brief layman's terms:

- Basic Authentication is a widely supported authentication mechanism involving sending the user's username and password encoded as Base64 via an HTTP POST. I won't get into what that means exactly here, suffice to say that it is a standard way of sending values to a web server, with those values represented in such a way that certain kinds of characters will not confuse or compromise the authentication mechanism. Such a transmitted string might look like "QWxhZGRpbjpvcGVuIHNlc2FtZQ==". While this may appear to be "secure" to the eye, since it's not the original string value (like your password), it isn't at all, because Base64 is easily decoded into it's original value. In other words, your credentials can be intercepted, decoded, and revealed.

Twitter allows the use of Basic Authentication, but they clearly don't like it. They're considering removing it in favor of OAuth. On their site, they say "We would like to deprecate Basic Auth at some point to prevent security issues but no date has been set for that."

So me, I'll use Basic Authentication will I'm dinking around with nailing in the UI for my Twitter client. But when I get ready to go live, I'll definitely want to switch to OAuth. It might very well for this reason that Twitter leaves Basic Authentication lying around; it's just easier to develop an app if you don't have to deal with OAuth.

- OAuth (useful beginners guide here) is an authentication protocol that allows users to approve applications to act on their behalf without sharing their password. The basics of it are this; the developer has to inform Twitter directly that they have created an application that will be making calls into their API that require authentication. You fill out the form and register your app at Applications that User Twitter page. Twitter returns to you tokens to be used when requests are being sent back and forth. A Token is generally a random string of letters and numbers that is unique, hard to guess, and paired with a secret key to protect the token from being abused.

The flow then goes something like this: you, the user fire up your Twitter client. If you have not already done so, the Twitter client should direct you to a web page where you can say, "Yes, allow this application to access my information based on my id" (not your username and password). From that point forward, the application sends its key, along with your unique Twitter-system user id, to the API. The Twitter system looks at the key, and the ID, and asks, "has this user authenticated this application". If the answer is yes, the interaction proceeds, if not, it's declined. Remember, this key is coupled with another secret token, so just intercepting the in-transit data won't work (unless the hacker has obtained your secret key somehow).

OAuth is considered sufficiently secure for this sort of interaction, and prevents the problem I described before about being able to capture user credentials, since the user never directly provides credentials to the application. Yes, once you approve the app at the Twitter site, the application can do wonky things, like making bad tweets on your behalf, but as soon as you see that you can either de-authorize the app, or Twitter will ban the application entirely by revoking the tokens. OAuth is most definitely what you should be looking at if you intend to release any kind of Twitter client. It is a VERY common security paradigm, e.g. Facebook uses it, so any developer getting into building apps for social networks should definitely get their head around it.

So, that aside...like I said, I want, for now, to be able to make calls as simply as humanly possible into the Twitter API, I don't care if they're secure or not at this point.

To that end, I found the tweetr ActionScript 3 library. By just copying the code in their example "Retrieving One Tweet from authenticated User Timeline", I was able to call into the API with my username and password, and as the name implies, retrieve one tweet from my account (it turned out to be my last one).

I haven't looked at the source code, but, since the library takes a username and password to make the request, and I haven't registered my application, I'm assuming with good reason that this library uses basic authentication, at least for this example. As I said, during this dev phase, that's fine, but I'm going to have to revisit this eventually.

The code looks like this; yes, I took out my username and password. Notice I put this in a Command-based class (it implements the ICommand interface, typically "execute ( )"). So I'm using Commands in the Mate framework. Nice.


private var tweetr:Tweetr;
public function execute ( ) : void
{
tweetr = new Tweetr();

// set the browserAuth to false so we actually use
// the AIR authentication scheme
tweetr.browserAuth = false;

tweetr.username = "xxx";
tweetr.password = "yyy";

tweetr.addEventListener(TweetEvent.COMPLETE, handleTweetsLoaded);
tweetr.addEventListener(TweetEvent.FAILED, handleTweetsFail);

// tweetr.getUserTimeLine();
tweetr.getFollowers ( );
}

private function handleTweetsLoaded(event:TweetEvent):void
{
// assign the latest response to a data object
var tweet : StatusData = event.responseArray [ 0 ] as StatusData;

// trace some data
trace ( tweet.user.profileImageUrl );
trace ( tweet.user.screenName, tweet.text, TweetUtil.returnTweetAge ( tweet.createdAt ) );
}

private function handleTweetsFail(event:TweetEvent):void
{
trace ( "TWITTER ERROR ARGH ", event.info );
}


So far so good; I've found a library that lets me proceed with my development, like creating user interfaces for posting tweets, managing friends and favorites, and so on. I'm using Basic Authentication for now, but I know I need to change it, and since I've done Facebook application development already, I shouldn't have any problem tracking down resources and libraries to get me through this on the Twitter side.

Next, retrieving my own timeline, and creating a view for it, such that I can toggle back 'n forth between the public timeline and my own.

As always, thanks for visiting.

Labels: , , , , , , , , , , ,

Sunday, May 31, 2009

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 3

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 3

As @lancearmstrong says, "onward".

This is a continuation of TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 2, in which I decided to complete a number of technical exercises by building a Twitter desktop client using the Twitter API, Adobe Air and the Mate Framework.

This time around, I completed two major steps: the full parsing of a tweet with all associated data (so that I can display the message info finally), and preliminary incorporation of ads, which I tried to make as unobtrusive as possible.

Parsing the tweets turned out to be easy. If you want to get an idea of the XML that makes up a tweet, take a look at this file, which is a dump of the raw XML returned from the service call I discussed in the day 1 article. Make sure you view the source of the page; if you just click the link and view it as a regular web page, it'll look like an endless string of jumbled user data.

If you look at the XML, you see that a user's data is actually represented by an element called "status" that contains two parts; a top-level set of children that holds the message info, and a child element called "user", which contains all the user info, like name, id, number of followers, etc. Manager_Tweets gets fed all that XML when it returns from the EventMap handler (see days 1 and 2 for an explanation of this), breaks it up into an array of "status" elements, and pushes them onto Model_Tweets as an array of new Data_Tweet objects. So, whenever I want to grab the current list of public tweets, I just have to call Model_Tweets.getInstance ( )._publicTweets, and I'll get back an array of Data_Tweets. As I get more tweets, I just keep pushing them onto these waiting arrays on Model_Tweets, so I get a running list of tweets for the entire user session. As I work with different kinds of tweets, like Area, Trends, and different accounts, I'll just add more service calls to the EventMap, add more arrays to Model_Tweets, and push new Data_Tweets onto them.

Each Data_Tweet object gets one "status" element, which it cuts up into two XML fragments: the message, and user, parts. I then iterate each of the child elements in both parts and push the values onto objects, with the element names as the property names. The end result; each Data_Tweet exposes two objects, one with all that user's message info, and one with all that user's identity info.

The code in Data_Tweets that does the chopping up looks like this. Note that I've created two arrays filled with the property names I'm interested in, then I iterate those arrays, using the property names as the identity of the XML elements I want. This is sort of a lazy man's way of pseudo-typing data; eventually I'll probably just use real properties so that code hinting and such reveals the properties like any other typed object. But for now, this is a good, fast way to get the job done, and I am still using the actual property names instead of something made up.


_messageInfoProps = [ "created_at",
"id",
etc. etc. ];

_userInfoProps = [ "id",
"name",
etc. etc. ];

_messageInfo = new Object ( );
_userInfo = new Object ( );

var xml : XML = XML ( data );
for ( var each : String in _messageInfoProps )
_messageInfo [ _messageInfoProps [ each ] ] = XML ( xml [ _messageInfoProps [ each ] ] ).text ( ).toString ( );

var userPropsList : XMLList = xml.user;
var userPropsXML : XML = XML ( userPropsList.toXMLString ( ) );
for ( each in _userInfoProps )
_userInfo [ _userInfoProps [ each ] ] = XML ( userPropsXML [ _userInfoProps [ each ] ] ).text ( ).toString ( );


There's really nothing to it; get the XML from the Mate handler, pass it to Manager_Tweets, which breaks it into a list of "status" elements, then itereate that list, feeding each element to a new Data_Tweet, which parses the data into the pseudo-typed objects, then push those Data_Tweet objects onto a waiting array in Model_Tweets. I now have a subsystem to receive, parse, and store, tweets. For now I'm just using public ones, but I'm willing to bet that account-specific ones are no different.

Now onto the money shot: ads. ARGH, I know, god damn ads. But c'mon; I'm investing time and effort, not to mention using software and hardware I purchased, and so on; it'd be nice to actually make some money doing this, or at least, show that I understand how to do it, which is a great demo item for getting contract work.

I decided right away, that however I implemented ads, I wanted to make sure:

- The ad impression (an industry term for showing an ad) is immediately visible, but unobtrusive.
- There is only one "forced impression" per user session, and it won't last more than five seconds.
- There needs to be a way to view the ad again in case the user is interested.
- I want to be free to tweak this at will.

The implementation:

- The ad appears at the bottom of the app for five seconds, then fades out.
- After fading out, the ad is replaced with a very thin, translucent bar at the bottom of the app.
- This "ad bar" displays a message "Click to see the [name of advertiser] ad".
- When you click the bar, it shows the ad again for five seconds. If you never click it, you'll never see another ad.
- When you click the ad, it opens a browser window for the target URL.

Regarding freedom to tweak, that means, not compromising this unobtrusive design in any way, which means, I can't pander to the requirements of any particular ad agency. So, I actually set up my own ad server. I'm using the latest version of OpenAds, which is a free and full-featured ad server, used by such techno-luminaries as TechCrunch. I've worked with OpenAds before, but never actually built out an instance of it. I was pleased to find, OpenAds is simple to set up and simple to use. Just go through the instructions and tutorials carefully, and you'll have a full-featured, industrial strength ad server, with campaign provisioning and tracking, even marketing integration, all ready to go. From Flash, you make XML-RPC calls to the OpenAds server, it runs its logic, and returns an ad it selects as an XML response containing the info to display, like URL of the ad, target when you click it, etc.

To get started, I have a friend that owns a business called Genius Ride; he leases smart cars, delivered right to your door. I took his ad, dumped it into the OpenAds system, and set up an advertising campaign with it. The Flash client calls OpenAds when it starts, requests an ad (which at this time always returns genius ride, because it's the only campaign I'm running), and displays it as previously mentioned.

The screenshots below show the current in-progress state of the TcozTwitter desktop client.

As always, thanks for visiting.



With ad:




After ad fades:




Expanded:


Labels: , , , , , , , ,

Thursday, May 28, 2009

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 2

This is a continuation of TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 1, in which I decided to complete a number of technical exercises by building a Twitter desktop client using the Twitter API, Adobe Air and the Mate Framework. 

If you recall, last time I was able to successfully make a call to the Twitter public data feed that returns the last 20 public tweets, and display them in a list in my client. It looked like this:




So, clearly I've got a ways to go, but certainly this represents a major element of the development; get the data, parse it, bind it to a list with the UI elements to properly display the data. Keep reading; the app doesn't look like this anymore.

The next step was to clean up the UI a bit, which is what we'll look at here. Although not a programmer as far as I know, iJustine, an internet/lifestyle tweeter and blogger of some notoriety, unknowingly gave me a suggestion for how to proceed. She said that she couldn't change the background color of her tweet display; I assume that if she wanted this feature, it would probably be a popular one, so I decided to implement a way to skin my Twitter client at a rudimentary level. 

And I must say, Mate made it pretty easy to do. I think any framework would have, being as the task of reading in config data is the same as reading in any other kind of XML data, and I had already set up a call/receive pipe for the public tweet XML, so ideally I should just be able to use the same exact technique, and that's exactly how it panned out. 

In the last article, I showed the fragment of Mate code (which is just MXML) that retrieved the public tweet feed. The code below does the same exact thing, except it hits a relative file, config.xml, instead of a remote service. 

The Mate formula for hitting data and storing it seems to be this:

- Create your Event class (in this case, Event_Config). This is a standard Flex/Flash event, nothing fancy. It should have a static constant (at least one, though it can have several) with the name/type of event you want to dispatch (which is always a best practice for events not matter what environment you're in). 
- Create a Manager class that will be passed arguments when the event is handled by the EventMap. This means creating at least one public method on the class. Interesting that none of the examples I have seen ever suggest exposing these public methods via an interface...which is something I'll comment on later. I used Manager_Config.
- Create a Model class, I like to use singletons, to hold the elements the Manager parses out.
- Tie the Event, and it's handler, to the Manager, via the EventMap. 
- Dispatch your event as needed, remembering that in Mate, events have to bubble to the EventMap, which initially, will be located in the top-level MXML file. This means that you can either only dispatch from an object that participates in the app-level DisplayList, or by using the GlobalEventDispatcher workaround detailed in my last article. 

The code fragment that does the above looks like this:



<mate:EventHandlers type="{Event_Config.GET_CONFIG}" debug="true">
<mate:HTTPServiceInvoker url="xml/config.xml" resultFormat="xml">
<mate:resultHandlers>
<mate:MethodInvoker generator="{Manager_Config}" method="storeConfig" arguments="{resultObject}" />
</mate:resultHandlers>
</mate:HTTPServiceInvoker>
</mate:EventHandlers>



So, when the app starts, I want to load the config.xml file, which I do like this:

- In creationComplete of TcozTwitter_AIR, I dispatch an instance of Event_Config, using type Event_Config.GET_CONFIG. 
- This bubbles to the EventMap handler MXML tag, which makes the call to the HTTPService, receives the result, and directs it to the Manager_Config class public method, storeConfigOptions.
- That method takes the result argument, parses the XML, stores the elements on the associated properties in Model_Config, which exposes them for use throughout the app. 
- At the appropriate times, the UI elements, like Tweet backgrounds, apply their colors as style elements. 

iJustine, there ya go. Again, more or less the same exact idea as grabbing tweets, or any data it would seem. 

Some observations on this flow:

This is the way the tutorials, and even more advanced samples I've seen, prescribe retrieving service data. Typically though, I would not use the HTTPService MXML tag (or any such MXML based mechanism for that matter), I'd forward the handling to a class using the Command pattern. I've read some ways to do this in Mate, but it seems that it's not the common practice; using the EventMap handler as the Command, and distributing the management of the result to Managers, is the norm. For basic things, this might be ok, but what if you have a complex command of some kind that runs several service calls? The MXML could get very bulky, or you'd need multiple handlers, which would seem to make atomic operations difficult to manage. In fact, I think that in an app of any size, EventMaps could get bulky fast, which would cause you to start thinking of your app in terms of layers of EventMaps. Conceptually, perhaps this isn't that much different than thinking of your app in terms of layers of Mediators in PureMVC, but plain old code looks a lot leaner 'n meaner to me than all those MXML carats, quotes, equal signs, and so on. 

Based on that, I'll probably only use an EventMap handler tag to initiate a command, like calling a service, if there is only ONE simple command and result. Anything more and I will broker it to a Command class, which fortunately, I know how to make dispatch events now (same as any non-view class, use GlobalEventDispatcher). I know Managers could be thought of as Commands, but they're really not, see below. 

Another observation which I touched on before; use of MXML tags instead of instances of classes lets developers avoid thinking of factoring their class hierarchies and exposing their public members using interfaces. I understand that the classes that back the MXML tags are well factored in this manner, but for example, in PureMVC, part of it is implementing the Command pattern as the "C" in "MVC" (control). As you may know if you've gotten this far, the Command pattern uses an interface to expose "execute". If you use a Template pattern (so you create a base class that implements the interface and you extend that base class whenever you create a specific kind of command), you've just made all your commands polymorphic, which lends to things like "undo", command stacks and chaining, etc. Mate doesn't seem to have this concept built in. 

Good thing, bad thing? I don't know. To me, one of the points of a framework is to prescribe patterns of development for common application tasks, like executing logic. If you use Cairngorm or PureMVC, all I need to know is that a developer understands the framework, and I know that when I say "call a service, handle the data, store it", that the developer--in the case of PureMVC--will dispatch an event to a Mediator, which will send a Command Notification to the Facade, which will execute the a Command class, which will make the service call and handle the result, then broker that result to to a Proxy class, which will parse the data and store it on the Model, which makes it available to the application. 

It may sound verbose, but it's explicit and actually saves a lot of time; I KNOW how the developer will perform the task, and if you're managing a bunch of them, that's a GREAT thing. Using Mate, it would seem that I'd have to lay out the flows myself and communicate them to the team as standards, and make sure they were doing it. With a team of PureMVC junkies, we may quibble about the best way to cut up an application with mediators, or the best way to represent a Model via a Proxy, but otherwise things like views calling views or views talking directly to models will never happen; if it does, the fix is to educate the developer on the prescribed mechanisms of the framework. 

Anyway, enough of that. The bottom line is, you make edits to an XML file, restart your app, and voila, there are your colors, nice gradients and all that. Note that an XML file is not how I intend to keep this; settings is a great opportunity to take advantage of Adobe Air local storage. But for now, until I establish a base set of requirements for preferences and settings, it's easiest to just keep it in something abstract and lightweight, as opposed to building out the settings UI now, knowing that it will just change drastically several times before I have a locked feature set. 

One other thing I took advantage of: Air's ability to have the app resize like a desktop app, and reflow the layout. This is a great thing IMHO; if you resize the Twitter HTML page, the tweets don't reflow to take up the entire width, they stay in one column. My client reflows the tweets to take advantage of the entire space, letting you see more tweets without scrolling. 

Next step: incorporating the metadata associated with a user, and getting that message field populated. 

Screenshots of the latest client below, showing the application of the config.xml, and the resize-reflow. As always, thanks for visiting.







Labels: , , , , , , ,

Monday, May 25, 2009

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 1

QuickStart: This subject of this article is a project that satisfies three goals:

- To complete a practical exercise of using the Twitter API.
- To create complete a practical exercise of using the Flex Mate framework.
- To have a Twitter desktop client that works *exactly* the way I want it to.

To that end, I decided to build a Twitter client, using Adobe Air and the Mate Framework.

Onto the discourse...

Why this group of technologies?

Twitter: If you're reading this article, I don't have to tell you why it's important, as a developer, to do more than dabble with it.

Air: I really like building Air apps. At it's most basic level, you could say that Air is Flash running on your desktop in a native dedicated runtime manager (called "Air"). Freed of the browser sandbox, Air has a lot of capability Flash doesn't, like real local file access and data storage, and doesn't suffer from some of the general performance issues of the browser-based Flash player. The NY Times has dumped Microsoft Silverlight in favor of Air, as has the Major League Baseball tech organization. It's a pretty exciting technology, and if you're already good with AS3/Flex, the learning curve is more a speed bump than a hill; write one Air app, run it on any machine with it's OS-specific runtime installed.

Mate: I'm predisposed to being dubious of Mate, because I prefer frameworks and patterns that translate to as many technologies as possible, and I prefer to avoid markup for UI layers whenever possible, because it tends to create scripted spaghetti. PureMVC, for example, is easy to implement in just about anything, and inclines the developer to some level of genuine C-style OOP. Mate, on the other hand, is inherently Flex targeted; it makes heavy use of Flex MXML and databinding. But, love it or hate it, I realized a while back that avoiding MXML isn't good for my business, so I skilled up, and these days a lot of people are loving Mate, so I should get a working knowledge--though I will say, this is often the case of things that make a complex technology seem easy, and it all collapses once you hit big apps.

If you want to know more about the Mate Framework, go to the Mate Flex Framework Home Page. There you can find the SVN and/or SWC downloads, tutorials, etc. etc.

Add these three things up, and it'd seem that, if I put in the time, I'll have a pretty cutting edge Twitter desktop client, insofar as the technologies involved to make it work are concerned.

Anyway, down to the bits 'n bytes of Day 1, TcozTwitter. I'll assume you know about things like Flex, working with APIs, and so on.

As I said, I have mixed feelings about Mate; it's true that it's pretty easy to learn and get working, which no doubt contributes to it's popularity. People talk about it like the second coming, and say that it doesn't prescribe a particular kind of development, your app isn't tied to it, etc. But from what I can see initially--granted I'm no Mate expert, but I've worked with other frameworks pretty deeply--this isn't true. Your app is VERY tied to it.

For example, Mate prescribes how you use events in a VERY particular way. Events dispatched directly from non-views (typically "managers" in Mate parlance) don't hit the all-important EventMap (essentially a clearing house for event handling), because in Mate, you bubble all your events up to the top-level application for handling, and bubbling is a function of the DisplayList; non-views need not apply.

There is a workaround; in the non-view, create an instance of a GlobalEventDispatcher and use that to dispatch the event so that it immediately hits the top level app, which contains the main EventMap, but that's not at all what I'd typically do; usually I'd just have the non-view extend EventDispatcher, either directly or in a base class, and dispatch away. I was surprised by this; in Cairngorm or PureMVC, the basis of how you dispatch an event isn't prescribed by the framework; what you do with that event once you catch it is. I guess this is a matter of perspective, and no doubt this statement will annoy the Mate advocate, but there it is.

Note: I don't dislike Mate. It's growing on me. But at this point I still prefer PureMVC. This may change over time, we'll see.

If you'd like to try some Mate twittering yourself, for your first Twitter call, here's a simple MXML fragment showing what to put in your MainEventMap (which is essentially a manager for handling bubbled-up events in the Mate framework):


<mate:EventHandlers type="{Event_GetLatest20Public.GET}" debug="true">
<mate:HTTPServiceInvoker url="http://twitter.com/statuses/public_timeline.xml" resultFormat="xml">
<mate:resultHandlers>
<mate:MethodInvoker generator="{Manager_Tweets}" method="storePublicTweets" arguments="{resultObject}" />
</mate:resultHandlers>
</mate:HTTPServiceInvoker>
</mate:EventHandlers>


Notice in there we have an HTTPServiceInvoker pointing to the twitter endpoint that dumps out the latest 20 public timeline tweets. You can grab them in a variety of formats just by changing the extension of the public_timeline call (instead of .xml, use .json for example). This is strictly preference; I like XML, so that's what I'm using. In addition to this, you'd have to write your Manager_Tweets class, with the "storePublicTweets" method, and dump it onto a model for binding and so on. If you need a primer that shows you how to set this all up (it's very easy), go through this tutorial. I used this as as starting point for my Mate explorations a while back and it was very helpful. While there's certainly a lot more to learn about Mate, understanding how the EventMap works in conjunction with Managers is the most important part, and this tutorial makes it very clear.

With all that understood, my first effort was to take that XML and bind it into a TileList, which has an itemRenderer that receives the individual data objects, which have properties that map to the original XML elements. So, in the itemRenderer, just by setting the image component's source to "data.profile_image_url", and the top text components text property to "data.name", I get the expected result; a scrolling TileList of the latest 20 public posts, with profile images and names.

It's not pretty; I didn't work out the sizing or layout, or scrolling, etc. This is entirely the first step. But hey...I've got an Air client, using the Mate framework, hitting the Twitter API and displaying user data. I'm on the way to achieving the three goals I mentioned at the top of this article.

So far so good. Next step; clean up that UI to display the scrolling list more neatly, and add in the message and metadata to that display of public posts.

As usual, thanks for stopping by. Pic of in-progress client below:




Labels: , , , , , , ,

Sunday, May 10, 2009

The New Sunday Morning: Kindle and iPhone

It used to be, you got the NYTimes and Daily News--I mean c'mon, you gotta have the comics--sat down to your breakfast, brunch or early lunch, chatted with whomever is at the table, and/or just wrapped yourself up in a cocoon of news and thought. 

How things have changed, or maybe they've just evolved...or devolved. Hmm.

It struck me this morning that while the ritual is similar, the tools have changed. Today I found myself sitting with my tea and girlfriend--and thinking of a mimosa, ahem--but no newspapers. Instead, I was flipping around some unread sections of blogs and looking over the news on my Kindle 2, and when I found something of interest, quietly pushed it out to my friends on Facebook, or tweeted it, on my iPhone. 

Interesting; has this civilized Sunday self enrichment ritual, involving newspapers, discussion, and reflection, devolved into looking for anything to FB update or tweet because I hadn't said anything in a while? Am I actually getting as much quality time and info as I used to?

Many might say, "I've been reading news online for years, I get it free, and I get more of what I want, because I can search and yada." Well ok, but do you and your wife/girlfriend/friends bring your laptops to Frank's Waterfront in Edgewater, break them out on the table, and engage in discussion while typing/searching and all that? I think not. A working lunch, or a solo nosh, sure, but with people or in any kind of upscale place...no.

This isn't to say that this sort of thing is universally unacceptable; there's places that cater to it. I hang out at some excellent spots in Brooklyn along Atlantic and down Clinton and Smith streets, get great food, and bring my laptop, and I'm sure every neighborhood has such a place, or at least, one close by.

Anyway...

...as I changed from the Sunday Times for a minute to scan some news via the integrated web browser on the Kindle, I actually found that Thomson Reuters had blogged a first disclosure of the Reuters Insider, an online news product that is an industrial strength example of "narrowcasting". I found it interesting, particularly because I'm managing a team of UI developers on the project, and am under strict NDA not to discuss the project other than saying "I'm working on it". I handed the Kindle to my girlfriend and showed her the article, and we discussed it (paranoid assurance: I only discussed the content of the article). 

Note: If you're interested, google Reuters Insider, and look for the "Full Disclosure" blog link, it should be the first one. 

This specific interaction prompted me to blog today. It was exactly as if I had handed over a newspaper and pointed out an article. Sure I could have done it on my iPhone, but there was something much more appealing about handing over the Kindle, and while she looked it over, I could discreetly refresh my tweets. We discussed a little, then she handed back the Kindle, and the cycle resumed.

As far as information and retention, I scanned my NYTimes, and CNN, and blogs, bookmarked and annotated some things on the Kindle for later review, and so on; I believe I got my fill of news updates and such, and additionally, saw some interesting comments and interactions from the threads I follow on Twitter and Facebook. Not to mention that a day without Sockington would be a tough one, and possibly KingPoo (who I'm giving a chance). 

Regarding social appropriateness, nobody seems bothered by me using the paperback-sized, slim, subdued device (note, I have pre-ordered a Kindle DX, but probably won't bring it to a setting like this, it's a lot bigger). There have been curious looks and even a couple of "what's thats", but because the device emits no light or noise, lies slim and flat (unlike a laptop) on the table and holds like a book, and frankly looks quite nice in its leather cover, it seems that it passes social muster. Also, the iPhone, with all volume turned off (buzz enabled of course), is very subtle, since you can nav with one hand very quickly and discreetly, unlike many hold-in-front-of-your-face thumb typing phones with their audible thumb typing clicks. Naturally, excessive texting would compromise this, but that's getting back to the aforementioned Irish Pub thing. 

End result; it was fun, interesting, integrating the social graph enhanced the experience, and the combination of Kindle and iPhone, used with restraint, didn't appear to irk anybody. A laptop wouldn't have enabled the  same environment or interaction; the e-book reader, with the hyper-enhanced ability to scan, search, and mark up blogs and news, all of which will sync to my iPhone Kindle reader, and the discreet use of FB and Twitter when I felt like looking over popular topics, adds up to my new Sunday brunch gigbag. 

Oh right, I still got the comics, both with the Kindle 2 and iPhone's Safari. I mean c'mon...you've gotta have the comics. 

Labels: , , , , , ,