Posts in Category "Projects"

Facebook Desktop! Open-Sourced!

Last year, I wrote about a side project of mine that I was working on at the time called “Facebook Desktop“.  In short, it is a real-time notification engine built for Facebook! I built it because I felt it filled a need that Facebook didn’t fill…

It kept me connected to Facebook (and my friends) without having to
keep a browser window opened to Facebook.com the entire time.

It ended up becoming quite a popular project, amassing over 500,000 downloads, over 2 million API calls PER DAY, written about by numerous blogs and publications around the world, used in over 30 countries, and localized into 20 different languages, all in the short 14 months since it was released!  Low-and-behold, Facebook had issue with my app (I think because I called it “Facebook Desktop”) and so they “asked” me to shut it down.  Rather than argue with the well-known startup company, I decided to comply. It was a wild ride, and I learned a LOT (perhaps I’ll write another blog post about this), but as the saying goes, “All good things must come to an end”.

However, there is always a silver lining!  To build Facebook Desktop, I had to write a lot of custom code (obviously).  I’ve already open-sourced a lot of the individual components that I wrote, including…

But, now that I’m moving on to other things, I’ve decided to go ahead and open-source the entire project!  Just as I’ve done with all of my other open-source projects, I’ve made Facebook Desktop available on GitHub.  You can download it and run it out-of-the-box!

Features

Facebook Desktop is a notification engine that provides real-time updates of your Facebook friends straight to your desktop, without requiring a browser!  Here is a short list of some of the features that I’ve built in…

  • Real-time notification of Facebook activity
  • Language support for 20 different languages!
  • User-presence logic that detects when to display notifications
  • Operating-system detection that adapts interface to match native applications
  • Smart notification engine, including adaptive repositioning, individual notification settings, variable display length, and support for custom styling
  • Persistent user-settings, including preferred language, display length, appearance, and icon-click action
  • Ability to fully filter notifications by source and action
  • Support for updating status

Dependencies

Facebook Desktop is written with Adobe Flash Builder 4.5 using the Adobe Flex 4.5 SDK and the Adobe AIR 3.0 SDK.  It makes use of the following open-source libraries…

Code, please!

I’ve released the code under the Apache License, Version 2.0 and made it all available on GitHub! Please, fork and extend!

Facebook Desktop on GitHub

This marks the end of a fun-filled side-project for me, but perhaps the start for someone else :D  As always, I love hearing from you so let me know what you think! Until next time, happy coding =)

 

Charles

ActionScript Notification Engine! Open-Sourced!

Last year, I posted about a side project that I was working on. Dubbed “Facebook Desktop“, it is essentially a notification engine that I built that would give you updates about your Facebook friends in real time! It became quite popular and I ended up building it out over the next year, pushing out 6 new releases in that time (0.80, 0.81, 0.82, 0.83, 0.84, and 0.85). Well, I’ve decided to contribute to the community and open-source the primary component in Facebook Desktop, the notification engine!

Project M6D Magnum Sidearm
That’s right, I codenamed my notification engine project “Project M6D Magnum Sidearm” (I have a weird naming convention for projects :p). Anyways, it is exactly how it sounds. It is a cross-platform, notification engine built on top of Adobe AIR. With a very simple interface, you can drop it into any AIR project and allow it to deliver messenger-style notifications to your users! Think Growl, but for all platforms :)

Mac:                                                                         Windows:

What can it do?
If you’re familiar with the Facebook Desktop project that this engine was built for, it supports all of the features that you see being used in that project, including…

  • Ability to display messenger-toast notifications as well as compact notifications.
  • Variable display length for notifications.
  • User-presence logic that detects when the user goes idle. If the user is away from the computer, notifications are held on-screen and queued for when the user returns.
  • Ability to replay the most five recent notifications.
  • Individual notification post settings, such as sticky, replayable, custom image, click URL, compact, etc.
  • Operating system detection to set logical default display locations for notifications for the various platforms (i.e. bottom-right on Windows, top-right on Mac).
  • Smart repositioning logic for extended length toasts.
  • Ability to see a summary notification when the user returns from idle after an extended period of time.
  • Support for changing notificaion images.
  • Custom styling which can be applied at run-time.
  • Optional notification sound.

These are just a few of the really cool features that we’ve built into this engine.
How can I use it?
Even though we’ve added a lot of powerful features to this library, using it is very easy! All you have to do is include the SWC (or source) into your project, and follow the patterns below…

// create engine with default settings
var notificationManager:NotificationManager =
	new NotificationManager("/assets/style/dark.swf",		   // default style
				"/assets/m6d-magnum-sidearm-50x50.png",	   // default notification image
				"/assets/m6d-magnum-sidearm-16x16.png",	   // default compact notification image
				"/assets/sounds/drop.mp3"		   // (optional) default notification sound
				NotificationConst.DISPLAY_LENGTH_DEFAULT,  // (optional) default display length
				NotificationConst.DISPLAY_LOCATION_AUTO);  // (optional) default display location
 
// now that we have an engine, let's create a notification and show it
var notification:Notification = new Notification();
notification.title = "Derek ► Jacobim";
notification.message = "What is this?  A center for ANTS?!";
notification.image = "/assets/images/profile/derek/avatar.png";
notification.link = "http://www.youtube.com/watch?v=_6GqqIvfSVQ";
notification.isCompact = false;
notification.isSticky = false;
notification.isReplayable = true;
notificationManager.showNotification(notification);
 
// we can also show notifications quickly using this API too
notificationManager.show("Derek Zoolander Foundation", "Now open!", "/assets/images/dzf-logo-50x50.png");

And that’s all it takes for you to add robust notifications to your application. You can even change many of the engines settings on the fly!

// let's change the default images, display length, and display location
notificationManager.defaultNotificationImage = "/assets/images/dzf-logo-50x50.png";
notificationManager.defaultCompactNotificationImage = "/assets/images/dzf-logo-16x16.png";
notificationManager.displayLength = NotificationConst.DISPLAY_LENGTH_SHORT;
notificationManager.displayLocation = NotificationConst.DISPLAY_LOCATION_TOP_RIGHT;
 
// we can even change the style and sound settings on the fly too!
notificationManager.loadStyle("/assets/style/light.swf");
notificationManager.loadSound("/assets/sounds/bing.mp3");

For those of you that want all the details, you can check out the ASDocs here.
Demo
I’ve also created a sample demo application that you can install and see the engine work in real time! It has an interface like this…

…where you can quickly test out all of the features of the engine! Take it for a spin and let me know what you think!

Download Notification Engine Test Console

Code, please!
I’ve released the code under the Apache License, Version 2.0 and made it all available on GitHub! Please, fork and extend!

ActionScript Notification Engine on GitHub

That’s it for now! Hopefully some of you will find this project useful. And as always, I love hearing from you so let me know what you think! Until next time, happy coding =)

Charles

Facebook Desktop – We’re international, baby!

Some of you might remember a side-project of mine that I announced here which I called Facebook Desktop.  In short, it was a small application that I initially wrote for myself to help me stay in touch with my friends and family through Facebook.  It would sit in my system tray or dock and quietly push messenger-style toast notifications to my screen whenever something happened in my Facebook stream.  Neat, huh?  I thought so.  So, I built it out and eventually released it as a free app for everyone to use!  Since then, it’s actually picked up quite a bit of steam and now enjoys thousands of users from all over the world!

Pleasantly Surprised
I’ve had a couple of releases since I first announced it, but this latest release is special and so I wanted to mention it here.  The popularity of the app, especially overseas, took me by surprise.  Considering this started out as a small utility I built for myself over a weekend, I didn’t anticipate it being used overseas.  But now, it’s actually used in over 20 countries all around the globe!  In fact, the bulk of our users are overseas!  After noticing this, I made the decision to devote the entire next release into adding language support for all of our international users.

Technically, localizing the application wasn’t a problem (I’ve had some experience in the area).  The bigger problem was actually getting all of the text I use in the app translated to all of the various languages I wanted to support.  Then, someone posted a beautiful message on our Facebook application page.

“Are you adding support for German?  If so, I volunteer to translate!”

Shortly after, a comment: “Me too, for Italian!”.  And another: “I can do Hindi”.  That’s when it hit me…crowdsourcing!

The Power of the Community
I’ve never done it before, and there are plenty of ways that it can blow up in my face, but it was obvious to me that our users wanted it, but more importantly, were willing to help make it happen!  So, I took advantage of it!  The next day, I posted a message to our page asking if there is anyone willing to help translate Facebook Desktop in their native language.  The response was amazing!  At the end of the day, we had over 30 responses with people volunteering to translate in over a dozen languages!

I couldn’t ignore this, and so I took everyone up on their offer and started getting all of the text translated.  A couple of months later, a bit of coding, and a lot testing, it’s released!  Facebook Desktop v0.84 went live last night at midnight with support for a whopping SIXTEEN languages.

Together is Better
This version of Facebook Desktop could not have been accomplished without the help of the community.  Plain and simple.  On top of that, engaging with the users in this way made this release that much more fun too!  In the future, I’ll definitely be looking to involve our users more.  It’s better for them, it’s better for me, and it’s better for the app!  To infinity, and beyond!

 

Charles

Relative Time Library for ActionScript

While working on a side-project of mine, I came across the need to display dates and times as relative instead of absolute. You know, saying “two hours ago” instead of “Mon Jan 5 17:24:33 GMT-0700 2011″. Since the web is going real-time these days, it just makes sense. Besides, everyone’s doing it, so it must be good! Anyways, I wrote a library (really, just a simple class) that you can use to do this with ActionScript. It’s really quite simple, but since I couldn’t find it anywhere else, I thought I’d contribute it here for everyone to use too. Here it is in action…

 

If you’re wondering, I’ve tried to follow the convention that Facebook uses for what format to display and when. Twitter has a very similar format, but I decided to go with Facebook’s. Also, if you notice, my library can handle times in the future as well as times in the past. Here’s how to use it…

Usage:

Once you’ve added the library to your project, it’s really quite easy to use. Just call any of the two available APIs and pass in a date or two and you’ll get back the relative time string. Done!

var relativeTime:String = RelativeDate.getRelativeDate(firstDate, secondDate);
var relativeTime:String = RelativeDate.getRelativeDateFromNow(someDate);

Code:
Finally, here is the code in all it’s glory!

package com.adobe.date
{
	import com.adobe.utils.DateUtil;
 
	/**
	 * Utility class to help create human-readable Strings representing
	 * the difference in time from two different dates (e.g. "just now"
	 * or "2 hours ago" or "13 minutes from now").
	 *
	 * @langversion ActionScript 3.0
	 * @playerversion Flash 10.0
	 */
	public class RelativeDate
	{
		private static const SECONDS_PER_MINUTE:uint = 60;
		private static const SECONDS_PER_TWO_MINUTES:uint = 120;
		private static const SECONDS_PER_HOUR:uint = 3600;
		private static const SECONDS_PER_TWO_HOURS:uint = 7200;
		private static const SECONDS_PER_DAY:uint = 86400;
		private static const SECONDS_PER_TWO_DAYS:uint = 172800;
		private static const SECONDS_PER_THREE_DAYS:uint = 259200;
 
		/**
		 * Creates a human-readable String representing the difference
		 * in time from the date provided and now.  This method handles
		 * dates in both the past and the future (e.g. "2 hours ago"
		 * and "2 hours from now".  For any date beyond 3 days difference
		 * from now, then a standard format is returned.
		 *
		 * @param date The date for which to compare against.
		 *
		 * @return Human-readable String representing the time elapsed.
		 */
		public static function getRelativeDateFromNow(date:Date, capitalizeFirstLetter:Boolean = false):String
		{
			return getRelativeDate(date, new Date(), capitalizeFirstLetter);
		}
 
		/**
		 * Creates a human-readable String representing the difference
		 * in time from the first date provided with respect to the
		 * second date provided.  If no second date is provided, then
		 * the relative date will be calcluated with respect to "now".
		 * This method handles dates in both the past and the
		 * future (e.g. "2 hours ago" and "2 hours from now".  For
		 * any date beyond 3 days difference from now, then a
		 * standard format is returned.
		 *
		 * @param firstDate The date for which to compare against.
		 * @param secondDate The date to use as "present" when comparing against firstDate.
		 *
		 * @return Human-readable String representing the time elapsed.
		 */
		public static function getRelativeDate(firstDate:Date, secondDate:Date = null, capitalizeFirstLetter:Boolean = false):String
		{
			var relativeDate:String;
			var isFuture:Boolean = false;
 
			if (secondDate == null)
			{
				secondDate = new Date();
			}
 
			// the difference between the passed-in date and now, in seconds
			var secondsElapsed:Number = (secondDate.getTime() - firstDate.getTime()) / 1000;
 
			if (secondsElapsed < 0)
			{
				isFuture = true;
				secondsElapsed = Math.abs(secondsElapsed);
			}
 
			switch(true)
			{
				case secondsElapsed < SECONDS_PER_MINUTE:
					relativeDate = "just now";
					break;
				case secondsElapsed < SECONDS_PER_TWO_MINUTES:
					relativeDate = "1 minute " + ((isFuture) ? "from now" : "ago");
					break;
				case secondsElapsed < SECONDS_PER_HOUR:
					relativeDate = int(secondsElapsed / SECONDS_PER_MINUTE) + " minutes " + ((isFuture) ? "from now" : "ago");
					break;
				case secondsElapsed < SECONDS_PER_TWO_HOURS:
					relativeDate = "about an hour " + ((isFuture) ? "from now" : "ago");
					break;
				case secondsElapsed < SECONDS_PER_DAY:
					relativeDate = int(secondsElapsed / SECONDS_PER_HOUR) + " hours " + ((isFuture) ? "from now" : "ago");
					break;
				case secondsElapsed < SECONDS_PER_TWO_DAYS:
					relativeDate = ((isFuture) ? "tomorrow" : "yesterday") + " at " + DateUtil.getShortHour(firstDate) + ":" + getMinutesString(firstDate) + DateUtil.getAMPM(firstDate).toLowerCase();
					break;
				case secondsElapsed < SECONDS_PER_THREE_DAYS:
					relativeDate = DateUtil.getFullDayName(firstDate) + " at " + DateUtil.getShortHour(firstDate) + ":" + getMinutesString(firstDate) + DateUtil.getAMPM(firstDate).toLowerCase();
					break;
				default:
					relativeDate = DateUtil.getFullMonthName(firstDate) + " " + firstDate.getDate() + " at " + DateUtil.getShortHour(firstDate) + ":" + getMinutesString(firstDate) + DateUtil.getAMPM(firstDate).toLowerCase()
					break;
			}
 
			return ((capitalizeFirstLetter) ? relativeDate.substring(0, 1).toUpperCase() + relativeDate.substring(1, relativeDate.length) : relativeDate);
		}
 
		/**
		 * @private
		 */
		private static function getMinutesString(date:Date):String
		{
			return ((date.minutes < 10) ? "0" : "") + date.minutes;
		}
	}
}

Hopefully, this can help someone out there looking to do the same! Also, see the code in my GitHub repo!

Until next time, happy coding!

Charles

*Note: Shout-out to Joel Hooks for creating and sharing his awesome date-picker component!

Introducing “Facebook Desktop” – A Lightweight, Unobtrusive Notification Engine for Facebook Built on Adobe AIR

Disclaimer: Facebook Desktop is a personal project. It is not sponsored by or affiliated with either Adobe® or Facebook®.

Once upon a time, I was involved in a project here at Adobe called “Project San Dimas“. That project eventually grew into a full-fledged product called “eBay Desktop” which enjoyed some impressive success. I was lucky enough to be part of the protyping, designing, and launching of the very first version, and it was very exciting. More recently, I’ve thought about doing something similar. Introducing, “Facebook Desktop“!

So, what is Facebook Desktop?
Facebook Desktop is a notification engine that gives you updates about your Facebook friends in real-time! Whenever someone posts a story, comments on your photo, tags you in a status-update, whatever…Facebook Desktop will let you know. It gives unobtrusive messenger-style toast messages whenever you have a notification.

Why build Facebook Desktop?
I moved away from my home in Vancouver for work and so Facebook has been a great tool to help keep me in touch with everyone. I found, though, that the browser metaphor for the Facebook “stream” just wasn’t working for me. I didn’t like refreshing my home page constantly to see what people were up to. I also didn’t like keeping a browser open whenever I wanted to read some of my friends posts. So, I made a simple AIR app that hits the Facebook APIs, grabs the latest posts, and delivers them to me in an unobtrusive way. I ended up finding it so useful, I started adding more and more features, like the ability to pause/resume, replay missed notifications, update my status, etc. Eventually, I was encouraged by a friend to polish it up and release it for others to use, and so here we are!

Anyways, if you’re interested in trying it out, install it here:

http://www.facebookdesktop.com/

You can also keep up with the project and reach out to me on any of our community pages:

And definitely, let me know what you think! Your feedback helps me make Facebook Desktop better and better. Until next time, happy Facebook’ing ;)

 
Charles