Ramblings from a Researcher-In-Training

Peer Reviewed

Posts tagged Widget
The Winning Widget of St. Jude/Relay FM Fundraiser Monitoring

A few weeks ago I shared my custom Pyto widget that automatically pulls from Relay FM's Tiltify page for their annual St. Jude Children's Research Hospital fundraiser, and shortly after that I shared Zach Knox's iterative improvement on the same concept. Well, now we've both been completely eclipsed by a lovely group of developers from the Relay FM members Discord, who quickly created a bespoke iOS app with native, customizable widgets all entirely dedicated to monitoring the fundraiser's progress. You can join the app's TestFlight beta to add its delightful widgets to your home screen. The app supports widgets of all sizes, displaying the total fundraiser goal as well as milestone progress, and even has notification support when reaching a milestone, "significant amounts" (like $250,000), or a custom dollar amount of your choosing.

Screenshots of the Relay For St. Jude widget, and accompanying settings.
Being able to set a custom dollar amount notification is a delightful touch!

The team behind this app has far outstripped what Zach and I cobbled together with mediocre scripts and middling widget design, and you should all go give the app a try if you want to keep an eye on the Relay FM community's donation progress. Oh, and you should go donate right now to St. Jude Children's Research Hospital — they do phenomenal, lifesaving work in kiddos with cancer all at no cost to their families. What better cause is there to give your money to? If you are reading this blog post, there's a good chance you are about to buy an expensive Apple product next week — figure out the sales tax on that purchase and go donate it to St. Jude.

iOSMatt VanOrmerWidget, iOS, St. Jude
A Home Screen Widget for Relay FM's Annual St. Jude Fundraiser

Every year, Relay FM and its surrounding community of tech nerds and podcast listeners rally together to raise money for St. Jude Children’s Research Hospital — one of the premier pediatric cancer research institutions in the world. The fundraiser is back and better than ever with sticker rewards for certain donors, donation thresholds for Flight Simulator streams, a horrifying amount of stickers, and the annual Podcastathon live stream on September 17th. Relay hopes to raise $333,333.33 (though I have a feeling that goal will be raised, since they racked up $456,000 last year to bring their cumulative total to well-over $1,000,000. I’m always delighted to donate to this cause because St. Jude does such amazing work, and this year I also worked out a way to track their progress live right on my iPhone home screen.

Relay runs their St. Jude fundraiser using Tiltify — a service that focuses entirely on campaigns like this, and importantly has a public-facing API. Because of that, it’s fairly easy to pull updates from Relay’s donation page using a POST request and parsing the (rather large) JSON dictionary that returns. An intrepid member of the Relay FM members Discord discovered this fact and created a Siri Shortcut to quickly display the total amount raised…but that gave me a better idea: what about a home screen widget?

When you need to call an API and create a dynamic home screen widget, two apps come to mind: Scriptable and Pyto — given that my only serviceable programming know-how is in Python, I chose the latter and got to work cobbling together a script.

Displaying Campaign Data, Dr. Drang-Style

The first thing I needed to do was connect to the Tiltify campaign with a POST request — big thanks to Ben in the Relay Discord for doing most of the heavy lifting with his Siri Shortcut! Tiltify expects a nightmarishly-long JSON payload in a POST request, but the JSON data it returns is much more straight-forward. Using Pyto, I called the API and parsed the JSON key:value pairs in the returned data to snag the totalAmountRaised and goal values from Relay’s 2021 St. Jude campaign. A little conversion turns those raw floats into properly-formatted dollar values with thousands-commas and dollar signs.

#Pull data from the returned JSON payload.
info = (r.json())
rawraised = info["data"]["campaign"]["totalAmountRaised"]["value"]
rawgoal = info["data"]["campaign"]["goal"]["value"]
# Convert pulled values into properly-formatted dollar values:
raised = "$" + '{0:,.2f}'.format(float(rawraised))
goal = "$" + '{0:,.2f}'.format(float(rawgoal))

Once I was able to pull the fundraiser's goal and the current amount raised, the next challenge was displaying that information within an iOS home screen widget. First and foremost, I really wanted a dynamic progress bar but wanted to generate one as simply as possible. My brother (a much more experienced programmer) helped me write this clever snippet of code to simply display a string of emojis 12 characters long, with two emojis (⬜ and 🟩) proportionally placed to form the progress bar. Here's what the code looks like:

# Generate a progress bar using emojis
def progressbar(raised, goal):
    # Modify these emoji to change the "empty" and "full" sections of the progress bar.
    progress_full = "🟩" 
    progress_empty = "⬜"
    bar_length = 12 # Modify this number to adjust the max width of the progress bar.
    progress_percent = float(raised)/float(goal)
    progress = ""
    progress = progress_full * int(bar_length * progress_percent)
    return '{:⬜<{x}}'.format(progress, x=bar_length) 
    #If you modify progress_empty above, you need to put it in this return statement as well.

The length of the progress bar needs to be fiddled with based on the width of the device; I'm sure there are much more clever ways to generate the proper number of emojis based on the device the code is being run on, but that was above my pay grade! Twelve emojis wide was just about perfect for a medium widget on my iPhone XS — your mileage may vary based on your device.

All that's left is to actually generate the widget to display all of this data on my home screen. I was expecting this to be much more challenging, since I had never used Pyto or its widget library, but luckily when you open a new script Pyto offers to automatically populate an example widget! A bit of hacking around with the example code and some digging in their widget documentation let me insert the variables I was interested in, change the background color, and remove the option of a small widget (it's just too small). In short order, I could present the amount raised, the fundraiser goal, the percent progress, and a delightful emoji progress bar right on my home screen! Here's the code:

if wd.link is None:
    widget = wd.Widget()
    wd.wait_for_internet_connection()
    background = wd.Color.rgb(219.7/255, 182.8/255, 72.2/255) 
    #You can modify the background color by altering the RGB values to your liking

    # Populate four rows of data, and accompanying font sizes:
    text1 = wd.Text("Raised: " + raised) 
    text1.font = wd.Font.bold_system_font_of_size(20)
    text2 = wd.Text("Goal: " + goal)
    text2.font = wd.Font.bold_system_font_of_size(20)
    text3 = wd.Text("Progress: " + progress)
    text3.font = wd.Font.bold_system_font_of_size(20)
    text4 = wd.Text(bar) #Progress bar
    text4.font = wd.Font.bold_system_font_of_size(18)

    # Supported layouts (the small widget is too small)
    layouts = [widget.medium_layout, widget.large_layout]
    for layout in layouts:
        layout.add_row([text1])
        layout.add_row([text2])
        layout.add_row([text3])
        layout.add_row([wd.Spacer()])
        layout.add_row([text4])
        layout.set_background_color(background)
        layout.set_link("https://stjude.org/relay")
    wd.schedule_next_reload(900) # Suggested refresh time in seconds
    wd.show_widget(widget)
else:
    open(wd.link) #This opens the link above when the widget is tapped.

And here's what the resulting widget looks like:

A screenshot of my home screen widget displaying the fundraiser’s progress.
The widget looks quite nice to me, and can be further modified in the Pyto code to your liking!

I think it looks pretty nice, given that I spent almost zero time optimizing the padding, font size, and background color in the Pyto code. Their widget documentation has many more UI customization options that intrepid readers can explore to make more advanced or aesthetically appealing widgets for themselves, but I'm pretty happy with where this simple version landed. As a nice bonus, Pyto also has a way to alter what tapping on the widget does — you'll notice that the entire widget generation code is wrapped in an IF-ELSE statement; tapping the widget sets wd.link to TRUE and instead runs the open(wd.link) function...which naturally directs to Relay's St. Jude Fundraiser page (if you've read this far and haven't donated yet, now's the time!). I think that having to bounce back into Pyto to make this happen is a bit clunky, but beggars can't be choosers. The widget also seems to refresh relatively often — Apple says that widgets dynamically refresh somewhere between 15-70 minutes depending on user behavior, which is more than enough to keep the raised amount relatively up-to-date.

I Don't Want to Read Your Code, I Just Want the Widget!

Fair enough, let's actually walk through the steps for you, dear reader, to get this widget on your iPhone:

  1. Download Pyto from the app store. Pyto has a 3-day free trial, but you'll need to pay the $2.99 in-app purchase to run this script beyond then.
  2. Download this python script from my GitHub page. It handles all of the steps I discussed above: Pulling the fundraiser data, generating a progress bar, and creating the widget using Pyto. Save it in the Files app so you can run it using Pyto (please don't judge my horrendous code too harshly, I'm still new to programming!) If you're feeling adventurous, you can also modify the font size and color, background color, and even what text is displayed — just dive into the code!
  3. Run the script once using Pyto
  4. Edit your home screen, and add the Run Script widget from Pyto (Medium or Large, your choice). Configure that widget to run the StJudeRelay2021.py script you just saved in Pyto

And just like that, you'll be able to monitor Relay's annual St. Jude fundraiser from your home screen. If you still haven't donated, you absolutely should click here now and do so — there's no better cause than St. Jude, and the Relay folks' partnership with them is exceptionally wholesome. And after you donate, you'll want to mark your calendar for the culmination of the campaign: the Podcastathon on September 17th over on Relay's Twitch channel. It's always a wild and wacky event full of fun shenanigans, all for a spectacular cause.