Not Mailing It In

Mail

A few months ago, I switched back to the default iOS Mail app (as seen on my home screen) after using third-party email apps for a while. I’m not an email power user (I don’t snooze my emails for example), so Mail is good enough for me.

There are a few things, though, that would make Mail more useful for email users of all levels and would help Mail better fit in the modern iOS ecosystem. Here are four easy things and one more advanced thing.

1.) Safari View Controller

When I tap a web link in an email, instead of Mail kicking over to Safari, the link should open right inside Mail using Safari View Controller. Perhaps this could be an option in Settings that is turned off by default so less tech-savvy users don’t have to know about it, don’t have to use it, and don’t have to be confused how to get back to their mail when they open a link in Safari View Controller.

Safari View Controller

2.) Returning to the inbox after acting on a message

Currently, when I’m viewing an email and I delete it or file it away to an archival folder, I’m shown the next or previous email from my inbox. I don’t necessarily want to act on it or mark it read (and then have to immediately mark it unread), so I would like an option to go back to my inbox after acting on a message. Perhaps this could be an option in Settings too.

Actions

3.) Account avatars

To help in quickly browsing an inbox, Mail should show avatars for each email in the list like each contact has in Messages. The avatar would be useful to visually process who the email is from.

Avatars

Currently when viewing an email, an avatar appears in the header information along with the from and to details. This avatar should be in the list view as well.

Message avatar

Additionally, while senders who are saved in Contacts use the image I have set for them, senders not in Contacts should use the domain’s favicon (if the email is from a company) or even the sender’s Gravatar instead of the sender’s initials as it works now (unless neither are available).

4.) Share sheet

For whatever reason, email messages can’t be acted on with the share sheet. I can share websites from Safari, notes from Notes, and locations from Maps, but why not emails from Mail?

Share

Not that I want to send my email to someone through the share sheet, but I might want to share it to another app. For example, if someone sends me a link to an article or video, I may want to send it to Pocket to view later. Currently, I have to tap the link, get kicked over to Safari, save the thing to Pocket with the share sheet, close the Safari page or tab, and go back to Mail. A Safari View Controller would save a few steps here, but being able to use the share sheet right in the email would save even more.

5.) Rules / smart inbox?

This one I realize could be considered more of a power-user feature, but I feel even casual email users could benefit from this too. While avatars for each email in the inbox list would be a small change to aid in triaging email, a smart inbox would be a big change. This could be something as simple as having the ability to set up rules which would work like they do in desktop email clients: if an incoming email matches a rule or set of rules (for example if it’s from a particular sender), it gets filtered to a particular folder.

But perhaps this could also be something more advanced like what Spark does: emails are grouped into predefined categories so more important emails are together at the top, and less important ones are together at the bottom.

SmartInbox

Mail already allows setting up VIPs, so perhaps one of the categories is VIP emails, another is other non-newsletter emails, and another is newsletter emails. There’s already some newsletter detection happening since Mail offers a link to unsubscribe, so at the very least why not group all the newsletter emails together so they don’t have the same weight as emails from friends and family. And if friends and family have their own MailChimp newsletters they’re sending me (or the automatic grouping missed something), there should be a way to mark the email as a particular type so it gets grouped correctly in the future.

A full modernization of Mail should also include the ability to snooze emails, create and save smart searches, and set email to send at a later date, but these five things would be a good start to making Mail more useful for both casual and more advanced users.

Mail feels like it’s good enough for many iOS users—me included—but that doesn’t mean it can’t be better. I hope a new version of iOS brings some updates to Mail so parts of the app don’t feel so, well, mailed in.

My Home Screen Setup, May 2018 Edition

I thought perhaps I would make sharing my home screen setup a regular thing. Back in January, I posted my then-current setup. Four months later, my home screen is a bit different, so here’s an update.

My current home screen (select to view a larger version):

home screen

These are the apps I use the most or I want easy access to. As for my wallpaper, this is a wallpaper I’ve been using for years (I have no idea where I originally found it) (and actually it’s too small for iPhone X, but I’m using it anyway). The subtle grays and textures are pleasing and allow the icons to pop. Below are a few notes on some of the apps I have on my home screen.

tweetbot

Tweetbot
For me, this is the gold standard of what a Twitter app should be. With thoughtful design and interactions, timeline sync, and more, Tweetbot is an all-around terrific Twitter app. I hope Twitter’s recent API news doesn’t make Tweetbot—and all third-party Twitter clients—unusable.

timr

Timr
I use Toggl to track my time on various tasks and projects. I wrote previously how I used Workflow to start and stop time entries because the official Toggl app isn’t for me. Wanting more functionality like editing or deleting time entries, I decided to make my own Toggl app since their API is rather robust. I don’t know ultimately what the roadmap for Timr is, but for now it offers me a better way to interface with Toggl—and, unlike the official app, works natively on iPad and with iPad multitasking too!

partly sunny

Partly Sunny
I’m the developer and designer behind this app that shows your weather in quick glances and detailed looks. If you just want a quick glance at what’s happening, Partly Sunny can show that. If you want a more detailed look at what’s happening in the next hour, day, or week, Partly Sunny can show that too. Whichever you prefer, everything is meant to feel at home on iOS. Some of the key features include: customizable hourly graphs; customizable conditions in current, hourly, and daily forecasts; interactive radar; a widget; and a dark mode.

workflow

Workflow
This is an indispensable app for connecting and combining apps and actions to automate tasks—thus saving me time and effort. I have workflows for sharing photos, adding calendar entries and reminders, adding Trello cards and attachments, adding Apple device frames to screenshots, parsing email receipts, and more. Sure, I could do all those things without Workflow, but Workflow makes those things easier. Plus, I love making workflows. I wish I could find a job as a “Senior Workflow Builder”.

things

Things
I recently started using Things to keep track of my to-dos. Its design is striking for two reasons: it’s beautiful and it’s calming—meaning it doesn’t stress me out to use it. Plus, there’s no concept of overdue in Things, so it’s never shaming me for not completing a task. The cost of the apps may be a dealbreaker for many (there’s a separate app for iPad), but Things is more than enjoyable and useful enough to justify the price.

momento

Momento
This is a journaling app that collects manual thoughts and media and also automatically imports tweets, Instagram and Facebook posts, and other social-media feeds. I’ve been using Momento for several years now, and looking back at memories and what I was doing, thinking, and even tweeting years ago is something special.

transit

Transit
I enjoy trying different apps to see how they solve the same problems (see: Things), and transportation apps are no exception. In Los Angeles where many public-transportation lines run infrequently or have earlier-than-ideal-end-of-service times, Transit has some key features for me: its active-trip mode lets me know when to get off, whether or not I’ll make a connection, and what my ETA is.

lire

lire
In the previous post, I had just started using this RSS reader, and here I am four months later still using it. Still one of the most notable things for me is it feels at home in iOS 11 with its design choices. Another notable thing is it can fetch the full text of articles that get truncated in feeds.

apollo

Apollo
Here’s a bar graph comparing my Reddit usage before Apollo was released vs after: ▁ ▇. With its many customization options, gestures, and the jump bar, it’s such a delight to use (it’s easy to tell much thought and love has been poured into the app). And like lire, it feels at home on iOS.

trello

Trello
Trello helps me organize Partly Sunny to-do lists, feature requests, and bug reports as well as plan out future updates. I started using it beyond project tracking too. This year, I embarked on a 365-day photo project where I take and share a photo each day. I have a Trello board to save sort-of photo drafts; if I want to revisit something for a future photo, I take a photo and add it to this board so I don’t forget about it.

halide

Halide
A polished, powerful manual camera app. One of my favorite features is when in manual-focus mode, I can turn on highlighting of what’s in focus in the frame—immensely helpful when I’m trying to compose a shot with a particular thing in focus.

And in my Dock:

cesium

Cesium
Since iOS 9, the default iOS Music app hasn’t been for me. Thankfully, Cesium exists with its customizable tabbed navigation, powerful list sorting and grouping, track details, queue editing, dark theme, and more. (I’m using an alternate icon to match the iOS 7 Music app color.)

drafts 5

Drafts
This app is great for when I need to jot down a quick note. From there, I can decide what to do with it later or immediately perform an action or set of actions on the text and send it somewhere else like a message, a tweet, or elsewhere with a URL scheme. The recent Drafts 5 (I’m using an alternate icon) brought a powerful new scripting environment giving me further options for processing text—and giving me opportunities to brush up on my Javascript.

So that’s my home screen setup. May 2018 edition. As I said last time, I like to tinker, so no doubt this will get tweaked soon. What does your home screen look like? Come find me on Twitter and let me know!

Gesturing for User-Friendliness

With my iPhone X in my hand, I’m checking the weather for my current location in Partly Sunny, and I want to see my full locations list. What do I do? I swipe from the left edge of the screen to go back. I’m done checking the weather, and I want to go to my home screen. What do I do? I swipe up from the bottom.

I open Photos, swipe through my Camera Roll, favorite some photos, and now I want to go to the Favorites album. What do I do? I swipe down on the current photo to get back to the Camera Roll, I swipe from the left edge to go back, and now I can tap on the Favorites album. With all that navigating, I didn’t press any buttons. I only used gestures.

Gestures are an increasingly important part of iOS. Whether they’re a simple tap to dismiss, a swipe to go back, or a pinch to close, gestures not only offer shortcuts, they offer increased usability.

There is one particular place in iOS that hasn’t been given some gesture love but dearly needs some: modal form sheets. No doubt you’ve seen and interacted with form sheets in iOS before. On iPhone, they slide up from the bottom of the screen and fully cover the other view you were interacting with. On iPad, they slide up from the bottom and occupy a portion of the width and height of the screen. The area of the other view not covered by the form sheet is dimmed underneath.

App Store Apple ID

By default, when modal form sheets are displayed, there is one way to dismiss them: the Done button in the top-left or top-right corner. This can make dismissing form sheets user-unfriendly. On iPads, this button occupies a tiny portion of the screen—meaning there’s just a tiny portion of the screen that can dismiss the modal. And on taller iPhones, reaching for the Done button can be challenging. How can dismissing form sheets be made easier? Gestures!

Before we get to that, let’s define a few things. First, what’s a modal? In its basic definition, a modal is a view that covers up another view and prevents interaction with that other view (the parent view) until an action occurs on the modal view. What are some examples of modal views?

In iOS, there are a variety of modal views. There are alerts (centered on the screen with usually a message and one more more buttons), action sheets (anchored to the bottom of the screen and usually show two or more choices to act on something), and activity sheets (commonly know as “share sheets” to copy, send, or share content).

Modals

These types of modal views are defined by iOS. One more type of modal view is defined by developers. When showing (called “presenting” in iOS parlance) a custom view—say a settings view with options and submenus—developers can choose to present the view modally. By default, the view will slide up from the bottom of the screen and cover the view the user was interacting with.

When presenting a view modally, developers can choose a few styles for the modal view. From the iOS Human Interface Guidelines, the styles are “full screen”, “page sheet”, and “form sheet”. On smaller screens, page sheets and form sheets cover the whole screen, but on larger screens, they cover a portion of the screen. The portion of the parent view not covered is dimmed underneath.

ModalPresentations

I’m going to focus specifically on form sheets though the improvements I discuss would also apply to page sheets and mostly to full screen modal views too.

What are some examples of form sheets? In App Store, viewing your Apple ID account presents a form sheet.

App Store Apple ID

In Settings > Apple ID, tapping “Set Up Family Sharing” presents a form sheet.

Family Sharing

And in Partly Sunny, viewing settings, editing the locations list, and viewing radar all present a form sheet.

Partly Sunny settings

Partly Sunny edit list

Partly Sunny radar

So how can dismissing form sheets be made easier with gestures? Here are two ways.

First, on iPad, tapping anywhere outside the form sheet where the parent view is dimmed underneath should dismiss it. Here’s the current active area of the screen where tapping will dismiss the form sheet: just the Done button.

Current tap area

And here’s what the active area to dismiss the form sheet should be: both the Done button AND the space outside the view (the status bar is still reserved for its interactions like scrolling a view to the top).

Proposed tap area

The space outside the form sheet currently is a touch dead zone; the dimmed area merely prevents taps to the view underneath. Why not use this space to dismiss the form sheet?

Tapping outside a view to dismiss it already exists elsewhere in iOS—even for dismissing modal views. When an action sheet or activity sheet is presented, tapping above or outside the buttons or view will dismiss the sheet.

Tap outside action sheet

In the iOS 11 App Store, tapping a Today story tile or list tile opens a sort-of page sheet where, on iPad, tapping to the left or right of the view in the blurred area will dismiss the view.

Tap outside App Store tile

This example isn’t a modal view per se, but it applies. On iPad when pulling down on a Messages notification banner to reply to the message, tapping to the left or right of the messages view in the blurred area will dismiss the view.

With the latter two examples, perhaps these relatively new interaction methods will inform an updated modal system in a future iOS version.

In the meantime, there’s a workaround to capture taps outside the form sheet and have them dismiss the modal. This Stack Overflow thread discusses the solution. Since I first discovered this workaround, there’s been an update for Swift 4. I’ve reproduced and tweaked it here:

import UIKit

class FormSheetViewController: UIViewController, UIGestureRecognizerDelegate {
    // gesture recognizer to test taps outside the form sheet
    var backgroundTapGestureRecognizer: UITapGestureRecognizer!
    
    // dismiss the modal and perform any other related actions (e.g. inform delegate)
    func done() {
        dismiss(animated: true, completion: nil)
    }
    
    // check if the tap was outside the form sheet
    @objc func handleTap(_ sender: UITapGestureRecognizer) {
        if sender.state == .ended {
            let location: CGPoint = sender.location(in: view)
            
            // if outside, dismiss the view
            if !view.point(inside: location, with: nil) {
                view.window?.removeGestureRecognizer(sender)
                done()
            }
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // set up gesture recognizer
        if backgroundTapGestureRecognizer == nil {
            backgroundTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
            backgroundTapGestureRecognizer.delegate = self
            backgroundTapGestureRecognizer.numberOfTapsRequired = 1
            backgroundTapGestureRecognizer.cancelsTouchesInView = false
            view.window?.addGestureRecognizer(backgroundTapGestureRecognizer)
        }
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // remove gesture recognizer
        if backgroundTapGestureRecognizer != nil {
            view.window?.removeGestureRecognizer(backgroundTapGestureRecognizer)
            backgroundTapGestureRecognizer = nil
        }
    }
    
    // don't forget the delegate method!
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

Partly Sunny uses this workaround, so in any of the previously mentioned form sheets, tapping outside the view will dismiss it.

Tap outside Partly Sunny settings

Tap outside Partly Sunny edit list

Tap outside Partly Sunny radar

This works for iPad, but what about iPhone where the form sheets cover the full screen and there isn’t any dimmed area? The second way to make dismissing form sheets easier is dragging. Once the view is dragged down a certain amount, the view should dismiss. This would work on iPads too.

Drag to dismiss

This idea of dragging down to dismiss something exists elsewhere in iOS. In Photos, when tapping on a photo in the Camera Roll or an album, the photo goes full screen. Tapping the back button goes back to the album, but also dragging down on the photo will shrink it and fade it to reveal the album—in other words, dragging down dismisses it.

Drag photo to dismiss

While Maps doesn’t use traditional modal views, the system it uses allows for dragging the cards down to get back to the content underneath.

Drag map card to dismiss

Third-party apps have started to employ dragging down modals to dismiss as well. I’m not sure where I first saw it, but I know of several apps that have this functionality. Partly Sunny is one of them. In any form sheet, dragging down on the view will dismiss it. Here it is in action:

Drag to dismiss

I added a sort-of guard to help prevent accidental dismissals. If you scroll the view and then scroll back to the top, if when you reach the top you’re still dragging down (so that the view is doing the iOS rubber-banding effect), the view won’t dismiss. But once you release, if you drag down again, the view will dismiss. I didn’t want anyone to be casually scrolling up and suddenly the view disappeared on them. Here’s what that code looks like added to the code above:

import UIKit

class FormSheetViewController: UIViewController, UIGestureRecognizerDelegate {
    // scroll view must be dragged down this distance to be dismissed
    var scrollDistanceToDismiss: CGFloat = 50
    
    // tracks whether or not the scroll view should be dismissed if dragged down from top boundary
    var dragScrollViewToDismiss = true
    
    // tracks whether or not dragScrollViewToDismiss is ready to be set
    var dragScrollViewToDismissIsReady = false
    
    // stores the initial offset of the scroll view
    var scrollViewInitialOffset: CGFloat = 0
    
    // stores if the scroll view was loaded; guards overwriting scrollViewInitialOffset
    var scrollViewLoaded = false
    
    
    
    // gesture recognizer to test taps outside the form sheet
    var backgroundTapGestureRecognizer: UITapGestureRecognizer!
    
    // dismiss the modal and perform any other related actions (e.g. inform delegate)
    func done() {
        dismiss(animated: true, completion: nil)
    }
    
    […]
}

extension FormSheetViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        // store initial content offset of scroll view
        if !scrollViewLoaded {
            scrollViewLoaded = true
            scrollViewInitialOffset = scrollView.contentOffset.y
        }
        
        if dragScrollViewToDismiss {
            // if scrolling up, cancel dismiss
            if scrollView.contentOffset.y - scrollViewInitialOffset > -scrollView.contentInset.top {
                dragScrollViewToDismiss = false
                dragScrollViewToDismissIsReady = false
            }
            // if scrolling down, dismiss view controller
            else if scrollView.contentOffset.y - scrollViewInitialOffset <= -scrollView.contentInset.top - scrollDistanceToDismiss {
                done()
            }
        }
        
    }
    
    // if scroll view released beyond top boundary, set dismiss ready
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if scrollView.contentOffset.y <= -scrollView.contentInset.top {
            dragScrollViewToDismissIsReady = true
        }
    }
    
    // if scroll view drifts beyond top boundary, set dismiss ready
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if scrollView.contentOffset.y <= -scrollView.contentInset.top {
            dragScrollViewToDismissIsReady = true
        }
    }
    
    // if scroll-to-top activated, set dismiss ready
    func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
        dragScrollViewToDismissIsReady = true
    }
    
    // when tapping again on scroll view, set dismiss active
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        if dragScrollViewToDismissIsReady {
            dragScrollViewToDismiss = true
        }
    }
}

Form sheets and modal views as a whole are important and useful tools for iOS app developers. Dismissing them could be a bit more user-friendly, and gestures—tapping outside the view and dragging down on the view—can accomplish that. I hope a future version of iOS gives developers out-of-the-box tools to do both and thus standardizes these interaction methods.

Until then, developers can use their own solutions like those above. If you have suggestions how I can improve tapping outside the view or dragging down on the view, please let me know. Now it’s time for me to swipe down on this and get back to work.