What I am working on
Handling focus in SwiftUI Lists
Focus management is a usability feature that is especially important for productivity apps. Let’s face it, users don’t use a to-do list app because they enjoy planning their day so much - they’d probably much rather read a book, watch a movie, or go for a walk. The ideal user experience in a productivity app lets the user get their job done as quickly as possible. And this is why focus management is so essential.
In Apple’s Reminders app, the user can create a new reminder by tapping on a button. This will add a new, empty reminder, and place the cursor into the new reminder, allowing the users to start entering the title for the new item straight away. Once the user has finished entering the reminder, they can just tap the [Enter] key to advance. This will create a new reminder in the next line.
If you watch closely, you will also notice that, once they’ve entered the text for a to-do item, the user can tap Enter again to create a new to-do item below. This makes entering items very efficient: the user doesn’t have to tap on any buttons to create new items - everything can be done by just using the keyboard.
Apple introduced APIs for managing focus in iOS 15, and there are a bunch of great articles out there that cover how to use this feature in input forms. Unfortunately, there is little information about how to use this feature in List views, and my own experimentation showed that focus management doesn’t work in List views. Or so I thought - until I brought this up in this Twitter thread that I use as a sort of development journal. @erithacus_ and @thecraftybrit mentioned they had been bothered by this as well, and shortly after @thecraftybrit mentioned he had solved this for Xcode 13.1 beta and iOS 15.2 beta, which allowed me to implement this in MakeItSo.
So even though this doesn’t work on physical devices just yet, let me walk you through the individual pieces of the solution.
Indicating which UI element should be focused is easy for UIs that have a predefined number of elements - we can define an enum with a value for each of the UI elements. This doesn’t work for lists, as the number of rows is dynamic. To solve this, we will use an enum with an associated value. This associated value will contain the id of the selected element, which will allows us to easily focus an element or track which element the user focused.
As we want to keep as much of the applications logic outside of the actual views, we use view models to hold the code that is closely related to each individual view. This means that the code for adding new elements also lives in a view model. So, when we add a new to-do element (e.g. when the user tapped the New Reminder button, or when they placed the cursor in the list and hit the Enter key), we need to set the focus from inside a method on the view model. Unfortunately,
@FocusState
can only be used on View s, so we cannot use it on our view model (which is a class conforming toObservableObject
). We can solve this by implementing a mechanism that syncs between a property on the view model and the view. I know… this sounds a lot like an@Published
property, but since property wrappers cannot be composed (yet?), we need to use a different approach, and sync using the.onChangeOf
view modifier. Trust me, this works brilliantly.When the user taps the Enter key while one of the to-do items is focused, we want to create a new item below and place the focus inside this new element. Detecting the Enter key is actually one of the things that is pretty straight forward - we can use the
.onSubmit
view modifier.And finally, we want to remove empty elements from the list once they lose focus. To achieve this, we will use a Combine pipeline (on the view model) that tracks the previously focused element and removes it from the list of reminders if it is empty. As you will see, building this pipeline has its own challenges to make sure the animations on the list look smooth.
To learn more about how all of this works in detail and see all the code snippets, head over to my blog to read my article Managing Focus in SwiftUI List Views. You can also check out this commit on the repository - it contains all the relevant bits and pieces.
Thanks to @thecraftybrit and @erithacus_ for helping me implement this feature and convincing me to not give up when I thought this wasn’t possible in pure SwiftUI. Check out our conversation on Twitter if you’re interested - it’s great to be part of a community that supports each other.
Firebase
#FirebaseSummit Community Week
I’ve mentioned Firebase Summit 2021 a couple of times before in this newsletter (it’s taking place next week - have you registered yet?), and this week we’re celebrating Firebase Summit Community Week! There are no less than 9 videos created by members of the community. Topics range from how to land your dream job, using Firebase Test Lab to test your Flutter app, fighting inequality using PWAs running on Firebase Hosting, to security and scaling your apps.
Check out my handy viewing guide!
Swift
Serverside Swift
Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns. The goal of the Swift project is to create the best available language for uses ranging from systems programming, to mobile and desktop apps, scaling up to cloud services. Most importantly, Swift is designed to make writing and maintaining correct programs easier for the developer (From https://www.swift.org/about/)
For the past couple of years, most of use have probably used Swift for developing on the frontend (mostly iOS and watchOS, and - to a lesser extent macOS and tvOS), and maybe wrote the odd shell script.
Using Swift on the server still seems to be rather niche (and if I understood Tim Condon’s talk at SwiftLeeds correctly, the server-side Swift community is still relatively small). But Apple seems to be pretty serious about Swift on the server. There might not be an official framework from Apple, but Vapor seems to have become the de-facto standard, and it now supports async/await!
If you’re interested in learning more about Swift on the server, watch this recording of Tim’s talk from iOS Conf SG 2020.
Tim knows a thing or two about server-side Swift, and he seems to be pretty stoked about the recent announcement of Distributed Actors.
It's hard to explain and get across how powerful this is 🤯 It's also difficult to comprehend how this, structured concurrency, task locals etc practically make Swift leap frog every other server side language out there. It's seriously incredible 🚀
(https://twitter.com/0xTim/status/1454040185423925254)
If you’re eager to learn more about Swift’s new concurrency model in general or actors in particular, check out the following resources:
- https://twitter.com/DonnyWals/status/1455136111945211911
- https://twitter.com/twannl/status/1455504482087936003
- https://twitter.com/icanzilb/status/1456246980850630667
Productivity
Steve Jobs' role in creating spreadsheet software
I promised you some computer history when I started this newsletter, so here we go - the history of spreadsheets. Did you know Steve Jobs was involved in creating spreadsheet software?
8 things Google Sheets can do
Thanks to the Internet, we no longer have to install software on our computers - software like Google Sheets just runs in the cloud (or rather, we download it from the cloud and run it in the JavaScript sandbox of our browser). Here are some pretty cool tips and tricks that will bring your Google Sheets skills to the next level.
Jobs
iOS Engineer at Collect @wetransfer
I’ve seen a couple of interesting job postings in the past few weeks, and thought it’d be good to surface them here as well. Instead of linking to the job postings, I will link to the people who mentioned them on Twitter, so you can reach out to them for more details (or to get a referral).
This first one is for the role of iOS Engineer at Collect @wetransfer.
Fun stuff
Playing With Time
You might have seen this Playing With Time video on your Twitter timeline this week - it is just brilliant.
Playing With 'Playing With Time' | Quick D
Now, if you just want to enjoy the video, and remain curious how it was made, I suggest you stop reading now.
However, if you’re curious how it was made, check out the following video by Captain Disillusion. Actually, I am not sure which video is more amazing - the original, or the one that destroys the illusion and disseminates the process of how the original most likely was created. Brilliant!
Comment
Hello everyone 👋🏻
This issue is slightly different from previous ones: it is the first in a series of issues in which I will write about an app that I am working on in more detail. If you follow me on Twitter (or have been a subscriber at least since issue #9), you will know that I started re-implementing Make It So. Make It So is a task list application, written in Swift. The idea behind this app is to see if it is possible to replicate Apple’s Reminders app using SwiftUI and Firebase.
And of course, the name is a nod to one of my favourite sci-fi series - Star Trek Next Generation.
When I first created MakeItSo in early 2020, SwiftUI was still really new, and some things just weren’t possible in SwiftUI. For example, SwiftUI didn’t have swipe actions, and it was impossible to manage input focus. SwiftUI has come a long way since then, and I felt it was time to pick the project back up again and see how close we can get this time.
Re-implementing this app will take some time (I’ve got some other obligations as well), and you can follow along as I implement the app and share my progress with you on Twitter, GitHub, and eventually on the Firebase YouTube channel.
I will also share some insights in this newsletter and on my blog - so make sure to subscribe if you haven’t done so already.
As always, I am keen to hear your feedback, so if you’ve got anything you’d like to share with me, just hit that reply button and let me know! Seriously - I do love hearing from you, don’t be shy!
Thanks for reading, Peter
P.S. if you’d like to say thanks beyond subscribing or sharing this newsletter with a friend, you can now send me a coffee through the internet!
Not Only Swift