Listacular & Pythonista
Hello! I wrote an improved version of this workflow. You can find it here.
Plain text apps on your phone are great, specially when they expand its possibilities. TaskPaper is a great task management system and Listacular is a great and gorgeous way to keep lists, however, both cases come with a syntax that keeps making things hard. Every task must be preceded by a hyphen and a space, meaning that do it is not a task, but - do it is. I hate these extra keyboard taps, so let's fix this thing altogether.
The Drafts-only way
I want a super simple list, one item per line. I can achieve that with Drafts only by using a quirky Dropbox rule and 2 other rules, one to recreate the document as we can't chain from a Dropbox action, unfortunately. You can download the Dropbox action here, I'll get in detail on the two other rules next.
The Dropbox action you just installed prepends the
[[title]] of the actual draft preceded by the "- " to convert it into a task. The file is predefined as Groceries.txt and the path is my Listacular folder within Apps. We're going to call this rule again numerous times.
This is the action you call to start the chain. It recreates your draft and plays our Dropbox action (called Add Groceries to Listacular), after succeeding it creates another full draft and calls the action Listacular Helper.
This little action here will create a new draft composed with the
[[body]] tag, the
[[title]] was already added in the previous action, then it will play the Dropbox action again, appending the first line of the new draft to our plain text document, this line is actually the second line from our whole document. After succeeding, the rule creates a new document with the
[[body]] and calls itself. It is a bit ugly to watch it doing the stuff, but it works, when you open Listacular or Taskpaper, you'll have an appropriate list of tasks right there for you.
The Pythonista way
Ok, I couldn't wait to finish the first part of this article to start discussing Python. If you're a smart guy, you bought Pythonista for $0.99 one month ago, otherwise you gotta pay $6.99, but it is totally worth as it drastically expands our ways to deal with automatization.
First, we create a regular Drafts action I like to call Convert to Listacular:
This action calls Pythonista and runs a workflow called Convert2Listacular, but before exploring my poorly written Python code, let's add one more action in Drafts, this time a Dropbox action called Pytho-Groceries. This rule is almost the same as the previous Dropbox action I listed, the only difference is that instead of
- [[title]] you have a basic
[[draft]]. Ok, let's move to Python and have some fun.
import urllib import webbrowser list = sys.argv[-1].splitlines() tasks =  lineb =  for t in list: f = '- ' + t tasks.append(f) for l in tasks[:-1]: s = l + '\n' lineb.append(s) lineb.append(tasks[-1]) tasks = ''.join(lineb) encoded = urllib.quote(tasks) drafts = 'drafts://x-callback-url/create?text=' + encoded + '&action=Pytho-Groceries' webbrowser.open(drafts)
Ok, let's go in parts Jack. I
import two modules in the beginning, gonna use them by the end of the workflow1. Then I define the variable
sys.argv, which picks the argument we brought from Drafts. The list comes like this: bananas\milk\beer, then I apply the
splitlines() function to convert it to a Python list:
['bananas','milk','beer']. That's the value of our
Afterwards, I create 2 empty lists called
lineb, I could create the second later, but screw it. Then comes the first loop:
for t in list: f = '- ' + t tasks.append(f)
This loop picks every element within the
list, they're called
t here, then it appends a
- and calls this variable as
f, afterwards, it appends
f to our empty list
tasks. Then it loops until there are no more items left. If you're lost, this is how
tasks looks like in the end:
['- bananas','- milk','- beer']. Next, we need line breaks.
for l in tasks[:-1]: s = l + '\n' lineb.append(s)
Almost the same thing as the previous loop, with a single difference: I exclude the last item from the loop, so it doesn't get a line break which would later render into a blank line on our apps. The results are appended to our previously created
lineb list, which right now looks like this:
['- bananas\n','- milk\n']. Oh, shit, where's our beer? We're going to add it in the next line using
lineb.append(tasks[-1]). You didn't think I'd let you out of beer, did you? Now it looks perfectly fine, but the last item doesn't have a line break2.
We still must convert our list into a string before encoding it and delivering it back to Drafts. The
tasks = ''.join(lineb) will pick
lineb and glue it together into a new
tasks variable3. Then
encoded = urllib.quote(tasks) will use one of the modules we imported in the beginning of the code to grab the new
tasks and percent-encode it so Drafts can read it fine.
drafts = 'drafts://x-callback-url/create?text=' + encoded + '&action=Pytho-Groceries'
This line creates a new variable called
drafts and inserts the result from our encoding in the text field of our upcoming Drafts comeback. It also calls the action Pytho-Groceries we did before, remember? To call drafts we use the last line, which relies on the last module we imported,
webbrowser.open(drafts). Now just watch Drafts do all the magic.
The Pythonista way is great because you aren't limited to this action. If you tweak it a little bit you can use the First Line statement as the title of your Dropbox-file and pick whatever file you want4.
I feel this will open a huge door when it comes to the future of this little blog. Now serve yourself.
UPDATE: Eric Pramono kicked my ass in lightning speed and cut my action down to almost a tweet:
from urllib import quote from webbrowser import open list = sys.argv.splitlines() list = "\n".join(('- ' + x) for x in list) encoded = quote(list) drafts = 'drafts://x-callback-url/create?text=' + encoded + '&action=Pytho-Groceries' open(drafts)
Show him some love at his site.
As far as I understood, modules are packages of functions. ↩
I'm 99% sure that I could achieve this same result using
ifwithin a single loop, but this is my first code, so be kind. ↩
Yes, I'm not creative with names. ↩
Free hint, I believe you can achieve that by changing
for t in list:to
for t in list[1:]:, and then after the loop do a
tasks.insert(0,list)or something like this. ↩