Redesigning the Apple Mail icon

 

Redesigning the Apple Mail icon

One thing I have always hated about OS X is the Apple Mail icon. It is way over the top, displaying a stamp with a photo in it and the stamped mark saying “Hello from Cupertino.” Johan Prag decided to take things into his own hands with a series called Redesigning OS X on his blog, &seen. It’s simple, identifiable, and beautiful. I, for one, am glad to have it in my dock.

via swissmiss »

Destroy Today now hosted by The Rackspace Cloud

 

Rackspace Cloud

If you can bet on your site being down each month, it’s probably a good indicator to look elsewhere for hosting. Though Dreamhost was a terrific deal, it wasn’t terrific enough to justify the downtime. I started looking around when Brian Connatser sent me a tweet suggesting I jump  on board his cloud. Like 99% of people with web space, Brian happens to have a ton he isn’t using.

I finished the move this morning and I’m hoping it will be smooth sailing from here on out. Thanks again to Brian and those who made a suggestion.

Poll: Replies vs Mentions

 

Replies vs Mentions

In implementing Lists as a replacement for Groups, the navigation changes a bit. I’m wondering if I should finally give in to the official Twitter nomenclature and replace “Replies” with “Mentions.” There are pros and cons to both. “Replies” isn’t entirely correct since you can be mentioned in a tweet and it not be a response. “Mentions” institutes another eight-letter “M” word, which could be confusing at quick glance. “Replies” widens the gap between the two sides and “Mentions” makes it a bit even. What do you think? Comment your reasoning.

Unexplainable bug with ContextMenus in AIR

 

I came across this freakish bug yesterday in DestroyTwitter. As mentioned in a previous post, the next release takes great advantage of ContextMenus. In doing so, I managed to crash ADL without any report to the console or debug views. The problem lies in the data property of the NativeMenuItem class. Setting it to a particular Number will shutdown the app, as if you forgot to press 4 8 15 16 23 42 (LOST reference).

It gets weirder. When I set the property to the Twitter ID of my @destroytwitter account, it busts, which is how I found the issue. BUT! If I set the property to the Twitter ID of either my @destroytoday or @jonniehallman accounts, it works as expected. On top of that, if you convert the Number to a String, it works. If you place the Number within an Object like {id: $id}, it works. Below is the source code, give it a shot. I’m running Flash Builder 4 on Mac OS X 10.6.1. The bug has been submitted to Adobe—I’m dying to find out what causes it.

[note] @jonniehallman is my private test account, not my private personal account. It consists of thousands of tweets like “test”, “test test test”, “yet another test”, and so on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package app.test {
	import flash.display.NativeMenu;
	import flash.display.NativeMenuItem;
	import flash.display.Sprite;
	import flash.utils.setTimeout;
 
	public class Test extends Sprite {
		public var _menu:NativeMenu;
 
		public function Test () {
			_menu = new NativeMenu ();
 
			_menu.addItem (new NativeMenuItem ("Open Link"));
 
			setTimeout (__init, 1000);;
		}
 
		private function __init ():void {
			// 14837781 works
			// 14839458 works
			// 2389723 doesn't work
			// 75443589 doesn't work
			_menu.getItemAt (0).data = 75443589;
 
			_menu.display (stage, mouseX, mouseY);
		}
	}
}

The Twitter Lists API, reverse engineered

 

After asking for access to the Twitter Lists API a number of times, I was first turned down and now ignored. Since DestroyTwitter 2.0 is starting to take shape, I want to make sure it includes Lists, but the lack of API access is a big roadblock. Since Twitter stopped listening, I decided to do a bit of reverse engineering to find out what the available methods are. Here is what I found:

https://twitter.com/[username]/lists.xml

This method returns an array of the specified user’s lists. It includes details about each list (id, name, subscribers, etc) and alsothe return values for the user who created this list. The method utilizes the new cursor format for paging. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0" encoding="UTF-8"?>
<lists_list>
<lists type="array">
<list>
  <id>640968</id>
  <name>Developers</name>
  <full_name>@destroytoday/developers</full_name>
  <slug>developers</slug>
  <subscriber_count>0</subscriber_count>
  <member_count>22</member_count>
  <uri>/destroytoday/developers</uri>
  <mode>private</mode>
  <user>
    <id>14839458</id>
    <name>Jonnie Hallman</name>
    <screen_name>destroytoday</screen_name>
    <location>Baltimore, MD</location>
    <description>Founder of Destroy Today. Developer of DestroyFlickr and DestroyTwitter. Experience Designer at Adobe.</description>
    <profile_image_url>http://a3.twimg.com/profile_images/124402983/about-1_normal.jpg</profile_image_url>
    <url>http://www.destroytoday.com</url>
    <protected>false</protected>
    <followers_count>3328</followers_count>
    <profile_background_color>222222</profile_background_color>
    <profile_text_color>AAADB6</profile_text_color>
    <profile_link_color>00728F</profile_link_color>
    <profile_sidebar_fill_color>222222</profile_sidebar_fill_color>
    <profile_sidebar_border_color>222222</profile_sidebar_border_color>
    <friends_count>129</friends_count>
    <created_at>Tue May 20 00:08:47 +0000 2008</created_at>
    <favourites_count>122</favourites_count>
    <utc_offset>-18000</utc_offset>
    <time_zone>Eastern Time (US &amp; Canada)</time_zone>
    <profile_background_image_url>http://s.twimg.com/a/1257191498/images/themes/theme1/bg.png</profile_background_image_url>
    <profile_background_tile>false</profile_background_tile>
    <statuses_count>12148</statuses_count>
    <notifications>false</notifications>
    <geo_enabled>false</geo_enabled>
    <verified>false</verified>
    <following>false</following>
  </user>
</list>
</lists>
<next_cursor>0</next_cursor>
<previous_cursor>0</previous_cursor>
</lists_list>


https://twitter.com/[username]/lists/subscriptions.xml

This method is the same setup as the previous method in that it returns an array of lists, but this is for lists that the user is following besides his own. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="UTF-8"?>
<lists_list>
<lists type="array">
<list>
  <id>1142867</id>
  <name>Flash devs not to follow</name>
  <full_name>@TheFlashBum/flash-devs-not-to-follow</full_name>
  <slug>flash-devs-not-to-follow</slug>
  <subscriber_count>1</subscriber_count>
 
  <member_count>8</member_count>
  <uri>/TheFlashBum/flash-devs-not-to-follow</uri>
  <mode>public</mode>
  <user>
    <id>26755983</id>
    <name>Jesse Freeman</name>
 
    <screen_name>TheFlashBum</screen_name>
    <location>NYC</location>
    <description>I am a homeless Flash Developer</description>
    <profile_image_url>http://a1.twimg.com/profile_images/475933036/flashbum_bio_normal.jpg</profile_image_url>
    <url>http://flashbum.com</url>
    <protected>false</protected>
 
    <followers_count>1146</followers_count>
    <profile_background_color>1A1B1F</profile_background_color>
    <profile_text_color>666666</profile_text_color>
    <profile_link_color>2FC2EF</profile_link_color>
    <profile_sidebar_fill_color>252429</profile_sidebar_fill_color>
    <profile_sidebar_border_color>181A1E</profile_sidebar_border_color>
 
    <friends_count>198</friends_count>
    <created_at>Thu Mar 26 14:07:20 +0000 2009</created_at>
    <favourites_count>140</favourites_count>
    <utc_offset>-18000</utc_offset>
    <time_zone>Eastern Time (US &amp; Canada)</time_zone>
 
    <profile_background_image_url>http://s.twimg.com/a/1257210731/images/themes/theme9/bg.gif</profile_background_image_url>
    <profile_background_tile>false</profile_background_tile>
    <statuses_count>4186</statuses_count>
    <notifications>false</notifications>
    <geo_enabled>false</geo_enabled>
    <verified>false</verified>
 
    <following>true</following>
  </user>
</list>
</lists>
<next_cursor>0</next_cursor>
<previous_cursor>0</previous_cursor>
</lists_list>


https://twitter.com/[username]/lists/[listname]/statuses.xml

This is the statuses method for a specific list. This is the same as any other statuses method. It includes the count, page, max_id, and since_id parameters. I haven’t tested for any others than those. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
  <created_at>Tue Nov 03 23:35:59 +0000 2009</created_at>
  <id>5405262473</id>
  <text>AT&amp;T complaining about Verizon ad accurately portraying the piss-poor suckiness of their service in 98% of the country: http://bit.ly/e4ieH</text>
  <source>&lt;a href=&quot;http://destroytwitter.com/&quot; rel=&quot;nofollow&quot;&gt;DestroyTwitter&lt;/a&gt;</source>
  <truncated>false</truncated>
  <in_reply_to_status_id></in_reply_to_status_id>
  <in_reply_to_user_id></in_reply_to_user_id>
  <favorited>false</favorited>
  <in_reply_to_screen_name></in_reply_to_screen_name>
  <user>
    <id>14551527</id>
    <name>rjowen</name>
    <screen_name>rjowen</screen_name>
    <location>Denver, CO</location>
    <description></description>
    <profile_image_url>http://a3.twimg.com/profile_images/494903369/twitter_normal.jpg</profile_image_url>
    <url>http://rjria.blogspot.com</url>
    <protected>false</protected>
    <followers_count>318</followers_count>
    <profile_background_color>1A1B1F</profile_background_color>
    <profile_text_color>666666</profile_text_color>
    <profile_link_color>2FC2EF</profile_link_color>
    <profile_sidebar_fill_color>252429</profile_sidebar_fill_color>
    <profile_sidebar_border_color>181A1E</profile_sidebar_border_color>
    <friends_count>176</friends_count>
    <created_at>Sat Apr 26 21:06:42 +0000 2008</created_at>
    <favourites_count>8</favourites_count>
    <utc_offset>-25200</utc_offset>
    <time_zone>Mountain Time (US &amp; Canada)</time_zone>
    <profile_background_image_url>http://a1.twimg.com/profile_background_images/4099338/IMG_0224.JPG</profile_background_image_url>
    <profile_background_tile>false</profile_background_tile>
    <statuses_count>1801</statuses_count>
    <notifications>false</notifications>
    <geo_enabled>false</geo_enabled>
    <verified>false</verified>
    <following>false</following>
  </user>
  <geo/>
</status>


https://twitter.com/[username]/lists/[listname]/members.xml

Lastly, the method for adding a user to a list. It looks like a user can be added simply by including the user’s id in the id parameter. The result is the same as lists.xml. This method in particular requires the POST method. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="UTF-8"?>
<list>
  <id>640968</id>
  <name>Developers</name>
  <full_name>@destroytoday/developers</full_name>
  <slug>developers</slug>
  <subscriber_count>0</subscriber_count>
  <member_count>22</member_count>
  <uri>/destroytoday/developers</uri>
  <mode>private</mode>
  <user>
    <id>14839458</id>
    <name>Jonnie Hallman</name>
    <screen_name>destroytoday</screen_name>
    <location>Baltimore, MD</location>
    <description>Founder of Destroy Today. Developer of DestroyFlickr and DestroyTwitter. Experience Designer at Adobe.</description>
    <profile_image_url>http://a3.twimg.com/profile_images/124402983/about-1_normal.jpg</profile_image_url>
    <url>http://www.destroytoday.com</url>
    <protected>false</protected>
    <followers_count>3330</followers_count>
    <profile_background_color>222222</profile_background_color>
    <profile_text_color>AAADB6</profile_text_color>
    <profile_link_color>00728F</profile_link_color>
    <profile_sidebar_fill_color>222222</profile_sidebar_fill_color>
    <profile_sidebar_border_color>222222</profile_sidebar_border_color>
    <friends_count>129</friends_count>
    <created_at>Tue May 20 00:08:47 +0000 2008</created_at>
    <favourites_count>122</favourites_count>
    <utc_offset>-18000</utc_offset>
    <time_zone>Eastern Time (US &amp; Canada)</time_zone>
    <profile_background_image_url>http://s.twimg.com/a/1257288876/images/themes/theme1/bg.png</profile_background_image_url>
    <profile_background_tile>false</profile_background_tile>
    <statuses_count>12159</statuses_count>
    <notifications>false</notifications>
    <geo_enabled>false</geo_enabled>
    <verified>false</verified>
    <following>false</following>
  </user>
</list>

In conclusion, I must say it’s pretty sad that an experienced Twitter developer needs to dig through the accepted developers’ work to be able to use the same features. I know Lists are new, but DestroyTwitter has been out far longer than the app I got this from. Also, the retweet and geo-location APIs have been public for months now, though the features aren’t completely implemented. DestroyTwitter doesn’t have millions of dollars worth of funding to bring to the table, but it has a pretty passionate developer who wants the latest features for his users.

[update] Thanks to Lim CHee Aun, who referred me to the draft documentation for Lists. It reveals a few more methods, including the creation and destruction of lists. The API URLs differ quite a bit from the Twitter API, using POST, DELETE, and GET with the same URL to create, delete, and return a list respectively. In the Twitter API, create and destroy are included in the URL itself. I’m hoping for the ability to bulk add/remove users to/from lists. That would seriously alleviate pressure from the hundreds of calls it would take otherwise.

Good news comes in threes

 

Adobe Dev Connection Featured Blogger

About a month ago, I wrote an article for Adobe Developer Connection regarding framerate throttling in AIR. Then last week, I was told I am this week’s featured blogger! I’m ecstatic about the good news of late and there is much more to share.

RIA Radio

This past Friday, I sat in on InsideRIA’s RIA Radio podcast with Garth Braithwaite, Leif Wells, and Zach Stepek. I tend to ramble, so the show ended up a half-hour longer than it usually does—and I still have more to talk about! It will be posted sometime this week and I’ll be sure to make an announcement when it goes live.

Flash Camp Philly

Lastly, this morning I woke up to a fantastic email from Robert Hall, inviting me to Flash Camp Philly on Saturday. It will give me another chance to sit in on some great sessions before the year is out and stay with the sister in center city.

Scrolling techniques—pick your poison

 

I’m always looking for ways to improve performance in my apps. One aspect that has always been in the back of my mind, but never implemented, is an improved scrolling technique.

Note: For the examples below, I used movies from my Netflix queue as dummy content. For demonstration purposes, the scrollRect and smooth recycling methods are not masked in these examples. Also, the names “Rigid Recycling” and “Smooth Recycling” are simply names I have given the following scrolling techniques—they are most likely not the correct terms.

scrollRect

At the moment, DestroyTwitter uses scrollRect—a property that masks a DisplayObject based on a set Rectangle. Each item in the data list is created, whether it’s visible or not. The upside to this method is scrolling speed—everything is rendered only once. The downside is memory usage—since there’s no recycling, every asset and object within each item is accounted for.

1
2
3
4
5
// bounds:Rectangle = new Rectangle (0, 0, _Area.width, _Area.height);
 
bounds.y = (_Content.height - _Area.height) * _Scroller.value;
 
_Content.scrollRect = bounds;

Rigid Recycling

An alternative is rigid recycling, which consists of only the visible items while the content of each is changed as the user scrolls. This is nice on the memory front, but smooth scrolling is a quality I just can’t strip from DestroyTwitter.

1
2
3
4
5
6
7
8
9
10
11
12
13
$itemHeight = 50;
$visibleItems = Math.round (_Area.height / $itemHeight);
$invisibleItems = _data.length - $visibleItems;
 
$A = _items.length;
 
for ($a = 0; $a < $A; $a++) {
	$Item = _items[$a];
 
	$n = Math.round ($invisibleItems * _Scroller.value) + $a;
 
	$Item.text = _data[$n];
}

Smooth Recycling

Along with rigid recycling is smooth recycling. There are only the visible items with two others for padding. As the user scrolls, the content moves much like the pure scrollRect technique. When the content’s y-coordinate is past a certain point, however, each item changes content and the list resets its position. This keeps memory low and covers the pixel-based scrolling, allowing the same effect that scrollRect has, but on a much lighter scale.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$itemHeight = 50;
$visibleItems = Math.round (_Area.height / $itemHeight);
$invisibleItems = _data.length - $visibleItems;
 
$n = Math.round ($invisibleItems * _Scroller.value);
 
bounds.y = $itemHeight * (1 + ($invisibleItems * _Scroller.value) - $n);
 
_Content.scrollRect = bounds;
 
$A = _items.length;
 
for ($a = 0; $a < $A; $a++) {
	$Item = _items[$a];
 
	$n = Math.round ($invisibleItems * _scroller.value) + $a - 1;
 
	$Item.text = ($n > -1 && $n < _data.length) ? _data[$n] : "";
}

One of the downsides to these recycling methods is rendering. Since you’re changing the content of each item whenever you scroll, AIR has to re-render everything that changes in the item. In DestroyTwitter’s case, this would be the bitmap icon, tweet text, and tweet background graphic. The scrollRect method renders once, then masks the list without having to render again. Though I’m not entirely sure how significant the speed hit would be, I’m guessing it won’t be too much since I cache user icons.

Another downside is that the item heights need to remain the same. The equation that makes them work requires a single value for the item height. This is a problem, since DestroyTwitter’s tweet heights vary based on the length of the tweet. I could standardize them, but I have a feeling it would look atrocious. Imagine a one-line tweet atop a five-line tweet. Since the item heights would have to be the max, that one-line tweet would have about 48 pixels of empty space.

What I want is a technique that might not be possible using a simple equation. It would require pre-processing to record the heights, then run on an equation that needs to reference the topmost tweet along with its height and ratio to the rest, and somehow scroll it smoothly with no hiccups. I think I consulted just about every developer I know to try to solve this, but it seems there is no simple way to go about it. I’ll keep hacking away, but if anyone has any suggestions, feel free to make an attempt.

Free Gems (AIR edition): Focus Booster

 

Focus Booster

I’m not sure why it took me this long to write a Free Gems post about an AIR app, but it’s time. Focus Booster is a fantastic little utility for improving your time management. It uses the Pomodoro technique, which is based on the following five steps:

  1. Choose a task to be accomplished
  2. Set the timer to 25 minutes
  3. Work on the task until the timer rings
  4. Take a short break
  5. Repeat, taking a longer break every four rounds

The app keeps this technique simple with a single-click to start and a stop button if need a timeout. You can even set your own work/break length. The UI is beautiful and a pleasure to have on the desktop.

I think time management and personal workflow are essential for any profession. I’ve been trying to start a routine lately, beginning jotting down a list of to-dos for the day. And since I work from home, I take a walk around the block to get into the working-mood. On the walk, I make sure my car is where I left it, especially after my recent impound experience. It’s also nice to get some fresh morning air.

I bring this up because life in front of the computer takes a toll on your body and surrounds you with an endless array of distractions. The more complex the workload, the more stressful it can be to focus. What techniques or apps do you use to stay on top of things?

In search of the best solution—speed and size

 

Programming is exhausting, especially if you type more than you have to. I’m always looking for ways to improve performance—not only regarding CPU and memory usage, but also with my approach. And, there are two points of view—the application’s and the developer’s. Sure, you can program a function that cuts a few milliseconds off your previous method, but if it’s not as legible, it might not be worth it.

In my dilemma, I’m thinking of a different approach to code that is already lightning fast. Why? It can be long-winded at times—you have to scroll just to see the other half of the statement. The problem is that the few alternatives all have their weaknesses. Here’s the currently used code:

1
2
3
if ($string == "Jonnie" || $string == "loves" || $string == "Subway" || $string == "cookies") {
	// code
}

This is quick and easy for a few evaluations, but the more you accrue, the more redundant and illegible the conditional becomes. If you’re fine with this approach, you can always make it prettier with tabs and linebreaks, but formatting soaks up a lot of time.

1
2
3
4
5
6
7
8
if (
	$string == "Jonnie" || 
	$string == "loves" || 
	$string == "Subway" || 
	$string == "cookies"
) {
	// code
}

Another solution is to use switch/case statements, which cut down on the redundancy, but also cut down on flexibility. In regards to speed, this switch/case statement is three times slower than our if statement.

1
2
3
4
5
6
7
switch ($string) {
	case "Jonnie":
	case "loves": 
	case "Subway": 
	case "cookies":
		// code
}

Then, there are the creative approaches. What if we used a temporary Array of the possible Strings to match and searched using the indexOf method? It is flexible, not redundant, and low on characters.

1
2
3
if (["Jonnie", "loves", "Subway", "cookies"].indexOf ($string) != -1) {
	// code
}

The downside is the speed—creating an array, searching the array, and comparing the result of the search. It is ten times slower than the logical or solution and a little over four times slower than the switch/case statement. Another weakness to mention is the complexity of readability—it includes a lot in a little space.

To overcome the lack of readability, you can create a global method.

1
2
3
4
5
6
7
public function isIn ($needle:*, ...$haystack:Array):Boolean {
	return ["Jonnie", "loves", "Subway", "cookies"].indexOf ($string) != -1;
}
 
if (isIn ($string, "Jonnie", "loves", "Subway", "cookies")) {
	// code
}

Though this makes the solution 12 times prettier, it is also 12 times slower than the logical or. The process now needs to track down the global method, use an untyped variable, and call the method.

What now? Either pick one or perhaps we can suggest something that’s currently impossible but shouldn’t be. In SQL and Python, we could easily get past all this with the following:

1
2
3
if ($string in ("Jonnie", "loves", "Subway", "cookies")) {
	// code
}

This is fast, legible, and low on characters. Why doesn’t it work in Actionscript 3? The in operator is already used in AS3, but as an alternative to the hasOwnProperty method. You can actually write this above in AS3 without any compiler or runtime error, but you’ll get false every time. I think it’s time we learn from other programming languages and adopt the usage. I know it would save me time—possibly enough to hold off carpel tunnel while I’m still young. I’m not sure how you go about suggesting things like this, but I’m going to try.

My Adobe Developer Connection premiere: Reducing CPU usage in Adobe AIR

 

Adobe Developer Connection article

I’ve been digging for things to write about lately, but am having a hard time thinking up something worthwhile. Then, I remembered my article for Adobe Developer Connection went live. It’s my first post on the site and I look forward to writing more. Check it out and let me know if it helps you out.