App Intents: Grouping Parent Parameters Using a Unified Entity Approach

Streaks developer Quentin Zervaas shared this great technique for working with complex parent parameters in App Intents – grouping them into a single, separate entity.
App Intents: Grouping Parent Parameters Using a Unified Entity Approach

From Quentin Zervaas, developer of Streaks, on their blog Crunchy Bagel in a post titled “Migrating Widget Configurations with Parent Parameters to use AppIntent”:

In order to model this in an App Entity using parameterSummary, we would then need a different summary for every task type (“automatic”, “specific”, “next on page”, “next in category”), as well as accounting for each chart type. This is 8 combinations.

Now consider another of our widgets: the “Tasks” widget. This lets you choose up to 4 different tasks, and has the same options:

The structure of the Tasks widget, which shows different task selection options based on the task1type, task2type, task3type, task4type values.
The structure of the Tasks widget, which shows different task selection options based on the task1type, task2type, task3type, task4type values.

In this case, there would be 16 combinations, which really doesn’t scale well. It’s extremely hard to maintain and is inflexible if future changes are needed.

To solve this, I introduced a new type called TaskTypeAppEntity, which encapsulates the four different types (automatic, specific, next on page, next in category) in a single entity:

struct TaskTypeAppEntity: AppEntity, Identifiable {
    static let typeDisplayRepresentation: TypeDisplayRepresentation = "Task Type"

    let id: TaskTypeAppEntityIdentifier

    var title: String

    var displayRepresentation: DisplayRepresentation {
        .init(title: .init(stringLiteral: title))
    }

    static let defaultQuery = TaskTypeAppEntityQuery()
}

enum TaskTypeAppEntityIdentifier {
    case automatic
    case task(TaskID)
    case category(CategoryID)
    case page(PageID)
}

When building the defaultQuery, it’s just a case of including all of the options in that query. You can even group it into separate sections:

The new task type selection screen once the different options are flattened into a single App Entity.
The new task type selection screen once the different options are flattened into a single App Entity.

This is more code than I’ve probably ever shared on my site, but this method is incredible for apps with more complex data models to build a clean App Intents experience for their users – all App Intents developers should take a look and see if they can use this.

I’ll definitely be recommending this to my clients – I had to save this here on my blog, as well as rewrite my own headline to clarify that this is useful beyond widget configurations as well as beyond moving from “INIntents” to App Intents.

View the original, see Quentin’s post, and get Streaks on the App Store.

Posts You Might Like

Tip: Create ~/Developer in Your Mac User Folder for AI Projects
Tip: Create ~/Developer in Your Mac User Folder for AI Projects
If you're building with a Terminal chatbot, make yourself a Developer directory to store all your projects.
How to build an App Intents Spotlight integration using Shortcuts »
How to build an App Intents Spotlight integration using Shortcuts »
Apple has introduced a new feature to display App Intents in Spotlight – Antoine Van Der Lee wrote up how he implemented the change in his app WeTransfer.
You Should Watch The Apple Intelligence Developer Sessions In This Order
You Should Watch The Apple Intelligence Developer Sessions In This Order
If you want to build for Apple Intelligence but don't know where to start, here's a suggested viewing order for the developer sessions.
App Intents are Limited to Thirty Seconds: Extend Execution as Live Activity with LongRunningIntent
App Intents are Limited to Thirty Seconds: Extend Execution as Live Activity with LongRunningIntent
Normally, App Intents have a 30-second limit to finish running – LongRunningIntent helps developers get beyond that by moving to a Live Activity. Plus, CancellableIntent makes sure it can be ended gracefully.