> For the complete documentation index, see [llms.txt](https://ios-course.cornellappdev.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ios-course.cornellappdev.com/resources/textbook/widgets/configuring-widgets.md).

# Configuring Widgets

### AppIntents

AppIntents is the framework developed by Apple that allows us to configure our widgets with custom information provided by the user.

### Creating a New Intent

We will create a new intent that allows the user to input a location and have the weather widget update its displayed conditions.

Let’s start by creating a new Swift file, which we will call `LocationAppIntent`.

Within that file, we will define a new structure that conforms to the `WidgetConfigurationIntent` protocol. This protocol provides us with an interface for configuring a WidgetKit widget.

{% code title="LocationAppIntent.swift" %}

```swift
import WidgetKit
import AppIntents

struct LocationAppIntent: WidgetConfigurationIntent {

}
```

{% endcode %}

This protocol requires us to implement a title for this Intent. Additionally, we can also implement a description on what this intent does.

{% code title="LocationAppIntent.swift" %}

```swift
static var title: LocalizedStringResource = "Location"
static var description = IntentDescription("Enter a location to view the weather.")
```

{% endcode %}

Next, we can define a parameter for this intent with a default value. The parameter will contain the location that use inputs.

{% code title="LocationAppIntent.swift" %}

```swift
@Parameter(title: "Location", default: "Ithaca, NY")
var location: String
```

{% endcode %}

### Changes to WeatherEntry

Since our intent can make changes to a widget entry within our timeline, we must include it inside of the WeatherEntry model.

{% code title="WeatherWidgetEntry.swift" %}

```swift
import WidgetKit

struct WeatherEntry: TimelineEntry {
    let date: Date
    let weather: Weather
    let configuration: LocationAppIntent
}
```

{% endcode %}

### Changes to WeatherTimelineProvider

We must also update our timeline provider to support this new app intent. We will change our provider to conform to the `AppIntentTimelineProvider` protocol to do so.

{% code title="WeatherWidgetProvider.swift" %}

```swift
struct Provider: AppIntentTimelineProvider {

}
```

{% endcode %}

Additionally, we will need to update the function headers for fetching a snapshot and timeline entry.

{% code title="WeatherWidgetProvider.swift" %}

```swift
func snapshot(for configuration: LocationAppIntent, in context: Context) async -> WeatherEntry {

}
```

{% endcode %}

{% code title="WeatherWidgetProvider.swift" %}

```swift
func timeline(for configuration: LocationAppIntent, in context: Context) async -> Timeline<WeatherEntry> {

}
```

{% endcode %}

These two functions provide us with the intent called `configuration` that contain user-customized values for the location.

Within both of these functions, we have to update our `WeatherEntry` instantiation to pass in the configuration.

{% code title="WeatherWidgetProvider.swift" %}

```swift
let entry = WeatherEntry(date: Date(), weather: possibleWeathers.randomElement()!, configuration: configuration) 
```

{% endcode %}

Additionally, we also have to update the entry created within our placeholder function with a new intent object.

{% code title="WeatherWidgetProvider.swift" %}

```swift
func placeholder(in context: Context) -> WeatherEntry {
    return WeatherEntry(date: Date(), weather: .sunny, configuration: LocationAppIntent())
}
```

{% endcode %}

### Changes to Widget Configuration

Within `WeatherWidget.swift`, we also have to change our widget’s configuration from `StaticConfiguration` to `AppIntentConfiguration`.

{% code title="WeatherWidget.swift" %}

```swift
AppIntentConfiguration(kind: kind, intent: LocationAppIntent.self, provider: Provider()) { entry in
    WeatherWidgetView(entry: entry)
}
```

{% endcode %}

### Changes to View

Finally, within `WeatherWidgetView`, we can update the “Ithaca, NY” string to display the location passed in through the app intent associated with the timeline entry being displayed.

{% code title="WeatherWidgetView\.swift" %}

```swift
HStack {
    Text(entry.configuration.location)
        .font(.system(size: 18, weight: .semibold))
        .minimumScaleFactor(0.5)
    Spacer()
}
```

{% endcode %}

Additionally, to view the widget in the Preview window, we will need to provide it with a default configuration. We can define a default intent as an extension of our `LocationAppIntent` within our view. Since we do not want this default value being used anywhere outside this file, we mark it with `fileprivate`.

{% code title="WeatherWidgetView\.swift" %}

```swift
extension LocationAppIntent {
    fileprivate static var cupertino: LocationAppIntent {
        let intent = LocationAppIntent()
        intent.location = "Cupertino, CA"
        return intent
    }
}
```

{% endcode %}

We then update the preview entries to use this new configuration.

{% code title="WeatherWidgetView\.swift" %}

```swift
#Preview(as: .systemSmall) {
    WeatherWidget()
} timeline: {
    WeatherEntry(date: .now, weather: .sunny, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .cloudy, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .overcast, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .rainy, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .lightning, configuration: .cupertino)
    WeatherEntry(date: .now, weather: .snowy, configuration: .cupertino)
}
```

{% endcode %}
