The online home of John Pollard

Released my new Sideboard app

My first new app in quite a while, and I made Club MacStories "App Debuts"!

Sideboard

After over two years of development, I can finally unveil my new Sideboard app

You can read all about Sideboard on the app’s main page, so I won’t repeat everything it does here, but to quote that page

Sideboard is an iOS, iPadOS, Mac, watchOS and visionOS app designed to summarise your upcoming meetings and enhance your productivity

I’d been working on Sideboard for probably over 2 years on and off, as was really a side project to keep my hand in native iOS development - my day job is mostly Flutter and NodeJS/JavaScript at the moment

It was originally a lot more ambitious app to control things “on the side”, including

  • Shwoing your upcoming meetings
  • Controlling your Apple Music or Spotify music player
  • Showing the latest weather forecast

… all while running on a dock

However the music part either didn’t work well (for Spotify) and when I gave up using Apple Music after a brief experiment, I lost interest. Also, when iOS 17 brought standby mode, I gave up on the app for a while, thinking it had been properly sherlocked.

After a while longer though, I figured out that if I built a nice widget the app would still have some value in standby mode for just the meetings part. That gave me the energy to finally get everything ready to ship, and here we are!

Sideboard in standby mode

Press Coverage!

I thought I’d actually do some (minimal!) promotion of the app, so I made a press pack and got in contact with a few Apple-focussed websites

I didn’t expect anything to come of it, but I was very pleasantly surprised when John Voorhees from MacStories got in contact to say Sideboard would be featured in issue 419 of Club MacStories (behind a paywall, but see the image at the top of the article)

Still to early to say how may downloads this will result in, but TBH I’m happy enough just to get in the newsletter!

Sideboard is “Charityware”

I decided early on not to charge for Sideboard. I’m not 100% convinced it adds a ton of value, and definitely not enough for my original plan of it being a subscription app

What I have done though is put a prompt in the settings asking for charity donations if people want to “say thanks” in some way

I’m really happy doing it this way, rather than putting in some probably awful ads or asking for money

Next Steps

I’m not sure I have any great ideas to extend the product, but if you do have any ideas for improvements do let me know

No Longer Business Time

Big changes for the business, small changes to the website

2024 has meant a big change to my working life, as Bravelocation Software Limited is no more ☹️

I’ve taken on a full time position as Head of Development at Paradym after working with Courtney and the team there for all of 2023. I’m really enjoying my work with Paradym, and our mission to make getting mental health help more available to everyone

What that’s meant is I’m shutting down my Brave Location business, and stopping being a contractor after many (many!) years and become a salaryman again

I’m also taking the opportunity to simplify my online life, which means:

  • This site is now my “personal” site, rather that pretending to be a “business” site
  • I’ve moved my blog back here (and old links from Writing on Tablets will be redirected here)
  • I’ve stopped doing any external support work for a couple of apps, and obviously taking on new contract work

I’m also making some other technical changes that I may blog about, although seeing that this is the first post for over a year I feel like that’s a promise I may not keep

Finally, I’m working on a not very exciting app in my spare time, mainly to keep my hand in at native iOS development (work is Flutter plus backend work now). I’ll hopefully be shipping v1.0 of that soon

Thanks for listening
John - no longer the spokesperson for Brave Location

Count The Days Left Rewrite

All new code, but still basically the same

I started my Count The Days Left iOS app back in 2015(!), mainly as an exercise to learn the (then) new Swift language, but also to have an app to count down to end of my current contract work!

I’ve made the occasional tweak over the years, but decided it was time it received a bit more love, so I’ve completely rewritten it - even though it basically works in the same way.

Switching to SwiftUI

I’d already switched the WatchOS app to SwiftUI a few years ago, but now all of the UI code is written in SwiftUI.

For such a simple app, SwiftUI is perfect. I’ve done quite a few SwiftUI projects recently and am happy that the ease of development and increased productivity outweigh the occasional glitches.

I’m not sure the Mac app settings screen is that great though. For SwiftUI to be truly great for cross-platform work, it’s on the Mac that is by far the most problematic. If I have the energy I may go back and try to improve that.

I think the app’s UIis so much better now. It was a lot easier to add a nice animation on the progress view - take a look at this preview video to see what I mean …

WatchOS now supports iCloud Key-Value store sync

The app uses both UserDefaults and iCloud key-value store to store the user’s settings. The latter is used so you can sync your settings across devices.

Previously, pushing the settings to the watch meant some complicated logic in manually pushing the settings across from the phone every time they changed, which was problematic and a bit unreliable.

Now in watchOS 9.0, the watch also supports iCloud Key-Value store sync, which made the code MUCH simpler as it can now reuse the data management code from the main app.

This has meant that the watch app now has a minimum OS version of 9.0+, but again I think the trade off of much increased reliability is worth it.

New features

I’ve completely rewritten the widget code, and also added some nice lock screen widgets for iOS 16 users.

Moving to watchOS 9.0 also means I can reuse the widget code to improve the watch complications.

The Siri shortcuts code is much improved too - moving to the new AppIntents framework and SwiftUI for the visual component.

I’m also using the new shortcut provider API to suggest an appropriate shortcut to access your days left data directly in the Shortcuts app.

Modernised Swift code

It’s probably to be expected, but some of the 7 year old code was VERY out of date, and a little embarrasing 😳

I’ve restructured so it’s much better organised, uses protocols and generics where appropriate, and is a much better showcase for what I can do (I hope!)

Accessibility Improvements

Using SwiftUI means the accessibilty features are generally better straight out of the box, but I have spent some time making sure that voice over works well, as well as making the UI scalable using differemnt font sizes.

Removed some legacy extensions

The old school Today widget has gone, as has the iMessage extension - that seemed a good idea at the time but they really haven’t take off (to say the least!)

I’ve also removed the “tip” option, where people could do an in-app purchase to say thanks. TBH so few people were using it - and I definitely wasn’t promoting it in any way! - that I couldn’t be bothered to spend the effort porting the code.

Summary

I’m really happy with the updated code, and I’ll be much happier in potential customers looking at it as an example of my work.

If you want to take a look yourself, it’s here on GitHub

iOS 16 Yeltzland Release

iOS 16 should be available any day soon now, so I’ve been adding some new features to the Yeltzland app to take advantage.

Lock Screen widgets

The biggest visible change in iOS 16 are the new lock screen widgets - which presumably will be great with the heaviliy rumoured always-on screens of the new phones.

The widgets show either the latest score, the last result or the next upcoming fixture, whatever is the most relevant at the current time.

The app already had Apple Watch complications, which made it very little work to add similar widgets on the lock screen.

Screenshot of the new lock screen widgets

It took a bit of fiddling to get the update frequency working correctly, especially during the match. This works quite well now, especially if you have the game time tweet notifications feature turned on (which I can use to trigger an widget update out of the scheduled timeline)

As you can see from the screenshot above, I’ve also added a new “badge only” widget, which just shows the club badge if you just want to personalise your phone a bit.

Improved complications on the Apple Watch

Watch complications and lock screen widget code has been unified, so I’ve been able to combine the code for both into a single extension.

This also means the watch complications are a bit better now, as they benefit from the work I put in to keep them better updated as the goals fly in.

Better Siri Shortcuts

Thankfully the old intent definition code has been deprecated into a much nicer system using AppIntents. This makes it much nicer to both define and build the logic for Shortcuts support, as well as to be able to donate shortcut suggestions directly from the app.

This means I have been able to delete a whole load of code - which is always nice - and simplify the discovery of the shortcuts the app supports.

There’s how I use the shortcuts (so I can ask Siri the latest score) …

Screenshot of a Yeltzland action in Shortcuts

… plus how it looks visually when this shortcut is run

Screenshot of the shortcut result dialog

Summary

It’s been the quietest summer for a while on the new feature front, with not many customer facing changes of note in iOS 16.

However, I think the lock screen widgets are a big improvement, and I’m pretty happy how they’ve turned out.

Let’s see if we have any surprises later today when the new hardware is announced 🤞

Adding Entries In Spotlight Search

Surprisingly easy to do

I’ve had a bit of down time recently - which has been great - and in-between watching the Euros and the Tour de France, I’ve had time to watch quite a few WWDC videos.

One video entitled Showcase app data in Spotlight looked interesting, as I’d never considered adding anything from any of my apps into Spotlight Search.

Now the video itself wasn’t massively useful for me, as it was most about how you can feed Core Data easily into Spotlight - and I don’t really use Core Data unless I absolutely have to!

However, it inspired me to get the fixture and results data from my Yeltzland app into Spotlight.

Adding entries into Spotlight

The logic of my code is as follows:

  1. Listen for updates to the fixtures data
  2. On update, first remove all entries for the fixture data domain identifier (a unique string denoting the set of entries)
  3. Then add a new index entry for each match in the data set

The full code is available on GitHub and should be pretty self-explanatory.

To remove all entries for a domain identifer, simply call:

CSSearchableIndex.default().deleteSearchableItems(
    withDomainIdentifiers: [SpotlightManager.domainIdentifier],
    completionHandler: completionHandler)

Then the code to add an individual entry to the search index is straightforward too:

    var items: [CSSearchableItem] = []
    
    // Fetch all fixtures
    let fixtures = FixtureManager.shared.allMatches
    for fixture in fixtures {

        // Create an attribute set to describe the fixture
        let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeData as String)
        attributeSet.title = fixture.spotlightSearchTitle
        attributeSet.contentDescription = fixture.spotlightSearchDescription
            
        // Create an item with a unique identifier, a domain identifier, and the attribute set you created earlier.
        let item = CSSearchableItem(uniqueIdentifier: "\(SpotlightManager.domainIdentifier)-\(fixture.identifier)",
                                    domainIdentifier: SpotlightManager.domainIdentifier,
                                    attributeSet: attributeSet)
        
        items.append(item)
    }
    
    CSSearchableIndex.default().indexSearchableItems(items) { error in
        if let error = error {
            print("Error add spotlight entries: ", error.localizedDescription)
        } else {
            print("Spotlight entries successfully added")
        }
    }

How it looks

That was all very simple, and you can see in the screenshot below it came out very nicely

Spotlight Example

If I’d have know it was that easy (and how to do it!), I would have added this years ago 😀