Redoing my diary

You’ve probably heard the computer science saying “You can write Fortran in any language.” It’s a recognition that when people move to a new system, they tend to hang on to ideas they learned under their old system. This sort of conservatism isn’t a sin—there’s also “if it ain’t broke, don’t fix it”—but it does prevent you from taking advantage of all the new system has to offer.

When I watched this June’s WWDC keynote, like many people, I was excited by Shortcuts, and that excitement continued through the summer as I heard more about it from the people who were using the iOS 12 beta. I had a particular set of automations that I thought would be improved by implementing it in Shortcuts, and I figured that would be the first thing I worked on after updating to iOS 12. And it was, but after a couple of days of playing with it, I realized that recasting the automations in Shortcuts was just writing Fortran in another language. What I ended up with is a big improvement on my old system, but it isn’t anything like what I was imagining all summer. And it doesn’t even use Shortcuts.

What I wanted to improve was my old system for creating entries in an elementary diary, meant mainly to keep track of my time on days I was traveling for work. The system was built around a Drafts action and a set of Launch Center Pro buttons. Whenever I left the office, got to a job site, arrived at a hotel, etc., I would tap the corresponding button in Launch Center Pro. The buttons were keyed to URL schemes that would create a new draft, add the appropriate text (“Leaving work,”, “At site,” “At hotel,” etc.), and then run a Drafts action. The Drafts action would append the draft and a time stamp to a Dropbox file named for the date (and would create that file if it didn’t already exist).

It was a nice system, and I’d been using it successfully for four years. It seemed natural to replace the Launch Center Pro buttons with Shortcuts so I could talk to Siri and just say “Leaving work,” “At site,” “At hotel,” etc. But I soon realized that the main difference between the me of today and the me of four years ago is not iOS 12 and the advent of Siri Shortcuts, it’s my wearing an Watch.

A Shortcut activated by “Hey Siri, leaving work” works if I’m talking to my iPhone or, less likely, my iPad, but it won’t work if I’m talking to my Watch, because the watch can’t run Drafts actions.

Shortcut attempt on watch

Now there’s no question but that saying “Hey Siri, leaving work” to my phone is an improvement over waking it up, starting Launch Center Pro, and tapping the “Leaving work” button, but it still forces me to have my phone out of my pocket, and I really want to be able to make diary entries through my watch. After some thinking and spending more time with the Drafts documentation (RTFM really is good advice), I think I have a solution that works the way I want.

First, I went to the settings in Drafts on my phone (the ⚙︎ icon in the lower right corner) and configured the Drafts watch app this way:

Drafts Apple Watch settings

Turing on the autocapture setting means that after I tap the Drafts complication (I use the Modular face), Drafts opens waiting for me to dictate. Most important is the “diary” tag attached to every draft made through the watch. With this setup, every time I dictate into my phone through the Drafts app, I’ll create a new draft with the “diary” tag in my Drafts Inbox. All these drafts can be accessed from either my iPhone or iPad. More important, all these drafts have metadata that can be processed from my iPhone or iPad.

In Drafts, I have an action group for work-related actions:

Work action group

When I’m done with a trip, I run the “Assemble diary” action, which collects all of the Inbox drafts tagged “diary” and lays them out in a new summary draft. Here’s an example from entries I made yesterday during a day in Chicago with my wife:

Diary as of 2018-09-23 07:32 -0500

2018-09-22 10:29 -0500
41.779527, -88.145043
At train station

2018-09-22 11:13 -0500
41.823875, -87.833883

2018-09-22 11:39 -0500
41.87075, -87.632507
Union station

2018-09-22 12:12 -0500
41.879616, -87.623718
Art institute

2018-09-22 14:06 -0500
41.88059, -87.624397
Launch at Pratt

2018-09-22 15:19 -0500
41.88875, -87.624678
Apple Store

2018-09-22 16:18 -0500
41.858962, -87.633807
Ping tom park

2018-09-22 19:51 -0500
41.879122, -87.638562
Union station again

Each entry is preceded by the date, time, and location at which its draft was created.1 The accuracy of the transcription is par for the course with Siri (we had lunch at Pret A Manger), but it’s usually close enough to remember what you meant. What makes this work is the metadata that Drafts saves with each draft.

The “Assemble diary” action has just one step, this JavaScript:

 1:  // Start a new draft
 4:  // Get all the "diary" drafts in the inbox
 5:  var diaryDrafts = Draft.query("", "inbox", ["diary"]);
 7:  // Assemble
 8:  var ds = draft.processTemplate("[[date|%Y-%m-%d %H:%M %z]]");
 9:  var diaryContent = "Diary as of " + ds + "\n\n";
10:  for (var i=0; i<diaryDrafts.length; i++) {
11:    var stamp = diaryDrafts[i].processTemplate("[[created|%Y-%m-%d %H:%M %z]]") + "\n" + diaryDrafts[i].processTemplate("[[created_latitude]], [[created_longitude]]") + "\n";
12:    diaryContent += stamp + diaryDrafts[i].content + "\n\n";
13:    diaryDrafts[i].isArchived = true;
14:    diaryDrafts[i].update();
15:  }
17:  // Make the diary
18:  editor.setText(diaryContent);

The comments explain most of what’s going on, but here’s a bit more detail:

  1. Line 5 uses a query to collect references to all the Inbox drafts tagged “diary.” The first parameter to the query function is a string to search for. Since we want all such drafts, regardless of content, this parameter is an empty string. The third parameter is supposed to be a list of all the tags to search on, which is why "diary" is in brackets.
  2. Lines 8 and 11 use the processTemplate function to access the metadata. Line 8 gets the current (when the script is run) date and time to put at the top of the new draft. Line 11, which is in the loop that runs for each diary entry draft, gets the date and time as well as the latitude and longitude that the diary draft was created.
  3. Lines 13 and 14 move the diary draft that’s the current subject of the loop into the Archive. The update is needed to ensure that the change sticks when the script is done. This cleans out the Inbox but leaves the diary drafts still accessible in case you need them again.

The keys to this script—the reasons it’s even possible—are the metadata that Drafts saves with each draft and the ways Drafts makes that metadata available to users. These features allow me to make diary entry drafts on the go from the watch and then include the times and locations later on when assembling the summary.

Eventually, I’ll have a bunch of old diary entry drafts in my Archive and it would be nice to have an efficient way to get rid of them. The “Trash archived diary entries” script does that. It’s also a single-step script action:

1:  // List of all archived diary drafts
2:  var diaryDrafts = Draft.query("", "archive", ["diary"]);
4:  // Trash them
5:  for (var i=0; i<diaryDrafts.length; i++) {
6:    diaryDrafts[i].isTrashed = true;
7:    diaryDrafts[i].update();
8:  }

This new system is distinctly better than the old one. It’s more flexible in that I can make entries with any content, and it uses the Watch the way it’s meant to be used, as a way to do small things without pulling your phone out of your pocket.

The annoying thing is that I could have done all this months ago, right after I got my watch. But I was stuck in a rut of thinking one way—using URL schemes or Workflow/Shortcuts to launch Drafts actions as each diary entry was made—that I didn’t see the better approach that was there all the time.

  1. The location is given as a latitude, longitude pair on a line under the date and time. I don’t expect to use this often (after all, I know where my office is), but I thought it might be helpful in some situations. The values have to be taken with a grain of salt, as the location accuracy can be poor when you’re inside.