TapWatch: a simple and beautiful stopwatch powered by Enyo 2.0

I'm extremely pleased to share that TapWatch, my recent Enyo 2.0 project, is now live on the App Store:

http://itunes.apple.com/us/app/tapwatch/id514660139?ls=1&mt=8

Currently, TapWatch is available exclusively for iOS, but thanks to the magic of Enyo and PhoneGap I am hoping to expand to other mobile platforms soon. If you ever need a stopwatch, I hope you will check it out!

I ended up developing TapWatch because not that long ago, I needed to time something. Having my iPhone handy, I figured it would be the work of a moment to find a simple stopwatch app and get on with things. I wanted but three things in my stopwatch:
  • No buttons
  • Aesthetically pleasing design
  • A log of recent times
Half an hour later, I emerged from the morass of the stopwatch apps in the App Store without having found anything that even satisfied two out of three (including the stopwatch mode in the built-in Clock app).

Fortunately, Enyo 2.0 came to the rescue, and my development timeline ended up being as follows (with work being done in my free time before and after work):
  • Tuesday: discover the app store devoid of decent stopwatches
  • Wednesday: ponder the problem
  • Thursday and Friday: design a Photoshop mockup of the app’s two screens
  • Saturday: code the bulk of the app
  • Sunday: spend the day making pie and other delicious baked goods, thus forfeiting the ability to claim that I developed an app in a weekend
  • Monday through Friday: further development, testing, and polishing
  • Saturday: distributed a feature-complete beta build
The beta then took about a week (mostly time spent finding people to test it and then waiting to hear back from them), and waiting for Apple to review the app took another.

Some interesting tidbits I learned over the course of the experience that might help my fellow Enyo devs:

Enyo 2.0 is not really production ready. TapWatch works great because it has such simple UI needs (everything is handled by custom kinds--or in some cases old-skool DOM scripting--except for the scrolling: horizontal pane switching is handled by onyx.Slideable and the recent history is wrapped in a standard enyo.Scroller). However, I literally was fixing bugs in TapNote right up to the day I sent it in to Apple for testing simply by pulling down the latest changes from GitHub. If you've got something fairly simple like TapWatch and are willing to test changes to the framework on the bleeding edge, then Enyo 2 will be a lot of fun. But for anything much more complicated, Enyo 2 will offer a fair amount of challenge.

You can subscribe to PhoneGap events using the Signals kind. This is pretty cool: you can subscribe to PhoneGap-specific events in Enyo 2 simply by doing the following fairly high up in your kinds stack (I run this code in my root app kind constructor):
// Subscribe to custom PhoneGap events
enyo.dispatcher.listen(document, "pause");
enyo.dispatcher.listen(document, "resume");
enyo.dispatcher.listen(document, "deviceready");
Then in the kind you want to listen to ondeviceready or whatever, simply add this to its components:
{kind: "Signals", ondeviceready: "deviceReadyHandler"}
The best part? You don't have to do any conditional logic to check for PhoneGap for this stuff; it'll work great in your browser, too (as long as your app doesn't rely on the deviceready event being sent for its basic functionality, of course).

Enyo 2 does not currently predefine the enyo variable. If you are compressing Enyo down for use in a production environment, be aware that the Enyo 2.0 source code does not currently predefine the enyo variable which can lead to errors when you try to execute the minified script; you'll probably need to prepend the minified Enyo source code with var enyo = {};

Building Enyo from the command line. I had trouble figuring out how to do this, so here's a snippet of my build script:
node ../source/enyo/tools/minifier/minify.js package.js -enyo ../source/enyo/ -output compiled/app
This lives in a tools folder in my project (I have the Enyo source in a source folder in the root of the project"), and writes out the compressed script to tools/compiled/app.js. The package.js file that it references is also living in the tools folder and it simply points the script to Enyo as a whole, and then to my app's source folder (which contains its own package.js script; when enyo.depends looks at a folder, it tries to load this script automatically):
enyo.depends(
'$enyo/source/',
'../source/'
);
In my root folder, I have two HTML files: dev.html, which contains script tags referencing the actual Enyo source and my source/package.js script, and final.html, which only references the compiled/app.js script. As part of my build script, I copy the various files for production use into a build directory where I can test the app out just like it will be in a production environment.

Of course for this to work at all, you have to have node installed and in your PATH.

Beware iPad retina displays. Writing an app in Enyo means, of course, that you are using pretty high-level languages, so of course you're not going to get the same level of performance as native code. That said, I was shocked at how poorly TapWatch ran when I tried it out on a third generation iPad with its retina screen. Something as simple as updating text over top a gradient background brought the iPad to its knees. The entire app slowed way down, and visual tearing was rampant. There are just too many pixels on that darn retina iPad! If you are coding an Enyo app (or any web app, really) for use on iPad, be aware that you are going to need to spend a fair amount of effort optimizing your animations and so forth for a godawful large display. It's not as easy as just providing larger image assets, tossing in a @media query, and calling it a day.

A snippet for checking for touch environments. I like to append little helper methods to Enyo that I need to use all over the place, and this one might be useful for other folks:
if (typeof enyo.isTouch === 'undefined') {
enyo.isTouch = function() {
// Returns true for touch environments
return "ontouchstart" in window;
};
}

Comments

  • Great Stuff! When is TapNote going to be released? ;)
  • Heh; TapWatch in a lot of ways was one step in feeling out the process for potentially porting TapNote to other platforms. My conclusions coming out of it are that the underlying tech simply isn't ready; PhoneGap + Enyo 2 offers a lot of promise, but the current state of Enyo is too much in flux for a complicated app like TapNote.

    I am currently working on some experimental Enyo 2 kinds with features that I want in TapNote, but are unlikely to be implemented in the core product, and my hope is that once Enyo 2 is a little closer to production-ready I'll be able to start the transition in earnest.

    We'll have to see, though. Rewriting the TapNote interface and underlying logic yet again while also implementing enough new/improved functionality to make it a major upgrade and competitive in the other app stores is a lot of work, to say the least.
  • This is some awesome commentary. Thanks -- we're still reading over all this and seeing what we can do to make things better.
  • Thanks for the feedback. I've fixed the minifier to always splat enyo = window.enyo || {} into the top of compressed packages.

    I hope to have a better tutorial for compressing out sometime this week.
  • Where is the minifier supposed to be tossing in the enyo declaration, @azakus? I've been testing it tonight (using latest bleeding edge Enyo code) and it still fails unless I toss something like that in there myself.
  • Sorry, we took that out.

    Instead, the minifier's supplied package.js should use "$enyo/source/minify", which includes the loader components that enyo.js loads in debug builds (and sets up the enyo object).

    I've made a gist for what a "minify" folder should look like, and pretty soon we should have an "enyo boilerplate" up in the vein of things like HTML5 boilerplate.

    Github Gist for Minification
  • Just FYI, but $lib/extra/phonegap has been added to listen for all the phonegap events and route them through the Signals kind.
  • @azakus: Awesome, thanks! You guys are going to spoil me; you keep solving my bugs before I have a chance to get to them. I'd been planning to figure out this morning why PhoneGap 1.6 broke my deviceready event, but the extra/phonegap stuff works a treat.

    Targeting the minify folder instead of the source folder for building out Enyo also works great.
  • TapWatch UI is simple and clean. Awesome!
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Twitter