The Death and Afterlife of Thalidomide

The New York Times posted a fascinating and heartbreaking mini-documentary on thalidomide. Once a popular and useful medication, thalidomide became infamous for the severe physical birth defects it causes when taken by pregnant women. You may have heard of this drug. What you might not know is that it is still manufactured for limited use in the treatment of several conditions, including leprosy.

Before making apps and before working as an ICU nurse, I worked as a pharmacy technician at a small town pharmacy. We carried thalidomide, if I recall correctly. Drugs like thalidomide (or Accutane, a commonly-prescribed acne medication with similar risks of devastating birth defects) are dispensed with extreme caution, even in a small town pharmacy. There’s a mind-boggling amount of paperwork and patient education every time someone is prescribed one of these drugs.

Not all drugs are this dangerous, but it’s still a good idea to understand any drugs you take regularly. Don’t hesitate to visit your pharmacist and ask her questions.

Pro tip: ask your pharmacist for one of the manufacturer’s drug information pamphlets — not the consumer pamphlets, but the richly-detailed ones that are printed on thin white paper, folded into stout squares, and glued to the backs of medical-grade drug packaging. The pharmacy probably throws most of these in the trash anyway. They have great summaries of the side effects seen during clinical trials, including comments on which ones were most frequently reported. Much of it is readable to a layperson, if you’re determined to learn something. You can see one in this photo, taped to the top of the small amoxicillin bottle.

Another pro tip: only capitalize brand names for drugs. Generic names should be set in lowercase.

|  23 Sep 2013




Unexpected Design Challenges While Updating Riposte and Whisper for iOS 7

New versions of Riposte and Whisper are coming out today, coinciding with the launch of iOS 7, Apple’s beleaguered new operating system. Jamin and I are really excited about both our app updates. They were harder to accomplish than they might appear. Here are some of the hard problems we had to solve while redesigning them for iOS 7.

Riposte’s Freshened-up Timeline

Riposte is largely the same, visually. We were fortunate that our minimal approach to user interface chrome worked to our benefit during this update. The familiar flat white posts, with simple hovering buttons are still there. Swipe-to-go-back is still there. The text is laid out more accurately now, and with a little more breathing room padding each post. This makes it easier to scan a busy timeline without needing heavy borders or gradients.

The coolest visual change to Riposte is the redesigned flip animation when you tap a post:

It’s more at home on iOS 7 with its added depth and subtle bounciness. More importantly, it solves one of our oldest problems. App.net has long posts, made even longer by our decision to present image attachments in large thumbnails that span the screen. The old animation style flipped the entire cell over, which looked pretty silly when flipping a long post. This new animation partially tilts the cell in from the bottom, so that the buttons are always accessible from the top of the post, no matter how long it is. It uses the new UIMotionEffects APIs, too. You can see them by tilting your device around in your hand after opening a post.

Better Typography

Our users love upgrading to Riposte Pro so they can customize their fonts. Every bit of text looks better on iOS 7, especially in the minor elements like buttons and settings labels. Riposte Pro users can now choose separate fonts for author names and body text for their timelines, with two additional typefaces for the former: Helvetica Neue Condensed Bold, and Avenir Next Condensed Bold. These look really good when set at one the two new enormous font sizes: “Biblical” and “Bruckheimer.”

Speaking of Helvetica Neue Condensed Bold: it’s now doing double-duty as the default Riposte font for navigation bar titles and back buttons. Apple’s redesign of the back button to use wide, borderless text instead of the familiar pointed roundrect leads to frequent overlapping between the back button text and the navigation bar title when using standard UI fonts. It’s sometimes impossible to distinguish the two from each other, especially for color-impaired users.


Our new navigation bar typography.

The solution I used in Riposte was switch to a condensed version of Helvetica Neue, which helps maintain a breezy margin between the titles and back buttons of navigation bars. Its sturdy precision introduces a different emotion, but in a way that makes Riposte Version 1.5 feel new, like a new Swiss Army Knife still in the box.

Syntax Highlighting

Riposte now highlights mentions, hashtags, and URLs as you type. If you upgrade to Riposte Pro, you can also use Markdown syntax to write custom links.


Click for full resolution.

The syntax highlighting was made easier by one of my favorite new iOS 7 APIs, the NSTextStorageDelegate protocol. Every UITextView has a new textStorage property. Set your custom class as its delegate, and you can override the following method to make edits to text and color attributes after the user types them, but before they’re committed to the display:

- (void)textStorage:(NSTextStorage *)textStorage willProcessEditing:(NSTextStorageEditActions)editedMask range:(NSRange)editedRange changeInLength:(NSInteger)delta NS_AVAILABLE_IOS(7_0);

It’s the perfect spot to replace dumb quotes with smart quotes, too.

Background Updating

People hate having gaps peppered throughout their timelines in Riposte. Jamin wired up Riposte and Whisper to take full advantage of the new background updating APIs available with iOS 7. They’ll update themselves after any push notification, and at any other time the OS thinks will help. The end result is that you can say goodbye to timeline gaps and stale conversations. New posts and messages will be there waiting for you.

Status Bar Challenges

Apple threw us all a curve ball when they redesigned the system status bar for iOS 7. I wrote about the technical implications yesterday, but there are huge design implications, too.

For years, the status bar had been made a subtle extension of the hardware, quietly separated from an app’s interface. Now it overlaps all apps by default, without any background color. Apple has capriciously left the repercussions of this decision up to each app designer to sort out on her own. We’re probably going to see as many bad solutions as good ones as app updates roll out on the App Store over the coming weeks.

The new paradigm in Apple’s own apps is to make the navigation bar background blend seamlessly into the status bar background. Neither Riposte or Whisper use navigation bars consistently, so this wasn’t an option for us. Some screens (Settings modals, New Posts, et cetera) have navigation bars, but the majority of the time our apps are full screen and nearly chrome-less. Furthermore, both apps have transient notifications and toolbars that show and hide from the top of the screen. It would have been a technical nightmare to keep these interactions consistent across all our app’s screens, making sure that all scrollable content isn’t obscured and that allowances are made for those times that navigation bars and status bars change their visibility states.

In our opinion, the iOS 6 plain black status bar is still the best solution for our users. We had to fake it with some clever changes, but it will look and behave the same in Riposte and Whisper for iOS 7 as it did on iOS 6.

Whisper Pressed Between Microscope Slides

Whisper’s visual style has been dramatically scaled-down for iOS 7. It isn’t completely flat, though. It’s more like the old Whisper has been sandwiched between microscope slides. Look closely at the new message bubbles and you’ll see that they’re subtly demarcated with top highlights and inner bottom shadows, giving the subtlest hint of depth. Borders and gradients have been drastically reduced, too, yet not eliminated.


Click for full resolution.

The rationale for the Whisper redesign is, in a word, the keyboard. The system keyboard occupies half of your screen when you’re chatting with friends. Just as the iOS 6 version of Whisper borrowed color and visual cues from its keyboard, so does the iOS 7 version. Lines are thinner and shapes are less bulky, in keeping with the rice-paper-thin keyboard buttons.

We also added some fun new stickers, too, to thank our hard-working beta testers. Every tester was asked to pick a new sticker design that they wanted to have for themselves, no matter how bizarre. See if you can guess which stickers belong to whom:


Click for full resolution.

Everything is Fine, Everything is Ruined

For every new API released with iOS 7, there were a dozen existing APIs that were either deprecated or downright broken. I would estimate that 90 percent of the work that went into these two updates was just getting all the broken features up and running again. A complete list of such things would be too tedious, but here’s a taste:

You can download the latest versions of Riposte and Whisper from the App Store today, as soon as Apple flips the switch and makes them available.

|  18 Sep 2013




Wrestling with Status Bars and Navigation Bars on iOS 7

While updating Riposte and Whisper for iOS 7, one of the recurring problems I had was getting our view hierarchy to layout correctly. The most troublesome APIs are those for the system status bar and UINavigationController. The API documentation is woefully inadequate as of this writing. The following is, to the best of my knowledge, essential information for any developer struggling with status bars and view controller containment on iOS 7:

  1. There is no way to preserve the iOS 6 style status bar layout. The status bar will always overlap your application on iOS 7.

  2. Do not confuse status bar appearance with status bar layout. The appearance (light or default) does not affect how the status bar is laid out (frame/height/overlap). It is important to note as well that the system status bar no longer has any background color. When the API refers to UIStatusBarStyleLightContent, they mean white text on a clear background. UIStatusBarStyleDefault is black text on a clear background.

  3. Status bar appearance is controlled along one of two mutually-exclusive basis paths: you can either set them programmatically in the traditional manner, or UIKit will update the appearance for you based on some new properties of UIViewController. The latter option is on by default. Check your app’s plist value for “ViewController-Based Status Bar Appearance” to see which one you’re using. If you set this value to YES, every top-level view controller in your app (other than a standard UIKit container view controller) needs to override preferredStatusBarStyle, returning either the default or the light style. If you edit the plist value to NO, then you can manage the status bar appearance using the familiar UIApplication methods.

  4. UINavigationController will alter the height of its UINavigationBar to either 44 points or 64 points, depending on a rather strange and undocumented set of constraints. If the UINavigationController detects that the top of its view’s frame is visually contiguous with its UIWindow’s top, then it draws its navigation bar with a height of 64 points. If its view’s top is not contiguous with the UIWindow’s top (even if off by only one point), then it draws its navigation bar in the “traditional” way with a height of 44 points. This logic is performed by UINavigationController even if it is several children down inside the view controller hierarchy of your application. There is no way to prevent this behavior.

  5. If you supply a custom navigation bar background image that is only 44 points (88 pixels) tall, and the UINavigationController’s view’s bounds matches the UIWindow’s bounds (as discussed in #4), the UINavigationController will draw your image in the frame (0,20,320,44), leaving 20 points of opaque black space above your custom image. This may confuse you into thinking you are a clever developer who bypassed rule #1, but you are mistaken. The navigation bar is still 64 points tall. Embedding a UINavigationController in a slide-to-reveal style view hierarchy makes this abundantly clear.

  6. Beware of the confusingly-named edgesForExtendedLayout property of UIViewController. Adjusting edgesForExtendedLayout does nothing in most cases. The only way UIKit uses this property is if you add a view controller to a UINavigationController, then the UINavigationController uses edgesForExtendedLayout to determine whether or not its child view controller should be visible underneath the navigation bar / status bar area. Setting edgesForExtendedLayout on the UINavigationController itself does nothing to alter whether or not the UINavigationController has a 44 or 64 point high navigation bar area. See #4 for that logic. Similar layout logic applies to the bottom of your view when using a toolbar or UITabBarController.

  7. If all you are trying to do is prevent your custom child view controller from underlapping the navigation bar when inside a UINavigationController, then set edgesForExtendedLayout to UIRectEdgeNone (or at least a mask that excludes UIRectEdgeTop). Set this value as early as possible in the life cycle of your view controller.

  8. UINavigationController and UITabBarController will also try to pad the contentInsets of table views and collection views in its subview hierarchy. It does this in a manner similar to the status bar logic from #4. There is a programmatic way of preventing this, by setting automaticallyAdjustsScrollViewInsets to NO for your table views and collection views (it defaults to YES). This posed some serious problems for Whisper and Riposte, since we use contentInset adjustments to control the layout of table views in response to toolbar and keyboard movements.

  9. To reiterate: there is no way to return to iOS 6 style status bar layout logic. In order to approximate this, you have to move all the view controllers of your app into a container view that is offset by 20 points from the top of the screen, leaving an intentionally black view behind the status bar to simulate the old appearance. This is the method we ended up using in Riposte and Whisper.

  10. Apple is pushing very hard to ensure that you don’t try to do #9. They want us to redesign all our apps to underlap the status bar. There are many cogent arguments, however, for both user experience and technical reasons, why this is not always a good idea. You should do what is best for your users and not simply follow the whimsy of the platform.

Accompanying Stack Overflow answer available here.

|  17 Sep 2013




Another Reason to be Bullish About App.net

Horace Dediu from an interview posted this morning (emphasis added):

An internet business is the arbitrageur who takes advantage of the inability of each market to price the other. History shows that arbitrage markets tend not be stable as information begins to leak across markets. Therefore what would blow the internet up is if consumers could become wiser about what they are giving up and advertisers would become wiser about aggregating consumer data. I imagine a system where each individual would allow bids on their consumption and a market mechanism where bidders competed for that data. This of course depends on users taking control and ownership of their own data.

[…]

It would create a new era which will have political dimensions. I imagine we’ll need an internet citizen’s bill of rights or some such movement which will reset expectations. Economically, could bode well for those who position themselves as protectors of the individuals and be a crisis for those who take advantage of consumer ignorance.

Note that this would be a structural difference, not a difference of technological capability. In other words, Facebook, Twitter, and Google could not copy it without destroying their established businesses. Isaac would have to sacrifice Abraham.

|  17 Sep 2013




Swipe To Go Everywhere

Swipe To Go Everywhere:

Jordan Cooper (a.k.a @blenderhead on App.net) invited Jamin Guy and I to his podcast this week to talk about the future of App.net, embarrassing oneself in eighth grade history class, offending family and friends with demonstrably funny jokes, location-aware apps for pot enthusiasts, and more.

|  27 Aug 2013