Action
public protocol Action
Actions that can be performed conform to this protocol to define their inputs, presenter and logic.
Actions are statically defined to avoid the mistake of storing state with them. Any state belongs in
the input
passed when performing the action.
Many of these static properties have default implementations provided by a protocol extension.
Note
Action implementations must be final due to Swift extension requirements.The same action can be reused in different features, so they receive all context they need when executing.
Note that actions have their own analytics ID defined statically.
-
An alias for the completion type used with this action. This is a convenience to make it less verbose to conform to this protocol.
Declaration
Swift
typealias Completion = CompletionRequirement<ActionPerformOutcome>
-
The InputType defines the type of value to expect as the input for the action. This provides your initial and perhaps changing state, if you want to pass it back in later.
If your action requires no input you can use
NoInput
, and parameter when performing.Note
Due to a Swift compiler issue, you cannot declare this as an optional type. As a result, all invocations are declared as
InputType?
so actions must always be ready to accept nil.See
Declaration
Swift
associatedtype InputType : FlintLoggable = NoInput
-
The type to use as the presenter (UI) for the action.
This provides high level UI functions that the action can drive.
You can use any type. It is better to use non-UI framework types and introduce your own cross-platform protocols instead. This makes unit testing of features and actions possible.
If your action requires no UI, you can set it to
NoPresenter
and omit the presenter when callingperform()
Declaration
Swift
associatedtype PresenterType = NoPresenter
-
name
Default implementationThe name of the action, for logging and UIs There is a default implementation provided.
Default Implementation
The default naming algorithm is to use the action type’s name tokenized on CamelCaseBoundaries and with
Action
removed from the end. e.g.CreateNewTweetAction
gets the nameCreate New Tweet
Declaration
Swift
static var name: String { get }
-
description
Default implementationThe description of the action, for debug or automation UIs There is a default implementation provided.
Default Implementation
The default alerts you to the fact there is no description. You should help yourself by always supplying something
Declaration
Swift
static var description: String { get }
-
The queue the action should be called on. The dispatcher will ensure this is the queue used.
The default value is
DispatchQueue.main
.Note
This must be a serial queue because in future we may set the context-specific loggers as a specific key on the queue. Concurrency would break this.Declaration
Swift
static var queue: DispatchQueue { get }
-
The session to use when calling
perform
on the action binding, to avoid having to be explicit. Most actions only make sense in the context of a single session e.g. the UI orbackground
.Declaration
Swift
static var defaultSession: ActionSession? { get }
-
hideFromTimeline
Default implementationIf
true
this action will never be reported to the Timeline. This is useful for internal actions that are not explicitly triggered by the user. There is a default implementation provided that returnsfalse
.Default Implementation
By default, all actions are included in the Timeline. Override this and return
true
if your action is not something that helps debug what the user has been doing.Declaration
Swift
static var hideFromTimeline: Bool { get }
-
Implement this static function to perform the action. You typically access
context.input
to read the input and call functions onpresenter
to update the UI.The
completion
closure must be called when the action has been performed.- param context: The action’s context, which includes the
input
, logging and source information - param presenter: The presenter the action must use
- param completion: The completion requirement that the action must use to indicate success or failure
Declaration
Swift
static func perform(context: ActionContext<InputType>, presenter: PresenterType, completion: Completion) -> Completion.Status
- param context: The action’s context, which includes the
-
analyticsID
Default implementationThe optional ID for this action in your analytics back-end. If no value is returned (the default), no analytics tracking will occur for the action.
Default Implementation
Default is to supply no analytics ID and no analytics event will be emitted for these actions
Declaration
Swift
static var analyticsID: String? { get }
-
analyticsAttributes(forRequest:)
Default implementationImplement this function to marshal the information about the action invocation into a dictionary for your analytics system. If you don’t use analytics, you don’t need to implement this.
param request: The action request that is being performed. You use the properties of this, including the
input
property of it, to return any extra attributes you’d like to be logged by your analytics system.return: A dictionary of keys and values to be send with the analytics event, or nil if there are none
Default Implementation
Default behaviour is to not provide any attributes for analytics
Declaration
Swift
static func analyticsAttributes<FeatureType>(forRequest request: ActionRequest<FeatureType, Self>) -> [String : Any?]? where FeatureType : FeatureDefinition
-
activityEligibility
Default implementationThe activity types the action supports. This must contain at least one eligibility value for the activity to be
registered with the system, and the
ActivitiesFeature` must be available.Eligiblity values control whether the action is also exposed for e.g. Spotlight or Handoff. If you just want Siri proactive suggestions, use
[.perform]
.Default Implementation
By default there are no activity types, so no
NSUserActivity
will be emitted.Declaration
Swift
static var activityEligibility: Set<ActivityEligibility> { get }
-
prepareActivity(_:)
Default implementationImplement this function to configure the NSUserActivity for any extra preparation required by the action.
The activity will have been already populated for the action’s ID and eligibility. You do not need to implement this if your feature and action support URL Routes, unless you have extra information not included in the URL that you wish to include.
The
input
property on the build contains the input to the action that should be encoded into theNSUserActivity
. Callcancel
on the builder to veto publishing the activity at all. If the activity cannot be used due to an error and your app needs to know this, you can throw an error.See
param activity: An instance of the activity builder that you use to set up the
NSUserActivity
instanceDefault Implementation
The default behaviour is to return the input activity unchanged.
Provide your own implementation if you need to customize the
NSUserActivity
for an Action.Declaration
Swift
static func prepareActivity(_ activity: ActivityBuilder<Self>) throws
-
suggestedInvocationPhrase
Default implementationA suggested Siri Shortcut phrase to show in the Siri UI when adding a shortcut or registering an
NSUserActivity
for this action.Note
This value is only used if youractivityEligibility
includes.prediction
, or when your action creates anINIntent
to donate.Default Implementation
Declaration
Swift
static var suggestedInvocationPhrase: String? { get }
-
associatedIntents(withInput:)
Default implementationImplement this function if the Action supports one or more Siri Intents for Shortcuts. This is used to automatically donate shortcuts with Siri if you have the
IntentShortcutDonationFeature
enabled.param input: The input to use when creating associated intents for this action.
return: An array of intents to donate to the system for this input, or nil if there are none.
Default Implementation
Implement this function if the Action supports a Siri Intent for Shortcuts. This is used to register a shortcut intent with Siri if you have the
IntentShortcutDonationFeature
enabled.Declaration
Swift
@available(iOS 12, *) static func associatedIntents(withInput input: InputType) throws -> [FlintIntent]?