Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an INIntent property be given the value "Ask Each Time"?

Let's say I've defined a custom intent, called FooIntent, in an .intentdefinition file.

It has a single parameter, bar, of type Decimal, for which:
- User can supply value in Siri and Shortcuts app is active.
- Default Value is 0.

Its autogenerated class definition now looks like this:

public class FooIntent: INIntent {
    @NSManaged public var bar: NSNumber?
}

If I construct a FooIntent, set bar to nil, and pass it into a INUIAddVoiceShortcutViewController:

let intent = FooIntent()
intent.bar = nil
intent.suggestedInvocationPhrase = "Do foo"

let shortcut = INShortcut(intent: intent)

let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut!)
viewController.delegate = self
window?.rootViewController?.present(viewController, animated: true, completion: nil)

the Add to Siri modal appears with the bar parameter filled in with 0, its default value.

If, in the Add to Siri UI, I then change bar to Ask Each Time and press Add to Siri, the resulting delegate method call produces an INVoiceShortcut object that contains a nil value for bar:

func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith shortcut: INVoiceShortcut?, error: Error?) {
    if let intent = shortcut?.shortcut.intent as? FooIntent {
        print(intent.bar) // nil
    }
    controller.dismiss(animated: true, completion: nil)
}

The same is true if I set bar to Clipboard in the UI.

If I set it to a value, e.g. 42, then intent.bar correctly returns 42.

Since nil seems to represent multiple concepts for a parameter, where is the concept of Ask Each Time stored in the shortcut or intent objects?

Is there anything I can pass into INUIAddVoiceShortcutViewController such that intent.bar = <Ask Each Time>?

like image 813
Naftali Beder Avatar asked Nov 07 '22 13:11

Naftali Beder


1 Answers

Usually you control the behavior (of whether or not to continue asking for user input for a particular param) in your IntentHanlder. For example I achieved to do it this way:

FooIntentHandler: NSObject, FooIntentHandling {

    func resolveBar(for intent: FooIntent, with completion: @escaping (FooBarResolutionResult) -> Void) {
        if let bar = intent.bar as? NSNumber {

            var everythingIsFine = false

            // Any logic here.
            // You can even assign an invalid magic number in your INUIAddVoiceShortcutViewController
            // so that your compare it here to see if the user has input anything different.

            if everythingIsFine {
                completion(FooBarResolutionResult.success(with: bar))
            } else {
                // With .needsValue() Siri will always ask for user input.
                completion(FooBarResolutionResult.needsValue())
            }
        } else {
            completion(FooBarResolutionResult.needsValue())
        }
    }
}

You can also assign a valid value as the initial one, in which case Siri will accept the param value (without asking for user input) as long as you call FooBarResolutionResult.success() in your resolve method as shown above.

In short, Siri calls this resolveBar() to decide whether or not asking for user input.

like image 66
Wei WANG Avatar answered Nov 15 '22 13:11

Wei WANG