Search code examples
swiftwidgetkitsirikitappintentsios17

Display AppEntity results depending on the selection of a Parameter in AppIntent


I'm transitioning from SiriKit Intents to AppIntents for the upcoming iOS 17 and would like to restore the same logic as in the current IntentHandler.

Based on the selection of the first parameter on the AppIntent, the app creates a list of options for a second parameter. E.g.: After selecting a country on the first parameter, I only want to show the cities located in that country on the second (instead of all cities from all countries).

I can't find a way to pass the country variable to my CityEntityQuery.

Changing the parameters of the AppIntent sadly isn't possible because it would fail to migrate from iOS 16 to iOS 17.

Snippet from the Intent:

struct MyIntent: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent {
    static let intentClassName = "MyIntent"

    static var title: LocalizedStringResource = "Do Something"
    static var description = IntentDescription("Description of Do Something")

    
    @Parameter(title: "Country")
    var country: CountryAppEntity?

    @Parameter(title: "City")
    var city: CityAppEntity?
}

My CityAppEntity where I'd like to access the country selected on the parent intent

struct CityAppEntity: AppEntity {
    static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "City")

    struct CityAppEntityQuery: EntityQuery {
        //I'd like to pass the selected country from the intent here somehow
        var countryAppEntity: CountryAppEntity?
        
        func entities(for identifiers: [CityAppEntity.ID]) async throws -> [CityAppEntity] {
            return await retrieveCities(country: countryAppEntity).filter { identifiers.contains($0.id) }
        }

        func suggestedEntities() async throws -> [CityAppEntity] {
            return await retrieveCities(country: countryAppEntity)
        }
        
        func retrieveCities(country: CountryAppEntity?) async -> [CityAppEntity] {
            //retrieve city based on country
            //...
        }
    }
    static var defaultQuery = CityEntityQuery()
    

    var id: String // if your identifier is not a String, conform the entity to EntityIdentifierConvertible.
    var displayString: String
    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(displayString)")
    }

    init(id: String, displayString: String) {
        self.id = id
        self.displayString = displayString
    }
}

Solution

  • Found the solution, I'll post it here for those who have the same issue.

    @IntentParameterDependency is the key to pass the intent into the AppEntity:

        struct CityAppEntityQuery: EntityQuery {
            //get the intent and requested property
            @IntentParameterDependency<MyIntent>(
                \.$country
            )
            var intent
            
            //code.....
        }