iosswiftshortcutappintents

Set default (custom value) in iOS AppIntent parameter


I am trying to create some shortcuts where one of the shortcuts I will set my device name. I will perform some action on the selected device(which is set up on my first shortcut) in another shortcut.

For this, I am trying to create a custom AppIntent where one of my parameter values is a string. I want to set the parameter's default value from my previously stored UserDefault. However, the default value doesn't take any let\var value. I tried the following

struct AppIntentSetUp: AppIntent {
    @Parameter(title: "DeviceName", description: "The device name", default: deviceName, inputOptions: String.IntentInputOptions(capitalizationType: .words), requestValueDialog: IntentDialog("What is the device name?"))
    var device: String
    
    
    static var parameterSummary: some ParameterSummary {
        Summary("Select the device \(\.$device)  ")
    }
    
    static var title: LocalizedStringResource {
        .init(stringLiteral: "AppIntentSetUp")
    }
    
    func perform() async throws -> some IntentResult {
        //do my action
        return .result(value: "")
    }
}


var deviceName: String? {
    UserDefaults(suiteName: "MyDeviceName")?.object(forKey: "MyDevice") as? String
}
 

Now I am getting the following error from the compiler

Expect a compile-time constant literal

From the error, I understand that the default value takes a compile-time constant value.

Is there any way to set the AppIntent parameter default value to a custom value?

or other ways I can achieve my primary goal is to set one shortcut and use that value in another shortcut.


Solution

  • As none is answering my question, I have found my question's solutions. The solution may not be perfect but solves the requirement.

    To set a custom default value in AppIntent parameter, We need to create a custom AppEnity which will be used as a parameter type.

    The custom AppEnity, defaultQuery needs to confirm EntityQuery which supports func defaultResult()

    By confirming defaultResult() we can provide a default value to the AppIntent parameter at runtime.

    To use one AppIntent selected property to another AppIntent, we need to save the first AppIntent parameter value to any storage during parameter value selection. We can achieve this by saving value inside func entities(for identifiers: [*.ID])

    And to get another AppIntent save value we can use defaultResult() function.

    My sample code is as follows

    import AppIntents
    
    struct AppIntentSetUp: AppIntent {
        @Parameter(title: "DeviceName", description: "The device name", requestValueDialog: IntentDialog("What is the device name?"))
        var device: DeviceAppEntity
        
        
        static var parameterSummary: some ParameterSummary {
            Summary("Select the device \(\.$device)  ")
        }
        
        static var title: LocalizedStringResource {
            .init(stringLiteral: "AppIntentSetUp")
        }
        
        func perform() async throws -> some IntentResult & ReturnsValue<String?>{
            //do my action
            return .result(value: "")
        }
    }
    
    
    struct DeviceAppEntity: AppEntity {
        static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Device entity")
        static var defaultQuery = DeviceAppEntityQuery()
        
        var id: String
        var displayString: String
        var displayRepresentation: DisplayRepresentation {
            DisplayRepresentation(title: "\(displayString)")
        }
    }
    
    struct DeviceAppEntityQuery: EntityQuery {
        func entities(for identifiers: [DeviceAppEntity.ID]) async throws -> [DeviceAppEntity] {
            let result = try await suggestedEntities().filter { identifiers.contains($0.id) }
            // Saving device in storage
            saveDeviceInStorage(result.first)
            return result
        }
        
        func suggestedEntities() async throws -> [DeviceAppEntity] {
            deviceList
        }
        
        func defaultResult() async -> DeviceAppEntity? {
            //getting device from storage
            _ = deviceInStorage()
            
            try? await suggestedEntities().first
        }
        
        func saveDeviceInStorage(_ device: DeviceAppEntity?) {
            // Save device in storage
        }
        
        func deviceInStorage() -> DeviceAppEntity? {
            // fetch device from storage
        }
    }
    
    let deviceList: [DeviceAppEntity] = [
        .init(id: "\(UUID().uuidString)", displayString: "One 1"),
        .init(id: "\(UUID().uuidString)", displayString: "One 2"),
        .init(id: "\(UUID().uuidString)", displayString: "One 3")
    ]