An In-depth Guide to Build an Amazing Daily Quotes App
I recently had some fun adding complications to my strength training app strength++, as I went straight to the “new” WidgetKit framework. It’s not really new, but what’s new in wOS 9 is that you can use WidgetKit instead of the old ClockKit to create complications for the clock.
Let’s not waste much time and get to work. you will get the code HereBoth the initial version if you want to code along and the final version if you want to see everything.
We’re using the Dailyquote app built for this purpose, which shares most of its code base between the iOS and watchOS apps. The iOS app is targeting iOS 16, and watchOS is, of course, the minimal version of WOS 9.
We need to add an extension for complications first, so in Xcode, go to File -> New -> Target, select the watchOS tab, and then choose Widget Extensions.
- Tap Next.
- Enter product name.
I went for the DailyQuote complications.
- Uncheck Include Configuration Intent, because the complexities we’re building today are not configurable
- Make sure your project is selected in the dropdown and embed is also set to your watch app.
Tap Finish and Activate to activate your new goal.
Now you can see in the project navigator that under the name you provided earlier there is a new folder containing a swift file, an assets folder and a Info.plist
file. Go ahead and open the newly created Swift file, and let’s start designing our widgets.
At this point, I want you to open this link This is the official documentation for what we’re doing here, and if I don’t give you enough information or you have some questions, you may find the answer.
Your Complexity Will Be Done By The Hard Lifting For The UI EntryView
structure, which in my case is DailyQuote_ComplicationsEntryView
,
Let’s first add a property to identify the widget family we’re designing for:
struct DailyQuote_ComplicationsEntryView : View @Environment(\.widgetFamily) var widgetFamilyvar entry: Provider.Entry
var body: some View Text(entry.date, style: .time)
so i have added widgetFamily
variable, which is pulling from Environment
to object to the price, well, widgetFamily
, At this point, you need to understand how complications are grouped. There are four groups leading to WOS complications:
accessoryInline
accessoryCorner
accessoryRectangular
accessoryCircular
You can choose and support whoever you want, but today we’ll go and create the complications for each. So let’s create four SwiftUI Views:
One of the ideas of each complexity is Text
At the point where I applied:
widgetAccentable
Which adds the scene and all its subviews to the utterance group.unredacted
which tells the OS that that specific scene doesn’t need to be modified at any point (meaning blurring)
Now let’s go back EntryView
And add our ideas to each widget family:
Now, let’s add some previews to all our complications.
- go to
_preview struct
who was born - existing duplicate
EntryView
four times for each type of complication
You will now have four previews in the canvas.
Something’s starting to show, isn’t it?
Now, I won’t go into the design for each complication type, in the end, it’s your choice how you want it to look, but I’ll go into my favorites: corner
,
For this specific one, I’ve added an image from SF symbols (note, it shows up as small, so think about it when designing complications) and used widgetLabel
Celebration. This function, according to Apple, “creates a label to display additional content outside the main SwiftUI view of an accessory family widget.” That’s the short version.
Alt + Tap
To read the full documentation on that.
For now the last thing we’ll do for the UI side is to update Widget
Structure to better “describe” our widget to the system and users. so, go to struct DailyQuote_Complications: Widget
and update it:
We just did the following:
- hardcoded a
kind
which is a unique identifier for this widget (if you will have more) - updated
configurationDisplayName
is the name that shows up in our complexities as complexity picker - One
description
Shown for the widget when a user adds or edits a widget
driven by your complexity TimelineEntry
… Entries. so Xcode generated this SimpleEntry: TimelineEntry
which we now need to rename QuoteEntry
,
and add a new property to it, a Quote
,
struct QuoteEntry: TimelineEntry let date: Datelet quote: Quote
don’t forget to add Quote
For targeted membership of the Complexity extension.
Now your entire file is red because every instantiation of QuoteEntry
is missing Quote
parameter. Let’s start updating them.
the first is func
placeholder(in context: context) -> QuoteEntry.
This method returns a hardcoded QuoteEntry
To use in specific scenarios where the OS shows your complexity in a “sensitive” context (if you need to read more on this, see the docs).
func placeholder(in context: Context) -> QuoteEntry let quote = Quote(quote: "Roses are red", author: "Nobody knows")return QuoteEntry(date: Date(), quote: quote)
is at the front func getSnapshot(in context: Context, completion: @escaping (QuoteEntry) -> ())
Which, according to Apple, is a timeline entry that represents the current time and position of a widget. In this scenario, we need to treat the two cases based on context, as the context can be a preview of the complexity or the actual complexity running on the clock.
For this we need to bring QuoteManager
So declare it in our struct (and again, don’t forget to set its target membership). If we’re not seeing the preview, we really want to get an actual quote out of our data layer.
The last thing we need to do is actually create a timeline for our widget, so let’s go and modify getTimeline()
,
In case it’s not self-explanatory, we’re creating a timeline of five entries, one minute apart, and each pulling a different quote from our storage.
We have the data and the UI, so let’s modify all of our Complication
a. think with QuoteEntry
property, which will be passed from EntryView
, we will also set .quote
property from entry as parameter for Text
on our UI.
Hint: At this point, you need to reset the target membership Quotes.json
File for complexity extension target.
And that’s it! Running the Complications goal on a clock simulator (and of course using Complications) now shows off our sexy new complications with a fancy daily quote.
Thanks for reading.